Analytic geometry, ordering vertices of triangle to capture shortes and second sortest sides - computational-geometry

If I have x and y coordinates for triangle corners A, B, and C, I want to know which of the six orderings of {A, B, C} put the shortest side of the triangle between the first two vertices in the ordering, and the second shortest side between the last two. I know how to solve this, but not in a way that isn't clumsy and inelegant and all around ugly. My favorite language is Ruby, but I respect all of them.

As the third side of a triangle cannot be deduced from the other two, you must compute the three distances.
As the three points may require to be permuted in one of six ways, you cannot work this out with a decision tree that has less than three levels (two levels can distinguish at most four cases).
Hence, compute the three distances and sort them increasingly using the same optimal decision tree as here: https://stackoverflow.com/a/22112521/1196549 (obviously their A, B, C correspond to your distances). For every leaf of the tree, determine what permutation of your points you must apply.
For instance, if you determine |AB|<|CA|<|BC|, you must swap A and B. Solve all six cases similarly.
Doing this you will obtain maximally efficient code.
If you are completely paranoid like I am, you can organize the decision tree in such a way that the cases that require a heavier permutation effort are detected in two tests rather than three.

Here's how I would do it: let's take a triangle with sides x, y, and z, such that l(x) <= l(y) <= l(z). Then, let x', y', and z' be the vertices opposite to x, y, and z, respectively.
Your output will be y', z', x' (if you draw out your triangle, you'll see that this is the order which achieves your requirement). So, the pseudocode looks like:
For points a, b, c each with some coordinates (x, y), calculate the length of the segment opposite to each point (e.g. for a this is segment bc)
Order a, b, c by the length of their opposing segment in the order of [2nd longest, longest, shortest]
Return
Does this make sense? The real work is mapping to the euclidean distance between the opposing points. If you get stuck, update your question with your code and I'm happy to help you work it out.

Related

Closest Pair of Points in 3+ Dimensions (Divide and Conquer)

I am struggling to wrap my head around how the divide and conquer algorithm works for dimensions greater than 2, specifically how to find the closest pair of points between two sub-problems.
I know that I need to only consider points within a distance d of the division between the two on the x axis.
I know that in the 3d case I need to compare each point to only 15 others.
What I don't understand is how to choose those 15 points. In the 2d case, one simply sorts the values by y value and goes through them in order. In the 3d case, however, each point needs to be compared to the 15 points closest to it on both the y and z axes. I can't seem to find a way to determine what those 15 points are in a way that doesn't have a worst case of O(n^2)...
What am I missing here?
A simple solution is to create an octree or a k-d tree, with all the points and then use it to find the nearest point for every point. That is O(N*log N) for the average case.
A faster solution that I think is O(N) for the average case can be implemented considering the following idea:
If you partition the space in half (say by some axis aligned plane), you get the points divided in two subsets, A and B, and the two nearest points can be both in A, both in B or one in A and one in B.
So, you have to create a queue of pairs of 3d boxes, ordered by the minimum distance between them and then:
1) Pick the first pair of boxes from the queue
2) If both boxes are the same box A, divide it in half in two boxes B and C and push the pairs (B, B), (C, C) and (B, C) into the queue.
3) If they are different (A, B), divide the biggest (for instance, B) in half obtaining boxes C and D and push into the queue the pairs (A, C) and (A, D).
4) Repeat.
Also, when the number of points inside the pair of boxes goes below some threshold you may use brute force to find the nearest pair of points.
The search stops once the distance between the two boxes in the pair at the top is bigger than the minimal distance found so far.

Tangents range for all pairs of points in a box

