Find the smallest angle to include all points in a plane - python

I would like to write a code in python that would solve for the smallest angle (θ) that would include all the points in a 2D plane given any number of points. The vertex of the angle is always centered at the origin (0,0). The points are defined using the Cartesian coordinate system with an (x,y) value. A figure below is shown for visualization. Any thoughts on how I should approach this problem?

Convert each of the Cartesian representations into polar coordinates.
Sort by reference angle.
Subtract adjacent reference angles to get the angles between adjacent vectors. Make sure to include the last and first points as one more angle to compute.
Identify the largest angle between adjacent vectors. The opposite side of this angle is the smallest angle that include all of the points.
For instance, using the canonical representation -- counter-clockwise from the x-positive ray -- you would find the reference angle for each polar vector. Sorted, you would have the list [d, c, b, a, e, f].
Next, you compute the angles dOc, cOb, bOa, ... and fOd.
You note that aOe is the largest angle of them all being somewhat in excess of a whole radian.
Therefore, eOa is the desired angle.

Related

How to recalculate the coordinates of a point after scaling and rotation?

I have the coordinates of 6 points in an image
(170.01954650878906, 216.98866271972656)
(201.3812255859375, 109.42137145996094)
(115.70114135742188, 210.4272918701172)
(45.42426300048828, 97.89037322998047)
(167.0367889404297, 208.9329833984375)
(70.13690185546875, 140.90538024902344)
I have a point as center [89.2458, 121.0896]. I am trying to re-calculate the position of points in python using 4 rotation degree (from 0,90,-90,180) and 6 scaling factor (0.5,0.75,1,1.10,1.25,1.35,1.5).
My question is how can I rotate and scale the abovementioned points relative to the center point and get the new coordinates of those 6 points?
Your help is really appreciated.
Mathematics
A mathematical approach would be to represent this data as vectors from the center to the image-points, translate these vectors to the origin, apply the transformation and relocate them around the center point. Let's look at how this works in detail.
Representation as vectors
We can show these vectors in a grid, this will produce following image
This image provides a nice way to look at these points, so we can see our actions happening in a visual way. The center point is marked with a dot at the beginning of all the arrows, and the end of each arrow is the location of one of the points supplied in the question.
A vector can be seen as a list of the values of the coordinates of the point so
my_vector = [point[0], point[1]]
could be a representation for a vector in python, it just holds the coordinates of a point, so the format in the question could be used as is! Notice that I will use the position 0 for the x-coordinate and 1 for the y-coordinate throughout my answer.
I have only added this representation as a visual aid, we can look at any set of two points as being a vector, no calculation is needed, this is only a different way of looking at those points.
Translation to origin
The first calculations happen here. We need to translate all these vectors to the origin. We can very easily do this by subtracting the location of the center point from all the other points, for example (can be done in a simple loop):
point_origin_x = point[0] - center_point[0] # Xvalue point - Xvalue center
point_origin_y = point[1] - center_point[1] # Yvalue point - Yvalue center
The resulting points can now be rotated around the origin and scaled with respect to the origin. The new points (as vectors) look like this:
In this image, I deliberately left the scale untouched, so that it is clear that these are exactly the same vectors (arrows), in size and orientation, only shifted to be around (0, 0).
Why the origin
So why translate these points to the origin? Well, rotations and scaling actions are easy to do (mathematically) around the origin and not as easy around other points.
Also, from now on, I will only include the 1st, 2nd and 4th point in these images to save some space.
Scaling around the origin
A scaling operation is very easy around the origin. Just multiply the coordinates of the point with the factor of the scaling:
scaled_point_x = point[0] * scaling_factor
scaled_point_y = point[1] * scaling_factor
In a visual way, that looks like this (scaling all by 1.5):
Where the blue arrows are the original vectors and the red ones are the scaled vectors.
Rotating
Now for rotating. This is a little bit harder, because a rotation is most generally described by a matrix multiplication with this vector.
The matrix to multiply with is the following
(from wikipedia: Rotation Matrix)
So if V is the vector than we need to perform V_r = R(t) * V to get the rotated vector V_r. This rotation will always be counterclockwise! In order to rotate clockwise, we simply need to use R(-t).
Because only multiples of 90° are needed in the question, the matrix becomes a almost trivial. For a rotation of 90° counterclockwise, the matrix is:
Which is basically in code:
rotated_point_x = -point[1] # new x is negative of old y
rotated_point_y = point[0] # new y is old x
Again, this can be nicely shown in a visual way:
Where I have matched the colors of the vectors.
A rotation 90° clockwise will than be
rotated_counter_point_x = point[1] # x is old y
rotated_counter_point_y = -point[0] # y is negative of old x
A rotation of 180° will just be taking the negative coordinates or, you could just scale by a factor of -1, which is essentially the same.
As last point of these operations, might I add that you can scale and/or rotated as much as you want in a sequence to get the desired result.
Translating back to the center point
After the scaling actions and/or rotations the only thing left is te retranslate the vectors to the center point.
retranslated_point_x = new_point[0] + center_point_x
retranslated_point_y = new_point[1] + center_point_y
And all is done.
Just a recap
So to recap this long post:
Subtract the coordinates of the center point from the coordinates of the image-point
Scale by a factor with a simply multiplication of the coordinates
Use the idea of the matrix multiplication to think about the rotation (you can easily find these things on Google or Wikipedia).
Add the coordinates of the center point to the new coordinates of the image-point
I realize now that I could have just given this recap, but now there is at least some visual aid and a slight mathematical background in this post, which is also nice. I really believe that such problems should be looked at from a mathematical angle, the mathematical description can help a lot.

