Generating intermediate vertices - java

I have a path say [vertex4, vertex5, vertex7, vertex8] starting at vertex 4, ending at vertex 8. I have access to the X and Y co-ordinates of each vertex.
How would I go about generating a series of vertices in between each pair of vertices. Say for instance, vertex4 -> vertex5 I want to be able to bisect the edge so that there will be more vertices along the edge to get to 5.
So for example, if I have a max 'step' size or something of 0.1, then the path would then be:
[4, 4.1, 4.2, 4.3 ... and so on up to 5].

I'm assuming each vertex is a point (X,Y) on the 2D plane and the edges are straight lines connecting them. You can easily bisect any edge on K equal parts:
Let A = (X0,Y0) and B = (X1,Y1) be the endpoints of the edge, then we can compute dX = (X1-X0)/K and dY = (Y1-Y0)/K. The intermediate points will be points of the form Pi = (X0+dXi,Y0+dYi) for 0 < i < K.
If you want the edges to have some specified length L, compute the length D of the edge AB using euclidian distance, and the number K of parts will be given by ceil(D/L).

Related

How to add z coordinates to the line to make it curve

I have inputs height if first coordinate, height of last coordinate, and n where n is a number of points I need to create on the edge including first and last.
I created points that are at equal distance but they form a straight line. I want to have a sinusoidal wave-like curve instead of a straight line. That means points closer to the first coordinate and last coordinates and the rest of the points are gradually increasing.
final double heightOfFirstCoordinate = 0;
final double heightOfLastCoordinate = 6;
final int n = 4;
final double step = (heightOfLastCoordinate - heightOfFirstCoordinate) / (n - 1);
final List<Double> collect = IntStream.range(0, n)
.mapToObj(i -> heightOfFirstCoordinate + step * I)
.collect(Collectors.toList());
As you can see on the screenshot what I produced is the black line but I need to produce the brown line.
I can't think of any simple algorithm to do this thing without making it much complicated.
assumed the derivative of the start and end points are exactly 0, you can use a cubic function running from 0 to 1 and returning values from 0 to 1:
double cubic(double x)
{
return 3*x*x-2*x*x*x;
}
To transform from the actual coordinates, use
y = y0+dy*cubic((x-x0)/dx);
where x0,y0 is the starting point the dy,dx are the deltas between start and end points.

Java: Intersection of two ellipse segments transformed into 3d space

