How does this code for delaunay triangulation work? - java

I have this Java code that with a set of Point in input return a set of graph's edge that represent a Delaunay triangulation.
I would like to know what strategy was used to do this, if exist, the name of algorithm used.
In this code GraphEdge contains two awt Point and represent an edge in the triangulation, GraphPoint extends Awt Point, and the edges of final triangulation are returned in a TreeSet object.
My purpose is to understand how this method works:
public TreeSet getEdges(int n, int[] x, int[] y, int[] z)
below the complete source code of this triangulation :
import java.awt.Point;
import java.util.Iterator;
import java.util.TreeSet;
public class DelaunayTriangulation
{
int[][] adjMatrix;
DelaunayTriangulation(int size)
{
this.adjMatrix = new int[size][size];
}
public int[][] getAdj() {
return this.adjMatrix;
}
public TreeSet getEdges(int n, int[] x, int[] y, int[] z)
{
TreeSet result = new TreeSet();
if (n == 2)
{
this.adjMatrix[0][1] = 1;
this.adjMatrix[1][0] = 1;
result.add(new GraphEdge(new GraphPoint(x[0], y[0]), new GraphPoint(x[1], y[1])));
return result;
}
for (int i = 0; i < n - 2; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = i + 1; k < n; k++)
{
if (j == k) {
continue;
}
int xn = (y[j] - y[i]) * (z[k] - z[i]) - (y[k] - y[i]) * (z[j] - z[i]);
int yn = (x[k] - x[i]) * (z[j] - z[i]) - (x[j] - x[i]) * (z[k] - z[i]);
int zn = (x[j] - x[i]) * (y[k] - y[i]) - (x[k] - x[i]) * (y[j] - y[i]);
boolean flag;
if (flag = (zn < 0 ? 1 : 0) != 0) {
for (int m = 0; m < n; m++) {
flag = (flag) && ((x[m] - x[i]) * xn + (y[m] - y[i]) * yn + (z[m] - z[i]) * zn <= 0);
}
}
if (!flag)
{
continue;
}
result.add(new GraphEdge(new GraphPoint(x[i], y[i]), new GraphPoint(x[j], y[j])));
//System.out.println("----------");
//System.out.println(x[i]+" "+ y[i] +"----"+x[j]+" "+y[j]);
result.add(new GraphEdge(new GraphPoint(x[j], y[j]), new GraphPoint(x[k], y[k])));
//System.out.println(x[j]+" "+ y[j] +"----"+x[k]+" "+y[k]);
result.add(new GraphEdge(new GraphPoint(x[k], y[k]), new GraphPoint(x[i], y[i])));
//System.out.println(x[k]+" "+ y[k] +"----"+x[i]+" "+y[i]);
this.adjMatrix[i][j] = 1;
this.adjMatrix[j][i] = 1;
this.adjMatrix[k][i] = 1;
this.adjMatrix[i][k] = 1;
this.adjMatrix[j][k] = 1;
this.adjMatrix[k][j] = 1;
}
}
}
return result;
}
public TreeSet getEdges(TreeSet pointsSet)
{
if ((pointsSet != null) && (pointsSet.size() > 0))
{
int n = pointsSet.size();
int[] x = new int[n];
int[] y = new int[n];
int[] z = new int[n];
int i = 0;
Iterator iterator = pointsSet.iterator();
while (iterator.hasNext())
{
Point point = (Point)iterator.next();
x[i] = (int)point.getX();
y[i] = (int)point.getY();
z[i] = (x[i] * x[i] + y[i] * y[i]);
i++;
}
return getEdges(n, x, y, z);
}
return null;
}
}

Looks like what is described here http://en.wikipedia.org/wiki/Delaunay_triangulation :
The problem of finding the Delaunay triangulation of a set of points in d-dimensional Euclidean space can be converted to the problem of finding the convex hull of a set of points in (d + 1)-dimensional space, by giving each point p an extra coordinate equal to |p|2, taking the bottom side of the convex hull, and mapping back to d-dimensional space by deleting the last coordinate.
In your example d is 2.
The vector (xn,yn,zn) is the cross product of the vectors (point i -> point j) and (point i -> point k) or in other words a vector perpendicular to the triangle (point i, point j, point k).
The calculation of flag checks whether the normal of this triangle points towards the negative z direction and whether all other points are on the side opposite to the normal of the triangle (opposite because the other points need to be above the triangle's plane because we're interested in the bottom side of the convex hull). If this is the case, the triangle (i,j,k) is part of the 3D convex hull and therefore the x and y components (the projection of the 3D triangle onto the x,y plane) is part of the (2D) Delaunay triangulation.

