Symbolic perturbation of plane-based geometry - computational-geometry

I know it's possible to apply a symbolic perturbation scheme like 'Simulation of Simplicity'(SoS) to geometric predicates like the 4-point orient, to avoid handling degenerate cases. I'm assuming it's also valid to do the same with plane-based geometry, where points are implicitly defined by the intersection of 3 planes, so I can have a similar orient predicate that tells me on which side of a 4th plane the point defined by the first 3 lies. I'd perturb the coefficients of the plane equation instead of the cartesian coordinates of a point.
The problem is that a point could be defined by many different planes. Each vertex in a cube is defined by 3 planes, but the apex of a pyramid has 4. Consistency seems to be everything with schemes like SoS, and I can't figure if it matters which 3 planes I select to define a point. Perhaps it doesn't, as long as every time I refer to that point I use the same 3 planes.
So, the question: Can I choose any 3 planes to represent a point?
Thanks in advance.

For a very similar problem, I represented the planes as perturbed bisectors between couples of points pi and pj:
Pij = {p | d2(pi,p) - ei = d2(p_j,p) - ej)}
where d2 denotes the squared Euclidean distance
and where ei = epsilon^(2^i) denotes the symbolic perturbation.
Then it is possible to write the equation of the intersection between three planes, inject it into the predicate, separate the nominator from the denominator to avoid divisions, order the ei terms and deduce the symbolic perturbation.
In your case, it would represent the degeneracy with a point on four planes as two points, each of them being on three of the four planes (exactly like order-4 vertices in Voronoi diagrams when using perturbed incircle predicate).
The advantage of this representation is that the symbolic perturbation is reasonably simple to write (only two terms per plane).
The implementation and documentation is available in my GEOGRAM library:
http://alice.loria.fr/software/geogram/doc/html/namespaceGEO_1_1PCK.html

Related

algorithm to select a pair of vectors for the best "zigzag" profile

