package ProGAL.geom2d.delaunay; import java.awt.Color; import java.util.ArrayList; import java.util.List; import ProGAL.geom2d.LineSegment; import ProGAL.geom2d.Point; import ProGAL.geom3d.predicates.ExactJavaPredicates; import ProGAL.math.Randomization; import java.util.HashSet; import java.util.logging.Level; import java.util.logging.Logger; import org.das2.util.LoggerManager; /** * * @author ras */ public class DTWithBigPoints { private static final Logger logger= LoggerManager.getLogger("ProGAL.geom2d.delaunay"); private final ExactJavaPredicates pred = new ExactJavaPredicates(); final List<Vertex> vertices; final List<Triangle> triangles; final Vertex[] bigPoints; public DTWithBigPoints(List<Point> points){ this.vertices = new ArrayList<Vertex>(points.size()); this.triangles = new ArrayList<Triangle>(points.size()); bigPoints = new Vertex[3]; bigPoints[0] = new Vertex(new Point(-3000,-3000)); bigPoints[1] = new Vertex(new Point( 3000, 0)); bigPoints[2] = new Vertex(new Point( 0, 3000)); Triangle bigTri = new Triangle(bigPoints[0], bigPoints[1], bigPoints[2]); triangles.add(bigTri); int ipoint=0; for(Point p: points) { ipoint++; addPoint(p); if ( ( ipoint%10000)==0 && ipoint>0 ) { System.err.println("triangulated "+ipoint+" points."); } } } public List<Triangle> getTriangles(){ return new ArrayList<Triangle>(triangles); } public List<int[]> getEdges(){ ArrayList<int[]> ret = new ArrayList<int[]>(); for(Triangle tri: triangles){ for(int i=0;i<3;i++){ int[] e = new int[]{tri.corners[i].id-3, tri.corners[(i+1)%3].id-3}; if(e[0]<0 || e[1]<0) continue; if(e[0]>e[1]){ int tmp = e[0]; e[0] = e[1]; e[1] = tmp; } if( !ret.contains(e) ) ret.add(e); } } return ret; } public Triangle walk(Point p){ return walk(p,null); } public Triangle walk(Point p, List<Point> trace ){ Triangle t = triangles.get(triangles.size()-1); return walk(p, trace, t); } /** * walk to find the triangle containing the point * @param p the location to find. * @param trace if non-null, then keep a list of triangles visited. * @param t initial triangle * @return the triangle containing point p */ public Triangle walk(Point p, List<Point> trace, Triangle t ){ HashSet<Triangle> visited= new HashSet<>(); if ( t==null ) t = triangles.get(triangles.size()-1); visited.add(t); while(true){ logger.log(Level.FINEST, "walk triangle: {0}", t); //printTriangle( t, p ); double a1 = Point.area(t.corners[0], t.corners[1], p); orientPredCounter++; double a2 = Point.area(t.corners[1], t.corners[2], p); orientPredCounter++; double a3 = Point.area(t.corners[2], t.corners[0], p); orientPredCounter++; if(a1<0 && a2<0) //No need to check the third side if(a2<a1) t = t.neighbors[0]; else t = t.neighbors[2]; else{ if(Math.min(a1, Math.min(a2, a3))<0){ //Does t contain p yet? if(a3<a1 && a3<a2) t = t.neighbors[1]; else if(a2<a1) t = t.neighbors[0]; else t = t.neighbors[2]; }else break; } if ( t==null ) throw new IllegalArgumentException("Point is outside of the big triangulation"); if ( visited.contains(t) ) { // uh-oh. We got lost. throw new IllegalArgumentException("cycle in DTWithBigPoints needs to be fixed."); } else { visited.add(t); } Point c= t.getCenter(); if ( trace!=null ) trace.add( c ); //This is the straightforward way. The above is faster. //if(Point.rightTurn(t.corners[0], t.corners[1], p)) t = t.neighbors[2]; //else if(Point.rightTurn(t.corners[1], t.corners[2], p)) t = t.neighbors[0]; //else if(Point.rightTurn(t.corners[2], t.corners[0], p)) t = t.neighbors[1]; //else break; } return t; } private static void printTriangle( Triangle t, Point p ) { //if ( p==null ) p= new Point( new double[] {-9999,-9999} ); //System.err.println( String.format( "%9d %9d %9d %s %s %s %s", t.corners[0].id, t.corners[1].id, t.corners[2].id, t.corners[0].toString(), t.corners[1].toString(), t.corners[2], p ) ); } /** * add the point to the tesselation. If the point is already a vertex, * then use the point, otherwise a copy is made. * @param point */ public void addPoint(Point point){ Vertex p; if ( point instanceof Vertex ) { p = (Vertex) point; } else { p = new Vertex(point); } vertices.add((Vertex)p); Triangle t = walk(p); printTriangle(t,p); Triangle[] ts = splitTriangle(p, t); boolean valid= true; valid= valid && checkValid(ts[0]); valid= valid && checkValid(ts[1]); valid= valid && checkValid(ts[2]); if ( !valid ) { printTriangle(t,p); } legalizeEdge(ts[0], 0); legalizeEdge(ts[1], 0); legalizeEdge(ts[2], 0); } private boolean checkValid( Triangle t ) { try { t.getCircumCircle(); return true; } catch ( RuntimeException ex ) { return false; } } private Triangle[] splitTriangle(Vertex p, Triangle t) { triangles.remove(t); Vertex[] ps = {t.corners[0], t.corners[1], t.corners[2]}; Triangle[] ns = {t.neighbors[0], t.neighbors[1], t.neighbors[2]}; Triangle[] ts = {new Triangle(p, ps[1], ps[2]), new Triangle(p, ps[2], ps[0]), new Triangle(p, ps[0], ps[1])}; for(int i=0;i<3;i++){ ts[i].neighbors[0] = ns[i]; if(ns[i]!=null) ns[i].neighbors[ (ns[i].indexOf(ps[(i+1)%3])+1)%3 ] = ts[i]; ts[i].neighbors[1] = ts[(i+1)%3]; ts[i].neighbors[2] = ts[(i+2)%3]; ps[i].first = ts[(i+1)%3]; triangles.add(ts[i]); } p.first = ts[0]; return ts; } void legalizeEdge(Triangle t, int e){ if(t.neighbors[e]==null) return; Triangle u = t.neighbors[e]; int f = (u.indexOf(t.corners[(e+1)%3])+1)%3; double inc = pred.incircle(t.corners[0].getCoords(),t.corners[1].getCoords(),t.corners[2].getCoords(), u.corners[f].getCoords()); boolean illegal = inc>0; predCounter++; if(illegal){ flip(t,e,u,f); // scene.repaint(); legalizeEdge(t, e); legalizeEdge(u, (f+2)%3); } } static void flip(Triangle t, int e, Triangle u, int f){ flipCounter++; Vertex p0 = t.corners[e]; Vertex p1 = t.corners[(e+1)%3]; Vertex p2 = u.corners[f]; Vertex p3 = t.corners[(e+2)%3]; Triangle n01 = t.neighbors[(e+2)%3]; Triangle n12 = u.neighbors[(f+1)%3]; Triangle n23 = u.neighbors[(f+2)%3]; Triangle n34 = t.neighbors[(e+1)%3]; t.corners[(e+2)%3] = p2; u.corners[(f+2)%3] = p0; t.setCorner(p2, (e+2)%3); u.setCorner(p0, (f+2)%3); t.neighbors[e] = n12; t.neighbors[(e+1)%3] = u; t.neighbors[(e+2)%3] = n01; u.neighbors[f] = n34; u.neighbors[(f+1)%3] = t; u.neighbors[(f+2)%3] = n23; if(n12!=null) n12.neighbors[(n12.indexOf(p1)+1)%3] = t; if(n34!=null) n34.neighbors[(n34.indexOf(p3)+1)%3] = u; if(p1.first==u) p1.first = t; if(p3.first==t) p3.first = u; } public boolean inCH(Triangle t){ if(t==null) return false; for(Point bp: bigPoints){ for(int c=0;c<3;c++) if(t.corners[c]==bp) return false; } return true; } public boolean onCH(Triangle t){ return inCH(t) && (!inCH(t.neighbors[0]) || !inCH(t.neighbors[1]) || !inCH(t.neighbors[2])); } public static int flipCounter = 0, predCounter = 0, orientPredCounter = 0; }