/// <summary> /// Give two points in any order. Will always be ordered so /// that q.y > p.y and q.x > p.x if same y value /// </summary> /// public DTSweepConstraint(TriangulationPoint p1, TriangulationPoint p2) // throws DuplicatePointException { p = p1; q = p2; if (p1.getY() > p2.getY()) { q = p1; p = p2; } else if (p1.getY() == p2.getY()) { if (p1.getX() > p2.getX()) { q = p1; p = p2; } else if (p1.getX() == p2.getX()) { logger.Info("Failed to create constraint {}={}", p1, p2); // throw new DuplicatePointException( p1 + "=" + p2 ); // return; } } q.addEdge(this); }
/// <summary> /// This implementation will use simple node traversal algorithm to find a /// point on the front /// </summary> /// /// <param name="point"></param> public AdvancingFrontNode locatePoint(TriangulationPoint point) { double px = point.getX(); AdvancingFrontNode node = findSearchNode(px); double nx = node.point.getX(); if (px == nx) { if (point != node.point) { // We might have two nodes with same x value for a short time if (point == node.prev.point) { node = node.prev; } else if (point == node.next.point) { node = node.next; } else { throw new Exception("Failed to find Node for given afront point"); // node = null; } } } else if (px < nx) { while ((node = node.prev) != null) { if (point == node.point) { break; } } } else { while ((node = node.next) != null) { if (point == node.point) { break; } } } search = node; return(node); }
/// <summary> /// Find closes node to the left of the new point and create a new triangle. /// If needed new holes and basins will be filled to. /// </summary> /// /// <param name="tcx"></param> /// <param name="point"></param> /// private static AdvancingFrontNode pointEvent(DTSweepContext tcx, TriangulationPoint point) { AdvancingFrontNode node, newNode; node = tcx.locateNode(point); if (tcx.isDebugEnabled()) { tcx.getDebugContext().setActiveNode(node); } newNode = newFrontTriangle(tcx, point, node); // Only need to check +epsilon since point never have smaller // x value than node due to how we fetch nodes from the front if (point.getX() <= node.point.getX() + EPSILON) { fill(tcx, node); } tcx.addNode(newNode); fillAdvancingFront(tcx, newNode); return(newNode); }
/// <summary> /// angle /// </summary> /// /// <param name="node">middle node</param> /// <returns>the angle between p-a and p-b in range [-pi,pi]</returns> /// private static double angle(TriangulationPoint p, TriangulationPoint a, TriangulationPoint b) { // XXX: do we really need a signed angle for holeAngle? // could possible save some cycles here /* Complex plane * ab = cosA +i*sinA * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) * atan2(y,x) computes the principal value of the argument function * applied to the complex number x+iy * Where x = ax*bx + ay*by * y = ax*by - ay*bx */ double px = p.getX(); double py = p.getY(); double ax = a.getX() - px; double ay = a.getY() - py; double bx = b.getX() - px; double by = b.getY() - py; return(Math.Atan2(ax * by - ay * bx, ax * bx + ay * by)); }
/// <summary> /// We use a balancing tree to locate a node smaller or equal to given key /// value. /// </summary> /// /// <param name="point"></param> public AdvancingFrontNode locateNode(TriangulationPoint point) { return(locateNode(point.getX())); }