What's the most efficient way to find the convex hull of the union of two convex polygons? - geometry

Given two convex polygons P and Q in the (x, y) plane, respectively having vertex sets {p1, ..., pa} and {q1, ..., qb} given in clockwise order (p1 is the furthest west of the furthest-north vertices of P; q1 is the furthest west of the furthest-north vertices of Q), I want to find R, the convex hull of the union of P and Q. This is another convex polygon, with at most a + b vertices. I want to get it in the same form, i.e. a sequence of vertices {r1, ..., rc} given in clockwise order with r1 the furthest-west of the furthest-north vertices. What's the most efficient way to do this?
It is not known at the outset whether or not P and Q intersect.

There is powerful method called Rotating Calipers.
Using them, one can make union of two convex hulls in linear time.
Sadly, nice page with a lot of explanations has been deleted (http://cgm.cs.mcgill.ca/~orm/rotcal.html, there is no copy in web archive either).
In general, you choose the leftmost point from your p1 and q1 as start, then walk through vertices of both polygons in parallel order (like merge step in mergesort), choosing the most "clockwise" one at every step. When edge of new convex hull changes from P to Q vertices or vice versa, it is called "bridge" (qj-pi at the picture)
Very short description, perhaps you are lucky to find better one.

It would be inappropriate for me to post the actual code I've written to solve this problem, but I'll post pseudocode instead. I believe this accomplishes the task in linear time, but I have not proven it; I lack either the mathematical sophistication or the motivation to do so. If it is correct and linear-time, it might be formally equivalent to the "rotating calipers" method referred to by MBo.
Note: This might go into a loop if the polygons fail to satisfy my hypotheses. You can detect this by (1) checking at the "find horizon" loop if it's looping too many times, and (2) counting the vertices produced and checking at each produced vertex whether more vertices have been produced than ought to be possible.
Note (2): All indices wrap around; pa + 1 is by definition another name for p1, and p0 is by definition another name for pa.
Note (3): We may assume without loss of generality that p1 is either due west, or anywhere north of q1 (or they are the same point).
let start_point be p[1]
let current_index be 1
let horizon_index be 1
while true:
let c = p[current_index]
let c' = p[current_index + 1]
let h = q[horizon_index]
yield c
-- Update the horizon on the other polygon.
while true:
let T1 = triangle(c, h, q[horizon_index - 1])
let T2 = triangle(c, h, q[horizon_index + 1])
let cond1 = "T1 is clockwise or degenerate"
let cond2 = "T2 is clockwise"
if cond1 and cond2:
-- Found the correct horizon.
break
increment horizon_index
let T = triangle(c, h, c')
let horizon_further be "from c, the horizon is further away than c'"
let should_bridge = case
when T is anticlockwise then false
when T is clockwise then true
when T is degenerate then horizon_further
end case
increment current_index
if should_bridge:
swap p and q
swap current_index and horizon_index
if p[current_index] is equal to start_point:
break

Related

corners of angled rect in 3d

Ive got 2 points in 3d space (with the same y coordinate). Ill call them c and m. I want to find the corner points (marked in the pic as p1-p4) of a square with the width w. The important thing is, that the square is not parallel to the x-axis. If it were, (for p1 as an example) I could just do:
p1.x = m.x + w / 2
p1.y = m.y + w / 2
p1.z = m.z
How would I do the same with a angled square? These are all the given points:
m; c
and lenghts:
w; d
There's multiple ways to do it, but here's one way.
If the two points are guaranteed to have the same y value, you should be able to do it as follows.
Take 'm - c' and call that u. Normalize u. Then take the cross product of u and the y axis to get v, a vector parallel to the xz plane that's perpendicular to u. (This can be optimized, but that's unlikely to be important.) Then take the cross product of u and v to get a third vector, w. Note that you can use 'm - c' or 'c - m', or use different orders for the cross-product arguments, and it'll still work, but the resulting vectors may point in different directions (but only opposite directions). You can also normalize at different points in the process and get the same results at the end.
Once you have m, v, and w, you can use some basic vector math to compute the corners.
[Edit: I see you have a variable named 'w', so I should clarify that the 'w' in my example is a different 'w' than yours. As for your 'w' and 'd', those would factor in in the vector math I mentioned at the end.]

How to compute the inverse orthogonal projection of a point in the viewing plane onto a plane in the scene?

Suppose I have a viewing plane vn, with an orientation q1 and a plane in the scene un with an orientation q2.
q1 and q2 are quaternions.
How would I find the unknown point ux, uy, uz such that proj_u_plane_vn is equal to a known point vx, vy, 0?
Would the problem be simpler by finding the relative orientation q2-q1?
Right now I'm trying to do it with i, j and k values, but it seems like overkill and I'm not seeing the answer pop out without doing inverse trig, not that I would mind that, but I'm looking for a more elegant solution.
Thanks in advance. :)
You have the following values:
vx, vy, vz; //These are the points in the viewing plane, which you know.
q1, q2; //The vectors describing the viewing and scene planes.
As you suspected, the trick to projection between planes is in using the relative orientations.
You should use your offsets (when you find the relative orientations) between planes to treat the scene plane as if it is offset from the front plane (the viewing plane). This is not only easier to visualize, but it will also make the answers which you looked up more relevant.
Knowing this, you can use your relative orientation to define n in the following equation:
q_proj = q - dot(q - p, n) * n
The projection of a point q = (x, y, z) onto a plane given by a point p = (a, b, c) and a normal n = (d, e, f).
Note that this answer was ripped from here: How do I find the orthogonal projection of a point onto a plane.