I have segments of lines and ellipses (NOT planes and ellipsoids) transformed into 3d space and need to calculate whether two given segments intersect and where.
I'm using Java but haven't yet found a library which solves my problem, nor came across some algorithms that I could use for my own implementation.
For line-line intersection test there are several ways to solve. The classic way is using linear algebra (i.e., solving a linear matrix system) but from software development point of view I like more the Geometric-Algebra way, in the form of Plucker Coordinates, which only requires to implement vector algebra operations (i.e., cross-product and dot-product) which are simpler to code than matrix operations for solving linear systems.
I will show both for the sake of comparison then you decide:
Linear Algebra Way
Given line segment P limited by points P1 and P2 and line segment Q limited by points Q1 and Q2.
The parametric form of the lines is given by:
P(t) = P1 + t (P2 - P1)
Q(t) = Q1 + t (Q2 - Q1)
Where t is a real number in the interval [0 1].
If two lines intersect then the following equation holds:
P(t0) = Q(t1)
Provided that the two unknown numbers t0 and t1 exist. Expanding the above equation we get:
t0 (P2 - P1) - t1 (Q2 - Q1) = Q1 - P1
We can solve for t0 and t1 by expressing the above equation in matrix algebra:
A x = B
Where A is a 3x2 matrix with coordinates of vector (P2 - P1) in the first column and coordinates of the vector (Q2 - Q1) in the second column; x is a 2x1 column vector of unknowns t0 and t1 and B is a 3x1column vector with coordinates of vector (Q1 - P1).
Classically the system can be solved calculating the pseudo-inverse of matrix A, denoted by A^+:
A^+ = (A^T A)^-1 A^T
See:
https://en.m.wikipedia.org/wiki/Generalized_inverse
Fortunately any matrix package in Java should be able to compute the above calculations very easily and perhaps very efficiently too.
If multiplying A with its pseudo-inverse A^+ is equal to the identity matrix I, i.e., (A A^+) == I, then there IS a unique answer (intersection) and you can get it computing the following product:
x = A^+ B
Of course if you cannot compute the pseudo-inverse in the first place, e.g., because (A^T A) is singular (i.e. determinant is zero), then no intersection exists.
Since we are dealing with segments, the intersection point is at point P(x0) or Q(x1) iff x0 and x1 are both in the interval [0 1].
OTHER METHOD OF SOLUTION
To avoid dealing with matrix algebra we can try to solve the system using vector algebra and substitution method:
t0 (P2 - P1) - t1 (Q2 - Q1) = Q1 - P1
t0 = a + t1 b
t1 = C • (Q1 - (1 - a) P1 - a P2) / |C|^2
Where:
a = (P2 - P1) • (Q1 - P1) / |P2 - P1|^2
b = (P2 - P1) • (Q2 - Q1) / |P2 - P1|^2
C = b (P2 - P1) - (Q2 - Q1)
I cannot provide a geometric intuition of the above results yet.
Plucker Coordinates way
Given line segment P limited by points P1 and P2 and line segment Q limited by points Q1 and Q2.
The Plucker Coordinates of line P is given by a pair of 3d vectors (Pd, Pm):
Pd = P2 - P1
Pm = P1 x P2
Where Pm is the cross-product of P1 and P2. The Plucker Coordinates (Qd, Qm) of line Q can be calculated in exactly the same way.
The lines P and Q only can intersect if they are coplanar. Thr lines P and Q are coplnanar iif:
Pd • Qm + Qd • Pm = 0
Where (•) is the dot-product. Since machines have finite precision a robust test should check not for zero but for a small number. If Pd x Qd = 0 then lines are parallel (here 0 is the zero vector). Again a robust test should be for instamce that the squared length of (Pd x Qd) is small.
If the lines are not parallel then they are coplanar and their intersection (called "meet" in Plucker's jargon) will be the point:
x = ((Pm • N) Qd - (Qm • N) Pd - (Pm • Qd) N) / (Pd x Qd) • N
Where N is any coordinate axis vector (i.e., (1,0,0) or (0,1,0) or (0,0,1)), such that (Pd x Qd) • N is non-zero.
If the neither P nor Q pass through the origin, then their Plucker coordinate Pm and Qm respectively will be non-zero and the following sinpler formula will work
x = Pm x Qm / Pd • Qm
For an introduction to Plucker Coordinates see:
https://en.m.wikipedia.org/wiki/Plücker_coordinates
http://www.realtimerendering.com/resources/RTNews/html/rtnv11n1.html#art3
For a general intersection formula see "Corollary 6" of:
http://web.cs.iastate.edu/~cs577/handouts/plucker-coordinates.pdf
Transforming Ellipses to Circles Forth and Back
We can always transform an ellipse into a circle. An ellipse has two "radius", called semi-axes, which you can visualize in your mind as two orthogonal vectors, one big called major semi-axes and one small called minor semi-axes. You can apply a non-uniform scaling transformation to both semi-axes vectors for making them of equal size, so you get a circle.
We define an ellipse "E" by its center O, which is a 3d point and its two semi-axes A1 and A2, which are also 3d vectors. A normal vector N to the ellipse's plane can be computed by the cross product of its semi-axes N = A1 x A2 and then normalizing it to have unit length.
For now suppose there is a linear function M that you can use to transform (scale) your ellipse E into a circle C, with radius equal to the minor semi-axes, by applying it to your ellipse's semi-axes A1 and A2 and to the ellipse's center O.
Notice that the eliipse's center O and ellipse's normal vector N are not changed by M. So M(N) = N and M(O) = O. That means that the circle is in the same plane and has the same position C than the ellipse. The linear function M has a corresponding inverse function M^-1 so we can transform back the vectors of the circle to get the original ellipse E.
Of course we can transform the endpoints of lines P and Q also using function M for sending them to the "circle space" and we can send them back to "ellipse space" using M^-1.
Using M we can compute the intersection of the lines P and Q with the ellipse E in the circle space. So now we can focus on the line-circle intersection.
Line-Plane Intersection
Given a plane with normal vector N and distance D such that:
N • x + D = 0
For every point x in the plane. Then the intersection with line P with Plucker Coordinates (Pd, Pm) is given by:
x = (N x Pm - D Pd) / N • Pd
This works only if the line P is not in the plane i.e.,:
(N • P1 + D) != 0 and (N • P2 + D) != 0
And for our ellipse E we have:
N = (A1 x A2)/|A1 x A2|
D = -N • O
Line-Circle and Point-Circle Intersection
Now having x, the point-in-circle check is easy:
|O - x| <= |A2|
Equality holds only when x is in circle boundary.
If line P is in circle's plane then the following sinple check will give you the answer:
https://stackoverflow.com/a/1079478/9147444
How to Compute the Linear Function M
A simple way to compute M is the following. Use the Ellipse's normal vector N and semi-axes A1 and A2 to create a 3x3 matrix U. Such that U has the vectors A1, A2 and N as columns.
Then scale the major semi-axes A1 to have the same length to the minor semi-axes A2. Then create the matrix V auch that V has the new vector A1 and A2 and N as columns.
Then we define the linear matrix system:
R U = V
Where R is a 3x3 (non-uniform-)scaling-rotation matrix.
We can solve for R by multiplying both sides of the equation by the inverse of U which is denoted by U^-1
R U U^-1 = V U^-1
Since U U^-1 is the identity matrix we get:
R = V U^+
Using R we define the affine transformation
M(x) = R (x - O) + O
We can use M to transform points to circle space, such as O, P1, P2, Q1 and Q2. But if we need to transform vectors such as A1, A2, N, Pd and Qd. We need to use the simpler M:
M(x) = R x
Since A1, A2 and N are eigenvectors of R then R is not singular and has an inverse. We define the inverse M as:
M^-1(x) = R^-1 (x - O) + O
And for vectors:
M^-1(x) = R^-1 x
Update: Ellipse-Ellipse intersection
Two intersecting non-coplanar 3d-ellipses have their intersection points on the line formed by the intersection between their planes. So you first find the line formed by the intersection of the planes containig the ellipses (if planes do not intersect i.e., they are parallel, then neither the ellipses intersect).
The line of intersection belong to both planes, so it is perpendicular to both normals. The direction vector V is the cross product of the plane normals:
V = N1 × N2
To fully determine the line we also need to find a point on the line. We can do that solving the linear equations of the planes. Given the 2x3 matrix N = [N1^T N2^T] with the normals N1 and N2 as rows, and the 2x1 column vector b = [N1 • C1, N2 • C2], where C1 and C2 are the centers of the ellipses, we can form the linear matrix system:
N X = b
Where X is some point satifying both plane equations. The system is underdetermined since there are infinite number of points in the line satifying the system. We can still find a particular solution closer to the origin by using the pseudo-inverse of matrix N, denoted by N^+.
X = N^+ b
The line equation is
L(t) = X + t V
For some scalar t.
Then you can apply the method described earlier to test the line-ellipse intersection i.e., scaling the ellipse to a circle and intersect with the coplanar line. If both ellipses intersect the line in the same points then they intersect.
Now, the case in which the ellipses actually lie on the same plane is more complex. You can ceck the approach taken by Dr Eberly in his excellent book "Geometric Tools" (also available online):
https://www.geometrictools.com/Documentation/IntersectionOfEllipses.pdf
And also you can check the C++ source code which is open source:
https://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrEllipse2Ellipse2.h

Find the shortest path to reach a given destination cell in 2D matrix with obstacles

I am working on below interview question and I am confuse on how to use BFS search here. I am confuse on how to deal with the blockades here?
Given a MxN matrix find the shortest path to reach a given destination
cell. The robot can move up, down, left or right. The matrix also
comes with set of blockades in few of the cells where the robot can't
pass through. Output the minimum number of moves the robot needs to
make to reach the destination. Output -1 if the destination is not
reachable. Assume that the blockade will never be at the starting
cell.
Input Format: First line contains the values of M and N matrix. Second
line contains the cell location of the robots starting position. Third
line contains the cell location of the destination. Fourth line and
the lines following that will contain the locations of the blockades.
The example below contains only one blockade at (2,2) where the robot
can't pass through. Below is the input:
3 3
1 1
3 3
2 2
Output should be 4 for above input.
Below is what I have started but confuse on how to deal with blockades here while doing BFS search:
public static void main(String args[] ) throws Exception {
Scanner sc = new Scanner(System.in);
int M = sc.nextInt();
int N = sc.nextInt();
int startX = sc.nextInt();
int startY = sc.nextInt();
int destinationX = sc.nextInt();
int destinationY = sc.nextInt();
while (sc.hasNext()) {
int blockedX = sc.nextInt();
int blockedY = sc.nextInt();
}
}
You can simply view the grid as a graph: each cell is connected to its four neighbors (or fewer if it's on an edge), excluding any blockades. Using your example:
1 2 3
1 • • •
2 • x •
3 • • •
we have the graph (using (row, col) notation):
(1,1) <-> (1,2)
(2,1) <-> (3,1)
(3,1) <-> (2,3)
(2,3) <-> (3,3)
(3,3) <-> (3,2)
(3,2) <-> (3,1)
(3,1) <-> (2,1)
(2,1) <-> (1,1)
where all edge lengths are 1. Now you can apply a standard BFS from the start node until you reach the target node, keeping track of which nodes you visit. In pseudocode:
Mark all cell distances as infinite except for the robot starting cell, which has distance zero (you can do this using an extra 2D array, or maybe even in-place depending on how you store the grid).
Initialize an empty queue of cells Q
Add the robot starting cell to Q
While Q is not empty:
Dequeue the next cell C from Q
For each non-blockade neighbor N of C (easy to determine from grid):
If N's distance is infinity, mark N's distance to be (C's distance) + 1, and add N to Q.
If N is the destination cell, return N's distance.
At this point we know there's no path from the start cell to the destination cell.

algorithm to calculate perimeter of unioned rectangles

I'm trying to calculate the perimeter of the union of a n rectangles, of which I have the bottom left and top right points. Every rectangle sits on the x axis (bottom left corner of every rectangle is (x, 0)). I've been looking into different ways of doing this and it seems like the Sweep-Line algorithm is the best approach. I've looked at Graham Scan as well. I'm aiming for an O(n log n) algorithm. Honestly though I am lost in how to proceed, and I'm hoping someone here can do their best to dumb it down for me and try to help me understand exactly how to accomplish this.
Some things I've gathered from the research I've done:
We'll need to sort the points (I'm not sure the criteria in which we are sorting them).
We will be dividing and conquering something (to achieve the O (log n)).
We'll need to calculate intersections (What's the best way to do this?)
We'll need some sort of data structure to hold the points (Binary tree perhaps?)
I'll ultimately be implementing this algorithm in Java.
The algorithm is a lot of fiddly case analysis. Not super complicated, but difficult to get completely correct.
Say all the rectangles are stored in an array A by lower left and upper right corner (x0, y0, x1, y1). So we can represent any edge of a rectangle as a pair (e, i) where e \in {L, R, T, B} for left, right, top, and bottom edge and i denotes A[i]. Put all pairs (L, i) in a start list S and sort it on A[i].x0.
We'll also need a scan line C, which is a BST of triples (T, i, d) for top edges and (B, i, d) for bottom. Here i is a rectangle index, and d is an integer depth, described below. The key for the BST is the edges' y coordinates. Initially it's empty.
Note that at any time you can traverse C in order and determine which portions of the sweep line are hidden by a rectangle and not. Do this by keeping a depth counter, initially zero. From least y to greatest, when you encounter a bottom edge, add 1 to the counter. When you see a top edge, decrement 1. For regions where the counter is zero, the scan line is visible. Else it's hidden by a rectangle.
Now you never actually do that entire traversal. Rather you can be efficient by maintaining the depths incrementally. The d element of each triple in C is the depth of the region above it. (The region below the first edge in C is always of depth 0.)
Finally we need an output register P. It stores a set of polylines (doubly linked lists of edges are convenient for this) and allows queries of the form "Give me all the polylines whose ends' y coordinates fall in the range [y0..y1]. It's a property of the algorithm that these polylines always have two horizontal edges crossing the scan line as their ends, and all other edges are left of the scan line. Also, no two polylines intersect. They're segments of the output polygon "under construction." Note the output polygon may be non-simple, consisting of multiple "loops" and "holes." Another BST will do for P. It is also initially empty.
Now the algorithm looks roughly like this. I'm not going to steal all the fun of figuring out the details.
while there are still edges in S
Let V = leftmost vertical edge taken from S
Determine Vv, the intersection of V with the visible parts of C
if V is of the form (L, i) // a left edge
Update P with Vv (polylines may be added or joined)
add (R, i) to S
add (T, i) and (B, i) to C, incrementing depths as needed
else // V is of the form (R, i) // a right edge
Update P with Vv (polylines may be removed or joined)
remove (T, i) and (B, i) from C, decrementing depths as needed
As P is updated, you'll generate the complex polygon. The rightmost edge should close the last loop.
Finally, be aware that coincident edges can create some tricky special cases. When you run into those, post again, and we can discuss.
The run time for the sort is of course O(n log n), but the cost of updating the scan line depends on how many polygons can overlap: O(n) for degenerate cases or O(n^2) for the whole computation.
Good luck. I've implemented this algorithm (years ago) and a few others similar. They're tremendous exercises in rigorous logical case analysis. Extremely frustrating, but also rewarding when you win through.
The trick is to first find the max height at every segment along the x axis (see the picture above). Once you know this, then the perimeter is easy:
NOTE: I haven't tested the code so there might be typos.
// Calculate perimeter given the maxY at each line segment.
double calcPerimeter(List<Double> X, List<Double> maxY) {
double perimeter = 0;
for(int i = 1; i < X.size(); i++){
// Add the left side of the rect, maxY[0] == 0
perimeter += Math.abs(maxY.get(i) - maxY.get(i - 1))
// add the top of the rect
perimeter += X.get(i) - X.get(i-1);
}
// Add the right side and return total perimeter
return perimeter + maxY.get(maxY.size() - 1);
}
Putting it all together, you will need to first calculate X and maxY. The full code will look something like this:
double calcUnionPerimeter(Set<Rect> rects){
// list of x points, with reference to Rect
List<Entry<Double, Rect>> orderedList = new ArrayList<>();
// create list of all x points
for(Rect rect : rects){
orderedList.add(new Entry(rect.getX(), rect));
orderedList.add(new Entry(rect.getX() + rect.getW(), rect));
}
// sort list by x points
Collections.sort(orderedList, new Comparator<Entry<Double,Rect>>(){
#Override int compare(Entry<Double, Rect> p1, Entry<Double, Rect> p2) {
return Double.compare(p1.getKey(), p2.getKey());
}
});
// Max PriorityQueue based on Rect height
Queue<Rect> maxQ = new PriorityQueue<>(orderedList, new Comparator<Rect>(){
#Override int compare(Rect r1, Rect r2) {
return Double.compare(r1.getH(), r2.getH());
}
}
List<Double> X = new ArrayList<>();
List<Double> maxY = new ArrayList<>();
// loop through list, building up X and maxY
for(Entry<Double, Rect> e : orderedList) {
double x = e.getKey();
double rect = e.getValue();
double isRightEdge = x.equals(rect.getX() + rect.getW());
X.add(x);
maxY.add(maxQ.isEmpty() ? 0 : maxQ.peek().getY());
if(isRightEdge){
maxQ.dequeue(rect); // remove rect from queue
} else {
maxQ.enqueue(rect); // add rect to queue
}
}
return calcPerimeter(X, maxY);
}