Related

Locker App Method

This is a lockers app I'm building that ensures that lockers are placed so that customers in the city are always within a short distance from the a locker in the ciry. To account for this, I need a way to model locker placements and distances from lockers.
For this I am provide the following:
A positive whole number range 1-9 representing the length of your city in city blocks
A positive whole number range 1-9 representing the width of your city in city blocks
An array containing all X coordinates representing Locker Locations, each X coordinate range 1-9.
An array containing all Y coordinates representing Locker Locations, each Y coordinate range 1-9.
The job here is to contruct a 2D grid of the city. Each element of the grid should be a positive whole number that specifies the number of blocks to the closet locker. The distance the between two blocks is the sum of their horizontal and vertical distance(a move in the diagonal direction is therefore considered a distance of 2). Return your grid as 2D array of integers where the first index corresponds to the X dimension and the second index corresponsds to the Y direction.
Example #1:
Given:
3
5
[1]
[1]
Return:
012
123
234
345
456
Example #2:
Given:
5
7
[2,4]
[3,7]
Return:
32345
21234
10123
21234
32323
43212
32101
This is the method I was aske to use:
static int[][] getLockerDistanceGrid(int cityLength, int cityWidth, int[] lockerXCoordinates, int[] lockerYCoordinates) {
}
How would I do this? Any help would be appreciated!
I solved it with a bit modified BFS
private static class Node {
public Node (int x, int y) {
this.x = x;
this.y = y;
}
public int x, y;
}
static int[][] getLockerDistanceGridBfs(int cityLength, int cityWidth, int[] lockerXCoordinates, int[] lockerYCoordinates) {
if (lockerXCoordinates == null || lockerYCoordinates == null || lockerXCoordinates.length != lockerYCoordinates.length)
return null;
int[][] city = new int[cityWidth][cityLength];
for (int i = 0; i < city[0].length; i++)
for (int j = 0; j < city.length; j++)
city[j][i] = Integer.MAX_VALUE;
Queue<Node> nodesToDo = new LinkedList<>();
for (int i = 0; i < lockerXCoordinates.length; i++) {
city[lockerXCoordinates[i] - 1][lockerYCoordinates[i] - 1] = 0;
nodesToDo.add(new Node(lockerXCoordinates[i] - 1, lockerYCoordinates[i] - 1));
}
while(!nodesToDo.isEmpty()) {
Node v = nodesToDo.poll();
int newDist = city[v.x][v.y] + 1;
List<Node> neighbours = getNeighbours(cityLength, cityWidth, v.x, v.y);
for(Node node : neighbours) {
if(newDist < city[node.x][node.y]) {
city[node.x][node.y] = newDist;
nodesToDo.add(node);
}
}
}
return city;
}
private static List<Node> getNeighbours(int cityLength, int cityWidth, int x, int y) {
List<Node> result = new ArrayList<>(4);
if(x - 1 >= 0) {
result.add(new Node(x - 1, y));
}
if(y - 1 >= 0) {
result.add(new Node(x, y - 1));
}
if(x + 1 < cityWidth) {
result.add(new Node(x + 1, y));
}
if(y + 1 < cityLength) {
result.add(new Node(x, y + 1));
}
return result;
}

Java optimized Cramers rule function

