/** * Test relation between this Pnt and circumcircle of a simplex. * @param simplex the simplex (as an array of Pnts) * @return -1, 0, or +1 for inside, on, or outside of circumcircle */ public int vsCircumcircle(Pnt[] simplex) { Pnt[] matrix = new Pnt[simplex.Length + 1]; for (int i = 0; i < simplex.Length; i++) { matrix[i] = simplex[i].extend(new double[] { 1, simplex[i].dot(simplex[i]) }); } matrix[simplex.Length] = this.extend(new double[] { 1, this.dot(this) }); double d = determinant(matrix); int result = -1; if (d > 0) { result = 1; } else if (d == 0) { result = 0; } if (content(simplex) < 0) { result = -result; } return(result); }
/** * Locate the triangle with point (a Pnt) inside (or on) it. * @param point the Pnt to locate * @return triangle (Simplex<Pnt>) that holds the point; null if no such triangle */ public Simplex locate(Pnt point) { Simplex triangle = mostRecent; if (!this.contains(triangle)) triangle = null; // Try a directed walk (this works fine in 2D, but can fail in 3D) Set visited = new HashSet(); while (triangle != null) { if (visited.contains(triangle)) { // This should never happen Console.WriteLine("Warning: Caught in a locate loop"); break; } visited.add(triangle); // Corner opposite point Pnt corner = point.isOutside((Pnt[]) triangle.toArray(new Pnt[0])); if (corner == null) return triangle; triangle = this.neighborOpposite(corner, triangle); } // No luck; try brute force Console.WriteLine("Warning: Checking all triangles for " + point); for (Iterator it = this.iterator(); it.hasNext();) { Simplex tri = (Simplex) it.next(); if (point.isOutside((Pnt[]) tri.toArray(new Pnt[0])) == null) return tri; } // No such triangle Console.WriteLine("Warning: No triangle holds " + point); return null; }
/** * Main program (used for testing). */ public static void main(String[] args) { Pnt p = new Pnt(1, 2, 3); Console.WriteLine("Pnt created: " + p); Pnt[] matrix1 = { new Pnt(1, 2), new Pnt(3, 4) }; Pnt[] matrix2 = { new Pnt(7, 0, 5), new Pnt(2, 4, 6), new Pnt(3, 8, 1) }; Console.WriteLine("Results should be -2 and -288: "); Console.WriteLine(determinant(matrix1) + " " + determinant(matrix2)); Pnt p1 = new Pnt(1, 1); Pnt p2 = new Pnt(-1, 1); Console.WriteLine("Angle between " + p1 + " and " + p2 + ": " + p1.angle(p2)); Console.WriteLine(p1 + " subtract " + p2 + ": " + p1.subtract(p2)); Pnt v0 = new Pnt(0, 0), v1 = new Pnt(1, 1), v2 = new Pnt(2, 2); Pnt[] vs = { v0, new Pnt(0, 1), new Pnt(1, 0) }; Pnt vp = new Pnt(.1, .1); Console.WriteLine(vp + " isInside " + toString(vs) + ": " + vp.isInside(vs)); Console.WriteLine(v1 + " isInside " + toString(vs) + ": " + v1.isInside(vs)); Console.WriteLine(vp + " vsCircumcircle " + toString(vs) + ": " + vp.vsCircumcircle(vs)); Console.WriteLine(v1 + " vsCircumcircle " + toString(vs) + ": " + v1.vsCircumcircle(vs)); Console.WriteLine(v2 + " vsCircumcircle " + toString(vs) + ": " + v2.vsCircumcircle(vs)); Console.WriteLine("Circumcenter of " + toString(vs) + " is " + circumcenter(vs)); }
/* Basic Drawing Methods */ /** * Draw a point. * @param point the Pnt to draw */ public void draw(Pnt point) { int r = pointRadius; int x = (int)point.coord(0); int y = (int)point.coord(1); g.fillOval(x - r, y - r, r + r, r + r); }
/** * Perpendicular bisector of two Pnts. * Works in any dimension. The coefficients are returned as a Pnt of one * higher dimension (e.g., (A,B,C,D) for an equation of the form * Ax + By + Cz + D = 0). * @param point the other point * @return the coefficients of the perpendicular bisector */ public Pnt bisector(Pnt point) { int dim = dimCheck(point); Pnt diff = this.subtract(point); Pnt sum = this.add(point); double dot = diff.dot(sum); return(diff.extend(new double[] { -dot / 2 })); }
/** * Check that dimensions match. * @param p the Pnt to check (against this Pnt) * @return the dimension of the Pnts * @throws IllegalArgumentException if dimension fail to match */ public int dimCheck(Pnt p) { int len = this.coordinates.Length; if (len != p.coordinates.Length) { throw new InvalidOperationException("Dimension mismatch"); } return(len); }
/** * Add. * @param p the other Pnt * @return a new Pnt = this + p */ public Pnt add(Pnt p) { int len = dimCheck(p); double[] coords = new double[len]; for (int i = 0; i < len; i++) { coords[i] = this.coordinates[i] + p.coordinates[i]; } return(new Pnt(coords)); }
/** * Dot product. * @param p the other Pnt * @return dot product of this Pnt and p */ public double dot(Pnt p) { int len = dimCheck(p); double sum = 0; for (int i = 0; i < len; i++) { sum += this.coordinates[i] * p.coordinates[i]; } return(sum); }
/** * Draw all the Voronoi edges. */ public void drawAllVoronoi() { // Loop through all the edges of the DT (each is done twice) for (Iterator it = dt.iterator(); it.hasNext();) { Simplex triangle = (Simplex)it.next(); for (Iterator otherIt = dt.neighbors(triangle).iterator(); otherIt.hasNext();) { Simplex other = (Simplex)otherIt.next(); Pnt p = Pnt.circumcenter((Pnt[])triangle.toArray(new Pnt[0])); Pnt q = Pnt.circumcenter((Pnt[])other.toArray(new Pnt[0])); draw(p, q); } } }
/** * Draw a circle. * @param center the center of the circle * @param radius the circle's radius * @param fillColor; null implies no fill */ public void draw(Pnt center, double radius, Color fillColor) { int x = (int)center.coord(0); int y = (int)center.coord(1); int r = (int)radius; if (fillColor != null) { Color temp = g.getColor(); g.setColor(fillColor); g.fillOval(x - r, y - r, r + r, r + r); g.setColor(temp); } g.drawOval(x - r, y - r, r + r, r + r); }
/* Pnts as simplices */ /** * Determine the signed content (i.e., area or volume, etc.) of a simplex. * @param simplex the simplex (as an array of Pnts) * @return the signed content of the simplex */ public static double content(Pnt[] simplex) { Pnt[] matrix = new Pnt[simplex.Length]; for (int i = 0; i < matrix.Length; i++) { matrix[i] = simplex[i].extend(new double[] { 1 }); } int fact = 1; for (int i = 1; i < matrix.Length; i++) { fact = fact * i; } return(determinant(matrix) / fact); }
/** * Mouse press. * @param e the MouseEvent */ public void mousePressed(MouseEvent e) { if (e.getComponent() != this) { return; } Pnt point = new Pnt(e.getX(), e.getY()); if (debug) { Console.WriteLine("Click " + point); } dt.delaunayPlace(point); repaint(); }
/** * Test if this Pnt is on a simplex. * @param simplex the simplex (an array of Pnts) * @return the simplex Pnt that "witnesses" on-ness (or null if not on) */ public Pnt isOn(Pnt[] simplex) { int[] result = this.relation(simplex); Pnt witness = null; for (int i = 0; i < result.Length; i++) { if (result[i] == 0) { witness = simplex[i]; } else if (result[i] > 0) { return(null); } } return(witness); }
/** * Place a new point site into the DT. * @param site the new Pnt * @return set of all new triangles created */ public Set delaunayPlace(Pnt site) { Set newTriangles = new HashSet(); Set oldTriangles = new HashSet(); Set doneSet = new HashSet(); LinkedList waitingQ = new LinkedList(); // Locate containing triangle if (debug) Console.WriteLine("Locate"); Simplex triangle = locate(site); // Give up if no containing triangle or if site is already in DT var triangle_null = triangle == null; if (triangle_null || triangle.contains(site)) return newTriangles; // Find Delaunay cavity (those triangles with site in their circumcircles) if (debug) Console.WriteLine("Cavity"); waitingQ.add(triangle); while (!waitingQ.isEmpty()) { triangle = (Simplex) waitingQ.removeFirst(); if (site.vsCircumcircle((Pnt[]) triangle.toArray(new Pnt[0])) == 1) continue; oldTriangles.add(triangle); Iterator it = this.neighbors(triangle).iterator(); for (; it.hasNext();) { Simplex tri = (Simplex) it.next(); if (doneSet.contains(tri)) continue; doneSet.add(tri); waitingQ.add(tri); } } // Create the new triangles if (debug) Console.WriteLine("Create"); for (Iterator it = Simplex.boundary(oldTriangles).iterator(); it.hasNext();) { Set facet = (Set) it.next(); facet.add(site); newTriangles.add(new Simplex(facet)); } // Replace old triangles with new triangles if (debug) Console.WriteLine("Update"); this.update(oldTriangles, newTriangles); // Update mostRecent triangle if (!newTriangles.isEmpty()) mostRecent = (Simplex) newTriangles.iterator().next(); return newTriangles; }
/** * Locate the triangle with point (a Pnt) inside (or on) it. * @param point the Pnt to locate * @return triangle (Simplex<Pnt>) that holds the point; null if no such triangle */ public Simplex locate(Pnt point) { Simplex triangle = mostRecent; if (!this.contains(triangle)) { triangle = null; } // Try a directed walk (this works fine in 2D, but can fail in 3D) Set visited = new HashSet(); while (triangle != null) { if (visited.contains(triangle)) // This should never happen { Console.WriteLine("Warning: Caught in a locate loop"); break; } visited.add(triangle); // Corner opposite point Pnt corner = point.isOutside((Pnt[])triangle.toArray(new Pnt[0])); if (corner == null) { return(triangle); } triangle = this.neighborOpposite(corner, triangle); } // No luck; try brute force Console.WriteLine("Warning: Checking all triangles for " + point); for (Iterator it = this.iterator(); it.hasNext();) { Simplex tri = (Simplex)it.next(); if (point.isOutside((Pnt[])tri.toArray(new Pnt[0])) == null) { return(tri); } } // No such triangle Console.WriteLine("Warning: No triangle holds " + point); return(null); }
/** * Draw all the empty circles (one for each triangle) of the DT. */ public void drawAllCircles() { // Loop through all triangles of the DT for (Iterator it = dt.iterator(); it.hasNext();) { Simplex triangle = (Simplex)it.next(); for (Iterator otherIt = initialTriangle.iterator(); otherIt.hasNext();) { Pnt p = (Pnt)otherIt.next(); if (triangle.contains(p)) { triangle = null; break; } } if (triangle != null) { Pnt c = Pnt.circumcenter((Pnt[])triangle.toArray(new Pnt[0])); double radius = c.subtract((Pnt)triangle.iterator().next()).magnitude(); draw(c, radius, null); } } }
/** * Circumcenter of a simplex. * @param simplex the simplex (as an array of Pnts) * @return the circumcenter (a Pnt) of simplex */ public static Pnt circumcenter(Pnt[] simplex) { int dim = simplex[0].dimension(); if (simplex.Length - 1 != dim) { throw new InvalidOperationException("Dimension mismatch"); } Pnt[] matrix = new Pnt[dim]; for (int i = 0; i < dim; i++) { matrix[i] = simplex[i].bisector(simplex[i + 1]); } Pnt hCenter = cross(matrix); // Center in homogeneous coordinates double last = hCenter.coordinates[dim]; double[] result = new double[dim]; for (int i = 0; i < dim; i++) { result[i] = hCenter.coordinates[i] / last; } return(new Pnt(result)); }
/** * Equality. * @param other the other Object to compare to * @return true iff the Pnts have the same coordinates */ public bool equals(object other) { // ficme: jsc should insert parenthesis var other_is_Pnt = (other is Pnt); if (!other_is_Pnt) { return(false); } Pnt p = (Pnt)other; if (this.coordinates.Length != p.coordinates.Length) { return(false); } for (int i = 0; i < this.coordinates.Length; i++) { if (this.coordinates[i] != p.coordinates[i]) { return(false); } } return(true); }
/** * Angle (in radians) between two Pnts (treated as vectors). * @param p the other Pnt * @return the angle (in radians) between the two Pnts */ public double angle(Pnt p) { return(Math.Acos(this.dot(p) / (this.magnitude() * p.magnitude()))); }
/** * Draw a line segment. * @param endA one endpoint * @param endB the other endpoint */ public void draw(Pnt endA, Pnt endB) { g.drawLine((int)endA.coord(0), (int)endA.coord(1), (int)endB.coord(0), (int)endB.coord(1)); }
/** * Mouse press. * @param e the MouseEvent */ public void mousePressed(MouseEvent e) { if (e.getComponent() != this) return; Pnt point = new Pnt(e.getX(), e.getY()); if (debug) Console.WriteLine("Click " + point); dt.delaunayPlace(point); repaint(); }
/** * Circumcenter of a simplex. * @param simplex the simplex (as an array of Pnts) * @return the circumcenter (a Pnt) of simplex */ public static Pnt circumcenter(Pnt[] simplex) { int dim = simplex[0].dimension(); if (simplex.Length - 1 != dim) throw new InvalidOperationException("Dimension mismatch"); Pnt[] matrix = new Pnt[dim]; for (int i = 0; i < dim; i++) matrix[i] = simplex[i].bisector(simplex[i + 1]); Pnt hCenter = cross(matrix); // Center in homogeneous coordinates double last = hCenter.coordinates[dim]; double[] result = new double[dim]; for (int i = 0; i < dim; i++) result[i] = hCenter.coordinates[i] / last; return new Pnt(result); }
/** * Test if this Pnt is inside a simplex. * @param simplex the simplex (an arary of Pnts) * @return true iff this Pnt is inside simplex. */ public bool isInside(Pnt[] simplex) { int[] result = this.relation(simplex); for (int i = 0; i < result.Length; i++) if (result[i] >= 0) return false; return true; }
/** * Test if this Pnt is outside of simplex. * @param simplex the simplex (an array of Pnts) * @return the simplex Pnt that "witnesses" outsideness (or null if not outside) */ public Pnt isOutside(Pnt[] simplex) { int[] result = this.relation(simplex); for (int i = 0; i < result.Length; i++) { if (result[i] > 0) return simplex[i]; } return null; }
/** * Check that dimensions match. * @param p the Pnt to check (against this Pnt) * @return the dimension of the Pnts * @throws IllegalArgumentException if dimension fail to match */ public int dimCheck(Pnt p) { int len = this.coordinates.Length; if (len != p.coordinates.Length) throw new InvalidOperationException("Dimension mismatch"); return len; }
/** * Place a new point site into the DT. * @param site the new Pnt * @return set of all new triangles created */ public Set delaunayPlace(Pnt site) { Set newTriangles = new HashSet(); Set oldTriangles = new HashSet(); Set doneSet = new HashSet(); LinkedList waitingQ = new LinkedList(); // Locate containing triangle if (debug) { Console.WriteLine("Locate"); } Simplex triangle = locate(site); // Give up if no containing triangle or if site is already in DT var triangle_null = triangle == null; if (triangle_null || triangle.contains(site)) { return(newTriangles); } // Find Delaunay cavity (those triangles with site in their circumcircles) if (debug) { Console.WriteLine("Cavity"); } waitingQ.add(triangle); while (!waitingQ.isEmpty()) { triangle = (Simplex)waitingQ.removeFirst(); if (site.vsCircumcircle((Pnt[])triangle.toArray(new Pnt[0])) == 1) { continue; } oldTriangles.add(triangle); Iterator it = this.neighbors(triangle).iterator(); for (; it.hasNext();) { Simplex tri = (Simplex)it.next(); if (doneSet.contains(tri)) { continue; } doneSet.add(tri); waitingQ.add(tri); } } // Create the new triangles if (debug) { Console.WriteLine("Create"); } for (Iterator it = Simplex.boundary(oldTriangles).iterator(); it.hasNext();) { Set facet = (Set)it.next(); facet.add(site); newTriangles.add(new Simplex(facet)); } // Replace old triangles with new triangles if (debug) { Console.WriteLine("Update"); } this.update(oldTriangles, newTriangles); // Update mostRecent triangle if (!newTriangles.isEmpty()) { mostRecent = (Simplex)newTriangles.iterator().next(); } return(newTriangles); }
/* Pnts as simplices */ /** * Determine the signed content (i.e., area or volume, etc.) of a simplex. * @param simplex the simplex (as an array of Pnts) * @return the signed content of the simplex */ public static double content(Pnt[] simplex) { Pnt[] matrix = new Pnt[simplex.Length]; for (int i = 0; i < matrix.Length; i++) matrix[i] = simplex[i].extend(new double[] { 1 }); int fact = 1; for (int i = 1; i < matrix.Length; i++) fact = fact * i; return determinant(matrix) / fact; }
/** * Add. * @param p the other Pnt * @return a new Pnt = this + p */ public Pnt add(Pnt p) { int len = dimCheck(p); double[] coords = new double[len]; for (int i = 0; i < len; i++) coords[i] = this.coordinates[i] + p.coordinates[i]; return new Pnt(coords); }
/** * Relation between this Pnt and a simplex (represented as an array of Pnts). * Result is an array of signs, one for each vertex of the simplex, indicating * the relation between the vertex, the vertex's opposite facet, and this * Pnt. <pre> * -1 means Pnt is on same side of facet * 0 means Pnt is on the facet * +1 means Pnt is on opposite side of facet</pre> * @param simplex an array of Pnts representing a simplex * @return an array of signs showing relation between this Pnt and the simplex * @throws IllegalArgumentExcpetion if the simplex is degenerate */ public int[] relation(Pnt[] simplex) { /* In 2D, we compute the cross of this matrix: * 1 1 1 1 * p0 a0 b0 c0 * p1 a1 b1 c1 * where (a, b, c) is the simplex and p is this Pnt. The result * is a vector in which the first coordinate is the signed area * (all signed areas are off by the same constant factor) of * the simplex and the remaining coordinates are the *negated* * signed areas for the simplices in which p is substituted for * each of the vertices. Analogous results occur in higher dimensions. */ int dim = simplex.Length - 1; if (this.dimension() != dim) throw new InvalidOperationException("Dimension mismatch"); /* Create and load the matrix */ Pnt[] matrix = new Pnt[dim + 1]; /* First row */ double[] coords = new double[dim + 2]; for (int j = 0; j < coords.Length; j++) coords[j] = 1; matrix[0] = new Pnt(coords); /* Other rows */ for (int i = 0; i < dim; i++) { coords[0] = this.coordinates[i]; for (int j = 0; j < simplex.Length; j++) coords[j + 1] = simplex[j].coordinates[i]; matrix[i + 1] = new Pnt(coords); } /* Compute and analyze the vector of areas/volumes/contents */ Pnt vector = cross(matrix); double content = vector.coordinates[0]; int[] result = new int[dim + 1]; for (int i = 0; i < result.Length; i++) { double value = vector.coordinates[i + 1]; if (Math.Abs(value) <= 1.0e-6 * Math.Abs(content)) result[i] = 0; else if (value < 0) result[i] = -1; else result[i] = 1; } if (content < 0) { for (int i = 0; i < result.Length; i++) result[i] = -result[i]; } if (content == 0) { for (int i = 0; i < result.Length; i++) result[i] = Math.Abs(result[i]); } return result; }
/** * Angle (in radians) between two Pnts (treated as vectors). * @param p the other Pnt * @return the angle (in radians) between the two Pnts */ public double angle(Pnt p) { return Math.Acos(this.dot(p) / (this.magnitude() * p.magnitude())); }
/** * Test if this Pnt is on a simplex. * @param simplex the simplex (an array of Pnts) * @return the simplex Pnt that "witnesses" on-ness (or null if not on) */ public Pnt isOn(Pnt[] simplex) { int[] result = this.relation(simplex); Pnt witness = null; for (int i = 0; i < result.Length; i++) { if (result[i] == 0) witness = simplex[i]; else if (result[i] > 0) return null; } return witness; }
/** * Perpendicular bisector of two Pnts. * Works in any dimension. The coefficients are returned as a Pnt of one * higher dimension (e.g., (A,B,C,D) for an equation of the form * Ax + By + Cz + D = 0). * @param point the other point * @return the coefficients of the perpendicular bisector */ public Pnt bisector(Pnt point) { int dim = dimCheck(point); Pnt diff = this.subtract(point); Pnt sum = this.add(point); double dot = diff.dot(sum); return diff.extend(new double[] { -dot / 2 }); }
/** * Test relation between this Pnt and circumcircle of a simplex. * @param simplex the simplex (as an array of Pnts) * @return -1, 0, or +1 for inside, on, or outside of circumcircle */ public int vsCircumcircle(Pnt[] simplex) { Pnt[] matrix = new Pnt[simplex.Length + 1]; for (int i = 0; i < simplex.Length; i++) matrix[i] = simplex[i].extend(new double[] { 1, simplex[i].dot(simplex[i]) }); matrix[simplex.Length] = this.extend(new double[] { 1, this.dot(this) }); double d = determinant(matrix); int result = -1; if (d > 0) result = 1; else if (d == 0) result = 0; if (content(simplex) < 0) result = -result; return result; }
/* Pnts as matrices */ /** * Create a String for a matrix. * @param matrix the matrix (an array of Pnts) * @return a String represenation of the matrix */ public static string toString(Pnt[] matrix) { var buf = new StringBuilder("{"); for (int i = 0; i < matrix.Length; i++) buf.Append(" " + matrix[i]); buf.Append(" }"); return buf.ToString(); }
/** * Compute the determinant of a matrix (array of Pnts). * This is not an efficient implementation, but should be adequate * for low dimension. * @param matrix the matrix as an array of Pnts * @return the determinnant of the input matrix * @throws IllegalArgumentException if dimensions are wrong */ public static double determinant(Pnt[] matrix) { if (matrix.Length != matrix[0].dimension()) throw new InvalidOperationException("Matrix is not square"); var columns = new bool[matrix.Length]; for (int i = 0; i < matrix.Length; i++) columns[i] = true; return determinant(matrix, 0, columns); }
/** * Compute the determinant of a submatrix specified by starting row * and by "active" columns. * @param matrix the matrix as an array of Pnts * @param row the starting row * @param columns a boolean array indicating the "active" columns * @return the determinant of the specified submatrix * @throws ArrayIndexOutOfBoundsException if dimensions are wrong */ private static double determinant(Pnt[] matrix, int row, bool[] columns) { if (row == matrix.Length) return 1; double sum = 0; int sign = 1; for (int col = 0; col < columns.Length; col++) { // fixme: ldelem bool should be supported var columns_col = columns[col]; if (columns_col) { columns[col] = false; sum += sign * matrix[row].coordinates[col] * determinant(matrix, row + 1, columns); columns[col] = true; sign = -sign; } } return sum; }
/** * Compute generalized cross-product of the rows of a matrix. * The result is a Pnt perpendicular (as a vector) to each row of * the matrix. This is not an efficient implementation, but should * be adequate for low dimension. * @param matrix the matrix of Pnts (one less row than the Pnt dimension) * @return a Pnt perpendicular to each row Pnt * @throws IllegalArgumentException if matrix is wrong shape */ public static Pnt cross(Pnt[] matrix) { int len = matrix.Length + 1; if (len != matrix[0].dimension()) throw new InvalidOperationException("Dimension mismatch"); var columns = new bool[len]; for (int i = 0; i < len; i++) columns[i] = true; double[] result = new double[len]; int sign = 1; try { for (int i = 0; i < len; i++) { columns[i] = false; result[i] = sign * determinant(matrix, 0, columns); columns[i] = true; sign = -sign; } } catch //(ArrayIndexOutOfBoundsException e) { throw new InvalidOperationException("Matrix is wrong shape"); } return new Pnt(result); }
/** * Dot product. * @param p the other Pnt * @return dot product of this Pnt and p */ public double dot(Pnt p) { int len = dimCheck(p); double sum = 0; for (int i = 0; i < len; i++) sum += this.coordinates[i] * p.coordinates[i]; return sum; }
/** * Relation between this Pnt and a simplex (represented as an array of Pnts). * Result is an array of signs, one for each vertex of the simplex, indicating * the relation between the vertex, the vertex's opposite facet, and this * Pnt. <pre> * -1 means Pnt is on same side of facet * 0 means Pnt is on the facet * +1 means Pnt is on opposite side of facet</pre> * @param simplex an array of Pnts representing a simplex * @return an array of signs showing relation between this Pnt and the simplex * @throws IllegalArgumentExcpetion if the simplex is degenerate */ public int[] relation(Pnt[] simplex) { /* In 2D, we compute the cross of this matrix: * 1 1 1 1 * p0 a0 b0 c0 * p1 a1 b1 c1 * where (a, b, c) is the simplex and p is this Pnt. The result * is a vector in which the first coordinate is the signed area * (all signed areas are off by the same constant factor) of * the simplex and the remaining coordinates are the *negated* * signed areas for the simplices in which p is substituted for * each of the vertices. Analogous results occur in higher dimensions. */ int dim = simplex.Length - 1; if (this.dimension() != dim) { throw new InvalidOperationException("Dimension mismatch"); } /* Create and load the matrix */ Pnt[] matrix = new Pnt[dim + 1]; /* First row */ double[] coords = new double[dim + 2]; for (int j = 0; j < coords.Length; j++) { coords[j] = 1; } matrix[0] = new Pnt(coords); /* Other rows */ for (int i = 0; i < dim; i++) { coords[0] = this.coordinates[i]; for (int j = 0; j < simplex.Length; j++) { coords[j + 1] = simplex[j].coordinates[i]; } matrix[i + 1] = new Pnt(coords); } /* Compute and analyze the vector of areas/volumes/contents */ Pnt vector = cross(matrix); double content = vector.coordinates[0]; int[] result = new int[dim + 1]; for (int i = 0; i < result.Length; i++) { double value = vector.coordinates[i + 1]; if (Math.Abs(value) <= 1.0e-6 * Math.Abs(content)) { result[i] = 0; } else if (value < 0) { result[i] = -1; } else { result[i] = 1; } } if (content < 0) { for (int i = 0; i < result.Length; i++) { result[i] = -result[i]; } } if (content == 0) { for (int i = 0; i < result.Length; i++) { result[i] = Math.Abs(result[i]); } } return(result); }