arc transform start end point to start angle end angle

Given a description of an arc which has a startpoint and endpoint (both in Cartesian x,y coordinates), radius and direction (clockwise or counter-clockwise), I need to convert the arc to one with a start-angle, end-angle, center, and radius.
Is there known algorithm or pseudo code that allows me to do this? Also, is there any specific term to describe these kinds of transformations?
You can find a center solving this equation system:
(sx-cx)^2 + (sy-cy)^2=R^2
(ex-cx)^2 + (ey-cy)^2=R^2
where (sx,sy) are coordinates of starting point, (ex,ey) for ending point, unknowns cx, cy for center.
This system has two solutions. Then it is possible to find angles as
StartAngle = ArcTan2(sy-cy, sx-cx)
EndAngle = ArcTan2(ey-cy, ex-cx)
Note that known direction doesn't allow to select one from two possible solutions without additional limitations. For example, start=(0,1), end=(1,0), R=1 and Dir = clockwise give us both Pi/2 arc with center (0,0) and 3*Pi/2 arc with center (1,1)
I'd propose a different approach than MBo to obtain the centers of the two circles, which have the given radius and pass to both start and end point.
If P and Q are start and end point of the arc, the center of each of the two circles lies on the line L which is orthogonal to PQ, the line from P to Q, and which bisects PQ. The distance d from the centers to L is easily obtained by Pythagoras theorem. If e is the length of PQ, then d^2 + (e/2)^2 = r^2. This way you avoid to solve that system of equations you get from MBo's approach.
Note that, in case you have a semicircle, any approach will become numerically unstable because there is only one circle of the given radius with P and Q on it. (I guess I recall the correct term is 'the problem is ill posed' in that case. It happens when P and Q are precisely 2r apart, and to figure out whether this actually true you need to check for equality of two doubles, which is always a bit problematic. If, for some reason, you know you have a semicircle you are better of to just calculate the center of PQ).

Best fit square to quadrilateral