Suppose i have a box with a lot of points. I need to be able to calculate min and max angles for all lines which go through all possible pairs of the points. I can do it in O(n^2) times by just enumerating every point with all others. But is there faster algorithm?
Taking the idea of dual plane proposed by Evgeny Kluev, and my comment about finding left-most intersection point, I'll try to give an equivalent direct solution without any dual space.
The solution is simple: sort your points by (x, y) lexicographically. Now draw a line through each two adjacent points in the sorted order. It can be proved that the minimal angle is achieved by one of these lines. In order to get maximal angle, you need to sort by (x, -y) lexicographically, and also check only adjacent pairs of points.
Let's prove by the idea for min angle. Consider the two points A and B which yield the minimal possible angle. Among such points we can choose the pair with minimal difference of x coordinates.
Suppose that they have same y. If there is no other point between them, then they are adjacent. If there are any points between them, then clearly at least one of them is adjacent to A in our order, and all of them yield the same angle.
Suppose that there exists a point P with x-coordinate in between A and B, i.e. Ax < Px < Bx. If P lies on AB, then AP has same angle but less difference of x coordinates, hence a contradiction. When P is not on AB, then either AP or PB would give you less angle, which also gives contradiction.
Now we have points A and B lying on two adjacent vertical lines. There are no other points between these lines. If A and B are the only points on their vertical lines, then the AB pair is clearly adjacent in sorted order and QED. If there many points on these lines, obviously the minimal angle is achieved by taking the highest point on the left vertical line (which must be A) and the lowest point on the right vertical line (which must be B). Since we sort points of equal x by y, these two points are also adjacent.
Sort the points (or use hash map) to find out if there are any horizontal lines.
Then solve this problem on dual plane. Here you only need to find the leftmost and the rightmost intersection points. Use binary searches to find a pair of horizontal coordinates such that all intersection points are between them. (You could quickly find approximate results just by continuing binary searches from these coordinates).
Then sort lines according to their tangents on dual plane. And for pairs of adjacent lines in this sorted order find intersections closest to those horizontal coordinates. This does not guarantee good complexity in the worst case (when some lines on primal plane are almost horizontal). But in most cases time complexity would be determined by sorting: O(N log N) + O(binary_search_complexity).

Combine Arbitrary number of polygons together

