public Triangle(TriPoint a, TriPoint b, TriPoint c) { Points = new TriPoint[] { a, b, c }; ConstrainedEdge = new bool[3]; DelaunayEdge = new bool[3]; _neighbours = new Triangle[3]; }
/// <summary> /// Legalize triagnle by rotating clockwise around oPoint /// </summary> /// <param name="opoint"></param> /// <param name="npoint"></param> public void Legalize(TriPoint opoint, TriPoint npoint) { if (opoint.Equals(Points[0])) { Points[1] = Points[0]; Points[0] = Points[2]; Points[2] = npoint; } else if (opoint.Equals(Points[1])) { Points[2] = Points[1]; Points[1] = Points[0]; Points[0] = npoint; } else if (opoint.Equals(Points[2])) { Points[0] = Points[2]; Points[2] = Points[1]; Points[1] = npoint; } else { Debug.Assert(false, "What happened here????"); } }
/// <summary> /// Represents a simple polygon's edge /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> public Edge(TriPoint p1, TriPoint p2) { P = p1; Q = p2; if (p1.Y > p2.Y) { Q = p1; P = p2; } else if (p1.Y == p2.Y) { if (p1.X > p2.X) { Q = p1; P = p2; } else if (p1.X == p2.X) { // Repeat points throw new Exception("Edge::Edge: p1 == p2"); } } Q.EdgeList = Q.EdgeList ?? new List <Edge>(); Q.EdgeList.Add(this); }
public Node LocatePoint(TriPoint point) { double px = point.X; Node node = _search_node; double nx = node.Point.X; 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 { Debug.Assert(false, "What happened here????"); } } } 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; } } } if (node != null) { _search_node = node; } return(node); }
public Triangle NeighborAcross(TriPoint opoint) { if (opoint.Equals(Points[0])) { return(_neighbours[0]); } else if (opoint.Equals(Points[1])) { return(_neighbours[1]); } return(_neighbours[2]); }
private void FinalizationPolygon(SweepContext tcx) { // Get an Internal triangle to start with Triangle t = tcx.Front._head.Next.Triangle; TriPoint p = tcx.Front._head.Next.Point; while (!t.GetConstrainedEdgeCW(p)) { t = t.NeighborCCW(p); } tcx.MeshClean(t); }
public Triangle NeighborCCW(TriPoint point) { if (point.Equals(Points[0])) { return(_neighbours[2]); } else if (point.Equals(Points[1])) { return(_neighbours[0]); } return(_neighbours[1]); }
public bool GetDelaunayEdgeCW(TriPoint p) { if (p.Equals(Points[0])) { return(DelaunayEdge[1]); } else if (p.Equals(Points[1])) { return(DelaunayEdge[2]); } return(DelaunayEdge[0]); }
public bool GetConstrainedEdgeCW(TriPoint p) { if (p.Equals(Points[0])) { return(ConstrainedEdge[1]); } else if (p.Equals(Points[1])) { return(ConstrainedEdge[2]); } return(ConstrainedEdge[0]); }
public void SetDelunayEdgeCW(TriPoint p, bool e) { if (p.Equals(Points[0])) { DelaunayEdge[1] = e; } else if (p.Equals(Points[1])) { DelaunayEdge[2] = e; } else { DelaunayEdge[0] = e; } }
public void SetConstrainedEdgeCW(TriPoint p, bool ce) { if (p.Equals(Points[0])) { ConstrainedEdge[1] = ce; } else if (p.Equals(Points[1])) { ConstrainedEdge[2] = ce; } else { ConstrainedEdge[0] = ce; } }
/// <summary> /// Mark edge as constrained /// </summary> /// <param name="p"></param> /// <param name="q"></param> public void MarkConstrainedEdge(TriPoint p, TriPoint q) { if ((q.Equals(Points[0]) && p.Equals(Points[1])) || (q.Equals(Points[1]) && p.Equals(Points[0]))) { ConstrainedEdge[2] = true; } else if ((q.Equals(Points[0]) && p.Equals(Points[2])) || (q.Equals(Points[2]) && p.Equals(Points[0]))) { ConstrainedEdge[1] = true; } else if ((q.Equals(Points[1]) && p.Equals(Points[2])) || (q.Equals(Points[2]) && p.Equals(Points[1]))) { ConstrainedEdge[0] = true; } }
private void SweepPoints(SweepContext tcx) { for (int i = 1; i < tcx.PointCount(); i++) { TriPoint point = tcx.GetPoint(i); Node node = PointEvent(tcx, point); if (point.EdgeList != null) { for (int j = 0; j < point.EdgeList.Count; j++) { EdgeEvent(tcx, point.EdgeList[j], node); } } } }
public static Winding Orient2d(TriPoint pa, TriPoint pb, TriPoint pc) { double detleft = (pa.X - pc.X) * (pb.Y - pc.Y); double detright = (pa.Y - pc.Y) * (pb.X - pc.X); double val = detleft - detright; if (val > -EPSILON && val < EPSILON) { return(Winding.Collinear); } else if (val > 0) { return(Winding.CCW); } return(Winding.CW); }
private TriPoint NextFlipPoint(TriPoint ep, TriPoint eq, Triangle ot, TriPoint op) { Winding o2d = TriUtil.Orient2d(eq, op, ep); if (o2d == Winding.CW) { // Right return(ot.PointCCW(op)); } else if (o2d == Winding.CCW) { // Left return(ot.PointCW(op)); } throw new NotSupportedException("[Unsupported] Opposing point on constrained edge"); }
private Node PointEvent(SweepContext tcx, TriPoint point) { Node node = tcx.LocateNode(point); Node new_node = 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.X <= node.Point.X + TriUtil.EPSILON) { Fill(tcx, node); } //tcx.AddNode(new_node); FillAdvancingFront(tcx, new_node); return(new_node); }
private bool IsEdgeSideOfTriangle(Triangle triangle, TriPoint ep, TriPoint eq) { int index = triangle.EdgeIndex(ep, eq); if (index != -1) { triangle.MarkConstrainedEdge(index); Triangle t = triangle.GetNeighbor(index); if (t != null) { t.MarkConstrainedEdge(ep, eq); } return(true); } return(false); }
public int Index(TriPoint p) { if (p.Equals(Points[0])) { return(0); } else if (p.Equals(Points[1])) { return(1); } else if (p.Equals(Points[2])) { return(2); } Debug.Assert(false, "What happened here????"); return(-1); }
/// <summary> /// The point counter-clockwise to given point /// </summary> /// <param name="point"></param> /// <returns></returns> public TriPoint PointCCW(TriPoint point) { if (point.Equals(Points[0])) { return(Points[1]); } else if (point.Equals(Points[1])) { return(Points[2]); } else if (point.Equals(Points[2])) { return(Points[0]); } Debug.Assert(false, "What happened here????"); return(TriPoint.Empty); }
/// <summary> /// Update neighbor pointers /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="t"></param> public void MarkNeighbor(TriPoint p1, TriPoint p2, Triangle t) { if ((p1.Equals(Points[2]) && p2.Equals(Points[1])) || (p1.Equals(Points[1]) && p2.Equals(Points[2]))) { _neighbours[0] = t; } else if ((p1.Equals(Points[0]) && p2.Equals(Points[2])) || (p1.Equals(Points[2]) && p2.Equals(Points[0]))) { _neighbours[1] = t; } else if ((p1.Equals(Points[0]) && p2.Equals(Points[1])) || (p1.Equals(Points[1]) && p2.Equals(Points[0]))) { _neighbours[2] = t; } else { Debug.Assert(false, "Specified trianlge is not a neighbor"); } }
public static bool InScanArea(TriPoint pa, TriPoint pb, TriPoint pc, TriPoint pd) { double oadb = (pa.X - pb.X) * (pd.Y - pb.Y) - (pd.X - pb.X) * (pa.Y - pb.Y); if (oadb >= -EPSILON) { return(false); } double oadc = (pa.X - pc.X) * (pd.Y - pc.Y) - (pd.X - pc.X) * (pa.Y - pc.Y); if (oadc <= EPSILON) { return(false); } return(true); }
private double Angle(TriPoint origin, TriPoint pa, TriPoint pb) { /* 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 = origin.X; double py = origin.Y; double ax = pa.X - px; double ay = pa.Y - py; double bx = pb.X - px; double by = pb.Y - py; double x = ax * by - ay * bx; double y = ax * bx + ay * by; return(System.Math.Atan2(x, y)); }
private void FlipEdgeEvent(SweepContext tcx, TriPoint ep, TriPoint eq, Triangle t, TriPoint p) { Triangle ot = t.NeighborAcross(p); TriPoint op = ot.OppositePoint(t, p); if (TriUtil.InScanArea(p, t.PointCCW(p), t.PointCW(p), op)) { // Lets rotate shared edge one vertex CW RotateTrianglePair(t, p, ot, op); tcx.MapTriangleToNodes(t); tcx.MapTriangleToNodes(ot); if (p == eq && op == ep) { if (eq == tcx.EdgeEvent.ConstrainedEdge.Q && ep == tcx.EdgeEvent.ConstrainedEdge.P) { t.MarkConstrainedEdge(ep, eq); ot.MarkConstrainedEdge(ep, eq); Legalize(tcx, t); Legalize(tcx, ot); } else { // XXX: I think one of the triangles should be legalized here? } } else { Winding o = TriUtil.Orient2d(eq, op, ep); t = NextFlipTriangle(tcx, o, t, ot, p, op); FlipEdgeEvent(tcx, ep, eq, t, p); } } else { TriPoint newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, t, ot, newP); EdgeEvent(tcx, ep, eq, t, p); } }
/** * <b>Requirement</b>:<br> * 1. a,b and c form a triangle.<br> * 2. a and d is know to be on opposite side of bc<br> * <pre> * a * + * / \ * / \ * b/ \c * +-------+ * / d \ * / \ * </pre> * <b>Fact</b>: d has to be in area B to have a chance to be inside the circle formed by * a,b and c<br> * d is outside B if TriUtil.Orient2d(a,b,d) or TriUtil.Orient2d(c,a,d) is CW<br> * This preknowledge gives us a way to optimize the incircle test * @param a - triangle point, opposite d * @param b - triangle point * @param c - triangle point * @param d - point opposite a * @return true if d is inside circle, false if on circle edge */ private bool Incircle(TriPoint pa, TriPoint pb, TriPoint pc, TriPoint pd) { double adx = pa.X - pd.X; double ady = pa.Y - pd.Y; double bdx = pb.X - pd.X; double bdy = pb.Y - pd.Y; double adxbdy = adx * bdy; double bdxady = bdx * ady; double oabd = adxbdy - bdxady; if (oabd <= 0) { return(false); } double cdx = pc.X - pd.X; double cdy = pc.Y - pd.Y; double cdxady = cdx * ady; double adxcdy = adx * cdy; double ocad = cdxady - adxcdy; if (ocad <= 0) { return(false); } double bdxcdy = bdx * cdy; double cdxbdy = cdx * bdy; double alift = adx * adx + ady * ady; double blift = bdx * bdx + bdy * bdy; double clift = cdx * cdx + cdy * cdy; double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; return(det > 0); }
public void InitTriangulation() { double xmax = _points[0].X; double xmin = _points[0].X; double ymax = _points[0].Y; double ymin = _points[0].Y; // Calculate bounds for (int i = 0; i < _points.Count; i++) { TriPoint p = _points[i]; if (p.X > xmax) { xmax = p.X; } if (p.X < xmin) { xmin = p.X; } if (p.Y > ymax) { ymax = p.Y; } if (p.Y < ymin) { ymin = p.Y; } } double dx = K_ALPHA * (xmax - xmin); double dy = K_ALPHA * (ymax - ymin); _head = new TriPoint(xmax + dx, ymin - dy); _tail = new TriPoint(xmin - dx, ymin - dy); // Sort points along y-axis _points.Sort(_cmp); }
public int EdgeIndex(TriPoint p1, TriPoint p2) { if (Points[0].Equals(p1)) { if (Points[1].Equals(p2)) { return(2); } else if (Points[2].Equals(p2)) { return(1); } } else if (Points[1].Equals(p1)) { if (Points[2].Equals(p2)) { return(0); } else if (Points[0].Equals(p2)) { return(2); } } else if (Points[2].Equals(p1)) { if (Points[0].Equals(p2)) { return(1); } else if (Points[1].Equals(p2)) { return(0); } } return(-1); }
private Node NewFrontTriangle(SweepContext tcx, TriPoint point, Node node) { Triangle triangle = new Triangle(point, node.Point, node.Next.Point); triangle.MarkNeighbor(node.Triangle); tcx.AddToMap(triangle); Node new_node = new Node(point); _nodes.Add(new_node); new_node.Next = node.Next; new_node.Prev = node; node.Next.Prev = new_node; node.Next = new_node; if (!Legalize(tcx, triangle)) { tcx.MapTriangleToNodes(triangle); } return(new_node); }
private void FlipScanEdgeEvent(SweepContext tcx, TriPoint ep, TriPoint eq, Triangle flip_triangle, Triangle t, TriPoint p) { Triangle ot = t.NeighborAcross(p); TriPoint op = ot.OppositePoint(t, p); if (TriUtil.InScanArea(eq, flip_triangle.PointCCW(eq), flip_triangle.PointCW(eq), op)) { // flip with new edge op->eq FlipEdgeEvent(tcx, eq, op, ot, op); // TODO: Actually I just figured out that it should be possible to // improve this by getting the next ot and op before the the above // flip and continue the flipScanEdgeEvent here // set new ot and op here and loop back to inScanArea test // also need to set a new flip_triangle first // Turns out at first glance that this is somewhat complicated // so it will have to wait. } else { TriPoint newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP); } }
public bool Contains(TriPoint p, TriPoint q) { return(Contains(p) && Contains(q)); }
public bool Contains(TriPoint p) { return(Points[0].Equals(p) || Points[1].Equals(p) || Points[2].Equals(p)); }