I am making a graphics application in which I can edit a polyline by dragging the control point of it.
However, I'd like to make it a bit easier to use by making it elastic; When dragging a control point, instead of moving a single point, I'd like the points within a certain distance of that point to be moved as well, depending on how hard the control point is 'pulled'.
Does anyone know a simple algorithm for this? It may be quite rudimentary, as the primary requirement is speed.
Actually, knowing how to call such behaviour would also be nice, so I can look it up on google. I tried 'snaking' line, but that seems to refer to active contours, which isn't what I'm looking for.
Thanks
At a simple level you could achieve this with a little help form Hooke's law. You can basically view your polyline as a string, made up of a load of vertices connected by springs:
o-o-o-o-o-o-o-o-o
Each vertex is connected to another vertex by a spring, which will contract if stretched and repel if squashed.
So, when a control point is moved, the connected springs will either expand (stretch) or contract (shrink). This, in turn applies a force to any vertex sharing that spring. So if I pulled the first vertex up and left, the spring would apply a force to the vertex to the right, drawing it closer. This continues to the next (with some energy dissipating) until all springs are 'comfortable'.
That's the basics of it, each time a control point moves you need to solve the equation to all vertices/springs and the points will 'snake' for you.
If you want further examples google for 'Rope Physics' or 'Cloth physics' (as a rope is a 1D cloth). Ignore gravity for your purposes though, obviously.
Basically you are looking for a method to move (deform/transform) multiple points.
Let's assume you have given the direction and strength of the move which would result in dx, dy for the point x, y.
Your transformation will at least two more parameters
The radius r in which the points will be affected
Since the points in the middle would be affected more and at the edge you should define how to interpolate the falloff (linear, normal distribution, etc...)
For linear interpolations the points that are affected would move according to the following formula:
r[i] = sqrt(sqr(x-x[i])+sqr(y-y[i]))
so if r[i] < r
x[i]' = x[i] + dx*(1-r[i]/r)
y[i]' = y[i] + dy*(1-r[i]/r)
this is for linear interpolation dx[i] = dx - r[i]/r
Related
I have a bunch of spheres with different radius scattered all over the place in a 3D system.
What would be the fastest way to determine what sphere a point is inside, and if it is inside more than one - also the closest sphere based on the sphere's center.
The bruteforce method is to simply loop over all spheres, calculate the distance to the point, check if that distance is smaller than the sphere's radius and then find the sphere with the shortest disrance.
However, I got a couple million points to check (with about 100k spheres), so this would be incredibly slow.
Another idea of mine would be to build some kind of BVH Acceleration structure and save for each cell what sphere is the closest. However, there are also cases where one cell could be overlapped by two or more spheres etc. So a lot of edge-cases to consider.
And after all, the computation of the BVH tree should not be slower than the bruteforce.
Any ideas?
I ended up doing it with the brute force method on the GPU via OpenCL - that's super fast :)
Maybe a Sweep and Prune¹-esque approach could work here?
Handwavy algorithm (2D case):
Create two arrays Ax and Ay.
Pick one circle out of n circles and project into onto the x-axis, i.e store the x-component of the circles center plusminus the radius in Ax. Project the circle onto the y-axis as well.
Repeat step 2 for all remaining circles.
Store the components for each point in Ax and Ay as well.
Sort Ax and Ay
From here on, a point P can only be within a sphere S iff it is contained within all three intervals of S.
Now, it's possible to determine for each point if it is contained by a sphere: Iterate over Ax and increment a counter k each time you "enter" an interval and decrement k when you "exit" an interval. If the counter is k when you sweep into a point, then the point is contained by a set I of k intervals. Check if the point is contained by any corresponding interval of I in Ay².
Again, sortedness of Ax and Ay should be of help when finding what sphere was closest to a point.
I'm confident that this approach can be (much) improved upon, and in practice the parallelized brute-force could be faster still.
Handwavy algorithm (3D case): Analogous to the 2D case.
¹. http://www.cs.jhu.edu/~cohen/Publications/icollide.pdf
². I obviously omit lots of d̶e̶t̶a̶i̶l̶s̶ ̶I̶ ̶h̶a̶v̶e̶ ̶y̶e̶t̶ ̶t̶o̶ ̶f̶i̶g̶u̶r̶e̶ ̶o̶u̶t boring bookkeeping details.
I'm using the centroid of polygons to attach a marker in a map application. This works definitely fine for convex polygons and quite good for many concave polygons.
However, some polygons (banana, donut) obviously don't produce the desired result: The centroid is in these cases outside the polygons area.
Does anybody know a better approach to find a suitable point within any polygons area (which may contain holes!) to attach a marker?
One approach would be to generate and refine a skeleton of the polygon, then use the midpoint of the skeleton to place your marker (and if it's text, to orient the text correctly). This works well for most shapes, including ones with holes, and banana-shaped or tadpole-shaped crescents.
The CGAL library has a 2D Straight Skeleton and Polygon Offsetting module, or you could use PostGIS, for example.
To rephrase comment of ChristopheRoussy we may look for the largest circle inside of the polygon.
The largest circle is the one which cannot grow anymore because it touches three vertices or edges (if it touches only two, it can become bigger or just moved until it touches third).
So if you have few vertices, you can just enumerate all possible triples of vertices/edges, find for each one a circle and then select the largest one.
But it will require creating four functions:
Circle(vertex,vertex,vertex)
Circle(vertex,vertex,edge)
Circle(vertex,edge,edge)
Circle(edge,edge,edge)
All of them are possible, but may require some effort.
Find the extreme ordinates and draw an horizontal line in the middle. It is guaranteed to cross the polygon.
Find the intersection with the sides and sort them by increasing abscissa. Pick a point in the middle of two intersections.
This is an O(N + K Log K) process where K is the number of intersections (usually a very small even number). Pretty straightforward to write.
To increase the chances of a nice placement, you can try three horizontals instead of one an pick the longest intersection segment.
I have no idea how to solve this for any possible shape (and not doing heavy computation), but maybe for simpler shapes like the ones you have shown:
https://en.wikipedia.org/wiki/Force-directed_graph_drawing
Heuristic: This could converge to a reasonable approximation after a while
transform shape border into many points (more = more precise)
start out with many random points inside the polygon
push them until they are furthest away from border points, or just compute distance ... (can be done in parallel)
take best point
Another way could be to use multiple algorithms depending on the nature of the shape (like another one for donuts ...). Also perhaps relying on measuring 'fattest' sections first ?
IMHO would ask this on a math forum.
Similar: Calculate Centroid WITHIN / INSIDE a SpatialPolygon
Similar: How to find two most distant points?
To get a point for a marker I would use Yves Daoust's method.
To get a point that is reliably "within any polygon with holes" I would split polygon into triangles with a reliable library (e.g. OpenGL's GLUtessellator), and then get centroid of triangle with largest area.
If I had time for developing and testing, and I wanted good performance, then I would use a hybrid method: First use Yves Daoust's method to get some candidate points and then test candidates to see if they are within polygon. If all candidates fail, then fall back to slower reliable method (e.g. GLUtesselator).
for (int i = 0; i < n; /*++i*/) {
p = RandomPointInsideConvexHull();
if (IsInsidePolygon(p)) {
++i;
d = DistanceToClosestEdge(p);
if (d > bestD) {
bestP = p;
}
}
}
After running this loop you will approximate solution by bestP. n is parameter to choose. If you want more accurate result you can restart search, but now instead of picking a point inside polygon's convex hull you can pick one in the neighborhood of bestP, say not farther than bestD / 5 (this time you don't need to check if random point is inside polygon).
I have a turtle-graphics-based algorithm for generating a space-filling Hilbert curve in two dimensions. It is recursive and goes like this:
Wa want to draw a curve of order n, in direction x (where x ∈ {L, R}), and let y be the direction opposite to x. We do as follows:
turn in the direction y
draw a Hilbert curve of order n-1, direction y
move one step forward
turn in the direction x
draw a Hilbert curve of order n-1, direction x
move one step forward
draw a Hilbert curve of order n-1, direction x
turn in the direction x
move one step forward
draw a Hilbert curve of order n-1, direction y
I understand this and was able to implement a working solution. However, I'm now trying to "upgrade" this to 3D, and here's where I basically hit a wall; in 3D, when we reach a vertex, we can turn not in two, but four directions (going straight or backing up is obviously not an option, hence four and not six). Intuitively, I think I should store the plane on which the turtle is "walking" and its general direction in the world, represented by an enum with six values:
Up
Down
Left
Right
In (from the camera's perspective, it goes "inside" the world)
Out (same as above, outside)
The turtle, like in 2D, has a state containing the information outlined above, and when it reaches as vertex (which can be thought of as a "crossing") has to make a decision where to go next, based on that state. Whereas in two dimensions it is rather simple, in three, I'm stumped.
Is my approach correct? (i.e., is this what I should store in the turtle's state?)
If it is, how can I use that information to make a decision where to go next?
Because there are many variants of 3D space filling Hilbert curves, I should specify that this is what I'm using as reference and to aid my imagination:
I'm aware that a similar question has already been asked, but the accepted answer links to a website there this problem is solved using a different approach (i.e., not turtle graphics).
Your 2d algorithm can be summarized as “LRFL” or “RLFR” (with “F” being “forward”). Each letter means “turn that direction, draw a (n-1)-curve in that direction, and take a step forward”. (This assumes the x in step 8 should be a y.)
In 3d, you can summarize the algorithm as the 7 turns you would need to go along your reference. This will depend on how you visualize the turtle starting. If it starts at the empty circle, facing the filled circle, and being right-side-up (with its back facing up), then your reference would be “DLLUULL”.
I'm creating path tool programmaticaly and im stucked in one point.
I need to add loops to connections with acute angle. I have all data but still dont know how to determine when set CW or CCW angle direction for loop arc. Result below for fixed CW.
So if you're just trying to go for clockwise or counterclockwise, it may be easiest to think of it as just left or right. To think about it that way, suppose you have the points a, b, and c in your example above. As you have guessed, that vector with p that you have in there makes a difference; basically if you average b and c to find their mid point, that will always be left or right of a which gives you your answer. So, average b and c, and check to see if the x coordinate is bigger than a's x coordinate. Hope that makes sense.
Note that this simple model will likely break down in ways you don't want for edge cases with things like near vertical angles - I'm not sure how you've chosen to handle those but ultimately you may want a more robust model.
Just wondering if there was a nice (already implemented/documented) algorithm to do the following
boo! http://img697.imageshack.us/img697/7444/sdfhbsf.jpg
Given any shape (without crossing edges) and two points inside that shape, compute all the paths between the two points such that all reflections are perfect reflections. The path lengths should be limited to a certain length otherwise there are infinite solutions. I'm not interested in just shooting out rays to try to guess how close I can get, I'm interested in algorithms that can do it perfectly. Search based, not guess/improvement based.
I think you can do better than computing fans. Call your points A and B. You want to find paths of reflections from A to B.
Start off by reflecting A in an edge, and call the reflection A1. Can you draw a line from A1 to B that only hits that edge? If yes, that means you have a path from A to B that reflects on the edge. Do this for all the edges and you'll get all the single reflection paths that exist. It should be easy to construct these paths using the properties of reflections. Along the way, you need to check that the paths are legal, i.e. they do not cross other edges.
You can continue to find paths consisting of two reflections by reflecting all the first generation reflections of A in all the edges, and checking to see whether a line can be drawn from those points through the reflecting edge to B. Keep on doing this search until the distance of the reflected points from B exceeds a threshold.
I hope this makes sense. It should be easier than chasing fans and dealing with their breakups, even though you're still going to have to do some work.
By the way, this is a corner of a well studied field of billiards on tables of various geometries. Of course, a billiard ball bounces off the side of a table the same way light bounces off a mirror, so this is just another way of thinking of reflections. You can delve into this with search terms like polygonal billiards unfolding illumination, although the mathematicians tend to dwell on finding cases where there are no pool shots between two points on a polygonal table, as opposed to directly solving the problem you've posed.
Think not in terms of rays but fans. A fan would be all the rays emanating from one point and hitting a wall. You can then check if the fan contains the second point and if it does you can determine which ray hits it. Once a fan hits a wall, you can compute the reflected fan by transposing it's origin onto the outside of the wall - by doing this all fans are basically triangle shaped. There are some complications when a fan partially hits a wall and has to be broken into pieces to continue. Anyway, this tree of reflected fans can be traversed breadth first or depth first since you're limiting the total distance.
You may also want to look into radiosity methods, which is probably similar to what I've just described, but is usually done in 3d.
I do not know of any existing solutions for such a problem. Good luck to you if you find one, but incase you don't the first step to a complete but exponential (with regard to the line count) would be to break it into two parts:
Given an ordered subset of walls A,B,C and points P1, P2, calculate if a route is possible (either no solutions or a single unique solution).
Then generate permutations of your walls until you exceed whatever limit you had in mind.
The first part can be solved by a simple set of equations to find the necessary angles for each ray bounce. Then checking each line against existing lines for collisions would tell you if the path is possible.
The parameters to the system of equations would be
angle_1 = normal of line A with P1
angle_2 = normal of line B with intersection of line A
angle_3 = normal of line C with ...
angle_n = normal of line N-1 with P2
Each parameter is bounded by the constraints to hit the next line, which may not be linear (I have not checked). If they are not then you would probably have to pick suitable numerical non-linear solvers.
In response to brainjam
You still need wedges....
alt text http://img72.imageshack.us/img72/6959/ssdgk.jpg
In this situation, how would you know not to do the second reflection? How do you know what walls make sense to reflect over?