I've got a shape consisting of four points, A, B, C and D, of which the only their position is known. The goal is to transform these points to have specific angles and offsets relative to each other.
For example: A(-1,-1) B(2,-1) C(1,1) D(-2,1), which should be transformed to a perfect square (all angles 90) with offsets between AB, BC, CD and AD all being 2. The result should be a square slightly rotated counter-clockwise.
What would be the most efficient way to do this?
I'm using this for a simple block simulation program.
As Mark alluded, we can use constrained optimization to find the side 2 square that minimizes the square of the distance to the corners of the original.
We need to minimize f = (a-A)^2 + (b-B)^2 + (c-C)^2 + (d-D)^2 (where the square is actually a dot product of the vector argument with itself) subject to some constraints.
Following the method of Lagrange multipliers, I chose the following distance constraints:
g1 = (a-b)^2 - 4
g2 = (c-b)^2 - 4
g3 = (d-c)^2 - 4
and the following angle constraints:
g4 = (b-a).(c-b)
g5 = (c-b).(d-c)
A quick napkin sketch should convince you that these constraints are sufficient.
We then want to minimize f subject to the g's all being zero.
The Lagrange function is:
L = f + Sum(i = 1 to 5, li gi)
where the lis are the Lagrange multipliers.
The gradient is non-linear, so we have to take a hessian and use multivariate Newton's method to iterate to a solution.
Here's the solution I got (red) for the data given (black):
This took 5 iterations, after which the L2 norm of the step was 6.5106e-9.
While Codie CodeMonkey's solution is a perfectly valid one (and a great use case for the Lagrangian Multipliers at that), I believe that it's worth mentioning that if the side length is not given this particular problem actually has a closed form solution.
We would like to minimise the distance between the corners of our fitted square and the ones of the given quadrilateral. This is equivalent to minimising the cost function:
f(x1,...,y4) = (x1-ax)^2+(y1-ay)^2 + (x2-bx)^2+(y2-by)^2 +
(x3-cx)^2+(y3-cy)^2 + (x4-dx)^2+(y4-dy)^2
Where Pi = (xi,yi) are the corners of the fitted square and A = (ax,ay) through D = (dx,dy) represent the given corners of the quadrilateral in clockwise order. Since we are fitting a square we have certain contraints regarding the positions of the four corners. Actually, if two opposite corners are given, they are enough to describe a unique square (save for the mirror image on the diagonal).
Parametrization of the points
This means that two opposite corners are enough to represent our target square. We can parametrise the two remaining corners using the components of the first two. In the above example we express P2 and P4 in terms of P1 = (x1,y1) and P3 = (x3,y3). If you need a visualisation of the geometrical intuition behind the parametrisation of a square you can play with the interactive version.
P2 = (x2,y2) = ( (x1+x3-y3+y1)/2 , (y1+y3-x1+x3)/2 )
P4 = (x4,y4) = ( (x1+x3+y3-y1)/2 , (y1+y3+x1-x3)/2 )
Substituting for x2,x4,y2,y4 means that f(x1,...,y4) can be rewritten to:
f(x1,x3,y1,y3) = (x1-ax)^2+(y1-ay)^2 + ((x1+x3-y3+y1)/2-bx)^2+((y1+y3-x1+x3)/2-by)^2 +
(x3-cx)^2+(y3-cy)^2 + ((x1+x3+y3-y1)/2-dx)^2+((y1+y3+x1-x3)/2-dy)^2
a function which only depends on x1,x3,y1,y3. To find the minimum of the resulting function we then set the partial derivatives of f(x1,x3,y1,y3) equal to zero. They are the following:
df/dx1 = 4x1-dy-dx+by-bx-2ax = 0 --> x1 = ( dy+dx-by+bx+2ax)/4
df/dx3 = 4x3+dy-dx-by-bx-2cx = 0 --> x3 = (-dy+dx+by+bx+2cx)/4
df/dy1 = 4y1-dy+dx-by-bx-2ay = 0 --> y1 = ( dy-dx+by+bx+2ay)/4
df/dy3 = 4y3-dy-dx-2cy-by+bx = 0 --> y3 = ( dy+dx+by-bx+2cy)/4
You may see where this is going, as simple rearrangment of the terms leads to the final solution.
Final solution

Projective transformation