Recently learned about Cramers rule in precalculus, and decided to make an algorithm in Java to help me understand it better.
The following code works 100% correctly, however it does not use any sort of for loop to do what it does in a much simpler fashion.
Question: Is there a more elegant implementation of Cramers Rule in Java?
I'm thinking that making a basic determinant method, and then doing some column swapping for when I need to take the determinant of Dx, Dy, and Dz. (for Dx, swap column 4 with column 1 of the original matrix, then take determinant and divide by original determinant.)
This sound good?
public static void main(String[] args) {
int[][] matrix = new int[3][3];
matrix[0] = new int[] { 3, 5, -1, -2 };
matrix[1] = new int[] { 1, -4, 2, 13 };
matrix[2] = new int[] { 2, 4, 3, 1 };
int[] r = crame(matrix);
info("x: " + r[0] + ", y: " + r[1] + ", z: " + r[2]);
for(int i = 0; i < matrix.length; i++) {
int[] base = matrix[i];
if(check(base, r, base[3])) {
info("System " + (i+1) + " checks!");
} else {
info("System " + (i+1) + " fails check!");
}
}
}
public static int[] crame(int[][] m) {
int[] result;
if (m.length == 2) {
result = new int[2];
int D = (m[0][0] * m[1][1]) - (m[1][0] * m[0][1]);
int Dx = (m[0][2] * m[1][1]) - (m[1][2] * m[0][1]);
int Dy = (m[0][0] * m[1][2]) - (m[1][0] * m[0][2]);
result[0] = (int) (Dx / D);
result[1] = (int) (Dy / D);
} else if (m.length == 3) {
result = new int[3];
int D = (((m[0][2] * m[1][1] * m[0][2]) + (m[2][1] * m[1][2] * m[0][0]) + (m[2][2]
* m[1][0] * m[0][2])) - ((m[0][0] * m[1][1] * m[2][2])
+ (m[0][1] * m[1][2] * m[0][2]) + (m[0][2] * m[1][0] * m[2][1])));
int Dx = (((m[2][3] * m[1][1] * m[0][2]) + (m[2][1] * m[1][2] * m[0][3]) + (m[2][2]
* m[1][3] * m[0][1])) - ((m[0][3] * m[1][1] * m[2][2])
+ (m[0][1] * m[1][2] * m[2][3]) + (m[0][2] * m[1][3] * m[2][1])));
int Dy = (((m[2][0] * m[1][3] * m[0][2]) + (m[2][3] * m[1][2] * m[0][3]) + (m[2][2]
* m[1][0] * m[0][3])) - ((m[0][0] * m[1][3] * m[2][2])
+ (m[0][3] * m[1][2] * m[2][0]) + (m[0][2] * m[1][0] * m[2][3])));
int Dz = (((m[2][0] * m[1][1] * m[0][3]) + (m[2][1] * m[1][3] * m[0][0]) + (m[2][3]
* m[1][0] * m[0][1])) - ((m[0][0] * m[1][1] * m[2][3])
+ (m[0][1] * m[1][3] * m[2][0]) + (m[0][3] * m[1][0] * m[2][1])));
result[0] = (int) (Dx / D);
result[1] = (int) (Dy / D);
result[2] = (int) (Dz / D);
} else {
return new int[] {};
}
return result;
}
public static int product(int[] a, int[] b) {
int p = 0;
int[] fin = new int[(a.length -1)];
for(int x = 0; x < fin.length; x++) {
fin[x] = a[x] * b[x];
}
for (int f : fin) {
p += f;
}
return p;
}
public static boolean check(int[] a, int[] b, int z) {
return product(a, b) == z;
}
public static void info(String log) {
System.out.println(log);
}
My question pertains to the specific algorithm that can be used to solve systems of equations using Cramers rule only, is there any algorithm that is more elegant? The function is only designed for square matrices.
This is not a homework assignment, after HS I will be studying CS and I've been working on developing algorithms as preliminary practice.
Thank you for checking this out
First of, there is one way in which Cramers rule is perfect: It gives the algebraic solution of a linear system as a rational function in its coefficients.
However, practically, it has its limits. While the most perfect formula for a 2x2 system, and still good for a 3x3 system, its performance, if implemented in the straightforward way, deteriorates with each additional dimension.
An almost literal implementation of Cramers rule can be achieved with the Leverrier-Faddeev algorithm a b. It only requires the computation of matrix products and matrix traces, and manipulations of the matrix diagonal. Not only does it compute the determinant of the matrix A (along with the other coefficients of the characteristic polynomial), it also has the adjugate or co-factor matrix A# in its iteration matrix. The interesting fact about this matrix is that it allows to write the solution of A*x=b as (A#*b)/det(A), that is, the entries of A#*b already are the other determinants required by Cramers rule.
Leverrier-Faddeev requires n4+O(n3) operations. The same results can be obtained by the more complicated Samuelson-Berkowitz algorith, which has one third of that complexity, that is n4/3+O(n3).
The computation of the determinants required in Cramers rule becomes downright trivial if the system (A|b) is first transformed into triangular form. That can be achieved by Gauß elimination, aka LU decomposition (with pivoting for numerical stability) or the QR decomposition (easiest to debug should be the variant with Givens rotations). The efficient application of Cramers rule is then backward substitution in the triangular system.
Your method sounds good to me at least; however, I just may not be aware of any more efficient methods. The not-fun part may be figuring out how to best implement the determinant-calculating method, as apparently it's not an inexpensive operation.
But once you know that that's working, the rest sounds pretty OK to me. Cache the determinant of the original matrix, substitute in columns, etc.
Figured out exactly how to do this effectively.
http://sandsduchon.org/duchon/math/determinantJava.html
Provides a method for seamless determinants, and mentions matrix decomposition. I have not learned this yet as it's not a HS level concept however I did some problems using it and it's a solid method.
Final Code:
public static void main(String[] args) {
int[][] matrix = new int[3][3];
matrix[0] = new int[] { 3, 5, -1, -2 };
matrix[1] = new int[] { 1, -4, 2, 13 };
matrix[2] = new int[] { 2, 4, 3, 1 };
int[] r = crame(matrix);
info("x: " + r[0] + ", y: " + r[1] + ", z: " + r[2]);
for (int i = 0; i < matrix.length; i++) {
int[] base = matrix[i];
if (check(base, r, base[3])) {
info("System " + (i + 1) + " checks!");
} else {
info("System " + (i + 1) + " fails check!");
}
}
}
public static int getDet(int[][] a) {
int n = a.length - 1;
if (n < 0)
return 0;
int M[][][] = new int[n + 1][][];
M[n] = a; // init first, largest, M to a
// create working arrays
for (int i = 0; i < n; i++)
M[i] = new int[i + 1][i + 1];
return getDet(M, n);
} // end method getDecDet double [][] parameter
public static int getDet(int[][][] M, int m) {
if (m == 0)
return M[0][0][0];
int e = 1;
// init subarray to upper left mxm submatrix
for (int i = 0; i < m; i++)
for (int j = 0; j < m; j++)
M[m - 1][i][j] = M[m][i][j];
int sum = M[m][m][m] * getDet(M, m - 1);
// walk through rest of rows of M
for (int i = m - 1; i >= 0; i--) {
for (int j = 0; j < m; j++)
M[m - 1][i][j] = M[m][i + 1][j];
e = -e;
sum += e * M[m][i][m] * getDet(M, m - 1);
} // end for each row of matrix
return sum;
} // end getDecDet double [][][], int
public static int[] crame(int[][] m) {
int[] result;
if (m.length == 2) {
result = new int[m.length];
int D = getDet(m);
for (int i = 0; i < m.length; i++) {
result[i] = getDet(slide(m, i, m.length)) / D;
}
} else if (m.length == 3) {
result = new int[m.length];
int D = getDet(m);
for (int i = 0; i < m.length; i++) {
result[i] = (getDet(slide(m, i, m.length)) / D);
}
} else {
return new int[] {};
}
return result;
}
public static int[][] slide(int[][] base, int col, int fin) {
int[][] copy = new int[base.length][];
for (int i = 0; i < base.length; i++) {
int[] aMatrix = base[i];
int aLength = aMatrix.length;
copy[i] = new int[aLength];
System.arraycopy(aMatrix, 0, copy[i], 0, aLength);
}
for (int i = 0; i < base.length; i++) {
copy[i][col] = base[i][fin];
}
return copy;
}
public static int product(int[] a, int[] b) {
int p = 0;
int[] fin = new int[(a.length - 1)];
for (int x = 0; x < fin.length; x++) {
fin[x] = a[x] * b[x];
}
for (int f : fin) {
p += f;
}
return p;
}
public static boolean check(int[] a, int[] b, int z) {
return product(a, b) == z;
}
public static void info(String log) {
System.out.println(log);
}