Rotation of indices of a 2d array by 90 degrees

I know how to rotate an entire 2d array by 90 degrees around the center(My 2d array lengths are always odd numbers), but I need to find an algorithm that rotates specific indices of a 2d array of known length. For example I know that the 2d array is a 17 by 17 grid and I want the method to rotate the indices [4][5] around the center by 90 degrees and return the new indices as two separate ints(y,x); Please point me in the right direction or if your feeling charitable I would very much appreciate some bits of code - preferably in java. Thanks!
Assuming cartesian coordinates (i.e. x points right, and y points up) and that your coordinates are in the form array[y][x] the center [cx, cy] of your 17x17 grid is [8, 8].
Calculate the offset [dx, dy] of your point [px, py] being [4, 5] from there, i.e. [-4, -3]
For a clockwise rotation, the new location will be [cx - dy, cy + dx]
If your array uses the Y axis pointing "downwards" then you will need to reverse some of the signs in the formulae.
For a non-geometric solution, consider that the element [0][16] needs to get mapped to [16][16], and [0][0] mapped to [0][16]. i.e. the first row maps to the last column, the second row maps to the second last column, etc.
If n is one less than the size of the grid (i.e. 16) that just means that point [y][x] will map to [x][n - y]
In theory, the geometric solution should provide the same answer - here's the equivalence:
n = 17 - 1;
c = n / 2;
dx = x - c;
dy = y - c;
nx = c - dy = c - (y - c) = 2 * c - y = n - y
ny = c + dx = c + (x - c) = x
​
If you have a square array with N elements in each row/column a 90deg turn anti-/counter-clockwise sends (x,y) to (N+1-y,x) doesn't it ?
That is, if like me, you think that the top-left element in a square array is (1,1) and row numbers increase down and column numbers to the right. I guess someone who counts from 0 will have to adjust the formula somewhat.
The point in Cartesian space x,y rotated 90 degrees counterclockwise maps to -y,x.
An array with N columns and M rows would map to an array of M columns and N rows. The new "x" index will be non-positive, and will be made zero-based by adding M:
a[x][y] maps to a[M-y][x]

Categories