if (_mesh.isOuter(tri)) continue; TriMesh.Node na = tri.nodeA(); TriMesh.Node nb = tri.nodeB(); TriMesh.Node nc = tri.nodeC(); Color ca = Color.WHITE; Color cb = Color.WHITE; if (_mesh.isOuter(tri)) continue; TriMesh.Node na = tri.nodeA(); TriMesh.Node nb = tri.nodeB(); TriMesh.Node nc = tri.nodeC(); Color ca = Color.WHITE; Color cb = Color.WHITE; int y1 = (int)(yshift+qc[1]*yscale); if (_drawPolys || !cb.equals(cc)) { TriMesh.Tri ta = tri.triNabor(na); if (ta!=null && _mesh.isInner(ta)) { TriMesh.Node nn = tri.nodeNabor(ta); pn[0] = x(nn); pn[1] = y(nn); TriMesh.Tri tb = tri.triNabor(nb); if (tb!=null && _mesh.isInner(tb)) { TriMesh.Node nn = tri.nodeNabor(tb); pn[0] = x(nn); pn[1] = y(nn);
public double accumulateAreas( double xp, double yp, TriMesh mesh, TriMesh.NodeList nodeList, TriMesh.TriList triList) { clear(); int ntri = triList.ntri(); TriMesh.Tri[] tris = triList.tris(); for (int itri=0; itri<ntri; ++itri) { TriMesh.Tri tri = tris[itri]; TriMesh.Node na = tri.nodeA(); TriMesh.Node nb = tri.nodeB(); TriMesh.Node nc = tri.nodeC(); double xa = na.xp(), ya = na.yp(); double xb = nb.xp(), yb = nb.yp(); double xc = nc.xp(), yc = nc.yp(); Geometry.centerCircle(xp,yp,xb,yb,xc,yc,_ca); Geometry.centerCircle(xp,yp,xc,yc,xa,ya,_cb); Geometry.centerCircle(xp,yp,xa,ya,xb,yb,_cc); Geometry.centerCircle(xa,ya,xb,yb,xc,yc,_ct); double aa = area(_cb,_cc,_ct); double ab = area(_cc,_ca,_ct); double ac = area(_ca,_cb,_ct); accumulate(na,aa); accumulate(nb,ab); accumulate(nc,ac); } return sum(); } private double[] _ca = new double[2]; // circumcenter of fake tri pbc
/** * Constructs a directed edge that references the specified nodes. * Optionally, a tri may be specified. If non-null, that tri must * reference the specified nodes. * @param a a node of the edge. * @param b a node of the edge. * @param abc a tri that references nodes A and B; null, if none. */ public Edge(Node a, Node b, Tri abc) { Node c = (abc!=null)?otherNode(abc,a,b):null; Check.argument(abc==null || c!=null,"tri references nodes"); _a = a; _b = b; if (c!=null) { if (nodesInOrder(abc,a,b,c)) { _triLeft = abc; _nodeLeft = c; _triRight = abc.triNabor(c); _nodeRight = (_triRight!=null)?abc.nodeNabor(_triRight):null; } else { _triRight = abc; _nodeRight = c; _triLeft = abc.triNabor(c); _nodeLeft = (_triLeft!=null)?abc.nodeNabor(_triLeft):null; } } }
private void processTris( double xp, double yp, TriMesh mesh, TriMesh.TriList triList) { _edgeList.clear(); int ntri = triList.ntri(); TriMesh.Tri[] tris = triList.tris(); for (int itri=0; itri<ntri; ++itri) { TriMesh.Tri tri = tris[itri]; TriMesh.Tri ta = tri.triA(); TriMesh.Tri tb = tri.triB(); TriMesh.Tri tc = tri.triC(); TriMesh.Node na = tri.nodeA(); TriMesh.Node nb = tri.nodeB(); TriMesh.Node nc = tri.nodeC(); tri.centerCircle(_xy); double xt = _xy[0]-xp, yt = _xy[1]-yp; processTriNabor(xp,yp,xt,yt,mesh,ta,nb,nc); processTriNabor(xp,yp,xt,yt,mesh,tb,nc,na); processTriNabor(xp,yp,xt,yt,mesh,tc,na,nb); } } private void processTriNabor(
/** * Validates the specified tri. */ private void validate(Tri tri) { Check.state(tri!=null,"tri not null"); Node na = tri.nodeA(); Node nb = tri.nodeB(); Node nc = tri.nodeC(); validate(na); validate(nb); validate(nc); Tri ta = tri.triA(); Tri tb = tri.triB(); Tri tc = tri.triC(); if (ta!=null) Check.state(ta.triNabor(tri.nodeNabor(ta))==tri,"a nabors ok"); if (tb!=null) Check.state(tb.triNabor(tri.nodeNabor(tb))==tri,"b nabors ok"); if (tc!=null) Check.state(tc.triNabor(tri.nodeNabor(tc))==tri,"c nabors ok"); }
/** * Computes the circumcenter of this tri. * @param c array of circumcenter coordinates {xc,yc}. * @return radius-squared of circumcircle. */ public double centerCircle(double[] c) { if (hasCenter()) { c[0] = _xc; c[1] = _yc; } else { double x0 = _n0._x; double y0 = _n0._y; double x1 = _n1._x; double y1 = _n1._y; double x2 = _n2._x; double y2 = _n2._y; Geometry.centerCircle(x0,y0,x1,y1,x2,y2,c); setCenter(c[0],c[1]); } double dx = _xc-_n2._x; double dy = _yc-_n2._y; return dx*dx+dy*dy; }
/** * Adds the mate of the edge of the specified tri that is opposite * the specified node, unless the edge is in the set, in which case * that edge is removed. Sets the current edge to the mate added or * the edge removed. * @param tri the tri that references the nodes in the edge. * @param node the other node in the tri that is not in the edge. * @return true, if the mate was added; false, if the edge was removed. */ boolean addMate(Tri tri, Node node) { Tri triNabor = tri.triNabor(node); Node nodeNabor = (triNabor!=null)?tri.nodeNabor(triNabor):null; if (node==tri._n0) { return add(tri._n2,tri._n1,nodeNabor,triNabor); } else if (node==tri._n1) { return add(tri._n0,tri._n2,nodeNabor,triNabor); } else if (node==tri._n2) { return add(tri._n1,tri._n0,nodeNabor,triNabor); } else { assert false:"node is referenced by tri"; return false; } }
private void processTriNabor( double xp, double yp, double xt, double yt, TriMesh mesh, TriMesh.Tri ta, TriMesh.Node nb, TriMesh.Node nc) { boolean saveEdge = true; if (ta!=null && mesh.isMarked(ta)) { ta.centerCircle(_xy); double xa = _xy[0]-xp; double ya = _xy[1]-yp; double xy = xt*ya-xa*yt; accumulate(nc,xy); saveEdge = false; } if (saveEdge) addEdge(xp,yp,xt,yt,nb,nc); }
/** * Marks the specified tri inner or outer. * The outer box must valid. */ private synchronized void markTriInnerOrOuter(Tri tri) { assert _xminOuter<_xmaxOuter:"outer box is valid"; assert _yminOuter<_ymaxOuter:"outer box is valid"; double[] po = {0.0,0.0}; double s = tri.centerCircle(po); double r = sqrt(s); double xo = po[0]; double yo = po[1]; if (xo-r>=_xminOuter && yo-r>=_yminOuter && xo+r<=_xmaxOuter && yo+r<=_ymaxOuter) { tri.setInner(); tri.clearOuter(); } else { tri.setOuter(); tri.clearInner(); } }
/** * Returns a new tri, possibly one resurrected from the dead. * Resurrection reduces the need for garbage collection of dead tris. */ private Tri makeTri(Node n0, Node n1, Node n2) { ++_ntri; int ndead = _deadTris.ntri(); if (ndead==0) { _troot = new Tri(n0,n1,n2); } else { _troot = _deadTris.remove(ndead-1); _troot.init(n0,n1,n2); } if (_ntriListeners>0) fireTriAdded(_troot); return _troot; }
private void addTri(double xp, double yp, TriMesh.Tri tri) { _mesh.mark(tri); _triList.add(tri); addNode(tri.nodeA()); addNode(tri.nodeB()); addNode(tri.nodeC()); TriMesh.Tri ta = tri.triA(); TriMesh.Tri tb = tri.triB(); TriMesh.Tri tc = tri.triC(); if (needTri(xp,yp,ta)) addTri(xp,yp,ta); if (needTri(xp,yp,tb)) addTri(xp,yp,tb); if (needTri(xp,yp,tc)) addTri(xp,yp,tc); } private void addNode(TriMesh.Node node) {
/** * Validates the specified node. */ private void validate(Node node) { Check.state(node==node._prev._next,"node==node._prev._next"); Check.state(node==node._next._prev,"node==node._next._prev"); Tri tri = node.tri(); if (_troot!=null) { Check.state(tri!=null,"tri!=null"); Check.state(node==tri.nodeA() || node==tri.nodeB() || node==tri.nodeC(), "node is one of tri nodes"); } }
/** * Given a node referenced by one edge of the hull, gets the next * edge on the hull that is opposite that node. */ private Edge getNextEdgeOnHull(Node node, Edge edge) { Tri tri = edge.triLeft(); Node next = edge.nodeLeft(); for (Tri tnext=tri.triNabor(node); tnext!=null; tnext=tri.triNabor(node)) { node = next; next = tri.nodeNabor(tnext); tri = tnext; } return new Edge(tri,node); }
/** * Returns the circumcenter of this tri. * @return array of circumcenter coordinates {xc,yc}. */ public double[] centerCircle() { double[] c = new double[2]; centerCircle(c); return c; }
/** * Given a tri and node on the hull, and another node, typically * inside (not on) the hull, gets the next tri on the hull that * is opposite the node on the hull. If the other node is also * on the hull, this method simply returns the specified tri. */ private Tri getNextTriOnHull(Tri tri, Node node, Node nodeOther) { for (Tri tnext=tri.triNabor(node); tnext!=null; tnext=tri.triNabor(node)) { node = nodeOther; nodeOther = tri.nodeNabor(tnext); tri = tnext; } return tri; }
private boolean needTri(double xp, double yp, TriMesh.Tri tri) { if (tri==null || _mesh.isMarked(tri)) return false; TriMesh.Node na = tri.nodeA(); TriMesh.Node nb = tri.nodeB(); TriMesh.Node nc = tri.nodeC(); double xa = na.xp(), ya = na.yp(); double xb = nb.xp(), yb = nb.yp(); double xc = nc.xp(), yc = nc.yp(); return Geometry.inCircle(xa,ya,xb,yb,xc,yc,xp,yp)>0.0; }
/** * Returns the quality of this tri. * Quality is a number between 0 and 1, inclusive. * Quality equals 1 for equilateral tris. * Quality equals 0 for degenerate tris with co-linear nodes. * @return triangle quality. */ public double quality() { if (_quality<0.0) _quality = quality(_n0,_n1,_n2); return _quality; }
/** * Constructs a new tri. * The nodes n0, n1, and n2 must be in CCW order. */ private Tri(Node n0, Node n1, Node n2) { init(n0,n1,n2); }