package ProGAL.geom3d.kineticDelaunay; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import ProGAL.dataStructures.Heap; import ProGAL.dataStructures.SortTool; import ProGAL.geom3d.Circle; import ProGAL.geom3d.Line; import ProGAL.geom3d.Point; import ProGAL.geom3d.volumes.Sphere; import ProGAL.geom3d.volumes.Tetrahedron; import ProGAL.geom3d.volumes.Torus; import ProGAL.geom3d.Vector; import ProGAL.math.Constants; import ProGAL.math.Functions; import ProGAL.math.Matrix; import ProGAL.math.Trigonometry; public class KineticAlphaComplex { // private static enum Direction { CW, CCW } private List vertices = new ArrayList(); private Set tets = new HashSet(); private Map mapTris = new HashMap(); // private List edges = new LinkedList(); private Map mapEdges = new HashMap(); private Set alphaEdges = new HashSet(); private Set alphaTris = new HashSet(); private Set alphaTets = new HashSet(); private final double alphaVal; public int nrFlips = 0; private boolean clashFirst = false; private boolean clash = false; private List clashes = new ArrayList(); private double shortestEdge = Double.POSITIVE_INFINITY; public double error = 0; public double maxError = 0; public int nrErrors = 0; public double numericalTime = 0; public double analyticalTime = 0; public double flipTime = 0; private Tet lastTet; private Double[] angles = new Double[4]; // Daisy: changed from 2 to 4 private double angleTotal = 0.0; private double angleLimit = Constants.TAU; private Vector rotationAxis; // rotation vector private Set rotIndx = new HashSet(); // indicies of vertices that move private Heap heap = new Heap(this.vertices.size(), new SortToolHeapItems()); // private boolean testing = true; private boolean testingPrint = false; private class HeapItem { private Double[] angles; private Tet t = null; private Tet nt = null; private Tri tri = null; private Edge edg = null; private HeapItem(Double[] angles, Tet t, Tet nt, Tri tri, Edge e) { this.angles = angles; this.t = t; this.tri = tri; this.nt = nt; this.edg = e; } private Double[] getAngles() { return angles;} private Tet getT() { return t; } private Tet getNT() { return nt; } private Tri getTri() { return tri; } private Edge getEdg() { return edg; } } private class SortToolHeapItems implements SortTool { public int compare(Object x1, Object x2) { if ((x1 instanceof HeapItem) && (x2 instanceof HeapItem)) { double d1 = ((HeapItem)x1).getAngles()[0]; double d2 = ((HeapItem)x2).getAngles()[0]; if (d1 < d2) return COMP_LESS; else { if (d1 > d2) return COMP_GRTR; else return COMP_EQUAL; } } else throw SortTool.err1; } } /** * Compute the static alpha complex from the specified points and alpha value. * * @param points The initial positions of the points * @param alpha The alpha value * @pre points.get(i)!=points.get(j) for all i!=j * @pre alpha>=0 * @pre points.size()>=4 * @pre points.get(i).get(d)<=200 //Because of big-points * @todo Add asserts to preconditions * @author Daisy & Rasmus */ public KineticAlphaComplex(List points, double alpha) { Tetrahedron bigT = Tetrahedron.regularTetrahedron(); bigT.blowUp(1000); lastTet = new Tet(bigT); for (int i = 0; i < 4; i++) vertices.add(lastTet.getCorner(i)); for (Point p: points) { insertPoint(p); } alphaVal=alpha; // Each vertex gets a pointer to one of its faces for (Tet tet : tets) { for (int i = 0; i < 4; i++) tet.getCorner(i).setTet(tet); } initializeAlphaComplex(); } /** Adds new event to the heap */ private void addToHeap(Double[] angles, Tet t, Tet nt) { heap.insert(new HeapItem(angles, t, nt, null, null)); } private void addToHeap(Double[] angles, Tet t) { HeapItem newItem = new HeapItem(angles, t, null, null, null); heap.insert(newItem); } private void addToHeap(Double[] angles, Tri t) { heap.insert(new HeapItem(angles, null, null, t, null)); } private void addToHeap(Double[] angles, Edge e) { heap.insert(new HeapItem(angles, null, null, null, e)); } /** Returns the number of vertices in the DT (without 4 big points*/ public int getNrVertices() { return vertices.size() - 4; } /** Returns the direction vector of the rotation axis */ public Vector getRotationAxis() { return rotationAxis; } // /** Returns the rotation point */ // public Point getRotationPoint() { return rotationPoint; } /** Assuming v is a corner of tet, this method returns the three tetrahedra that are neighbors of * tet and have v as a corner point. */ public Tet[] getTetrahedra(Vertex v, Tet tet) { int indxV = tet.indexOf(v); Tet[] nTet = new Tet[3]; for (int i = 0; i < 3; i++) { nTet[i] = tet.neighbors[(indxV+i+1)/3]; } return nTet; } /** Returns a tetrahedron containing vertex v */ public Tet getTetrahedron(Vertex v) { for (Tet tet : tets) if (tet.hasVertex(v)) return tet; return null; } /** Inserts new point into DT */ private void insertPoint(Point p){ Vertex v = new Vertex(p); vertices.add(v); Tet c = walk(p); //Corresponds to findNTes List newTets = new LinkedList(); HashSet processed = new HashSet(); processed.add(null); Stack fringe = new Stack(); fringe.add(c); while(!fringe.isEmpty()){ c = fringe.pop(); if(processed.contains(c)) continue; for(int f=0;f<4;f++){ Tet neigh = c.neighbors[f]; if(neigh==null || !neigh.insideCircumsphere(p)){ //-3 -2 0 1 .. c //-2 -1 0 1 .. neigh .. neigh.apex(c) should be 0 //Create new cell Vertex[] corners = new Vertex[4]; corners[3] = v; for(int i=1;i<4;i++) corners[i-1] = c.getCorner((f+i)%4); Tet newTet = new Tet(corners); newTet.neighbors[3] = neigh; if(neigh!=null) neigh.neighbors[neigh.apex(c)] = newTet; newTets.add(newTet); }else if(!processed.contains(neigh)){ fringe.add(neigh); } } processed.add(c); tets.remove(c); } lastTet = newTets.get(0); restoreNeighborhood(newTets); tets.addAll(newTets); } private void initializeRadiusEvents() { //Test each tetrahedron for (Tet T : tets) { angles = getRoot(T.getCorner(0), T.getCorner(1), T.getCorner(2), T.getCorner(3), T.getCount()); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, T); } //Test each triangle for (Tri t : T.getListOfTris()) { angles = getRoot(t.getCorner(0), t.getCorner(1), t.getCorner(2), t.getCount()); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, t); } } //Test each edge for (Edge e : T.getEdges()) { angles = getRoot(e.getCorner(0), e.getCorner(1), e.getCount()); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, e); } } } } // Daisy private boolean isGabriel(Edge e) { Sphere s = new Sphere(Point.getMidpoint(e.getCorner(0), e.getCorner(1)), e.getCircumRadius()); for (Point p : vertices) { if (e.hasVertex(new Vertex(p))) continue; if (s.contains(p)) return false; } return true; } private boolean isGabriel(Tri t) { Sphere s = new Sphere(new Circle(t.getCorner(0), t.getCorner(1), t.getCorner(2)).getCenter(), t.getCircumRadius()); for (Point p : vertices) { if (t.hasVertex(new Vertex(p))) continue; if (s.contains(p)) return false; } return true; } private void initializeAlphaComplex() { for (Tet t : tets) { if (!t.isAlive()) continue; // System.out.println("Tet = "+t.toString()); Double[] angles; Vertex v0 = t.getCorner(0); Vertex v1 = t.getCorner(1); Vertex v2 = t.getCorner(2); Vertex v3 = t.getCorner(3); //Test each tetrahedron int count = t.getCount(); int idxR0 = -1; int idxR1 = -1; int idxS0 = -1; int idxS1 = -1; int idxS2 = -1; int idxS3 = -1; if (count==8 || count==7) { idxR0 = 3; idxS0 = 0; idxS1 = 1; idxS2 = 2; } else if (count==4 || count==11) { idxR0 = 2; idxS0 = 0; idxS1 = 1; idxS2 = 3; } else if (count==2 || count==13) { idxR0 = 1; idxS0 = 0; idxS1 = 2; idxS2 = 3; } else if (count==1 || count==14) { idxR0 = 0; idxS0 = 1; idxS1 = 2; idxS2 = 3; } else if (count==3) { idxR0 = 0; idxR1 = 1; idxS0 = 2; idxS1 = 3; } else if (count==6) { idxR0 = 1; idxR1 = 2; idxS0 = 0; idxS1 = 3; } else if (count==12) { idxR0 = 2; idxR1 = 3; idxS0 = 0; idxS1 = 1; } else if (count==9) { idxR0 = 0; idxR1 = 3; idxS0 = 1; idxS1 = 2; } else if (count==5) { idxR0 = 0; idxR1 = 2; idxS0 = 1; idxS1 = 3; } else if (count==0 || count==15) { idxS0 = 0; idxS1 = 1; idxS2 = 2; idxS3 = 3; } else if (count==10) { idxR0 = 1; idxR1 = 3; idxS0 = 0; idxS1 = 2; } if (count == 0 || count == 15) { noRotate(t, t.getCorner(idxS0), t.getCorner(idxS1), t.getCorner(idxS2), t.getCorner(idxS3)); } if (count == 1 || count == 2 || count == 4 || count == 8 || count == 7 || count == 11 || count == 13 || count == 14) { oneRotate(t, t.getCorner(idxS0), t.getCorner(idxS1), t.getCorner(idxS2), t.getCorner(idxR0)); } if (count == 3 || count == 6 || count == 12 || count == 9 || count == 5 || count == 10) { twoRotate(t, t.getCorner(idxS0), t.getCorner(idxS1), t.getCorner(idxR0), t.getCorner(idxR1)); } //Test each edge Edge tmp; if (!mapEdges.containsKey(new EdgePoints(v0, v1))) { tmp = new Edge(v0, v1); if (tmp.getLength() newCells){ for(Tet c1: newCells){ cellLoop: for(Tet c2: newCells){ if(c1==c2) break; //Check if c1 and c2 share a face based on corner vertices //Both will contain the last inserted vertex (highest index) //i and j run over the arrays, I and J record the location of differences int i=0,j=0, I=-1, J=-1; while(i<=3&&j<=3){ if(c1.getCorner(i)==c2.getCorner(j)) { i++;j++; } else if(i<3 && c1.getCorner(i+1)==c2.getCorner(j)) { if(I>=0) continue cellLoop; I=i;i++; } else { if(J>=0) continue cellLoop; J=j;j++; } } c1.neighbors[I] = c2; c2.neighbors[J] = c1; } } } private void setRotationAxis(Line l) { Vector translate = new Vector(-l.getP().get(0),-l.getP().get(1),-l.getP().get(2)); for (Point v : vertices) v.addThis(translate); Vector dir = l.getDir(); rotationAxis = new Vector(0,0,1); if (!dir.isParallel(rotationAxis)) { //Rotate Vector rotAxis = dir.cross(rotationAxis); rotAxis.normalizeThis(); double angle = dir.angle(rotationAxis); Matrix rotMatrix = Matrix.createRotationMatrix(angle, rotAxis); for (Point v : vertices) { rotMatrix.multiplyIn(v); } } } /** Identifies the tetrahedron into which new point has to be inserted */ private Tet walk(Point p){ Tet t = lastTet; mainWalk: while(true){ for(int f=0;f<4;f++){ if(!t.insideFace(f, p)){ t = t.neighbors[f]; lastTet = t; continue mainWalk; } } return t; } } //Daisy private double angleCW(Vector v1, Vector v2) { double ret = Math.atan2(v1.y(), v1.x()) - Math.atan2(v2.y(), v2.x()); if (ret<0) { ret = Constants.TAU+ret; return ret; } if (ret>0) { /*ret = (-1)*ret;*/ return ret; } return ret; } private double angleCCW(Vector v1, Vector v2) { double ret = Math.atan2(v1.y(), v1.x()) - Math.atan2(v2.y(), v2.x()); if (ret<0) { ret = (-1)*ret; return ret; } if (ret>0) { ret = Constants.TAU-ret; return ret; } return ret; } /** * Find the roots that correspond to radius events, assuming that A is a static point and B is a rotating point. */ private Double[] getRootSR(Vertex A, Vertex B, int dir) { // if (A.distanceSquared(B) > 4*alphaVal*alphaVal) { System.out.println("Distance A to B is too big : "+A.distance(B)+" squared : "+A.distanceSquared(B)); return null; } //Creates a sphere with center A and radius 2*alphaVal Double[] angles = new Double[4]; Sphere S = new Sphere(A, 2*alphaVal); Circle C = new Circle(new Point(0.0,0.0,B.getCoord(2)), B.distanceXY(), rotationAxis); //Checks for intersection as B rotates on its circle path Point[] intersectionPoints = S.getIntersections(C); if (!(intersectionPoints==null) && intersectionPoints.length>1) { int i = 0; for (Point p : intersectionPoints) { Point z = new Point(0.0, 0.0, B.getCoord(2)); if (dir == 1) { angles[i] = (angleTotal+angleCCW(z.vectorTo(p), z.vectorTo((Point)B))); } else angles[i] = (angleTotal+angleCW(z.vectorTo(p), z.vectorTo((Point)B))); i += 1; } } return getRotAngle(angles, 0); } /** * Find the roots that correspond to radius events, assuming that A and B are static and that * C is a rotating point. * * @author Daisy */ private Double[] getRootSSR(Vertex A, Vertex B, Vertex C, int dir) { /*if (A.getId()==118 && B.getId()==145 && C.getId()== 18) { System.out.println("NOW!"); }*/ //Create torus from static points and intersect it with the moving Double[] angles = new Double[4]; if (A.distanceSquared(B) >= 4*alphaVal*alphaVal) return null; Point torusCenter = Point.getMidpoint(A, B); //Find major radius using pythagoras: double R = Math.sqrt( Math.abs(alphaVal*alphaVal-A.distanceSquared(torusCenter)) ); // double R = Math.pow(Math.abs(alphaVal*alphaVal-A.distanceSquared(torusCenter)), 0.5); //Static torus Vector torusNormal = A.vectorTo(torusCenter).normalize(); Torus torus = new Torus(torusCenter, torusNormal, R, alphaVal); //Create rotation circle (path of C) double circleRadius = C.distanceXY(); Circle circle = new Circle(new Point(0,0,C.getCoord(2)), circleRadius, rotationAxis); //Find intersections Point[] intersections = torus.getIntersectionCircle(circle); int i = 0; if (!(intersections==null)) { for (Point p : intersections) { if (p==null) break; Point z = new Point(0.0, 0.0, C.getCoord(2)); if (dir==1) { angles[i] = (angleTotal+angleCCW(z.vectorTo(p), z.vectorTo((Point)C))); } else angles[i] = (angleTotal+angleCW(z.vectorTo(p), z.vectorTo((Point)C))); i += 1; } } return getRotAngle(angles, 0); } /** * Find the roots that correspond to radius events, assuming that A, B, and C are static and that * D is a rotating point. * @author Daisy */ private Double[] getRootSSSR(Vertex A, Vertex B, Vertex C, Vertex D, int dir) { //Create two spheres from three static points and radius alphaVal. Double[] angles = new Double[4]; Circle c = new Circle(A, B, C); Point midpoint = c.getCenter(); // Pythagoras double cMinusa = alphaVal*alphaVal-A.distanceSquared(midpoint); if (cMinusa<0) return null; double distToCenter = Math.sqrt(Math.abs(cMinusa)); Vector vecToCenter = c.getNormal().clone(); vecToCenter.scaleToLengthThis(distToCenter); Point center0 = midpoint.clone().addThis(vecToCenter); Point center1 = midpoint.clone().addThis(vecToCenter.multiply(-1.0)); //Check for intersections between these and the rotation circle Circle rotationC = new Circle(new Point(0.0, 0.0, D.getCoord(2)), D.distanceXY(), rotationAxis); Sphere S0 = new Sphere(center0, alphaVal); Point[] intersectionPoints1 = S0.getIntersections(rotationC); int i; if (intersectionPoints1!=null) { i = 0; for (Point p : intersectionPoints1) { Point z = new Point(0.0, 0.0, D.getCoord(2)); if (dir==1) { angles[i] = (angleTotal+angleCCW(z.vectorTo(p), z.vectorTo((Point)D))); } else angles[i] = (angleTotal+angleCW(z.vectorTo(p), z.vectorTo((Point)D))); i += 1; } } else i = 0; Sphere S1 = new Sphere(center1, alphaVal); Point[] intersectionPoints2 = S1.getIntersections(rotationC); if (intersectionPoints2!=null) { // int i = 2; for (Point p : intersectionPoints2) { Point z = new Point(0.0, 0.0, D.getCoord(2)); if (dir==1) { angles[i] = (angleTotal+angleCCW(z.vectorTo(p), z.vectorTo((Point)D))); } else angles[i] = (angleTotal+angleCW(z.vectorTo(p), z.vectorTo((Point)D))); i += 1; } } return getRotAngle(angles, 0); } /** * Find the roots that correspond to radius events, assuming that A and B are static and that * C and D are rotating points. * @author Daisy */ private Double[] getRootSSRR(Vertex A, Vertex B, Vertex C, Vertex D, int dir) { //Numerical method // System.out.println("Called with ["+A.getId()+", "+B.getId()+", "+C.getId()+", "+D.getId()+"]"); double precision = 0.05; Double[] angles = new Double[4]; int numOfAngles = 0; double offRadius = new Sphere(A, B, C, D).getRadius()-alphaVal; double sign = Math.signum(offRadius); Point Cnew; Point Dnew; // if (dir == 1) k = -1; double angleSoFar = Math.floor(Math.toDegrees(angleTotal)); for (double i = precision ; i<=Math.ceil(Math.toDegrees(angleLimit)-angleSoFar) ; i+=precision) { Cnew = C.clone(); Dnew = D.clone(); if (dir == 0) { Cnew.rotationCW(rotationAxis, Math.toRadians(i)); Dnew.rotationCW(rotationAxis, Math.toRadians(i)); } else { // Cnew.rotationCCW(Z, Math.toRadians(i)); // Dnew.rotationCCW(Z, Math.toRadians(i)); } double radius = new Sphere(A, B, Cnew, Dnew).getRadius(); /* if (A.getId()==5 && B.getId()==38 && C.getId()== 11 && D.getId()==13) { System.out.println("Radius = "+radius+" angletotal = "+angleTotal); System.out.println("Radius-alphaVal = "+(radius-alphaVal)); }*/ offRadius = radius-alphaVal; if (Math.signum(offRadius) != sign) { /* if (A.getId()==5 && B.getId()==38 && C.getId()== 11 && D.getId()==13) { System.out.println("sign changed"); }*/ // System.out.println("Change in sign at "+i); sign = Math.signum(offRadius); Double angle = findAngle(i-precision, i, A, B, C, D, 0); if (angle==null) { /* if (A.getId()==5 && B.getId()==38 && C.getId()== 11 && D.getId()==13) { System.out.println("Angles was null for this Tet"); }*/ // System.out.println("findAngle returned null"); return null; } angles[numOfAngles] = Math.toRadians(angle)+angleTotal; // System.out.println("Angle in radians = "+angles[numOfAngles]); numOfAngles++; } } if (numOfAngles==0) { return null; } else return angles; } private Double findAngle(double start, double end, Vertex A, Vertex B, Vertex C, Vertex D, int dir) { Point Cnew = C.clone(); Point Dnew = D.clone(); if (dir == 0) { Cnew.rotationCW(rotationAxis, Math.toRadians(start)); Dnew.rotationCW(rotationAxis, Math.toRadians(start)); } double radius = new Sphere(A, B, Cnew, Dnew).getRadius(); if (Math.abs(radius-alphaVal) pIndices, Line axis) { heap.clear(); setRotVertices(pIndices); setRotationAxis(axis); // set constants associated with vertices - does not include vertices of big points for (Vertex v : vertices) { if (testingPrint) System.out.print(v.getId() + ": " + v.toString(2)); if (v.distanceSquared() < Constants.EPSILON) { //takes care of the special case when the rotation center overlaps with one of the given points v.setSquaredPolarRadius(0.0); v.setPolarRadius(0.0); v.setPolarAngle(0.0); if (testingPrint) System.out.println(", polar angle: 0.0"); v.setCosAngle(1.0); v.setSinAngle(0.0); v.setType(Vertex.VertexType.S); rotIndx.remove((Integer)v.getId()); } else { v.setSquaredPolarRadius(v.distanceSquared()); // remains unchanged when rotating around the same point v.setPolarRadius(v.distance()); // remains unchanged when rotating around the same point v.setPolarAngle(v.polarAngleXY()); if (testingPrint) System.out.println(", initial polar angle: " + Functions.toDeg(v.getPolarAngle())); v.setCosAngle(v.polarAngleCosXY()); v.setSinAngle(v.polarAngleSinXY()); } } int count = 0; int count4 = 0; Tet nt = null; Vertex oppV; for (Tet t : tets) { count4 = t.getCount(); for (int i = 0; i < 4; i++) { nt = t.neighbors[i]; if (nt != null) { oppV = nt.getCorner(nt.apex(t)); if (t.getCorner(t.apex(nt)).getId() < oppV.getId()) { count = count4; if (oppV.getType() == Vertex.VertexType.R) count = count + 16; angles = getRoot(t, oppV, count); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, t, nt); if (testingPrint) System.out.println(t + " " + nt + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } } } } } initializeRadiusEvents(); } /** * Performs a 2-3-flip of the two specified tetrahedra. The two existing tetrahedra are preserved and * a new is created and returned. * @requires Arrays.equals(t0.corners, Arrays.sort(t0.corners) ) && * Arrays.equals(t1.corners, Arrays.sort(t1.corners) ) && * convex(t0,t1) * @return The newly created tetrahedron. */ private Tet[] flip23(Tet t0, Tet t1){ long start = System.nanoTime(); nrFlips++; Vertex vns0 = t0.getCorner(t0.apex(t1)); Vertex vns1 = t1.getCorner(t1.apex(t0)); Edge commonEdge = new Edge(vns0, vns1); //To be created in complex if (commonEdge.isAlpha(alphaVal)) { commonEdge.setAlph(true); alphaEdges.add(commonEdge); } angles = getRoot(commonEdge.getCorner(0), commonEdge.getCorner(1), commonEdge.getCount()); if (angles!=null && angles[0]< angleLimit) { addToHeap(angles, commonEdge); } Tri commonTri = t0.getTri(vns0); //To be deleted in complex if (commonTri.getAlph()==1) { alphaTris.remove(commonTri); } commonTri.setAlive(false); // identify three shared vertices Vertex[] vs = new Vertex[3]; int k = 0; for (int i = 0; i < 4; i++) if (t0.getCorner(i) != vns0) vs[k++] = t0.getCorner(i); Tet[] nt = new Tet[3]; Tet nt0 = new Tet(vns0, vns1, vs[0], vs[1]); nt0.setEdge(commonEdge); nt[0] = nt0; Tet nt1 = new Tet(vns0, vns1, vs[1], vs[2]); nt1.setEdge(commonEdge); nt[1] = nt1; Tet nt2 = new Tet(vns0, vns1, vs[2], vs[0]); nt2.setEdge(commonEdge); nt[2] = nt2; // New triangles for (int i = 0 ; i<3 ; i++) { Tet t = nt[i]; Tri tri = new Tri(vns0, vns1, vs[i]); //tri.setTet(t); t.setTri(tri, t.indexOf(vs[(i+1)%3])); Tet n = nt[(i+2)%3]; //tri.setTet(n); n.setTri(tri, n.indexOf(vs[(i+2)%3])); int count = tri.getCount(); Vertex S0 = tri.getCorner(0); Vertex S1 = tri.getCorner(1); Vertex R0 = tri.getCorner(2); if (count == 0 || count == 7) { if (tri.isAlpha(alphaVal)){ alphaTris.add(tri); tri.setAlph(1); } } else { if (count == 1 || count == 6) { R0 = tri.getCorner(0); S0 = tri.getCorner(1); S1 = tri.getCorner(2); } if (count == 2 || count == 5) { R0 = tri.getCorner(1); S0 = tri.getCorner(0); S1 = tri.getCorner(2); } if ( count == 4 || count == 3) { R0 = tri.getCorner(2); S0 = tri.getCorner(0); S1 = tri.getCorner(1); } if (tri.isAlpha(alphaVal)) { alphaTris.add(tri); tri.setAlph(1); } else { Point center = Point.getMidpoint(S0, S1); Circle C = new Circle(center, alphaVal, center.vectorTo(S0).normalize()); double dist = C.getDistanceSquared(R0); if (dist < (alphaVal*alphaVal)+Constants.EPSILON) { tri.setAlph(2); } else tri.setAlph(0); } angles = getRoot(tri.getCorner(0), tri.getCorner(1), tri.getCorner(2), tri.getCount()); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, tri); } } } for (Edge e : t0.getEdges()) { if (e.equals(new Edge(vns0, vs[0]))) { nt0.setEdge(e); nt2.setEdge(e); } else if (e.equals(new Edge(vns0, vs[1]))) { nt0.setEdge(e); nt1.setEdge(e); } else if (e.equals(new Edge(vns0, vs[2]))) { nt2.setEdge(e); nt1.setEdge(e); } else if (e.equals(new Edge(vs[0], vs[1]))) { nt0.setEdge(e); } else if (e.equals(new Edge(vs[1], vs[2]))) { nt1.setEdge(e); } else if (e.equals(new Edge(vs[0], vs[2]))) { nt2.setEdge(e); } } for (Edge e : t1.getEdges()) { if (e.equals(new Edge(vns1, vs[0]))) { nt0.setEdge(e); nt2.setEdge(e); } else if (e.equals(new Edge(vns1, vs[1]))) { nt0.setEdge(e); nt1.setEdge(e); } else if (e.equals(new Edge(vns1, vs[2]))) { nt2.setEdge(e); nt1.setEdge(e); } } // commonEdge.setTet(nt0); nt0.setEdge(commonEdge); nt1.setEdge(commonEdge); nt2.setEdge(commonEdge); // Events for new tetrahedra for (Tet t : nt) { int count = t.getCount(); int idxR = -1; int idxS0 = -1; int idxS1 = -1; int idxS2 = -1; if (count == 0 || count == 15) { if (t.isAlpha(alphaVal)) { t.setAlph(1); alphaTets.add(t); } } else { if (t.isAlpha(alphaVal)) { t.setAlph(1); alphaTets.add(t); } else if (t.nrRotating()==1){ if (count == 8 || count == 7) { idxR = 3; idxS0 = 0; idxS1 = 1; idxS2 = 2; } if (count==4 || count == 11) { idxR = 2; idxS0 = 0; idxS1 = 1; idxS2 = 3; } if (count==2 || count == 13) { idxR = 1; idxS0 = 0; idxS1 = 3; idxS2 = 2; } if (count==1 || count == 14) { idxR = 0; idxS0 = 3; idxS1 = 1; idxS2 = 2; } Vertex r = t.getCorner(idxR); Vertex s0 = t.getCorner(idxS0); Vertex s1 = t.getCorner(idxS1); Vertex s2 = t.getCorner(idxS2); double d0 = s0.distanceSquared(s1); double d1 = s1.distanceSquared(s2); double d2 = s2.distanceSquared(s0); double a0 = r.distanceSquared(s0); double a1 = r.distanceSquared(s1); double a2 = r.distanceSquared(s2); if (a0 < d0 && a1 < d0 && a1 < d1 && a2 < d2 && a2 < d2 && a0 < d2) { t.setAlph(2); } else t.setAlph(0); } angles = getRoot(t.getCorner(0), t.getCorner(1), t.getCorner(2), t.getCorner(3), count); if (angles!=null && angles[0]< angleLimit) { addToHeap(angles, t); } } } alphaTets.remove(t0); alphaTets.remove(t1); // vertices get new tetrahedron pointers vns0.setTet(nt0); vns1.setTet(nt0); vs[0].setTet(nt0); vs[1].setTet(nt0); vs[2].setTet(nt1); // nt0 contain vs[0] and vs[1] if (!nt1.hasVertex(vs[0])) nt0.neighbors[nt0.indexOf(vs[0])] = nt1; else nt0.neighbors[nt0.indexOf(vs[0])] = nt2; if (!nt1.hasVertex(vs[1])) nt0.neighbors[nt0.indexOf(vs[1])] = nt1; else nt0.neighbors[nt0.indexOf(vs[1])] = nt2; Tet t = t1.neighbors[t1.indexOf(vs[2])]; Tri tri = t1.getTri(t1.indexOf(vs[2])); // tri.setTet(nt0); nt0.neighbors[nt0.indexOf(vns0)] = t; nt0.setTri(tri, nt0.indexOf(vns0)); if (t != null) t.neighbors[t.apex(t1)] = nt0; t = t0.neighbors[t0.indexOf(vs[2])]; tri = t0.getTri(t0.indexOf(vs[2])); // tri.setTet(nt0); nt0.setTri(tri, nt0.indexOf(vns1)); nt0.neighbors[nt0.indexOf(vns1)] = t; if (t != null) t.neighbors[t.apex(t0)] = nt0; // nt1 contains vs[1] and vs[2] if (!nt0.hasVertex(vs[1])) nt1.neighbors[nt1.indexOf(vs[1])] = nt0; else nt1.neighbors[nt1.indexOf(vs[1])] = nt2; if (!nt0.hasVertex(vs[2])) nt1.neighbors[nt1.indexOf(vs[2])] = nt0; else nt1.neighbors[nt1.indexOf(vs[2])] = nt2; t = t1.neighbors[t1.indexOf(vs[0])]; tri = t1.getTri(t1.indexOf(vs[0])); // tri.setTet(nt1); nt1.setTri(tri, nt1.indexOf(vns0)); nt1.neighbors[nt1.indexOf(vns0)] = t; if (t != null) t.neighbors[t.apex(t1)] = nt1; t = t0.neighbors[t0.indexOf(vs[0])]; tri = t0.getTri(t0.indexOf(vs[0])); // tri.setTet(nt1); nt1.setTri(tri, nt1.indexOf(vns1)); nt1.neighbors[nt1.indexOf(vns1)] = t; if (t != null) t.neighbors[t.apex(t0)] = nt1; // nt2 contains vs[2] and vs[0] if (!nt0.hasVertex(vs[2])) nt2.neighbors[nt2.indexOf(vs[2])] = nt0; else nt2.neighbors[nt2.indexOf(vs[2])] = nt1; if (!nt0.hasVertex(vs[0])) nt2.neighbors[nt2.indexOf(vs[0])] = nt0; else nt2.neighbors[nt2.indexOf(vs[0])] = nt1; t = t1.neighbors[t1.indexOf(vs[1])]; tri = t1.getTri(t1.indexOf(vs[1])); // tri.setTet(nt2); nt2.setTri(tri, nt2.indexOf(vns0)); nt2.neighbors[nt2.indexOf(vns0)] = t; if (t != null) t.neighbors[t.apex(t1)] = nt2; t = t0.neighbors[t0.indexOf(vs[1])]; tri = t0.getTri(t0.indexOf(vs[1])); // tri.setTet(nt2); nt2.setTri(tri, nt2.indexOf(vns1)); nt2.neighbors[nt2.indexOf(vns1)] = t; if (t != null) t.neighbors[t.apex(t0)] = nt2; tets.remove(t0); t0.setAlive(false); tets.remove(t1); t1.setAlive(false); Tet[] newTets = new Tet[3]; newTets[0] = nt0; newTets[1] = nt1; newTets[2] = nt2; tets.add(nt0); tets.add(nt1); tets.add(nt2); //Flip event angles = getRoot(nt0, nt1); if (angles!=null && angles[0] < angleLimit) { addToHeap(angles, nt0, nt1); if (testingPrint) System.out.println(nt0 + " " + nt1 + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } angles = getRoot(nt0, nt2); if (angles!=null && angles[0] < angleLimit) { addToHeap(angles, nt0, nt2); if (testingPrint) System.out.println(nt0 + " " + nt2 + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } angles = getRoot(nt1, nt2); if (angles!=null && angles[0] < angleLimit) { addToHeap(angles, nt1, nt2); if (testingPrint) System.out.println(nt1 + " " + nt2 + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } // check for new events for new tetrahedra neighbours Tet nti; for (int i = 0; i < 4; i++) { nti = nt0.neighbors[i]; if ((nti != null) && (nti != nt1) && (nti != nt2)) { angles = getRoot(nt0, nti); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, nt0, nti); if (testingPrint) System.out.println(nt0 + " " + nti + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } } } for (int i = 0; i < 4; i++) { nti = nt1.neighbors[i]; if ((nti != null) && (nti != nt0) && (nti != nt2)) { angles = getRoot(nt1, nti); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, nt1, nti); if (testingPrint) System.out.println(nt1 + " " + nti + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } } } for (int i = 0; i < 4; i++) { nti = nt2.neighbors[i]; if (nti != null && nti != nt0 && nti != nt1) { angles = getRoot(nt2, nti); if (angles != null && angles[0] < angleLimit) { addToHeap(angles, nt2, nti); if (testingPrint) System.out.println(nt2 + " " + nti + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } } } flipTime += (System.nanoTime() - start)/1000000.0; return newTets; } /** * Performs a 3-2-flip of the three specified tetrahedra. Two of these tetrahedra are preserved * and the third (deleted) is returned. * @requires Arrays.equals(t0.corners, Arrays.sort(t0.corners) ) && * Arrays.equals(t1.corners, Arrays.sort(t1.corners) ) && * Arrays.equals(t1.corners, Arrays.sort(t1.corners) ) && * _two vertices shared by all three tetrahedra_ * @return The deleted tetrahedron. */ private Tet[] flip32(Tet t0, Tet t1, Tet t2){ long start = System.nanoTime(); nrFlips++; //Locate three non-shared vertices Vertex[] vns = new Vertex[3]; vns[0] = t0.getCorner(t0.apex(t1)); vns[1] = t1.getCorner(t1.apex(t2)); vns[2] = t2.getCorner(t2.apex(t0)); //kill common edge boolean foundEdge = false; for (Edge e : t0.getEdges()) { if (t1.hasEdge(e) && t2.hasEdge(e)) { foundEdge = true; e.setAlive(false); if (e.getAlph()) { e.setAlph(false); alphaEdges.remove(e); } break; } } if (!foundEdge) { System.out.println("Did not find common edge of edges "); for (Edge e : t0.getEdges()) { System.out.println(" "+e.toString()); } System.out.println(); for (Edge e : t1.getEdges()) { System.out.println(" "+e.toString()); } System.out.println(); for (Edge e : t2.getEdges()) { System.out.println(" "+e.toString()); } } //remove common triangles Tri tri0 = t0.getTri(vns[0]); if (tri0.getAlph()==1) { alphaTris.remove(tri0); } tri0.setAlive(false); Tri tri1 = t1.getTri(vns[1]); if (tri1.getAlph()==1) { alphaTris.remove(tri1); } tri1.setAlive(false); Tri tri2 = t2.getTri(vns[2]); if (tri2.getAlph()==1) { alphaTris.remove(tri2); } tri2.setAlive(false); //Locate two shared vertices Vertex[] vs = new Vertex[2]; int nrSharedFound = 0; for (int i = 0; (i < 4) && (nrSharedFound < 2); i++) { Vertex v = t0.getCorner(i); if (t1.hasVertex(v) && t2.hasVertex(v)) vs[nrSharedFound++] = v; } Tet[] nt = new Tet[2]; Tet nt0 = new Tet(vns[0], vns[1], vns[2], vs[0]); nt[0] = nt0; Tet nt1 = new Tet(vns[0], vns[1], vns[2], vs[1]); nt[1] = nt1; // New common triangle Tri tri = new Tri(vns[0], vns[1], vns[2]); // tri.setTet(nt0); // tri.setTet(nt1); nt0.setTri(tri, nt0.indexOf(vs[0])); nt1.setTri(tri, nt1.indexOf(vs[1])); int count = tri.getCount(); Vertex S0 = tri.getCorner(0); Vertex S1 = tri.getCorner(1); Vertex R0 = tri.getCorner(2); if (count == 0 || count == 7) { if (tri.isAlpha(alphaVal)) { alphaTris.add(tri); tri.setAlph(1); } } else { if (count == 1 || count == 6) { R0 = tri.getCorner(0); S0 = tri.getCorner(1); S1 = tri.getCorner(2); } if (count == 2 || count == 5) { R0 = tri.getCorner(1); S0 = tri.getCorner(0); S1 = tri.getCorner(2); } if ( count == 4 || count == 3) { R0 = tri.getCorner(2); S0 = tri.getCorner(1); S1 = tri.getCorner(0); } if (tri.isAlpha(alphaVal)) { alphaTris.add(tri); tri.setAlph(1); } else { Point center = Point.getMidpoint(S0, S1); Circle C = new Circle(center, alphaVal, center.vectorTo(S0).normalize()); double dist = C.getDistanceSquared(R0); if (dist < (alphaVal*alphaVal)+Constants.EPSILON) { tri.setAlph(2); } else tri.setAlph(0); } angles = getRoot(tri.getCorner(0), tri.getCorner(1), tri.getCorner(2), tri.getCount()); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, tri); } } for (Edge e : t0.getEdges()) { if (e.equals(new Edge(vs[0], vns[0]))) { nt0.setEdge(e); } else if (e.equals(new Edge(vs[0], vns[1]))) { nt0.setEdge(e); } else if (e.equals(new Edge(vs[1], vns[0]))) { nt1.setEdge(e); } else if (e.equals(new Edge(vs[1], vns[1]))) { nt1.setEdge(e); } else if (e.equals(new Edge(vns[1], vns[0]))) { nt1.setEdge(e); nt0.setEdge(e); } } for (Edge e : t1.getEdges()) { if (e.equals(new Edge(vs[0], vns[2]))) { nt0.setEdge(e); } else if (e.equals(new Edge(vs[0], vns[1]))) { nt0.setEdge(e); } else if (e.equals(new Edge(vs[1], vns[2]))) { nt1.setEdge(e); } else if (e.equals(new Edge(vs[1], vns[1]))) { nt1.setEdge(e); } else if (e.equals(new Edge(vns[1], vns[2]))) { nt1.setEdge(e); nt0.setEdge(e); } } for (Edge e : t2.getEdges()) { if (e.equals(new Edge(vs[0], vns[2]))) { nt0.setEdge(e); } else if (e.equals(new Edge(vs[0], vns[0]))) { nt0.setEdge(e); } else if (e.equals(new Edge(vs[1], vns[2]))) { nt1.setEdge(e); } else if (e.equals(new Edge(vs[1], vns[0]))) { nt1.setEdge(e); } else if (e.equals(new Edge(vns[0], vns[2]))) { nt1.setEdge(e); nt0.setEdge(e); } } // Events for new tetrahdra for (Tet t : nt) { count = t.getCount(); int idxR = -1; int idxS0 = -1; int idxS1 = -1; int idxS2 = -1; if (count == 0 || count == 15) { if (t.isAlpha(alphaVal)) { t.setAlph(1); alphaTets.add(t); } } else { if (t.isAlpha(alphaVal)) { t.setAlph(1); alphaTets.add(t); } else if (t.nrRotating()==1){ if (count == 8 || count == 7) { idxR = 3; idxS0 = 0; idxS1 = 1; idxS2 = 2; } if (count==4 || count == 11) { idxR = 2; idxS0 = 0; idxS1 = 1; idxS2 = 3; } if (count==2 || count == 13) { idxR = 1; idxS0 = 0; idxS1 = 3; idxS2 = 2; } if (count==1 || count == 14) { idxR = 0; idxS0 = 3; idxS1 = 1; idxS2 = 2; } Vertex r = t.getCorner(idxR); Vertex s0 = t.getCorner(idxS0); Vertex s1 = t.getCorner(idxS1); Vertex s2 = t.getCorner(idxS2); double d0 = s0.distanceSquared(s1); double d1 = s1.distanceSquared(s2); double d2 = s2.distanceSquared(s0); double a0 = r.distanceSquared(s0); double a1 = r.distanceSquared(s1); double a2 = r.distanceSquared(s2); if (a0 < d0 && a1 < d0 && a1 < d1 && a2 < d2 && a2 < d2 && a0 < d2) { t.setAlph(2); } else t.setAlph(0); } angles = getRoot(t.getCorner(0), t.getCorner(1), t.getCorner(2), t.getCorner(3), count); if (angles!=null && angles[0]< angleLimit) { addToHeap(angles, t); } } } alphaTets.remove(t0); alphaTets.remove(t1); alphaTets.remove(t2); // vertices get new tetrahedron pointers vs[0].setTet(nt0); vs[1].setTet(nt1); vns[0].setTet(nt0); vns[1].setTet(nt0); vns[2].setTet(nt0); // update neighbor information nt0.neighbors[nt0.indexOf_slow(vs[0])] = nt1; nt1.neighbors[nt1.indexOf_slow(vs[1])] = nt0; Tet tn0 = t2; if (!t0.hasVertex(vns[0])) tn0 = t0; else { if (!t1.hasVertex(vns[0])) tn0 = t1; } Tet tn1 = t2; if (!t0.hasVertex(vns[1])) tn1 = t0; else { if (!t1.hasVertex(vns[1])) tn1 = t1; } Tet tn2 = t2; if (!t0.hasVertex(vns[2])) tn2 = t0; else { if (!t1.hasVertex(vns[2])) tn2 = t1; } for (int i = 0; i < 4; i++) { Tri triangle; Tet n0 = tn0.neighbors[i]; triangle = tn0.getTri(i); int idx; if (n0 == null) { if (tn0.getCorner(i)==vs[1]) { nt0.setTri(triangle, nt0.indexOf_slow(vns[0])); } else nt1.setTri(triangle, nt1.indexOf_slow(vns[0])); } else if((n0 != tn1) && (n0 != tn2)) { idx = n0.apex(tn0); if (n0.hasVertex(vs[0])) { n0.neighbors[idx] = nt0; triangle = n0.getTri(idx); // triangle.setTet(nt0); nt0.setTri(triangle, nt0.indexOf_slow(vns[0])); nt0.neighbors[nt0.indexOf_slow(vns[0])] = n0; } else { n0.neighbors[idx] = nt1; triangle = n0.getTri(idx); // triangle.setTet(nt1); nt1.setTri(triangle, nt1.indexOf_slow(vns[0])); nt1.neighbors[nt1.indexOf_slow(vns[0])] = n0; } } } for (int i = 0; i < 4; i++) { Tri triangle; Tet n1 = tn1.neighbors[i]; triangle = tn1.getTri(i); int idx; if (n1 == null) { if (tn1.getCorner(i)==vs[1]) { nt0.setTri(triangle, nt0.indexOf_slow(vns[1])); } else nt1.setTri(triangle, nt1.indexOf_slow(vns[1])); } else if((n1 != tn0) && (n1 != tn2)) { idx = n1.apex(tn1); if (n1.hasVertex(vs[0])) { n1.neighbors[idx] = nt0; triangle = n1.getTri(idx); // triangle.setTet(nt0); nt0.setTri(triangle, nt0.indexOf_slow(vns[1])); nt0.neighbors[nt0.indexOf_slow(vns[1])] = n1; } else { n1.neighbors[idx] = nt1; triangle = n1.getTri(idx); // triangle.setTet(nt1); nt1.setTri(triangle, nt1.indexOf_slow(vns[1])); nt1.neighbors[nt1.indexOf_slow(vns[1])] = n1; } } } for (int i = 0; i < 4; i++) { Tri triangle; Tet n2 = tn2.neighbors[i]; triangle = tn2.getTri(i); int idx; if (n2 == null) { if (tn2.getCorner(i)==vs[1]) { nt0.setTri(triangle, nt0.indexOf_slow(vns[2])); } else nt1.setTri(triangle, nt1.indexOf_slow(vns[2])); } else if((n2 != tn0) && (n2 != tn1)) { idx = n2.apex(tn2); if (n2.hasVertex(vs[0])) { n2.neighbors[idx] = nt0; triangle = n2.getTri(idx); // triangle.setTet(nt0); nt0.setTri(triangle, nt0.indexOf_slow(vns[2])); nt0.neighbors[nt0.indexOf_slow(vns[2])] = n2; } else { n2.neighbors[idx] = nt1; triangle = n2.getTri(idx); // triangle.setTet(nt1); nt1.setTri(triangle, nt1.indexOf_slow(vns[2])); nt1.neighbors[nt1.indexOf_slow(vns[2])] = n2; } } } tets.remove(t0); t0.setAlive(false); tets.remove(t1); t1.setAlive(false); tets.remove(t2); t2.setAlive(false); Tet[] newTets = new Tet[2]; newTets[0] = nt0; newTets[1] = nt1; tets.add(nt0); tets.add(nt1); //Flip event angles = getRoot(nt0, nt1); if (angles!=null && angles[0] < angleLimit) { addToHeap(angles, nt0, nt1); if (testingPrint) System.out.println(nt0 + " " + nt1 + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } // check for new events Tet nti; for (int i = 0; i < 4; i++) { nti = nt0.neighbors[i]; if ((nti != null) && (nti != nt1)) { angles = getRoot(nt0, nti); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, nt0, nti); if (testingPrint) System.out.println(nt0 + " " + nti + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } } } for (int i = 0; i < 4; i++) { nti = nt1.neighbors[i]; if ((nti != null) && (nti != nt0)) { angles = getRoot(nt1, nti); if ((angles != null) && (angles[0] < angleLimit)) { addToHeap(angles, nt1, nti); if (testingPrint) System.out.println(nt1 + " " + nti + " " + Functions.toDeg(angles[0]) + " " + Functions.toDeg(angles[1])); } } } flipTime += (System.nanoTime() - start)/1000000.0; return newTets; } /** Returns TRUE id the tetrahedron is Delaunay (circumscribing sphere contains no point) */ public boolean isDelaunay() { boolean cont = true; for (Tet t : tets) { if (t.isBig()) continue; t.setCircumSphere(); // List noBigpoints = new ArrayList(vertices.size()); if (!t.circumSphere.isEmpty(vertices, Constants.EPSILON)) { System.out.print(t + " is not empty: "); t.circumSphere.contains(vertices, Constants.EPSILON); cont = false; } } return cont; } /** Rotates points */ private void rotatePoints(double angle) { int steps = 1; double angleStep = angle/steps; for (int k = 0; k < steps; k++) { for (Integer i : rotIndx) { Vertex v = vertices.get(i); v.rotationCW(rotationAxis, angleStep); // if (screenAlpha) v.toScene(scene, Color.RED, 0.1); } // try { Thread.sleep(30); } catch (InterruptedException e) {} // if (testingScreen && sphereAnimation) animateSpheres(); //if (k==0) isAlpha(); // System.out.println("AlphaComplex? "+isAlpha()+" : "+alphaTets.toString()+" , "+alphaTris.toString()+", "+alphaEdges.toString()); } } public void rotateTo(double rotateTo) { if (rotateTo>angleLimit) { throw new RuntimeException("Angle is bigger than limit=360"); } HeapItem heapItem; Tet t, nt, tt; Edge edg; Tri tri; int nrFlips = 0; double rotAngle; clashFirst = alphaEdges.isEmpty(); clash = clashFirst; while (!heap.isEmpty() && angleTotal < rotateTo) { HeapItem angleCheck = (HeapItem) heap.peek(); if (angleCheck.angles[0]>rotateTo) break; heapItem = (HeapItem) heap.extract(); t = heapItem.getT(); tri = heapItem.getTri(); if (t!=null) { nt = heapItem.getNT(); if (nt!=null) { if (testingPrint) { System.out.print(t.toString()); if (!t.isAlive()) System.out.print(""); System.out.print(nt.toString()); if (!nt.isAlive()) System.out.print(""); } angles = heapItem.getAngles(); rotAngle = angles[0]; if (rotAngle > rotateTo) break; if (t.isAlive() && nt.isAlive()) { angleTotal = rotAngle; // System.out.println("AngleTotal = "+angleTotal); if (!t.isConvex(nt)) { tt = KineticToolbox.getThirdTet(t, nt); if (tt != null) { // System.out.println("Flip event with "+t.toString()+" and "+nt.toString()+" and "+tt.toString()); if (testingPrint) { System.out.print(tt.toString()); if (!tt.isAlive()) System.out.print("___"); System.out.print(" rotated to angle = " + Functions.toDeg(heapItem.getAngles()[0])); System.out.println(); } flip32(t, nt, tt); if (testingPrint) System.out.println(++nrFlips + ". flip."); } else { System.out.println(" not convex but tt = null"); // break; } } else { // System.out.println("Flip event with "+t.toString()+" and "+nt.toString()); if (testingPrint) { System.out.print(" rotated to angle = " + Functions.toDeg(heapItem.getAngles()[0])); System.out.println(); } flip23(t, nt); if (testingPrint) System.out.println(++nrFlips + ". flip."); } if (clash!=alphaEdges.isEmpty()) { clash = alphaEdges.isEmpty(); clashes.add(Math.toDegrees(angleTotal)); } if (clash!=alphaEdges.isEmpty()) { clash = alphaEdges.isEmpty(); clashes.add(Math.toDegrees(angleTotal)); } // isAlpha(); // isDelaunay(); } } else { //radiusevent tetrahedron // System.out.println("Radius event : tet "+t.toString()); angles = heapItem.getAngles(); rotAngle = angles[0]; if (t.isAlive() && rotAngle < angleLimit) { if (t.nrRotating()==1) { // one corner is rotating rotatePoints(rotAngle-angleTotal); angleTotal = rotAngle; // System.out.println("AngleTotal = "+angleTotal); int alph = t.getAlph(); int count = t.getCount(); int idxR = -1; int idxS0 = -1; int idxS1 = -1; int idxS2 = -1; if (count == 8 || count == 7) { idxR = 3; idxS0 = 0; idxS1 = 1; idxS2 = 2; } else if (count==4 || count == 11) { idxR = 2; idxS0 = 0; idxS1 = 1; idxS2 = 3; } else if (count==2 || count == 13) { idxR = 1; idxS0 = 0; idxS1 = 3; idxS2 = 2; } else if (count==1 || count == 14) { idxR = 0; idxS0 = 3; idxS1 = 1; idxS2 = 2; } Vertex r = t.getCorner(idxR); Vertex s0 = t.getCorner(idxS0); Vertex s1 = t.getCorner(idxS1); Vertex s2 = t.getCorner(idxS2); Circle circum = new Circle(s0, s1, s2); /* double d0 = s0.distanceSquared(s1); double d1 = s1.distanceSquared(s2); double d2 = s2.distanceSquared(s0); double a0 = r.distanceSquared(s0); double a1 = r.distanceSquared(s1); double a2 = r.distanceSquared(s2);*/ boolean onBoundary = false; boolean insideBoth = false; Vector vec = r.vectorTo(circum.getCenter()); Vector centerToRotate = vec.cross(circum.getNormal()); boolean orthogonal = centerToRotate.isZeroVector(); if (orthogonal && r.distance(circum.getCenter()) > circum.getRadius()-Constants.EPSILON && r.distance(circum.getCenter()) < circum.getRadius()+Constants.EPSILON) { onBoundary = true; } if (r.distance(circum.getCenter()) > circum.getRadius()-Constants.EPSILON && r.distance(circum.getCenter()) < circum.getRadius()+Constants.EPSILON) { insideBoth = true; } if (alph == 0) { //if (a0 <= Constants.EPSILON || a1 <= Constants.EPSILON || a2 <= Constants.EPSILON) { if (onBoundary) { t.setAlph(2); } else { t.setAlph(1); alphaTets.add(t); } } else if (alph == 1) { //if (a0 <= Constants.EPSILON || a1 <= Constants.EPSILON || a2 <= Constants.EPSILON) { if (onBoundary) { t.setAlph(1); } else if (insideBoth) {//if (a0 < d0 && a1 < d0 && a1 < d1 && a2 < d2 && a2 < d2 && a0 < d2) { t.setAlph(2); alphaTets.remove(t); } else { t.setAlph(0); alphaTets.remove(t); } } else { //if (a0 <= Constants.EPSILON || a1 <= Constants.EPSILON || a2 <= Constants.EPSILON) { if (onBoundary) { t.setAlph(0); } else { t.setAlph(1); alphaTets.add(t); } } Double[] tmp = new Double[4]; int i = -1; for (Double angle : angles){ if (i==-1) { i += 1; continue; } if (angle==null) break; tmp[i] = angle; i += 1; } if (i>0) { Double[] newangles = new Double[i]; for (int j = 0 ; j rotList) { rotIndx = rotList; for (Vertex v : vertices) v.setType(Vertex.VertexType.S); for (int i : rotIndx) vertices.get(i).setType(Vertex.VertexType.R); } /** returns the list of tetrahedra in this kinetic Dalaunay tessellation */ public Set getTetrahedra(){ return tets; } /** Returns the set of tetrahedra that are currently part of the alpha complex */ public Set getAlphaTetrahedra(){ return alphaTets; } public double getAlpha() { return alphaVal; } }