Matching Angles between Edges

I'm scripting in python for starters.
Making this example simple, I have one edge, with uv Coordinates of ([0,0],[1,1]), so its a 45 degree angle. I have another edge that is ([0,0],[0,1]) so its angle is 0/360 degrees. My goal is to compare the angles of those two edges in order to get the difference so I can modify the angle of the second edge to match the angle of the first edge. Is there a way to do this via vector math?
Easiest to reconstruct and thus constructively remember is IMO the complex picture. To compute the angle from a=a.x+i*a.y to b=b.x+i*b.y rotate b back by multiplying with the conjugate of a to get an angle from the zero angle resp. the positive real axis,
arg((a.x-i*a.y)*(b.x+i*b.y))
=arg((a.x*b.x+a.y*b.y)+i*(a.x*b.y-a.y*b.x))
=atan2( a.x*b.y-a.y*b.x , a.x*b.x+a.y*b.y )
Note that screen coordinates use the opposite orientation to the Cartesian/complex plane, thus change use a sign switch as from atan2(y,x) to atan2(-y,x) to get an angle in the usual direction.
To produce a vector b rotated angle (in radians) w from a, multiply by cos(w)+i*sin(w) to obtain
b.x = cos(w)*a.x - sin(w)*a.y
b.y = cos(w)*a.y + sin(w)*a.x
You will have to rescale to get a specified length of b.

How to plot two linear lines on a graph in python with radius 1 and center at origin and measure the angle difference?

I have an issue that I can't seem to solve. I have already acquired data from another source and created 2 polynomials that are identical in shape but not in orientation, that is one is rotated x degrees compared to the other, and if you rotate the graph x degrees back they will match.
I have already taken the derivative of both of the graphs at a certain point.
I would like to graph these slopes onto a unit circle on a polar graph, and somehow find the angle difference between these two line segments of slope i and j that extend from the origin.
I'm fairly new to python so I so not know how to begin plotting these in polar or finding a way to determine the angle difference. I know that by hand, you can take the inverse tangent but that will only give you a range from +90 to -90. I would like my number to fall in the range from 0 to 360 for rotation.
Any help is appreciated. If this isn't enough info or if it isn't clear enough I can provide more.

Constructing a polygon from list of vertices in 3d in python

