So I have a structure that is similar to a maze, but with much more open space. And for each node in the structure, I would like to find all it's 'neighbours' (nodes are neighbours if they are in line of sight, i.e no walls blocking the straight line between them).
Here is a little image to help explain what I mean.
Black lines are walls.
Red dots are nodes.
Blue lines are lines to join neighbours (note no blue line crosses a black line).
I am currently implimenting a very naive and extremely costly brute force approch. In which I check every combination of nodes for an intersect with any of the maze walls (walls stored in 'edges').
for n1 in nodes:
for n2 in nodes:
if not intersect(n1, n2, edges):
n1.neighbours.append(n2)
n2.neighbours.append(n1)
This works fine for small structures like the pexample above. But I would love for this to be scalable to much larger structures.
So my question is if there is any way to find all the neighbours of each node much faster/ more efficiently.
Cheers :)
You might want to read Monge's book on projective geometry :)
Let's use an occlusive screen around each node, a square is computationally easy, a circle needs more math. The screen is a collection of edges that hide space from the node. The screen.occlude() method takes one of your walls as input an calculates the projection on the screen, and then extends the occlusion by adding an edge or extending one.
The result is that there are (much?) less occlusion edges then walls.
Then we invert the loops over occlusion edges and nodes to gain time. Note that the method .remove_occluded_by() only loops over remaining candidate neighbours, which is a shrinking collection. I guess the gain is from O(n^2) to O(n*log(n))
You can also have on each side of the square 2 points that are the extremes of the occlusion in that direction, possibly the corners of the virtual square. Every node outside the 4 occlusion cones is visible. Not sure this will gain time.
for n1 in nodes:
n1.occlusion = a_1_by_1_square_occlusion( centre = n1 )
for e in edges:
n1.occlusion.occlude( e )
n1.neighbours = nodes - n1 # your choice
n1.neigbours.remove_connected_walls( n1 ) # your choice
for o in n1.occlusion.edges:
n1.neighbours.remove_occluded_by( o )
Related
Given a polygon that may be concave and may have holes, how can I get the largest simple convex polygon composed of a subset of its vertices?
ie, given the simple concave polygon:
p = Polygon([(30, 2.01), (31.91, 0.62), (31.18, -1.63), (28.82, -1.63), (28.09, 0.62), (30, -0.001970703138552843)])
I want the largest simple convex polygon (perhaps the same but without the leftmost point (28.09, 0.62) and replace (28.82, -1.63) with (30, -1.63)). Like this:
This is just an unmeasured example. It may be that in fact both (28.09, 0.62) and (30, 2.01) must be removed, if this produces a larger area, such as might result from the cut indicated by the green line here:
But, assuming the first cut was correct, If we added a hole to the "other side":
p = Polygon([(30, 2.01), (31.91, 0.62), (31.18, -1.63), (28.82, -1.63), (28.09, 0.62), (30, -0.001970703138552843)],
[[(30.1,0.62), (30.1,1.25), (31, 1.25), (31,0.62)]])
the largest simple convex polygon might in such cases rotate to the other half of the polygon, so instead of dropping the previous point, it would drop (30, 2.01) and replace (31.91, 0.62) with a point between that and (31, -1.63). Obviously, in this case it would throw out all of the vertices of the hole.
commentary
Any hole that would be left intact inside the polygon would introduce a concave angle to the polygon by definition. in the case that there is a hole in the input polygon, at most one edge from it can remain in the output polygon (and, by definition of "simple polygon", that edge would be a member of the exterior coordinates).
There's a little bit of sloppiness in this definition so I should try to be more clear. All interior and exterior vertices are members of the set of possible points in the output simple polygon. So are all points that intersect the interior and exterior bounds (so the line segments between them). The selection of points should result in a simple, convex polygon that is inscribed in the source polygon. In the case that the source polygon is a simple, convex polygon, it should return the same polygon as output. It is quite possible to have whole families of candidate solutions with equal area. If they are maximal, any one of them will do.
Sketch approach: if you throw out cuts like in the sample with the green line, then all that remains are removal of points with projections from segments. So you could count all interior and exterior points as a set, and exclude subsets of 0 or more of them, then find the largest convex polygon. So, either just exclude the point or when excluding a point produces a new concave angle, project from the line segment on that side of the angle to the line segment on the other side of the polygon (this is the approach used to produce the first sample solution image). Revisiting the green line cuts, these are lines that bisect the polygon and tangent the center point of the concave angle. If this bisection must run perpendicular to the line from the center point to the centroid of the remaining polygon, then this is not much more complex. But I'm not sure that that is true. And in any case, that is a lot of polygons to consider.
note: at first I marked a duplicate, thinking this is essentially a more complicated version of another question (Finding largest subset of points forming a convex polygon but with holes). However, this approach does not allow for addition of new vertices in the solution. For example, Delaunay triangulation of the first shape in this article produces no new points:
[ 'POLYGON ((28.09 0.62, 28.82 -1.63, 30 -0.001970703138552843, 28.09 0.62))',
'POLYGON ((28.09 0.62, 30 -0.001970703138552843, 30 2.01, 28.09 0.62))',
'POLYGON ((30 2.01, 30 -0.001970703138552843, 31.91 0.62, 30 2.01))',
'POLYGON ((31.91 0.62, 30 -0.001970703138552843, 31.18 -1.63, 31.91 0.62))',
'POLYGON ((28.82 -1.63, 31.18 -1.63, 30 -0.001970703138552843, 28.82 -1.63))']
The article provided as possible duplicate only counts subsets of the points to find the maximal convex hull -- ie, it does not introduce points on the line.
I am not really sure your problem is well specified (or rather, they way you describe it it is reduced to a well-known, simpler problem).
First, let me introduce you the idea of the Convex Hull:
Given a list of points, the convex hull is the smallest convex (simple) polygon that contains all points.
The shape of the CH is essentially what you would get if you were to "place a rubber band" around the points so that it touches the outer ones.
Now, there is a straightforward property of the CH:
Given a set of points, the are of their CH is larger (or equal) than the area of any other (simple) polygon those may form.
This is true because
i) If they form a convex polygon, then they form the CH by definition.
ii) otherwise, they form some non convex shape. Visually, you can get from the CH to that non convex shape by "removing triangles" comprised of 2 points on the CH and one inner point. So you are removing area, so the CH has the largest area.
So, the largest convex polygon comprise of all the vertices is the CH.
Now, about selecting a subset of the original vertices: This will obviously give you a smaller (or equal) -sized shape. So there is no point in selecting any subset, really.
Also, holes don't really impact this argument. Keeping the whole is obviously to your benefit, since you can add the area around the hole.
So, the final answer (unless I missed something), is that all you need is the Convex Hull.
Fortunately, there are some good python libraries for computing, plotting and messing around with convex hulls.
Consider a set of n cubes with colored facets (each one with a specific color
out of 4 possible ones - red, blue, green and yellow). Form the highest possible tower of k cubes ( k ≤ n ) properly rotated (12 positions of a cube), so the lateral faces of the tower will have the same color, using and evolutionary algorithm.
What I did so far:
I thought that the following representation would be suitable: an Individual could be an array of n integers, each number having a value between 1 and 12, indicating the current position of the cube (an input file contains n lines, each line shows information about the color of each face of the cube).
Then, the Population consists of multiple Individuals.
The Crossover method should create a new child(Individual), containing information from its parents (approximately half from each parent).
Now, my biggest issue is related to the Mutate and Fitness methods.
In Mutate method, if the probability of mutation (say 0.01), I should change the position of a random cube with other random position (for example, the third cube can have its position(rotation) changed from 5 to 12).
In Fitness method, I thought that I could compare, two by two, the cubes from an Individual, to see if they have common faces. If they have a common face, a "count" variable will be incremented with the number of common faces and if all the 4 lateral faces will be the same for these 2 cubes, the count will increase with another number of points. After comparing all the adjacent cubes, the count variable is returned. Our goal is to obtain as many adjacent cubes having the same lateral faces as we can, i.e. to maximize the Fitness method.
My question is the following:
How can be a rotation implemented? I mean, if a cube changes its position(rotation) from 3, to 10, how do we know the new arrangement of the faces? Or, if I perform a mutation on a cube, what is the process of rotating this cube if a random rotation number is selected?
I think that I should create a vector of 6 elements (the colors of each face) for each cube, but when the rotation value of a cube is modified, I don't know in what manner the elements of its vector of faces should be rearranged.
Shuffling them is not correct, because by doing this, two opposite faces could become adjacent, meaning that the vector doesn't represent that particular cube anymore (obviously, two opposite faces cannot be adjacent).
First, I'm not sure how you get 12 rotations; I get 24: 4 orientations with each of the 6 faces on the bottom. Use a standard D6 (6-sided die) and see how many different layouts you get.
Apparently, the first thing you need to build is a something (a class?) that accurately represents a cube in any of the available orientations. I suggest that you use a simple structure that can return the four faces in order -- say, front-right-back-left -- given a cube and the rotation number.
I think you can effectively represent a cube as three pairs of opposing sides. Once you've represented that opposition, the remaining organization is arbitrary numbering: any valid choice is isomorphic to any other. Each rotation will produce an interleaved sequence of two opposing pairs. For instance, a standard D6 has opposing pairs [(1, 6), (2, 5), (3, 4)]. The first 8 rotations would put 1 and 6 on the hidden faces (top and bottom), giving you the sequence 2354 in each of its 4 rotations and their reverses.
That class is one large subsystem of your problem; the other, the genetic algorithm, you seem to have well in hand. Stack all of your cubes randomly; "fitness" is a count of the most prevalent 4-show (sequence of 4 sides) in the stack. At the start, this will generally be 1, as nothing will match.
From there, you seem to have an appropriate handle on mutation. You might give a higher chance of mutating a non-matching cube, or perhaps see if some cube is a half-match: two opposite faces match the "best fit" 4-show, so you merely rotate it along that axis, preserving those two faces, and swapping the other pair for the top-bottom pair (note: two directions to do that).
Does that get you moving?
I'm trying to find the closest vertex on a mesh but within a radius. This is to avoid having to loop through all the vertices as that's time consuming. Example, I have 2 shirts with different vertex count and I'm trying to find the closest vertex of vertex1 that's on mesh2's right sleeve on mesh1's right sleeve. I don't want to loop through verts beyond the sleeve as logically no vertices will be close enough. I understand that there is an assumption that there could be other vertices closer, but for the usage I'm looking for, I don't foresee that being an issue.
I have the code to loop through vertices and get the closest point, but if the mesh has a high vert count, it takes a long time, even if it's using the API.
Is there a function in maya that lets you limit vertices based of a radius? Or any tips on how I can write a function that could do that?
You can use the node nearestPointOnMesh. In maya API, you can look for MFnMesh::closestIntersection class that can raycast (Querying of a point is within a mesh maya python api)
vtx = 'shirt1.vtx[0]'
pos = cmds.pointPosition(vtx)
m = 'shirts2'
objShape = cmds.listRelatives(m, ni=True, type='mesh')[0]
node = cmds.createNode('nearestPointOnMesh')
cmds.connectAttr(objShape + ".worldMesh", node + ".inMesh")
cmds.setAttr(node + ".inPosition", type = 'double3', *pos)
target_pos = cmds.getAttr(node + '.position')[0]
face = cmds.getAttr(node + ".nearestFaceIndex")
I need to join two convex, non-intersecting polygons into one joined covex polygon in way of minimisation of resulting area, like in picture below: I'm seeking for an alhorithm doing this. I also would be appreciate if someone provide me with corresponding python implementation.
If there are two non-intersecting polygons having say, m and n vertices respectively, then your problem can be thought of in this way:
Finding the convex polygon of the least area containing all of the m+n points. Having said this, check out the QuickHull Algorithm here: http://www.geeksforgeeks.org/quickhull-algorithm-convex-hull/
Additionally you can also check out these algorithms.
Jarvis's Algorithm: http://www.geeksforgeeks.org/convex-hull-set-1-jarviss-algorithm-or-wrapping/
And, Graham's Scan: http://www.geeksforgeeks.org/convex-hull-set-2-graham-scan/
Hope this helps.
P.S. I think you can find the python implementations of these algorithms anywhere on the internet. :)
For an efficient solution, you can adapt the Monotone Chain method (https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain) as follows:
for both polygons, find the leftmost and rightmost sites (in case of ties, use the highest/lowest respectively);
these sites split the polygons in two chains, that are ordered on X;
merge the two upper and two lower chains with comparisons on X (this is a pass of mergesort);
reject the reflex sites from the upper and lower chains, using the same procedure as in the monotone chain method (a variant of Graham's walk).
The total running time will be governed by
n + m comparisons to find the extreme sites;
n + m comparisons for the merge;
n + m + 2 h LeftOf tests (signed area; h is the number vertices of the result).
Thus the complexity is O(n + m), which is not optimal but quite probably good enough for your purposes (a more sophisticated O(Log(n + m) solution is possible when the polygons do not overlap, but not worth the fuss for small polygon sizes).
In the example, the result of the merges are just the concatenation of the chains, but more complex cases can arise.
Final remark: if you keep all polygons as the concatenation of two monotone chains, you can spare the first step of the above procedure.
Finding the convex hull of both sets would work but the following approach is probably faster as it only needs to visit the polygons vertices in order:
Given polygons P and Q, pick from every one a vertex p1 and q1.
Search in Q the vertex q2 contiguous to q1 such that the rotation from p1-q1 to p1-q2 is clockwise (this can be checked easyly using vector cross product).
Repeat until you reach a point qk whose two contiguous vertices in Q generate and anticlockwise rotation.
Now, invert the process traveling from p1 across contigous vertices in P such that the rotation is anticlockwise until an extreme pl is found again.
Repeat from 2 until no more advance is possible. You have now two points pm and pn which are two the vertices where one side of the red area meets the black polygons in your drawing above.
Now repeat the algorithm again but changing the directions, from clockwise to anti-clockwise and vice-versa in order to find the vertices for the other side of the red area.
The only remaining work is generating the final polygon from the two red area sides already found and the segments from the polygons.
I have plotted n random points (the black points) and used delaunay triangulation, now I want to interpolate m random evaluation points (the red points) so I need to calculate which triangle the evaluation point is inside.
What is the approach for calculating the vertices of the triangle for each point?
For a given triangle, ABC, a point is inside the triangle if it is on the same side of line AB as point C is, on the same side of line BC as point A is, and on the same side of line AC as point B is. You can pre-optimize this check for each triangle and check them all until you find the triangle(s) it is in. See this page for more details.
To save computation, you can compute the minimum and maximum X and Y coordinates of the points for each triangle. If the X and Y coordinates of a point are not within the minimum and maximum values, you can immediately skip checking that triangle. The point cannot be inside it if it isn't inside the rectangle that bounds the triangle.
I'll assume that triangles do not intersect except of common edges.
You don't want to check every triangle (or subset of them) independently. The main reason is computation errors - due to them you may get answer "inside" for more than one triangle (or zero) which may break logic of your program.
More robust way is:
Find closest edge to the point
Select one of triangles touching this edge
Make one check for that triangle (the point lies on the same side as the third triangle vertex)
If "inside" - return this triangle
If "outside" - return another triangle on this edge (or "nothing" if there is no other triangle)
Even if you will return wrong triangle because of computation error, there still be exactly one triangle and point will lie close enough to it to accept such mistakes.
For #1 you can use something like quad-tree as Michael Wild suggests.
This simple example triangulates 10 random points, a further 3 random points are generated and if they fall inside a triangle the vertices are given:
import numpy as np
from pyhull.delaunay import DelaunayTri
def sign(a,b,c):
return (a[0]-c[0])*(b[1]-c[1])-(b[0]-c[0])*(a[1]-c[1])
def findfacet(p,simplice):
c,b,a = simplice.coords
b1 = sign(p,a,b) < 0.0
b2 = sign(p,b,c) < 0.0
b3 = sign(p,c,a) < 0.0
return b1 == b2 == b3
data = np.random.randn(10, 2)
dtri = DelaunayTri(data)
interpolate = np.random.randn(3, 2)
for point in interpolate:
for triangle in dtri.simplices:
if findfacet(point,triangle):
print "Point",point,"inside",triangle.coords
break
Using matplotlib to visualize (code omitted):
The dotted cyan lines now connect the points to interpolate with the vertices of triangle it lays within. The black lines are the convex hull, and the solid cyan lines are the delaunay triangulation.
A Delaunay triangulation is in itself a search data structure. Your Delaunay triangulation implementation probably has location functions. How have you computed the Delaunay triangulation of your points?
CGAL has an implementation of 2D and 3D triangulations. The resulting data structure is able to localize any point using a walk from a given point. See for example that chapter of the manual. CGAL is a C++ library, but it has python bindings.