How to find the maximum number of points lying on the same straight line

Suppose you have an array of Points on a 2D plane. Point being defined as such:
class Point {
public int x;
public int y;
Point(int _x, int _y) { x = _x; y = _y; }
}
How could I find the maximum number of points lying on the same straight line in java?
For each point in the array, calculate the angle between this point and other points. Counting the number of those with the same angle using a hashMap. Expected time O(n^2)
Pseudo code
int result = 0;
for(int i = 0; i < data.length; i++){
HashMap<Double, Integer> map = new HashMap();
for(int j = 0; j < data.length; j++){
if(i == j)
continue;
double angle = calculateAngle(data[i], data[j]);
if(map.containsKey(slope)){
map.put(angle, map.get(slope) + 1);
}else{
map.put(angle, 1);
}
result = max(result, map.get(slope));
}
}
Note: As mention in NiklasB 's comment, using double will cause some problems with precision, especially when we need to compare those floating values. We can avoid that by using the Rational class suggested by NiklasB. (Or less precise, using this)
Here is a solution in Java using precise arithmetic:
import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class Solver {
public int maxPointsOnLine(List<Point> points) {
int ans = 0;
Map<Line, Integer> lines = new HashMap<Line, Integer>();
for (Point a : points) {
int max = 0;
int same = 0;
lines.clear();
for (Point b : points) {
if (a.x == b.x && a.y == b.y) {
++same;
} else {
Line line = new Line(b.x - a.x, b.y - a.y);
Integer count = lines.get(line);
if (count == null) {
count = 0;
}
++count;
lines.put(line, count);
max = Math.max(max, count);
}
}
ans = Math.max(ans, same + max);
}
return ans;
}
static class Line {
final int dx;
final int dy;
Line(int dx, int dy) {
if (dy == 0) {
dx = Math.abs(dx);
}
else if (dy < 0) {
dx = -dx;
dy = -dy;
}
int gcd = gcd(Math.abs(dx), dy);
dx /= gcd;
dy /= gcd;
this.dx = dx;
this.dy = dy;
}
#Override
public boolean equals(Object other) {
if (!(other instanceof Line)) {
return false;
}
Line another = (Line)other;
return dx == another.dy && dy == another.dy;
}
#Override
public int hashCode() {
return 31 * dx + dy;
}
}
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
}
/**
* Definition for a point.
* struct Point {
* int x;
* int y;
* Point() : x(0), y(0) {}
* Point(int a, int b) : x(a), y(b) {}
* };
*/
class Solution {
public:
int maxPoints(vector<Point> &points) {
int n = points.size(); //number of the points
if (n<=2){return n;}
vector<double> k; //vector to store the slops for one point with all the other points
int res = 0;
for (int i=0;i<n;i++){ // for each point in the 2d plane
k.clear();
int dup = 1; // number of the duplicates with currrent point
for (int j=0;j<n;j++){
if (i!=j){ // for every other point
if (points[i].x-points[j].x==0){ // if the slope is a vertical line
if (points[i].y-points[j].y==0){ // if the point j is the same as point i
dup++;
}else{
k.push_back(99999); //store the vertical line to a specific slope
}
}else{ // if it is the regular slop between point i and j
k.push_back(10000*(points[i].y-points[j].y)/(points[i].x-points[j].x)); // store the slope
}
}
}
sort(k.begin(),k.end()); //sort the slopes for counting
int pp = 1; //number of points in the same line of the point i
if (k.size()==0){pp=0;}
for (int jj=1;jj<k.size();jj++){ //count pp
if (k[jj]==k[jj-1]){
pp++;
}else{
if (pp+dup>res){res=pp+dup;} // res = pp + the number of duplicates
pp = 1;
}
}
if (pp+dup>res){res = pp+dup;}
}
return res;
}
};