I have a list of vertices in 3d, in random order. I need to construct a polygon from them.
I've found a solution for this in 2d, that uses polar coordinates: ordering shuffled points that can be joined to form a polygon (in python)
It calculates the center of the shape, then arranges the vertices by polar coordinate. Problem is, in 3d there are 2 angles involved, if I use spherical coordinates. How do I sort my list of vertices in case of sphereical coordinates?
Are the points lying on a plane? First find the center, then use a vector cross product on the relative positions of a couple randomly chosen points to find the normal to the plane. Analyze the coordinates of the points relative to the center into components along the normal and perpendicular. The perpendicular components are a 2D problem, for which you've already found a solution.

Hausdorff Distance Between Convex Polygons

I'm interested in calculating the Hausdorff Distance between 2 polygons (specifically quadrilaterals which are almost rectangles) defined by their vertices. They may overlap.
Recall $d_H(A,B) = \max(d(A,B), d(B,A))$ where $d$ is the Hausdorff semi-metric
$d(A,B) = \sup_{a\in A}\inf_{b\in B}d(a,b)$.
Is it true that, given a finite disjoint covering of $A$, ${A_i}$, $d(A,B)=\max{d(A_i,B)}$? A corollary of which is that $d(A,B)=d(A\setminus B,B)$.
I have found a paper by Atallah 1 (PDF). I'm interested in working in Python and would be open to any preprogrammed solutions.
In the case of convex polygons, d(A, B) is the maximum of the distances from vertices of A to any point in B. Therefore the Hausdorff distance is not too hard to calculate if you can calculate the distance from an arbitrary point to a convex polygon.
To calculate the distance from a point to a convex polygon you first have to test whether the point is inside the polygon (if so the distance is 0), and then if it is not find the minimum distance to any of the bounding line segments.
The answer to your other query is no. As an example let A and B both be the same 2x2 square centered at the origin. Partition A into 4 1x1 squares. The Hausdorff distance from each Ai to B is sqrt(2), but the distance from A to B is 0.
UPDATE: The claim about the vertices is not immediately obvious, therefore I'll sketch a proof that is good in any finite number of dimensions. The result I am trying to prove is that in calculating d(A, B) with both polygons and B convex, it suffices to find the distances from the vertices of A to B. (The closest point in B might not be a vertex, but one of the farthest points in A must be a vertex.)
Since both are finite closed shapes, they are compact. From compactness, there must exist a point p in A that is as far as possible from B. From compactness, there must exist a point q in B that is as close as possible to A.
This distance is 0 only if A and B are the same polygon, in which case it is clear that we achieve that distance at a vertex of A. So without loss of generality we may assume that there is a positive distance from p to q.
Draw the plane (in higher dimensions, some sort of hyperplane) touching q that is perpendicular to the line from p to q. Can any point in B cross this plane? Well if there was one, say r, then every point on the line segment from q to r must be in B because B is convex. But it is easy to show that there must be a point on this line segment that is closer to p than q is, contradicting the definition of q. Therefore B cannot cross this plane.
Clearly p cannot be an interior point, because if it was, then continue along the ray from q to p and you find points in A that are farther from the plane that B is bounded behind, contradicting the definition of p. If p is a vertex of A, then the result is trivially true. Therefore the only interesting case is if p is on a boundary of A but is not a vertex.
If so, then p is on a surface. If that surface were not parallel to the plane we constructed, it would be easy to travel along that surface, away from the plane we have bounded B behind, and find points farther away from B than p. Therefore that surface must be parallel to that plane. Since A is finite, that surface must terminate in vertices somewhere. Those vertices are the same distance from that plane as p, and therefore are at least as far from B as p. Therefore there exists at least one vertex of A that is as far as possible from B.
That is why it sufficed to find the maximum of the distances from the vertices of the polygons to the other polygon.
(I leave constructing a pair of polygons with q not a vertex as a fun exercise for the reader.)

Categories

Resources