I have an arbitrary number of polygons (hexes in this case) that are arranged randomly, but they are all touching another hex.
Each individual hex has 6 x,y vertices. The vertex's are known for all the hexes.
Can anyone point me in the direction of an algorithm that will combine all the hexes into a single polygon? Essentially I'm just looking for a function that spits out an array of vertex locations that are ordered in a way that when drawing lines from one to the next, it forms the polygon.
This is my method so far:
Create array of all the vertices for all the hexes.
Determine the number of times a vertex occurs in the array
If vertex is in the array 3+ times, delete the vertices from the array.
If vertex is in the array 2 times, delete one of them.
The next step is tricky though. I'm using canvas to draw out these polygons, which essentially involves drawing a line from one vertex to the next. So the order of the vertices in the final array is important. It can't be sorted arbitrarily.
Also, I'm not looking for a "convex hull" algorithm, as that would not draw the polygon correctly.
Are there any functions out there that do something like this? Am I on the right track or is there a better more efficient way?
I would do something like this:
List all the sides. A side is defined by two pairs of coordinates.
If any side shows up more than once remove all instances of that side.
Pick an arbitrary side, and from that side choose one of its points.
Place that point in an array.
Follow the current side and put the other point in the array.
Delete the side you just followed.
Then find the other side that has a point that is the same as the last point in the array. There will be only one such side. If there is none, you're done.
Go back to step 5.
You should now have an array of points that make up, in order, the shape you want.
Just be aware that this won't handle holes. The shape must be defineable by a single path.
without keeping track of the coordinate pairs that make up the lines, it would be impossible to determine the outer border of the shape
if you know the coordinate pairs that make up the lines, THEN
Create 2 lists, one of vertexs (list 1), one of the lines (list 2)
Remove all duplicate vertexes from the vertex list
Make a new list (list 3) of all the vertexes that have 3 lines attached to them
Using list 3, remove all the lines that have 2 vertexes from list 3 as their two coordinate pairs
It's time to traverse the shape, the list of lines remaining should form the shape you want
just start with an arbitrary coordinate and then
for each coordinate
for all lines
if (x1,y1) = current coordinate then add (x2,y2) to stack and remove that line from list
break
elseif (x2,y2) = current coordinate then add (x1,y1) to stack and remove that line from list
break
For each hex you have a list of 6 vertices. Sort the list, if necessary, so that the the vertices are ordered in counter-clockwise order (that's the mathematical convention).
Now you have a set of polygons (initially hexagons). The idea is to combine polygons until there is only one (or as few as can be).
Pick an edge of a polygon, and look for that same edge (i.e. that same pair of vertices) among the other polygons. If there are two instances, combine the two polygons at that edge, e.g. (a, b, c, d, e, f) + (g, h, d, c, i, j) => (a, b, c, i, j, g, h, d, e, f). (If the two vertices are in the same order in both polygons, or if there are three or more instances of the edge, report an error and abort.) Iterate through all edges. If the hexes really formed a contiguous group, there will be only one polygon left.
The polygon may have duplicated edges. If an edge occurs more than once, eliminate it by splitting the list in two, e.g. (a, b, c, d, b, a, e, f, g) => (b, c, d) + (a, e, f, g). Or if the the edges are adjacent, remove them: (a, b, c, b, d, e) => (a, b, d, e). Or if that list has only that edge, remove the list: (a,b) => nothing.
Once you've eliminated duplicate edges, there'll be one list for the counter-clockwise outer edge of the polygon, and perhaps one or more lists for the clockwise interior edges of holes.

Find the slice cut by a line segment, an origin point on a 3D polygon

I have an array of triangle vertices (faces of the polygon), something like
[[[a, b, c], [d, e, f], [g, h, i]], ...]
I have a line segment, represented by 2 3D vertices, let's say [[j, k, l], [m, n, o]].
And I have a point [p, q, r].
What I want to do is, project the point on the polygon, through the line segment, and check if it completely slices the polygon (I think 4 points of contact should be enough? I could be wrong). And if it does, I need all the points of intersection which lie on the edges and vertices.
I'm completely lost here. Any pointers would be appreciated.
We can assume without loss of generality that the triangle formed by the point & line segment (henceforth T) lies in the x-y plane. (Otherwise, rotate everything appropriately).
We loop through the triangle faces, for any pair of vertices of a face where their y-coordinates have different signs (i.e. for any edge that cuts the x-y plane), we check the intersection of the edge with the x-y plane and make sure it's within T.
It holds that T "completely slices the polygon" if and only if all such checks are true.
Running time is O(number of faces).
All the operations described are pretty simple. E.g. Checking that something is in the bounds of T is simply checking two inequalities with the equations of the two lines that define T (i.e. from the point to the end points of the line segment).
All POI with the edges (and thus vertices) can be calculated within the loop - it's simply the POI of the edge with the x-y plane.

Anyone know were i could find an algorithm or have a algorithm they could share to split a sphere (mesh) into random parts?

I have a list a vertices and a list of triangles. I'd like to split this single mesh into, say 5, randomly shaped meshes. When the 5 randomly shaped meshes are in place the sphere should all line up and look like 1 solid mesh.
I need a algorithm to do this programmatically, not a tool to do it form me. Any pointers would be great!
Similar to Svante's proposal but a slightly different approach:
Select five random vertices, mark these vertices as "visited" with the number 1 to 5
From each of the visited vertices, go to all adjacent vertices. Store the same number there as well.
If you visit a vertex which already has a number assigned, stop there
Stop, if all vertices are visited. All vertices marked with the same number end up in the same piece
This appears to me to be the simplest to implement, while still resulting in nice puzzle pieces. For added random-ness, you could add a probability, of visiting each adjacent vertex.
Nevertheless, any "too random" approach might result in heavily concave pieces, like very long pieces consisting only of a long strip of single triangles; and pieces with deep ugly thin cuts into them. You should possibly specify another question on how to make nice puzzle pieces (and what nice puzzle pieces are!) if you care for that.
You could make a crack by walking a random walk across the edges, until the number of pieces you want is achieved. If you want to have mostly big pieces, you could modify the randomness of the walk by reducing the attractiveness of edges that are close to an existing crack.
Select 3 random points and split along that plane. What is the problem?
When you split a triangle along a plane you end up in one of two situations: either the plane doesn't intersect either line segments in the triangle or it intersects exactly two line segments. Only triangles that are intersected are interesting.
If you have triangle (A, B, C), with A, B and C being vertices.
Assume that the plane intersects the line segments (A, B) and (A, C) in the points D and E.
Define a vertex, F, between B and C (for example B + (C - B) / 2), but any vertex on the line segment between B and C will do).
Your new triangles are then the following
(A, D, E), (B, D, F), (D, E, F) and (C, E, F)

Resources