Maze not working?

code:
Array is a predefined boolean array that I made, and val is the length of the array (it is a square). I use it as a starting point, rather than using a random value
import java.util.*;
import javax.swing.*;
public class Main
{
public void main()
{
String Val = JOptionPane.showInputDialog("Enter the number of rows/columns");
int x = Integer.parseInt(Val);
boolean mazeArch[][] = new boolean [x][x];
BoundariesDeclared(mazeArch, x);
generateMaze(mazeArch, x);
convertArray(mazeArch, x);
}
public void printArray(String Array[][]) // Prints out the array
{
for (int i =0; i < Array.length; i++) {
for (int j = 0; j < Array.length; j++) {
System.out.print(" " + Array[i][j]);
}
System.out.println("");
}
}
public void convertArray(boolean Array[][], int z)
{
String RealArray[][] = new String [z][z];
for(int x = 0; x < Array.length; x++)
{
for(int y = 0; y < Array.length; y++)
{
if(Array[x][y] == true)
{
RealArray[x][y] = "*";
}
if(Array[x][y] == false)
{
RealArray[x][y] = " ";
}
}
}
printArray(RealArray);
}
public void BoundariesDeclared(boolean Array[][], int y)
{
for(int x = 0; x < Array.length; x++)
Array[0][x] = true;
for (int x = 0; x < Array.length; x++)
Array[x][0] = true;
for (int x = 0; x < Array.length; x++)
Array[x][Array.length-1] = true;
for (int x = 0; x < Array.length; x++)
Array[Array.length-1][x] = true;
}
public void generateMaze(boolean Array[][], int val)
{
Stack<Integer> StackX = new Stack<Integer>();
Stack<Integer> StackY = new Stack<Integer>();
int x = val / 2; // Start in the middle
int y = val / 2; // Start in the middle
StackX.push(x);
StackY.push(y);
while(!StackX.isEmpty())
{
Array[x][y] = true; // is Visited
x = StackX.peek();
y = StackY.peek();
if(Array[x][y+1] == false)
{
StackX.push(x);
StackY.push(y+1);
y = y + 1;
}
else if(Array[x][y-1] == false)
{
StackX.push(x);
StackY.push(y-1);
y = y - 1;
}
else if(Array[x+1][y] == false)
{
StackX.push(x+1);
StackY.push(y);
x = x+1;
}
else if(Array[x-1][y] == false)
{
StackX.push(x-1);
StackY.push(y);
x = x-1;
}
else
{
StackX.pop();
StackY.pop();
}
}
}
}
Whenever I print the results, I only get stars, which mean that every single boolean is set to true. I understand my error, because I am visiting every spot the result will be that they are all set to true. But what can i do to fix this? I think I have the concept correct, just not the application. I previously asked the question and was told that I need to make two Arrays (1 for walls, another for visiting) but how would I apply this as well?
You didn't mention what are you trying to do. So not much we can help.
What is this maze doing?
What's your input?
What's your expected result?
Add this line and debug yourself.
public void generateMaze(boolean Array[][], int val) {
Stack<Integer> StackX = new Stack<Integer>();
Stack<Integer> StackY = new Stack<Integer>();
int x = val / 2; // Start in the middle
int y = val / 2; // Start in the middle
StackX.push(x);
StackY.push(y);
while (!StackX.isEmpty()) {
Array[x][y] = true; // is Visited
x = StackX.peek();
y = StackY.peek();
if (Array[x][y + 1] == false) {
StackX.push(x);
StackY.push(y + 1);
y = y + 1;
} else if (Array[x][y - 1] == false) {
StackX.push(x);
StackY.push(y - 1);
y = y - 1;
} else if (Array[x + 1][y] == false) {
StackX.push(x + 1);
StackY.push(y);
x = x + 1;
} else if (Array[x - 1][y] == false) {
StackX.push(x - 1);
StackY.push(y);
x = x - 1;
} else {
StackX.pop();
StackY.pop();
}
convertArray(Array, val); // add this line
}
}
The solution is still the same as when you last posted this question - you need to have two arrays
-one that is true for every place in the maze that is a wall - the maze's tiles
-one that starts all false - the solver's tiles
The solver can move onto a tile only if both arrays are false at that point, and sets the second array (the solver's tiles) to true while leaving the first array (the maze's tiles) alone.
This is not a 'coding' bug, per say. You simply don't know what behavior you want. Try commenting out the line where you generate the maze. Run your program with 6 as a parameter. You get:
* * * * * *
* *
* *
* *
* *
* * * * * *
What kind of maze is this? Where is the exit? Again, this is not a coding issue, this is a design flaw. Of course if you start within the bounds of this maze, you will visit all of the squares!
I'm not clear what do you expect in your output exactly, but I can see where the issue is. In your generateMaze() method you are travelling like in spiral mode which ends up touching each and every node in the end. Like suppose you have 5x5 array, you travel and make true like (boundaries are already true) [2,2]->[2,3]->[3,3]->[3,2]->[3,1]->[2,1]->[1,1]->[1,2]->[1,3]
you start from middle, you start visiting and take turns just before you find already true (boundary or visited), and it covers all the nodes