I have a set of distinct 2D vectors (over real numbers), pointing in different directions. We are allowed to pick a pair of vectors and construct their linear combination, such that the coefficients are positive and their sum is 1.
In simple words we are allowed to take a "weighted average" of any two vectors.
My goal is for an arbitrary direction to pick a pair of vectors whose "weighted average" is in this direction and is maximized.
Speaking algebraically given vectors a and b and a direction vector n we are interested in maximizing this value:
[ a cross b ] / [ (a - b) cross n ]
i.e. pick a and b which maximize this value.
To be concrete the application of this problem is for sailing boats. For every apparent wind direction the boat will have a velocity given by a polar diagram. Here's an example of such a diagram:
(Each line in this diagram corresponds to a specific wind magnitude). Note the "impossible" front sector of about 30 degrees in each direction.
So that in some direction the velocity will be high, for some - low, and for some directions it's impossible to sail directly (for instance in the direction strictly opposite to the wind).
If we need to advance in a direction in which we can't sail directly (or the velocity isn't optimal) - it's possible to advance in zigzags. This is called tacking.
Now, my goal is to recalculate a new diagram which denotes the average advance velocity in any direction, either directly or indirectly. For instance for the above diagram the corrected diagram would be this:
Note that there are no more "impossible" directions. For some directions the diagram resembles the original one, where it's best to advance directly, and no maneuver is required. For others - it shows the maximum average advance velocity in this direction assuming the most optimal maneuver is periodically performed.
What would be the most optimal algorithm to calculate this? Assume the diagram is given as a discrete set of azimuth-velocity pairs, from which we can calculate the vectors.
So far I just check all the vector pairs to select the best. Well, there're cut-off criterias, such as picking only vectors with positive projection on the advance direction, and opposite perpendicular projections, but still the complexity is O(N^2).
I wonder if there's a more efficient algorithm.
EDIT
Many thanks to #mcdowella. For both computer-science and sailor answers!
I too thought in terms of convex polygon, figured out that it's only worth probing vectors on that hull (i.e. if you take a superposition of 2 vectors on this hull, and try to replace one of them by a vector which isn't on this hull, the result would be worse since new vector's projection on the needed direction is worse than of both source vectors).
However I didn't realize that any "weighted average" of 2 vectors is actually a straight line segment connecting those vectors, hence the final diagram is indeed this convex hull! And, as we can see, this is also in agreement with what I calculated by "brute-force" algorithm.
Now the computer science answer
A tacking strategy gives you the convex combination of the vectors from the legs that make up the tacks.
So consider the outline made by just one contour in your diagram. The set of all possible best speeds and directions is the convex polygon formed by taking all convex combinations of the vectors to the contour. So what you want to do is form the convex hull of your contour (https://en.wikipedia.org/wiki/Convex_hull). To find out how to go fast in any particular direction, intersect that vector with the convex hull, and use tacks with legs that correspond to the corners on either side of the edge of the convex hull that you intersect with.
Looking at your diagram, the contour is concave straight upwind and straight downwind, which is what you would expect. However there is also another concave section, somewhere between 4 and 5 O'Clock and also symmetrically between 7 and 8 O'Clock, which appears as a straight line in your corrected diagram - so I guess there is a third direction to tack in, using two reaches on the same side of the wind which I don't recognise from traditional sailing.
First the ex-laser sailor answer
At least for going straight upwind or downwind, the obvious guess is to tack so that each leg is of the same length and of the same bearing to the wind. If the polar diagram is symmetric around the upwind-downwind axis this is correct. Suppose upwind is the Y axis and possible legs are (A, B), (-A, B), (a, b) and (-a, b). Symmetrical tacking moves (A, B)/2 + (-A, B)/2 = (0, B) and the other symmetrical tack gives you (0, b). Asymmetrical tacking is (-A, B)a/(a+A) + (a, b)A/(a+A) = (0, (a/(a+A))B + (A/(a+A))b) and if b!=B lies between b and B and so is not as good as whichever of b or B is best.
For any direction which lies between the port and starboard tacks that you would take to work your way upwind, the obvious strategy is to change the length of those legs but not their direction so that the average vector traveled is in the required direction. Is this the best strategy? If not, the better strategy is making progress upwind faster that the port and starboard tacks that you would take to work your way upwind, which I think is a contradiction - so for any direction which lies between the port and starboard tacks made to go upwind I think the best strategy is indeed to make those tacks but alter the leg lengths to go in the required direction. The same thing should apply for tacking downwind, if you have a boat that makes that a good idea.

How can I approximate an algebraic segment using a Curve_2 of Arr_conic_traits_2?

I am computing the plane bisector of two line segments (of type RatKernel::Segment_2) which can be composed by parabolic arcs, rays and line segments.
Using the Arr_conic_traits_2<RatKernel, AlgKernel, NtTraits> class I could easily create the parts that were parabolic arcs, and this was not a problem. As specified in the reference, the supporting curves of the arcs need to be of the form: rx^2 + sy^2 + txy + ux + vy + w = 0 where all six coefficients need to be rational numbers. However, the endpoints of the arcs can be Point_2 with algebraic coordinates.
The problem arises with the rays (which anyway had to be bounded to very long segments as the conic traits class only supports bounded curves) and the segments, because in order to connect them to the parabolic arcs, they
also need to have algebraic endpoints. This means that the supporting curve (a line) would have also algebraic coefficients, but this is not supported.
I really need all pieces of the bisector to be connected to each other, because approximating the segment parts with rational segments (and thus making the bisector pieces disconnected) appears to cause errors in other computation.
One idea was to approximate these segment bisector parts using almost flat curves; the problem is that I just have the two endpoints, and I can create a third point in the middle and move it slightly (it can therefore easily have rational coordinates) so that the curve passing through the three points would not be flat.
Having three points (two forcefully algebraic) I'd need to create a curve that satisfies them all and that has rational coefficients. Is this possible? Are there better solutions?
P.S.: Using another arrangement class such as Arr_algebraic_segment_traits_2 would allow me to use unbounded rays, but if I understood correctly the endpoints of all curves would need to have as x coordinate an integer number, which is even a bigger problem.
Try to use Arr_algebraic_segment_traits_2 after all.
The curves handled by this traits are the graph of the zero set of polynomials. The restriction is that the coefficients must be integral numbers, which implies that polynomials with rational coefficients can be handled as well. The coordinates of a point are real numbers.
To construct a real number and use it as a coordinate, do something like:
#include <CGAL/Algebraic_kernel_d_1.h>
typedef CGAL::Algebraic_kernel_d_1<Integer> AK;
typedef AK::Polynomial_1 Polynomial_1;
AK ak;
AK::Construct_algebraic_real_1 construct_algreal_1 =
ak.construct_algebraic_real_1_object();
Polynomial_1 px = CGAL::shift(AK::Polynomial_1(1),1);
Algebraic_real_1 c = construct_algreal_1(px*px-2,1);
Point_2 p = construct_point(c, c);

Plotting a location into an irregular rectangle

I have 4 Point values: TopLeft, TopRight, BottomLeft, BottomRight. These define a 4 sided shape (like a distorted rectangle) on my monitor. These are the point a Tobii gaze device thinks I am looking at when in fact I am looking at the four corners of my monitor.
This picture shows a bitmap on the left representing my monitor, and the points the Tobii device tells me I am looking at when I am in fact looking at the corners of the screen. (It's a representation, not real).
I want to use those four calibration points to take a screen X,Y position that is from an inaccurate gaze position and correct it so that it is positioned as per the image on the right.
Edit: New solution for the edited question is at the end.
This problem is call bilinear interpolation.
Once you grasp the idea, it will be very easy and you would remember it for the rest of your life.
It would be quite long to post all detail here, but I will try.
First, I will name the point on the left to be (x,y) and the right to be (X,Y).
Let (x1,y1), (x1,y2), (x2,y1), (x2,y2) be the corner points on the left rectangle.
Secondly, let's split the problem into 2 bilinear interpolation problems:
want to find X
want to find Y
Let's find them one by one (X or Y).
Define : Qxx are the value of X or Y of the four corner in the right rectangle.
Suppose that we want to find the value of the unknown function f at
the point (x, y). It is assumed that we know the value of f at the
four points Q11 = (x1, y1), Q12 = (x1, y2), Q21 = (x2, y1), and Q22 =
(x2, y2).
The f(x,y) of your problem is X or Y in your question.
Then you interpolate f(x,y1) and f(x,y2) to be f(x,y) in the same way.
Finally, you will got X or Y=f(x,y)
Reference : All pictures/formulas/text here are copied from the wiki link (some with modification).
Edit: After the question has been edited, it become very different.
The new one is opposite, and it is called "inverse bilinear interpolation" which is far harder.
For more information, please read http://www.iquilezles.org/www/articles/ibilinear/ibilinear.htm
You can define a unique Linear Transform using 6 equations. The 3 points which have to align provide those 6 equations, as each pair of matching points provides two equations in x and y.
If you want to pursue this, I can provide the matrix equation which defines the Linear Transform based on how it maps three points. You invert this matrix and it will provide the linear transform.
But having done that, the transform is completely specified. You have no control over where the corner points of the original quadrilateral will go. In general, you can't even define a linear transform to map one quadrilateral onto another; this gives 8 equations (2 for each corner) with only 6 unknowns. Its over-specified. In fact a Linear Transform must always map a rectangle to a parallelogram, so in general you can't define a Linear Transform which maps one quadrilateral to another.
So if it can't be a Linear Transform, can it be a non-Linear Transform? Well, yes, but non-Linear Transforms don't necessarily map straight lines to straight lines, so the mapped edges of the quadrilateral won't be straight. Or any other lines. And you still have 14 equations (2 for each point and corner) for which you have to invent some non-Linear transform with 14 unknowns.
So the problem as stated cannot be solved with a Linear Transform; its over specified. Using a non-Linear transform will require you to devise a non-Linear transform which has 14 free variables (vs the 6 in a Linear Transform), this will map the 7 points correctly but straight lines will no longer be straight. Adding this requirement in adds an infinite number of constraints (one for every point in the line) and you won't even be able to use continuous functions.
There may be some solution to what you are doing in terms of what you are really trying to do (ie the underlying application need), but as a mathematical problem it is unsolvable.
Let me know if you want the matrix equation to produce a Linear Transform based on how it transforms 3 points.

segment intersecting a tetrahedron

I am trying to write C++ code to find the intersection points of a segment intersecting a tetrahedron. I reduced the problem like this:
For each face of the tetrahedron (a triangle), find the intersection point of the line segment. Then, I have three cases:
a) The segment doesn't intersect any face - thus either the segment is entirely in the tetrahedron or completely outside.
b) The segment only intersects one face. Then I just need to determine the side of the segment that is in the tetrahedron and I get the two points that are in the tetrahedron.
c) The segment intersects two faces.
I am having trouble implementing this algorithm. Here are the issues:
If the segment and triangle are in the same plane, how do I find the intersection points?
How can I determine if the segment lies on one of the edges of the tetrahedron?
Thanks.
Hint:
You can't avoid a complex case discussion. Here I introduce the planar case of a line segment and a triangle.
The sides of the triangle define three straight lines that partition the plane in 7 regions, one bounded and 6 unbounded. On the figure, they are designated by the signs obtained when you plug the coordinates of a point in the three implicit equations of these lines.
If you need to consider endpoints exactly on a side, you need to add 6 half-lines and 3 segments to the discussion.
Then take all possible combinations of the starting and ending regions.
Many of the cases are straightforward. When the two segment endpoint belong to the same region, the segment is wholly inside or outside; when one of the regions is +++ and the other is different, there is exactly one intersection...
In the case of the figure (--+ to ++-), you are sure to have one intersection with the bottom edge; but which is the other intersected side is unsure: to answer this, you need to tell on what side of the line segment the top vertex lies.
With some courage, you can discuss all 16 x 15 / 2 = 120 cases, many of which are identical to a permutation of the elements.
This is just an appetizer compared to the 3D problem.
"How can I determine if the segment lies on one of the edges of the tetrahedron?"
Write a function that computes the area of the triangle determined by three points in space. This can be computed from a determinant, as explained here and many other sites.
Then write a function that determines if two segments ab and cd are collinear.
They are if and only if the area of abc is zero, and the area of abd is zero.
Finally, write a function that determines if one point c lies on the segment ab. With all this, the remainder is easy.
To answer the general question, i.e. how to find the (up to two) intersections between a segment and a tetrahedron, I'd prefer to avoid the painful case-by-case analysis (mentioned in your problem reduction and in another answer).
I would use a variant of Sutherland-Hogdman's reentrant clipping (explained in 2D in [1]): the idea is to consider the tetrahedron as the intersection between four oriented half-spaces (limited by the support planes of the four faces of the tetrahedron).
Thus to compute the intersection between a segment and a tetrahedron, you can proceed as follows:
S := your segment
for f := 0 to 3 {
H := half_space(tet, f)
S := intersect(S, H)
}
H is just a plane equation (coefficients a,b,c,d of equation ax+by+cz+d=0,
[a,b,c] is the normal to the facet, oriented towards the interior of the tetrahedron. d is obtained by injecting a vertex incident to the facet into the equation).
The function intersect() is simple to implement (just test the sign of ax+by+cz+d at both vertices of the segment, if they differ, there is an intersection, that can be computed by injecting a parametric equation of S
x=x1+t(x2-x1), y=y1+t(y2-y1), z=z1+t(z2-z1) into (ax+by+cz+d=0) and solving for t, where (x1,y1,z1) and (x2,y2,z2) denote the two extremities of S.
In addition, the function intersect() may compute two booleans, to keep track of which vertex of S is a generated intersection.
[1] https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm

How to perform spatial partitioning in n-dimensions?

I'm trying to design an implementation of Vector Quantization as a c++ template class that can handle different types and dimensions of vectors (e.g. 16 dimension vectors of bytes, or 4d vectors of doubles, etc).
I've been reading up on the algorithms, and I understand most of it:
here and here
I want to implement the Linde-Buzo-Gray (LBG) Algorithm, but I'm having difficulty figuring out the general algorithm for partitioning the clusters. I think I need to define a plane (hyperplane?) that splits the vectors in a cluster so there is an equal number on each side of the plane.
[edit to add more info]
This is an iterative process, but I think I start by finding the centroid of all the vectors, then use that centroid to define the splitting plane, get the centroid of each of the sides of the plane, continuing until I have the number of clusters needed for the VQ algorithm (iterating to optimize for less distortion along the way). The animation in the first link above shows it nicely.
My questions are:
What is an algorithm to find the plane once I have the centroid?
How can I test a vector to see if it is on either side of that plane?
If you start with one centroid, then you'll have to split it, basically by doubling it and slightly moving the points apart in an arbitrary direction. The plane is just the plane orthogonal to that direction.
But you don't need to compute that plane.
More generally, the region (i) is defined as the set of points which are closer to the centroid c_i than to any other centroid. When you have two centroids, each region is a half space, thus separated by a (hyper)plane.
How to test on a vector x to see on which side of the plane it is? (that's with two centroids)
Just compute the distance ||x-c1|| and ||x-c2||, the index of the minimum value (1 or 2) will give you which region the point x belongs to.
More generally, if you have n centroids, you would compute all the distances ||x-c_i||, and the centroid x is closest to (i.e., for which the distance is minimal) will give you the region x is belonging to.
I don't quite understand the algorithm, but the second question is easy:
Let's call V a vector which extends from any point on the plane to the point-in-question. Then the point-in-question lies on the same side of the (hyper)plane as the normal N iff V·N > 0

Resources