Given two image buffers (assume it's an array of ints of size width * height, with each element a color value), how can I map an area defined by a quadrilateral from one image buffer into the other (always square) image buffer? I'm led to understand this is called "projective transformation".
I'm also looking for a general (not language- or library-specific) way of doing this, such that it could be reasonably applied in any language without relying on "magic function X that does all the work for me".
An example: I've written a short program in Java using the Processing library (processing.org) that captures video from a camera. During an initial "calibrating" step, the captured video is output directly into a window. The user then clicks on four points to define an area of the video that will be transformed, then mapped into the square window during subsequent operation of the program. If the user were to click on the four points defining the corners of a door visible at an angle in the camera's output, then this transformation would cause the subsequent video to map the transformed image of the door to the entire area of the window, albeit somewhat distorted.
Using linear algebra is much easier than all that geometry! Plus you won't need to use sine, cosine, etc, so you can store each number as a rational fraction and get the exact numerical result if you need it.
What you want is a mapping from your old (x,y) co-ordinates to your new (x',y') co-ordinates. You can do it with matrices. You need to find the 2-by-4 projection matrix P such that P times the old coordinates equals the new co-ordinates. We'll assume that you're mapping lines to lines (not, for instance, straight lines to parabolas). Because you have a projection (parallel lines don't stay parallel) and translation (sliding), you need a factor of (xy) and (1), too. Drawn as matrices:
[x ]
[a b c d]*[y ] = [x']
[e f g h] [x*y] [y']
[1 ]
You need to know a through h so solve these equations:
a*x_0 + b*y_0 + c*x_0*y_0 + d = i_0
a*x_1 + b*y_1 + c*x_1*y_1 + d = i_1
a*x_2 + b*y_2 + c*x_2*y_2 + d = i_2
a*x_3 + b*y_3 + c*x_3*y_3 + d = i_3
e*x_0 + f*y_0 + g*x_0*y_0 + h = j_0
e*x_1 + f*y_1 + g*x_1*y_1 + h = j_1
e*x_2 + f*y_2 + g*x_2*y_2 + h = j_2
e*x_3 + f*y_3 + g*x_3*y_3 + h = j_3
Again, you can use linear algebra:
[x_0 y_0 x_0*y_0 1] [a e] [i_0 j_0]
[x_1 y_1 x_1*y_1 1] * [b f] = [i_1 j_1]
[x_2 y_2 x_2*y_2 1] [c g] [i_2 j_2]
[x_3 y_3 x_3*y_3 1] [d h] [i_3 j_3]
Plug in your corners for x_n,y_n,i_n,j_n. (Corners work best because they are far apart to decrease the error if you're picking the points from, say, user-clicks.) Take the inverse of the 4x4 matrix and multiply it by the right side of the equation. The transpose of that matrix is P. You should be able to find functions to compute a matrix inverse and multiply online.
Where you'll probably have bugs:
When computing, remember to check for division by zero. That's a sign that your matrix is not invertible. That might happen if you try to map one (x,y) co-ordinate to two different points.
If you write your own matrix math, remember that matrices are usually specified row,column (vertical,horizontal) and screen graphics are x,y (horizontal,vertical). You're bound to get something wrong the first time.
EDIT
The assumption below of the invariance of angle ratios is incorrect. Projective transformations instead preserve cross-ratios and incidence. A solution then is:
Find the point C' at the intersection of the lines defined by the segments AD and CP.
Find the point B' at the intersection of the lines defined by the segments AD and BP.
Determine the cross-ratio of B'DAC', i.e. r = (BA' * DC') / (DA * B'C').
Construct the projected line F'HEG'. The cross-ratio of these points is equal to r, i.e. r = (F'E * HG') / (HE * F'G').
F'F and G'G will intersect at the projected point Q so equating the cross-ratios and knowing the length of the side of the square you can determine the position of Q with some arithmetic gymnastics.
Hmmmm....I'll take a stab at this one. This solution relies on the assumption that ratios of angles are preserved in the transformation. See the image for guidance (sorry for the poor image quality...it's REALLY late). The algorithm only provides the mapping of a point in the quadrilateral to a point in the square. You would still need to implement dealing with multiple quad points being mapped to the same square point.
Let ABCD be a quadrilateral where A is the top-left vertex, B is the top-right vertex, C is the bottom-right vertex and D is the bottom-left vertex. The pair (xA, yA) represent the x and y coordinates of the vertex A. We are mapping points in this quadrilateral to the square EFGH whose side has length equal to m.
Compute the lengths AD, CD, AC, BD and BC:
AD = sqrt((xA-xD)^2 + (yA-yD)^2)
CD = sqrt((xC-xD)^2 + (yC-yD)^2)
AC = sqrt((xA-xC)^2 + (yA-yC)^2)
BD = sqrt((xB-xD)^2 + (yB-yD)^2)
BC = sqrt((xB-xC)^2 + (yB-yC)^2)
Let thetaD be the angle at the vertex D and thetaC be the angle at the vertex C. Compute these angles using the cosine law:
thetaD = arccos((AD^2 + CD^2 - AC^2) / (2*AD*CD))
thetaC = arccos((BC^2 + CD^2 - BD^2) / (2*BC*CD))
We map each point P in the quadrilateral to a point Q in the square. For each point P in the quadrilateral, do the following:
Find the distance DP:
DP = sqrt((xP-xD)^2 + (yP-yD)^2)
Find the distance CP:
CP = sqrt((xP-xC)^2 + (yP-yC)^2)
Find the angle thetaP1 between CD and DP:
thetaP1 = arccos((DP^2 + CD^2 - CP^2) / (2*DP*CD))
Find the angle thetaP2 between CD and CP:
thetaP2 = arccos((CP^2 + CD^2 - DP^2) / (2*CP*CD))
The ratio of thetaP1 to thetaD should be the ratio of thetaQ1 to 90. Therefore, calculate thetaQ1:
thetaQ1 = thetaP1 * 90 / thetaD
Similarly, calculate thetaQ2:
thetaQ2 = thetaP2 * 90 / thetaC
Find the distance HQ:
HQ = m * sin(thetaQ2) / sin(180-thetaQ1-thetaQ2)
Finally, the x and y position of Q relative to the bottom-left corner of EFGH is:
x = HQ * cos(thetaQ1)
y = HQ * sin(thetaQ1)
You would have to keep track of how many colour values get mapped to each point in the square so that you can calculate an average colour for each of those points.
I think what you're after is a planar homography, have a look at these lecture notes:
http://www.cs.utoronto.ca/~strider/vis-notes/tutHomography04.pdf
If you scroll down to the end you'll see an example of just what you're describing. I expect there's a function in the Intel OpenCV library which will do just this.
There is a C++ project on CodeProject that includes source for projective transformations of bitmaps. The maths are on Wikipedia here. Note that so far as i know, a projective transformation will not map any arbitrary quadrilateral onto another, but will do so for triangles, you may also want to look up skewing transforms.
If this transformation has to look good (as opposed to the way a bitmap looks if you resize it in Paint), you can't just create a formula that maps destination pixels to source pixels. Values in the destination buffer have to be based on a complex averaging of nearby source pixels or else the results will be highly pixelated.
So unless you want to get into some complex coding, use someone else's magic function, as smacl and Ian have suggested.
Here's how would do it in principle:
map the origin of A to the origin of B via a traslation vector t.
take unit vectors of A (1,0) and (0,1) and calculate how they would be mapped onto the unit vectors of B.
this gives you a transformation matrix M so that every vector a in A maps to M a + t
invert the matrix and negate the traslation vector so for every vector b in B you have the inverse mapping b -> M-1 (b - t)
once you have this transformation, for each point in the target area in B, find the corresponding in A and copy.
The advantage of this mapping is that you only calculate the points you need, i.e. you loop on the target points, not the source points. It was a widely used technique in the "demo coding" scene a few years back.

Resources