public DelaunayTriangle(TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3) { Points[0] = p1; Points[1] = p2; Points[2] = p3; }
public void SetConstrainedEdgeCW( TriangulationPoint p, bool ce ) { EdgeIsConstrained[(IndexOf(p)+1)%3] = ce; }
public void SetDelaunayEdgeCW( TriangulationPoint p, bool ce ) { EdgeIsDelaunay[(IndexOf(p)+1)%3] = ce; }
public DelaunayTriangle NeighborCWFrom(TriangulationPoint point) { return Neighbors[(Points.IndexOf(point)+1)%3]; }
public TriangulationPoint PointCWFrom(TriangulationPoint point) { return Points[(IndexOf(point)+2)%3]; }
public int IndexOf(TriangulationPoint p) { int i = Points.IndexOf(p); if (i==-1) throw new Exception("Calling index with a point that doesn't exist in triangle"); return i; }
/// <summary> /// Mark edge as constrained /// </summary> public void MarkConstrainedEdge(TriangulationPoint p, TriangulationPoint q) { int i = EdgeIndex(p,q); if ( i != -1 ) EdgeIsConstrained[i] = true; }
/// <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> private static AdvancingFrontNode PointEvent( DTSweepContext tcx, TriangulationPoint point ) { AdvancingFrontNode node, newNode; node = tcx.LocateNode(point); if (tcx.IsDebugEnabled) tcx.DTDebugContext.ActiveNode = 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.X <= node.Point.X + TriangulationUtil.EPSILON) Fill(tcx, node); tcx.AddNode(newNode); FillAdvancingFront(tcx, newNode); return newNode; }
/// <summary> /// Rotates a triangle pair one vertex CW /// n2 n2 /// P +-----+ P +-----+ /// | t /| |\ t | /// | / | | \ | /// n1| / |n3 n1| \ |n3 /// | / | after CW | \ | /// |/ oT | | oT \| /// +-----+ oP +-----+ /// n4 n4 /// </summary> private static void RotateTrianglePair( DelaunayTriangle t, TriangulationPoint p, DelaunayTriangle ot, TriangulationPoint op ) { DelaunayTriangle n1, n2, n3, n4; n1 = t.NeighborCCWFrom(p); n2 = t.NeighborCWFrom(p); n3 = ot.NeighborCCWFrom(op); n4 = ot.NeighborCWFrom(op); bool ce1, ce2, ce3, ce4; ce1 = t.GetConstrainedEdgeCCW(p); ce2 = t.GetConstrainedEdgeCW(p); ce3 = ot.GetConstrainedEdgeCCW(op); ce4 = ot.GetConstrainedEdgeCW(op); bool de1, de2, de3, de4; de1 = t.GetDelaunayEdgeCCW(p); de2 = t.GetDelaunayEdgeCW(p); de3 = ot.GetDelaunayEdgeCCW(op); de4 = ot.GetDelaunayEdgeCW(op); t.Legalize(p, op); ot.Legalize(op, p); // Remap dEdge ot.SetDelaunayEdgeCCW(p, de1); t.SetDelaunayEdgeCW(p, de2); t.SetDelaunayEdgeCCW(op, de3); ot.SetDelaunayEdgeCW(op, de4); // Remap cEdge ot.SetConstrainedEdgeCCW(p, ce1); t.SetConstrainedEdgeCW(p, ce2); t.SetConstrainedEdgeCCW(op, ce3); ot.SetConstrainedEdgeCW(op, ce4); // Remap neighbors // XXX: might optimize the markNeighbor by keeping track of // what side should be assigned to what neighbor after the // rotation. Now mark neighbor does lots of testing to find // the right side. t.Neighbors.Clear(); ot.Neighbors.Clear(); if (n1 != null) ot.MarkNeighbor(n1); if (n2 != null) t.MarkNeighbor(n2); if (n3 != null) t.MarkNeighbor(n3); if (n4 != null) ot.MarkNeighbor(n4); t.MarkNeighbor(ot); }
/// <summary> /// When we need to traverse from one triangle to the next we need /// the point in current triangle that is the opposite point to the next /// triangle. /// </summary> private static TriangulationPoint NextFlipPoint( TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle ot, TriangulationPoint op ) { Orientation o2d = TriangulationUtil.Orient2d(eq, op, ep); switch ( o2d ) { case Orientation.CW: return ot.PointCCWFrom(op); case Orientation.CCW: return ot.PointCWFrom(op); case Orientation.Collinear: // TODO: implement support for point on constraint edge throw new PointOnEdgeException("Point on constrained edge not supported yet",eq,op,ep); default: throw new NotImplementedException("Orientation not handled"); } }
/// <summary> /// After a flip we have two triangles and know that only one will still be /// intersecting the edge. So decide which to contiune with and legalize the other /// </summary> /// <param name="tcx"></param> /// <param name="o">should be the result of an TriangulationUtil.orient2d( eq, op, ep )</param> /// <param name="t">triangle 1</param> /// <param name="ot">triangle 2</param> /// <param name="p">a point shared by both triangles</param> /// <param name="op">another point shared by both triangles</param> /// <returns>returns the triangle still intersecting the edge</returns> private static DelaunayTriangle NextFlipTriangle( DTSweepContext tcx, Orientation o, DelaunayTriangle t, DelaunayTriangle ot, TriangulationPoint p, TriangulationPoint op ) { int edgeIndex; if (o == Orientation.CCW) { // ot is not crossing edge after flip edgeIndex = ot.EdgeIndex(p, op); ot.EdgeIsDelaunay[edgeIndex] = true; Legalize(tcx, ot); ot.EdgeIsDelaunay.Clear(); return t; } // t is not crossing edge after flip edgeIndex = t.EdgeIndex(p, op); t.EdgeIsDelaunay[edgeIndex] = true; Legalize(tcx, t); t.EdgeIsDelaunay.Clear(); return ot; }
/// <summary> /// Creates a new front triangle and legalize it /// </summary> private static AdvancingFrontNode NewFrontTriangle( DTSweepContext tcx, TriangulationPoint point, AdvancingFrontNode node ) { AdvancingFrontNode newNode; DelaunayTriangle triangle; triangle = new DelaunayTriangle(point, node.Point, node.Next.Point); triangle.MarkNeighbor(node.Triangle); tcx.Triangles.Add(triangle); newNode = new AdvancingFrontNode(point); newNode.Next = node.Next; newNode.Prev = node; node.Next.Prev = newNode; node.Next = newNode; tcx.AddNode(newNode); // XXX: BST if (tcx.IsDebugEnabled) tcx.DTDebugContext.ActiveNode = newNode; if (!Legalize(tcx, triangle)) tcx.MapTriangleToNodes(triangle); return newNode; }
private static bool IsEdgeSideOfTriangle( DelaunayTriangle triangle, TriangulationPoint ep, TriangulationPoint eq ) { int index = triangle.EdgeIndex(ep, eq); if ( index == -1 ) return false; triangle.MarkConstrainedEdge(index); triangle = triangle.Neighbors[index]; if (triangle != null) triangle.MarkConstrainedEdge(ep, eq); return true; }
/// <summary> /// Scan part of the FlipScan algorithm<br> /// When a triangle pair isn't flippable we will scan for the next /// point that is inside the flip triangle scan area. When found /// we generate a new flipEdgeEvent /// </summary> /// <param name="tcx"></param> /// <param name="ep">last point on the edge we are traversing</param> /// <param name="eq">first point on the edge we are traversing</param> /// <param name="flipTriangle">the current triangle sharing the point eq with edge</param> /// <param name="t"></param> /// <param name="p"></param> private static void FlipScanEdgeEvent( DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle flipTriangle, DelaunayTriangle t, TriangulationPoint p ) { DelaunayTriangle ot; TriangulationPoint op, newP; bool inScanArea; ot = t.NeighborAcrossFrom(p); op = ot.OppositePoint(t, p); if (ot == null) { // If we want to integrate the fillEdgeEvent do it here // With current implementation we should never get here throw new Exception("[BUG:FIXME] FLIP failed due to missing triangle"); } if (tcx.IsDebugEnabled) { Console.WriteLine("[FLIP:SCAN] - scan next point"); // TODO: remove tcx.DTDebugContext.PrimaryTriangle = t; tcx.DTDebugContext.SecondaryTriangle = ot; } inScanArea = TriangulationUtil.InScanArea(eq, flipTriangle.PointCCWFrom(eq), flipTriangle.PointCWFrom(eq), op); if (inScanArea) { // 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 flipTriangle first // Turns out at first glance that this is somewhat complicated // so it will have to wait. } else { newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, flipTriangle, ot, newP); } }
public AdvancingFrontNode(TriangulationPoint point) { this.Point = point; this.Value = point.X; }
/// <summary> /// In the case of a pointset with some constraint edges. If a triangle side is collinear /// with a part of the constraint we split the constraint into two constraints. This could /// happen when the given constraint migth intersect a point in the set.<br> /// This can never happen in the case when we are working with a polygon. /// /// Think of two triangles that have non shared sides that are collinear and the constraint /// is set from a point in triangle A to a point in triangle B so that the constraint is /// the union of both those sides. We then have to split the constraint into two so we get /// one constraint for each triangle. /// </summary> /// <param name="ep"></param> /// <param name="eq"></param> /// <param name="p">point on the edge between ep->eq</param> private static void SplitEdge( TriangulationPoint ep, TriangulationPoint eq, TriangulationPoint p ) { #if !DOTNET2 DTSweepConstraint edge = eq.Edges.First( e => e.Q==ep || e.P==ep ); #else DTSweepConstraint edge = null; for ( int i=0;i<eq.Edges.Count;i++) if (eq.Edges[i].Q == ep || eq.Edges[i].P == ep) { edge = eq.Edges[i]; break; } #endif edge.P = p; new DTSweepConstraint(ep, p); // Et tu, Brute? --MM // // Redo this edge now that we have split the constraint // newEdgeEvent( tcx, edge, triangle, point ); // // Continue with new edge // newEdgeEvent( tcx, edge, triangle, p2 ); }
public int IndexCWFrom(TriangulationPoint p) { return (IndexOf(p)+2)%3; }
public void AddSteinerPoint( TriangulationPoint point ) { if (_steinerPoints == null) _steinerPoints = new List<TriangulationPoint>(); _steinerPoints.Add(point); }
/// <summary> /// Legalize triangle by rotating clockwise around oPoint /// </summary> /// <param name="oPoint">The origin point to rotate around</param> /// <param name="nPoint">???</param> public void Legalize(TriangulationPoint oPoint, TriangulationPoint nPoint) { RotateCW(); Points[IndexCCWFrom(oPoint)] = nPoint; }
public abstract TriangulationConstraint NewConstraint(TriangulationPoint a, TriangulationPoint b);
public DelaunayTriangle NeighborAcrossFrom(TriangulationPoint point) { return Neighbors[ Points.IndexOf(point) ]; }
/// <summary> /// Get the index of the neighbor that shares this edge (or -1 if it isn't shared) /// </summary> /// <returns>index of the shared edge or -1 if edge isn't shared</returns> public int EdgeIndex(TriangulationPoint p1, TriangulationPoint p2) { int i1 = Points.IndexOf(p1); int i2 = Points.IndexOf(p2); // Points of this triangle in the edge p1-p2 bool a = (i1==0 || i2==0); bool b = (i1==1 || i2==1); bool c = (i1==2 || i2==2); if (b&&c) return 0; if (a&&c) return 1; if (a&&b) return 2; return -1; }
/// <param name="t">Opposite triangle</param> /// <param name="p">The point in t that isn't shared between the triangles</param> public TriangulationPoint OppositePoint(DelaunayTriangle t, TriangulationPoint p) { Debug.Assert(t != this, "self-pointer error"); return PointCWFrom(t.PointCWFrom(p)); }
public bool GetConstrainedEdgeAcross( TriangulationPoint p ) { return EdgeIsConstrained[ IndexOf(p) ]; }
public void SetConstrainedEdgeAcross( TriangulationPoint p, bool ce ) { EdgeIsConstrained[ IndexOf(p) ] = ce; }
public bool GetConstrainedEdgeCW( TriangulationPoint p ) { return EdgeIsConstrained[(IndexOf(p)+1)%3]; }
public void SetDelaunayEdgeAcross( TriangulationPoint p, bool ce ) { EdgeIsDelaunay[ IndexOf(p) ] = ce; }
public bool GetDelaunayEdgeAcross( TriangulationPoint p ) { return EdgeIsDelaunay[ IndexOf(p) ]; }
/// <summary> /// Update neighbor pointers /// </summary> /// <param name="p1">Point 1 of the shared edge</param> /// <param name="p2">Point 2 of the shared edge</param> /// <param name="t">This triangle's new neighbor</param> private void MarkNeighbor( TriangulationPoint p1, TriangulationPoint p2, DelaunayTriangle t ) { int i = EdgeIndex(p1,p2); if ( i==-1 ) throw new Exception( "Error marking neighbors -- t doesn't contain edge p1-p2!" ); Neighbors[i] = t; }
public bool GetDelaunayEdgeCW( TriangulationPoint p ) { return EdgeIsDelaunay[(IndexOf(p)+1)%3]; }
public bool Contains(TriangulationPoint p) { return Points.Contains(p); }