How to align an object to match path

I am animating an object along a spline path in OpenGL. I am using some code I found to generate the spline. Sadly, I don't yet understand the mechanics of it. I want my object to align to match the tangent of path so that it looks like its following the path.
Two questions.
How do I find a vector that is tangent to the path at a given point?
Secondly, given that vector and a vector pointing up, how do rotate the object to align?
Here is my spline code.
public Spline(Vector Path[])
{
ControlPoints = Path;
// Flatten out the control points array.
int len = ControlPoints.length;
float[] controlsX = new float[len];
float[] controlsY = new float[len];
float[] controlsZ = new float[len];
for (int i = 0; i < len; ++i)
{
controlsX[i] = ControlPoints[i].x;
controlsY[i] = ControlPoints[i].y;
controlsZ[i] = ControlPoints[i].z;
}
// Calculate the gamma values just once.
final int n = ControlPoints.length - 1;
float[] gamma = new float[n + 1];
gamma[0] = 1.0f / 2.0f;
for (int i = 1; i < n; ++i) gamma[i] = 1 / (4 - gamma[i - 1]);
gamma[n] = 1 / (2 - gamma[n - 1]);
// Calculate the cubic segments.
cubicX = calcNaturalCubic(n, controlsX, gamma);
cubicY = calcNaturalCubic(n, controlsY, gamma);
cubicZ = calcNaturalCubic(n, controlsZ, gamma);
}
private Cubic[] calcNaturalCubic(int n, float[] x, float[] gamma)
{
float[] delta = new float[n + 1];
delta[0] = 3 * (x[1] - x[0]) * gamma[0];
for (int i = 1; i < n; ++i)
{
delta[i] = (3 * (x[i + 1] - x[i - 1]) - delta[i - 1]) * gamma[i];
}
delta[n] = (3 * (x[n] - x[n - 1])-delta[n - 1]) * gamma[n];
float[] D = new float[n + 1];
D[n] = delta[n];
for (int i = n - 1; i >= 0; --i)
{
D[i] = delta[i] - gamma[i] * D[i + 1];
}
// Calculate the cubic segments.
Cubic[] C = new Cubic[n];
for (int i = 0; i < n; i++) {
final float a = x[i];
final float b = D[i];
final float c = 3 * (x[i + 1] - x[i]) - 2 * D[i] - D[i + 1];
final float d = 2 * (x[i] - x[i + 1]) + D[i] + D[i + 1];
C[i] = new Cubic(a, b, c, d);
}
return C;
}
final public Vector GetPoint(float Position)
{
if(Position >= 1) { return ControlPoints[ControlPoints.length - 1]; }
float position = Position * cubicX.length;
int splineIndex = (int)Math.floor(position);
float splinePosition = position - splineIndex;
return new Vector(cubicX[splineIndex].eval(splinePosition), cubicY[splineIndex].eval(splinePosition), cubicZ[splineIndex].eval(splinePosition));
}
First question:
If you keep track of the previous position of your object as well as the new position, you can find out the facing direction without finding the tangent of the spline, like so:
facing = newPosition - previousPosition
Second question:
You can use the answers described here for rotating an object to face a particular direction: What is the easiest way to align the Z axis with a vector?

Categories