internal CdtFrontElement(CdtSite leftSite, CdtEdge edge) { Debug.Assert(edge.upperSite.Point.X != edge.lowerSite.Point.X && edge.upperSite.Point.X < edge.lowerSite.Point.X && leftSite == edge.upperSite || edge.upperSite.Point.X > edge.lowerSite.Point.X && leftSite == edge.lowerSite); RightSite = edge.upperSite == leftSite ? edge.lowerSite : edge.upperSite; LeftSite = leftSite; Edge = edge; }
CdtSite AddSite(Point point, object relatedObject) { CdtSite site; if (PointsToSites.TryGetValue(point, out site)) { site.Owner = relatedObject;//set the owner anyway return site; } PointsToSites[point] = site = new CdtSite(point) { Owner = relatedObject }; return site; }
public EdgeTracer(CdtEdge edge, Set<CdtTriangle> triangles, RbTree<CdtFrontElement> front, List<CdtSite> leftPolygon, List<CdtSite> rightPolygon) { this.edge = edge; this.triangles = triangles; this.front = front; this.leftPolygon = leftPolygon; this.rightPolygon = rightPolygon; a = edge.upperSite; b = edge.lowerSite; }
// internal CdtTriangle(CdtSite aLeft, CdtSite aRight, CdtSite bRight, CdtEdge a, CdtEdge b, Func<CdtSite, CdtSite, CdtEdge> createEdgeDelegate) { // Debug.Assert(Point.GetTriangleOrientation(aLeft.Point, aRight.Point, bRight.Point) == TriangleOrientation.Counterclockwise); Sites[0] = aLeft; Sites[1] = aRight; Sites[2] = bRight; Edges[0] = a; Edges[1] = b; BindEdgeToTriangle(aLeft, a); BindEdgeToTriangle(aRight, b); CreateEdge(2, createEdgeDelegate); }
internal CdtSweeper(List<CdtSite> listOfSites, CdtSite p_1, CdtSite p_2, Func<CdtSite, CdtSite, CdtEdge> createEdgeDelegate) { this.listOfSites=listOfSites; var firstTriangle=new CdtTriangle(p_1, p_2, listOfSites[0], createEdgeDelegate); Triangles.Insert( firstTriangle ); front.Insert(new CdtFrontElement(p_1, firstTriangle.Edges[2] )); front.Insert(new CdtFrontElement(listOfSites[0], firstTriangle.Edges[1])); this.p_1 = p_1; this.p_2 = p_2; this.createEdgeDelegate = createEdgeDelegate; //ShowFront(); }
internal CdtTriangle(CdtSite a, CdtSite b, CdtSite c, Func<CdtSite, CdtSite, CdtEdge> createEdgeDelegate) { var orientation = Point.GetTriangleOrientationWithNoEpsilon(a.Point, b.Point, c.Point); switch (orientation) { case TriangleOrientation.Counterclockwise: FillCcwTriangle(a, b, c, createEdgeDelegate); break; case TriangleOrientation.Clockwise: FillCcwTriangle(a, c, b, createEdgeDelegate); break; default: throw new InvalidOperationException(); } }
void ProcessSite(CdtSite site) { PointEvent(site); //ShowFrontWithSite(site); for (int i = 0; i < site.Edges.Count; i++) { var edge = site.Edges[i]; if (edge.Constrained) { EdgeEvent(edge); } } // TestThatFrontIsConnected(); }
List <DebugCurve> ShowIllegalEdge(CdtEdge edge, CdtSite pi, int i) { List <DebugCurve> ls = new List <DebugCurve>(); ls.Add(new DebugCurve(new Ellipse(2, 2, pi.Point))); for (int j = 0; j < 3; j++) { var ee = edge.CcwTriangle.Edges[j]; ls.Add(new DebugCurve(j == i ? "red" : "blue", new LineSegment(ee.upperSite.Point, ee.lowerSite.Point))); } ls.Add(new DebugCurve(100, 1, "black", Circumcircle(edge.CcwTriangle.Sites[0].Point, edge.CcwTriangle.Sites[1].Point, edge.CcwTriangle.Sites[2].Point))); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(ls); return(ls); }
// void ShowDebug(IEnumerable<CdtTriangle> cdtTriangles, CdtEdge cdtEdge, CdtTriangle cdtTriangle) { // var l = new List<DebugCurve> { new DebugCurve(10,"red",new LineSegment(start,end)) }; // if(cdtEdge!=null) // l.Add(new DebugCurve(100,3,"navy", new LineSegment(cdtEdge.upperSite.Point,cdtEdge.lowerSite.Point))); // AddTriangleToListOfDebugCurves(l,cdtTriangle,100,2,"brown"); // LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(l); // // } // static void AddTriangleToListOfDebugCurves(List<DebugCurve> debugCurves,CdtTriangle triangle,byte transparency,double width,string color) { // foreach(var cdtEdge in triangle.Edges) { // debugCurves.Add(new DebugCurve(transparency,width,color,new LineSegment(cdtEdge.upperSite.Point,cdtEdge.lowerSite.Point))); // } // } internal int GetHyperplaneSign(CdtSite cdtSite) { var area = Point.SignedDoubledTriangleArea(start, cdtSite.Point, end); if (area > ApproximateComparer.DistanceEpsilon) { return(1); } if (area < -ApproximateComparer.DistanceEpsilon) { return(-1); } return(0); }
internal CdtSweeper(List <CdtSite> listOfSites, CdtSite p_1, CdtSite p_2, Func <CdtSite, CdtSite, CdtEdge> createEdgeDelegate) { this.listOfSites = listOfSites; var firstTriangle = new CdtTriangle(p_1, p_2, listOfSites[0], createEdgeDelegate); Triangles.Insert(firstTriangle); front.Insert(new CdtFrontElement(p_1, firstTriangle.Edges[2])); front.Insert(new CdtFrontElement(listOfSites[0], firstTriangle.Edges[1])); this.p_1 = p_1; this.p_2 = p_2; this.createEdgeDelegate = createEdgeDelegate; //ShowFront(); }
CdtSite AddSite(Point point, object relatedObject) { CdtSite site; if (PointsToSites.TryGetValue(point, out site)) { site.Owner = relatedObject;//set the owner anyway return(site); } PointsToSites[point] = site = new CdtSite(point) { Owner = relatedObject }; return(site); }
void AddP1AndP2() { var box = Rectangle.CreateAnEmptyBox(); foreach (var site in PointsToSites.Keys) { box.Add(site); } var delx = box.Width / 3; var dely = box.Height / 3; P1 = new CdtSite(box.LeftBottom + new Point(-delx, -dely)); P2 = new CdtSite(box.RightBottom + new Point(delx, -dely)); }
// int count; // bool db { get { return count == 147; } } void PointEvent(CdtSite pi) { RBNode <CdtFrontElement> hittedFrontElementNode; ProjectToFront(pi, out hittedFrontElementNode); CdtSite rightSite; CdtSite leftSite = hittedFrontElementNode.Item.X + ApproximateComparer.DistanceEpsilon < pi.Point.X ? MiddleCase(pi, hittedFrontElementNode, out rightSite) : LeftCase(pi, hittedFrontElementNode, out rightSite); var piNode = InsertSiteIntoFront(leftSite, pi, rightSite); TriangulateEmptySpaceToTheRight(piNode); piNode = FindNodeInFrontBySite(front, leftSite); TriangulateEmptySpaceToTheLeft(piNode); }
/// <summary> /// compare first y then -x coordinates /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns>1 if a is above b, 0 if points are the same and -1 if a is below b</returns> static internal int Above(CdtSite a, CdtSite b) { var del = a.Point.Y - b.Point.Y; if (del > 0) { return(1); } if (del < 0) { return(-1); } del = a.Point.X - b.Point.X; return(del > 0 ? -1 : (del < 0 ? 1 : 0)); //for a horizontal edge the point with the smaller X is the upper point }
void LegalizeEdge(CdtSite pi, CdtEdge edge) { Debug.Assert(pi != edge.upperSite && pi != edge.lowerSite); if (edge.Constrained || edge.CcwTriangle == null || edge.CwTriangle == null) { return; } if (edge.CcwTriangle.Contains(pi)) { LegalizeEdgeForOtherCwTriangle(pi, edge); } else { LegalizeEdgeForOtherCcwTriangle(pi, edge); } }
// /// <summary> // /// returns CdtEdges crossed by the segment a.Point, b.Point // /// </summary> // /// <param name="prevA">if prevA is not a null, that means the path is passing through prevA and might need to include // /// the edge containing a.Point if such exists</param> // /// <param name="a"></param> // /// <param name="b"></param> // /// <returns></returns> // internal IEnumerable<CdtEdge> GetCdtEdgesCrossedBySegment(PolylinePoint prevA, PolylinePoint a, PolylinePoint b) { // count++; // if (dd) { // var l = new List<DebugCurve> { // new DebugCurve("red", new Ellipse(5, 5, a.Point)), // new DebugCurve("blue", new Ellipse(5, 5, b.Point)), // new DebugCurve("blue", new LineSegment(a.Point, b.Point)) // }; // // l.AddRange( // GetTriangles().Select( // tr => new DebugCurve(100, 1, "green", new Polyline(tr.Sites.Select(v => v.Point)) {Closed = true}))); // LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(l); // // } // var ret = new List<CdtEdge>(); // CdtEdge piercedEdge; // CdtTriangle t = GetFirstTriangleAndPiercedEdge(a, b, out piercedEdge); // if (ProperCrossing(a, b, piercedEdge)) // ret.Add(piercedEdge); // // ret.AddRange(ContinueThreadingThroughTriangles(a,b,t, piercedEdge)); // // return ret; // } /* * static bool ProperCrossing(Point a, Point b, CdtEdge cdtEdge) { * return cdtEdge != null && cdtEdge.upperSite.Owner != cdtEdge.lowerSite.Owner && * CrossEdgeInterior(cdtEdge, a, b); * } */ // static int count; // static bool db { get { return count == 125; }} internal IEnumerable <CdtEdge> ThreadEdgeThroughTriangles(CdtSite startSite, Point end) { CdtEdge piercedEdge; var triangle = FindFirstPiercedTriangle(startSite, end, out piercedEdge); if (triangle == null) { yield break; } var start = startSite.Point; foreach (var cdtEdge in ThreadThroughTriangles(start, end, triangle, piercedEdge)) { yield return(cdtEdge); } }
/// <summary> /// Determines the edges of the triangulation together with their desired length (distance between nodes). /// </summary> /// <param name="originalGraph"></param> /// <param name="cdt"></param> /// <param name="targetSizes"></param> /// <param name="desiredEdgeDistances"></param> /// <returns></returns> public static int GetProximityEdgesWithDistance(GeometryGraph originalGraph, Cdt cdt, Size[] targetSizes, out List <Tuple <int, int, double, double> > desiredEdgeDistances) { desiredEdgeDistances = new List <Tuple <int, int, double, double> >(); int numberOverlappingPairs = 0; var edgeSet = new HashSet <CdtEdge>(); //add edges foreach (CdtTriangle triangle in cdt.GetTriangles()) { foreach (CdtEdge triangleEdge in triangle.Edges) { CdtSite site1 = triangleEdge.upperSite; CdtSite site2 = triangleEdge.lowerSite; var nodeId1 = (int)site1.Owner; var nodeId2 = (int)site2.Owner; if (edgeSet.Contains(triangleEdge)) { continue; //edge already included } edgeSet.Add(triangleEdge); Point point1 = site1.Point; Point point2 = site2.Point; double t; double distance = GetIdealDistanceBetweenNodes(nodeId1, nodeId2, point1, point2, targetSizes, out t); if (t > 1) { numberOverlappingPairs++; } int nodeIdSmall = nodeId1; int nodeIdBig = nodeId2; if (nodeId1 > nodeId2) { nodeIdSmall = nodeId2; nodeIdBig = nodeId1; } var tuple = new Tuple <int, int, double, double>(nodeIdSmall, nodeIdBig, distance, t); desiredEdgeDistances.Add(tuple); } } return(numberOverlappingPairs); }
internal CdtTriangle(CdtSite a, CdtSite b, CdtSite c, Func <CdtSite, CdtSite, CdtEdge> createEdgeDelegate) { var orientation = Point.GetTriangleOrientationWithNoEpsilon(a.Point, b.Point, c.Point); switch (orientation) { case TriangleOrientation.Counterclockwise: FillCcwTriangle(a, b, c, createEdgeDelegate); break; case TriangleOrientation.Clockwise: FillCcwTriangle(a, c, b, createEdgeDelegate); break; default: throw new InvalidOperationException(); } }
static void ShowFlip(CdtSite pi, CdtTriangle t, CdtTriangle ot) { List <DebugCurve> ls = new List <DebugCurve>(); ls.Add(new DebugCurve(new Ellipse(2, 2, pi.Point))); for (int i = 0; i < 3; i++) { var e = t.Edges[i]; ls.Add(new DebugCurve(100, 1, "red", new LineSegment(e.upperSite.Point, e.lowerSite.Point))); } for (int i = 0; i < 3; i++) { var e = ot.Edges[i]; ls.Add(new DebugCurve(100, 1, "blue", new LineSegment(e.upperSite.Point, e.lowerSite.Point))); } ls.Add(new DebugCurve(Circumcircle(t.Sites[0].Point, t.Sites[1].Point, t.Sites[2].Point))); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(ls); }
internal CdtTriangle(CdtSite pi, CdtEdge edge, Func<CdtSite, CdtSite, CdtEdge> createEdgeDelegate) { switch (Point.GetTriangleOrientationWithNoEpsilon(edge.upperSite.Point, edge.lowerSite.Point, pi.Point)) { case TriangleOrientation.Counterclockwise: edge.CcwTriangle = this; Sites[0] = edge.upperSite; Sites[1] = edge.lowerSite; break; case TriangleOrientation.Clockwise: edge.CwTriangle = this; Sites[0] = edge.lowerSite; Sites[1] = edge.upperSite; break; default: throw new InvalidOperationException(); } Edges[0] = edge; Sites[2] = pi; CreateEdge(1, createEdgeDelegate); CreateEdge(2, createEdgeDelegate); }
CdtSite LeftCase(CdtSite pi, RBNode <CdtFrontElement> hittedFrontElementNode, out CdtSite rightSite) { //left case // if(db)ShowFrontWithSite(pi, new LineSegment(pi.Point, hittedFrontElementNode.Item.Edge.upperSite.Point), new LineSegment(pi.Point, hittedFrontElementNode.Item.Edge.lowerSite.Point)); Debug.Assert(ApproximateComparer.Close(pi.Point.X, hittedFrontElementNode.Item.X)); var hittedFrontElement = hittedFrontElementNode.Item; InsertAndLegalizeTriangle(pi, hittedFrontElement); var prevToHitted = front.Previous(hittedFrontElementNode); var leftSite = prevToHitted.Item.LeftSite; rightSite = hittedFrontElementNode.Item.RightSite; // if(db)ShowFrontWithSite(pi, new LineSegment(pi.Point, leftSite.Point), new LineSegment(pi.Point, prevToHitted.Item.RightSite.Point)); InsertAndLegalizeTriangle(pi, prevToHitted.Item); front.DeleteNodeInternal(prevToHitted); var d = front.Remove(hittedFrontElement); Debug.Assert(d != null); return(leftSite); }
CdtTriangle FindFirstPiercedTriangle(CdtSite startSite, Point target, out CdtEdge piercedEdge) { if (startSite != null) { foreach (var t in startSite.Triangles) { piercedEdge = GetPiercedEdgeInSiteTriangle(t, startSite, target); if (piercedEdge != null) { if (!PointIsInsideOfTriangle(target, t)) { return(t); } } } } piercedEdge = null; return(null); }
void TriangulatePolygon(int start, int end, List<CdtSite> polygon, CdtSite a, CdtSite b, bool reverseTrangleWhenCompare) { // if(CdtSweeper.db) // CdtSweeper.ShowFront(triangles,front, Enumerable.Range(start, end-start+1).Select(i=> new Ellipse(10,10,polygon[i].Point)).ToArray(), new[]{new LineSegment(a.Point,b.Point)}); var c = polygon[start]; int cIndex = start; for (int i = start + 1; i <= end; i++) { var v = polygon[i]; if (LocalInCircle(v, a, b, c, reverseTrangleWhenCompare)) { cIndex = i; c = v; } } var t = new CdtTriangle(a, b, c, createEdgeDelegate); triangles.Insert(t); addedTriangles.Add(t); if (start < cIndex) TriangulatePolygon(start, cIndex - 1, polygon, a, c, reverseTrangleWhenCompare); if (cIndex < end) TriangulatePolygon(cIndex + 1, end, polygon, c, b, reverseTrangleWhenCompare); }
static internal CdtEdge GetOrCreateEdge(CdtSite a, CdtSite b) { if (Above(a.Point, b.Point) == 1) { var e = a.EdgeBetweenUpperSiteAndLowerSite(b); if (e != null) { return(e); } return(CreateEdgeOnOrderedCouple(a, b)); } else { var e = b.EdgeBetweenUpperSiteAndLowerSite(a); if (e != null) { return(e); } return(CreateEdgeOnOrderedCouple(b, a)); } }
// /// <summary> // /// Testing that s in inside of the circumcircle of (p,q,r). // /// The good explanation of this test is in // /// "Guibas, Stolfi,"Primitives for the Manipulation of General Subdivisions and the Computation of Voronoi Diagrams // /// // /// </summary> // /// <param name="s"></param> // /// <param name="p"></param> // /// <param name="q"></param> // /// <param name="r"></param> // /// <param name="ccc"></param> // /// <returns></returns> // public static bool InCircle0(CdtSite s, CdtSite p, CdtSite q, CdtSite r, double ccc) { // Debug.Assert(Point.GetTriangleOrientationWithNoEpsilon(p.Point, q.Point, r.Point) == TriangleOrientation.Counterclockwise); // /* // * det(p.x,p.y, p*p,1 // * q.x,q.y, q*q,1 // * r.x,r.y, r*r,1 // * s.x,s.y, s*s,1) > 0 // */ // // var a = p.Point.X; // var b = p.Point.Y; // var c = a*a + b*b; // var d = q.Point.X; // var e = q.Point.Y; // var f = d*d + e*e; // var g = r.Point.X; // var h = r.Point.Y; // var k = g*g + h*h; // var l = s.Point.X; // var m = s.Point.Y; // var n = l*l + m*m; // // // // double ddd = ccc - ((a - d) * (h * n - k * m) + (e - b) * (g * n - k * l) + (c - f) * (g * m - h * l) + // (g - l) * (b * f - c * e) + (m - h) * (a * f - c * d) + (k - n) * (a * e - b * d)); // if (Math.Abs(ddd) > diff) { // diff = ddd; // Console.WriteLine(diff); // } // return (a - d)*(h*n - k*m) + (e - b)*(g*n - k*l) + (c - f)*(g*m - h*l) + // (g - l)*(b*f - c*e) + (m - h)*(a*f - c*d) + (k - n)*(a*e - b*d) > ApproximateComparer.Tolerance; // } /// <summary> /// Testing that d in inside of the circumcircle of (a,b,c). /// The good explanation of this test is in /// "Guibas, Stolfi,"Primitives for the Manipulation of General Subdivisions and the Computation of Voronoi Diagrams /// /// </summary> /// <param name="d"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> /// <returns></returns> public static bool InCircle(CdtSite d, CdtSite a, CdtSite b, CdtSite c) { Debug.Assert(Point.GetTriangleOrientationWithNoEpsilon(a.Point, b.Point, c.Point) == TriangleOrientation.Counterclockwise); /* * | ax-dx ay-dy (ax-dx)^2+(ay-dy)^2| * | bx-dx by-dy (bx-dx)^2+(by-dy)^2| * | cx-dx cy-dy (cx-dx)^2+(cy-dy)^2| */ var axdx = a.Point.X - d.Point.X; var aydy = a.Point.Y - d.Point.Y; var bxdx = b.Point.X - d.Point.X; var bydy = b.Point.Y - d.Point.Y; var cxdx = c.Point.X - d.Point.X; var cydy = c.Point.Y - d.Point.Y; var t0 = axdx * axdx + aydy * aydy; var t1 = bxdx * bxdx + bydy * bydy; var t2 = cxdx * cxdx + cydy * cydy; return(axdx * (bydy * t2 - cydy * t1) - bxdx * (aydy * t2 - cydy * t0) + cxdx * (aydy * t1 - bydy * t0) > ApproximateComparer.Tolerance); }
void RegularStepFromSite(CdtSite site) { CdtTriangle triangle = null; foreach (var t in site.Triangles) { int index = t.Sites.Index(site); if (PointIsInsideCone(segEnd.Point, site.Point, t.Sites[index + 2].Point, t.Sites[index + 1].Point)) { triangle = t; var segEndOrientation = Point.GetTriangleOrientation(segEnd.Point, t.Sites[index + 1].Point, t.Sites[index + 2].Point); if (segEndOrientation != TriangleOrientation.Counterclockwise) { CrossTriangleEdge(t.OppositeEdge(site)); return; } } } if (triangle == null) { lastCrossedFeature = OutsideOfTriangulation; return; } if (PointBelongsToInteriorOfTriangle(segEnd.Point, triangle)) { lastCrossedFeature = triangle; } else { foreach (var e in triangle.Edges.Where(e => e.IsAdjacent(site))) { if (Point.GetTriangleOrientation(e.upperSite.Point, e.lowerSite.Point, segEnd.Point) == TriangleOrientation.Collinear) { lastCrossedFeature = e; return; } } } }
void ShowFrontWithSite(CdtSite site, params ICurve[] redCurves) { var ls = new List <DebugCurve>(); if (site.Edges != null) { foreach (var e in site.Edges) { ls.Add(new DebugCurve(100, 0.001, e.Constrained?"pink":"brown", new LineSegment(e.upperSite.Point, e.lowerSite.Point))); } } ls.Add(new DebugCurve(100, 0.01, "brown", new Ellipse(0.5, 0.5, site.Point))); foreach (var t in Triangles) { for (int i = 0; i < 3; i++) { var e = t.Edges[i]; ls.Add(new DebugCurve(e.Constrained?(byte)150:(byte)50, e.Constrained?0.002:0.001, e.Constrained? "pink":"navy", new LineSegment(e.upperSite.Point, e.lowerSite.Point))); } } foreach (var c in redCurves) { ls.Add(new DebugCurve(100, 0.005, "red", c)); } foreach (var frontElement in front) { ls.Add(new DebugCurve(100, 0.005, "green", new LineSegment(frontElement.Edge.upperSite.Point, frontElement.Edge.lowerSite.Point))); } LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(ls); }
RBNode <CdtFrontElement> InsertSiteIntoFront(CdtSite leftSite, CdtSite pi, CdtSite rightSite) { CdtEdge leftEdge = null, rightEdge = null; foreach (var edge in pi.Edges) { if (leftEdge == null && edge.lowerSite == leftSite) { leftEdge = edge; } if (rightEdge == null && edge.lowerSite == rightSite) { rightEdge = edge; } if (leftEdge != null && rightEdge != null) { break; } } Debug.Assert(leftEdge != null && rightEdge != null); front.Insert(new CdtFrontElement(leftSite, leftEdge)); return(front.Insert(new CdtFrontElement(pi, rightEdge))); }
void InsertAndLegalizeTriangle(CdtSite pi, CdtFrontElement frontElement) { if (Point.GetTriangleOrientationWithNoEpsilon(pi.Point, frontElement.LeftSite.Point, frontElement.RightSite.Point) != TriangleOrientation.Collinear) { var tr = new CdtTriangle(pi, frontElement.Edge, createEdgeDelegate); Triangles.Insert(tr); LegalizeEdge(pi, tr.Edges[0]); } else //we need to split the triangle below the element in to two triangles and legalize the old edges //we also delete, that is forget, the frontElement.Edge { var e = frontElement.Edge; e.upperSite.Edges.Remove(e); var t = e.CcwTriangle ?? e.CwTriangle; var oppositeSite = t.OppositeSite(e); RemoveTriangleButLeaveEdges(triangles, t); t = new CdtTriangle(frontElement.LeftSite, oppositeSite, pi, createEdgeDelegate); var t1 = new CdtTriangle(frontElement.RightSite, oppositeSite, pi, createEdgeDelegate); triangles.Insert(t); triangles.Insert(t1); LegalizeEdge(pi, t.OppositeEdge(pi)); LegalizeEdge(pi, t1.OppositeEdge(pi)); } }
internal CdtTriangle(CdtSite pi, CdtEdge edge, Func <CdtSite, CdtSite, CdtEdge> createEdgeDelegate) { switch (Point.GetTriangleOrientationWithNoEpsilon(edge.upperSite.Point, edge.lowerSite.Point, pi.Point)) { case TriangleOrientation.Counterclockwise: edge.CcwTriangle = this; Sites[0] = edge.upperSite; Sites[1] = edge.lowerSite; break; case TriangleOrientation.Clockwise: edge.CwTriangle = this; Sites[0] = edge.lowerSite; Sites[1] = edge.upperSite; break; default: throw new InvalidOperationException(); } Edges[0] = edge; Sites[2] = pi; CreateEdge(1, createEdgeDelegate); CreateEdge(2, createEdgeDelegate); }
internal CdtEdge OppositeEdge(CdtSite pi) { var index = Sites.Index(pi); Debug.Assert(index != -1); return Edges[index + 1]; }
/// <summary> /// here a,b,c comprise a ccw triangle /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> /// <param name="createEdgeDelegate"></param> void FillCcwTriangle(CdtSite a, CdtSite b, CdtSite c, Func<CdtSite, CdtSite, CdtEdge> createEdgeDelegate) { Sites[0] = a; Sites[1] = b; Sites[2] = c; for (int i = 0; i < 3; i++) CreateEdge(i, createEdgeDelegate); }
internal bool Contains(CdtSite cdtSite) { return Sites.Contains(cdtSite); }
void ShowIllegalEdge(CdtEdge edge, int i, CdtSite pi) { List<DebugCurve> ls=new List<DebugCurve>(); ls.Add(new DebugCurve(new Ellipse(2, 2, pi.Point))); for(int j=0;j<3;j++) { var ee=edge.CwTriangle.Edges[j]; ls.Add(new DebugCurve(j==i?"red":"blue", new LineSegment(ee.upperSite.Point,ee.lowerSite.Point))); } LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(ls); }
void AddSiteToLeftPolygon(CdtSite site) { AddSiteToPolygonWithCheck(site, leftPolygon); }
// /// <summary> // /// Testing that s in inside of the circumcircle of (p,q,r). // /// The good explanation of this test is in // /// "Guibas, Stolfi,"Primitives for the Manipulation of General Subdivisions and the Computation of Voronoi Diagrams // /// // /// </summary> // /// <param name="s"></param> // /// <param name="p"></param> // /// <param name="q"></param> // /// <param name="r"></param> // /// <param name="ccc"></param> // /// <returns></returns> // public static bool InCircle0(CdtSite s, CdtSite p, CdtSite q, CdtSite r, double ccc) { // Debug.Assert(Point.GetTriangleOrientationWithNoEpsilon(p.Point, q.Point, r.Point) == TriangleOrientation.Counterclockwise); // /* // * det(p.x,p.y, p*p,1 // * q.x,q.y, q*q,1 // * r.x,r.y, r*r,1 // * s.x,s.y, s*s,1) > 0 // */ // // var a = p.Point.X; // var b = p.Point.Y; // var c = a*a + b*b; // var d = q.Point.X; // var e = q.Point.Y; // var f = d*d + e*e; // var g = r.Point.X; // var h = r.Point.Y; // var k = g*g + h*h; // var l = s.Point.X; // var m = s.Point.Y; // var n = l*l + m*m; // // // // double ddd = ccc - ((a - d) * (h * n - k * m) + (e - b) * (g * n - k * l) + (c - f) * (g * m - h * l) + // (g - l) * (b * f - c * e) + (m - h) * (a * f - c * d) + (k - n) * (a * e - b * d)); // if (Math.Abs(ddd) > diff) { // diff = ddd; // Console.WriteLine(diff); // } // return (a - d)*(h*n - k*m) + (e - b)*(g*n - k*l) + (c - f)*(g*m - h*l) + // (g - l)*(b*f - c*e) + (m - h)*(a*f - c*d) + (k - n)*(a*e - b*d) > ApproximateComparer.Tolerance; // } /// <summary> /// Testing that d in inside of the circumcircle of (a,b,c). /// The good explanation of this test is in /// "Guibas, Stolfi,"Primitives for the Manipulation of General Subdivisions and the Computation of Voronoi Diagrams /// /// </summary> /// <param name="d"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> /// <returns></returns> public static bool InCircle(CdtSite d, CdtSite a, CdtSite b, CdtSite c) { Debug.Assert(Point.GetTriangleOrientationWithNoEpsilon(a.Point, b.Point, c.Point) == TriangleOrientation.Counterclockwise); /* * | ax-dx ay-dy (ax-dx)^2+(ay-dy)^2| * | bx-dx by-dy (bx-dx)^2+(by-dy)^2| * | cx-dx cy-dy (cx-dx)^2+(cy-dy)^2| */ var axdx = a.Point.X - d.Point.X; var aydy = a.Point.Y - d.Point.Y; var bxdx = b.Point.X - d.Point.X; var bydy = b.Point.Y - d.Point.Y; var cxdx = c.Point.X - d.Point.X; var cydy = c.Point.Y - d.Point.Y; var t0 = axdx * axdx + aydy * aydy; var t1 = bxdx * bxdx + bydy * bydy; var t2 = cxdx * cxdx + cydy * cydy; return axdx * (bydy * t2 - cydy * t1) - bxdx * (aydy * t2 - cydy * t0) + cxdx * (aydy * t1 - bydy * t0) > ApproximateComparer.Tolerance; }
static bool IsIllegal(CdtSite pi, CdtSite a, CdtSite b, CdtSite c) { return InCone(pi, a, b, c) && InCircle(pi, a, b, c); }
// /// <summary> // /// returns CdtEdges crossed by the segment a.Point, b.Point // /// </summary> // /// <param name="prevA">if prevA is not a null, that means the path is passing through prevA and might need to include // /// the edge containing a.Point if such exists</param> // /// <param name="a"></param> // /// <param name="b"></param> // /// <returns></returns> // internal IEnumerable<CdtEdge> GetCdtEdgesCrossedBySegment(PolylinePoint prevA, PolylinePoint a, PolylinePoint b) { // count++; // if (dd) { // var l = new List<DebugCurve> { // new DebugCurve("red", new Ellipse(5, 5, a.Point)), // new DebugCurve("blue", new Ellipse(5, 5, b.Point)), // new DebugCurve("blue", new LineSegment(a.Point, b.Point)) // }; // // l.AddRange( // GetTriangles().Select( // tr => new DebugCurve(100, 1, "green", new Polyline(tr.Sites.Select(v => v.Point)) {Closed = true}))); // LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(l); // // } // var ret = new List<CdtEdge>(); // CdtEdge piercedEdge; // CdtTriangle t = GetFirstTriangleAndPiercedEdge(a, b, out piercedEdge); // if (ProperCrossing(a, b, piercedEdge)) // ret.Add(piercedEdge); // // ret.AddRange(ContinueThreadingThroughTriangles(a,b,t, piercedEdge)); // // return ret; // } /* static bool ProperCrossing(Point a, Point b, CdtEdge cdtEdge) { return cdtEdge != null && cdtEdge.upperSite.Owner != cdtEdge.lowerSite.Owner && CrossEdgeInterior(cdtEdge, a, b); } */ // static int count; // static bool db { get { return count == 125; }} internal IEnumerable<CdtEdge> ThreadEdgeThroughTriangles(CdtSite startSite, Point end) { CdtEdge piercedEdge; var triangle = FindFirstPiercedTriangle(startSite, end, out piercedEdge); if (triangle == null) yield break; var start = startSite.Point; foreach (var cdtEdge in ThreadThroughTriangles(start, end, triangle, piercedEdge)) yield return cdtEdge; }
CdtTriangle FindFirstPiercedTriangle(CdtSite startSite, Point target, out CdtEdge piercedEdge) { if (startSite != null) { foreach (var t in startSite.Triangles) { piercedEdge = GetPiercedEdgeInSiteTriangle(t, startSite, target); if (piercedEdge != null) if (!PointIsInsideOfTriangle(target, t)) return t; } } piercedEdge = null; return null; }
void LegalizeEdgeForOtherCwTriangle(CdtSite pi, CdtEdge edge) { var i=edge.CwTriangle.Edges.Index(edge); // if (i == -1) // { // List<DebugCurve> ls = new List<DebugCurve>(); // ls.Add(new DebugCurve(new Ellipse(2, 2, pi.Point))); // for (int j = 0; j < 3; j++) // { // var ee = edge.CwTriangle.Edges[j]; // ls.Add(new DebugCurve(100,1, j == i ? "red" : "blue", new LineSegment(ee.upperSite.Point, ee.lowerSite.Point))); // } // ls.Add(new DebugCurve("purple", new LineSegment(edge.upperSite.Point, edge.lowerSite.Point))); // // LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(ls); // } Debug.Assert(i>=0); if (IsIllegal(pi, edge.upperSite, edge.CwTriangle.Sites[i + 2], edge.lowerSite)) { //ShowIllegalEdge(edge, i, pi); CdtEdge e = Flip(pi, edge); LegalizeEdge(pi, e.CwTriangle.OppositeEdge(pi) ); LegalizeEdge(pi, e.CcwTriangle.OppositeEdge(pi)); } }
/// <summary> /// compare first y then -x coordinates /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns>1 if a is above b, 0 if points are the same and -1 if a is below b</returns> static internal int Above(CdtSite a, CdtSite b) { var del = a.Point.Y - b.Point.Y; if (del > 0) return 1; if (del < 0) return -1; del = a.Point.X - b.Point.X; return del > 0 ? -1 : (del < 0 ? 1 : 0); //for a horizontal edge the point with the smaller X is the upper point }
void CheckSite(Point end, Set <Polyline> obstaclesToIgnore, HashSet <CdtSite> checkedSites, CdtSite s, double upperBound, Dictionary <Polyline, double> obstacles) { if (!checkedSites.Add(s)) { return; } var poly = (Polyline)s.Owner; if (obstaclesToIgnore.Contains(poly)) { return; } //distance to the obstacle PolylinePoint pp = FindPolylinePoint(poly, s.Point); double par; double d12 = Point.DistToLineSegment(end, pp.Point, pp.NextOnPolyline.Point, out par); double d22 = Point.DistToLineSegment(end, pp.Point, pp.PrevOnPolyline.Point, out par); double dist = Math.Min(d12, d22); if (dist > upperBound) { return; } double currentValue; if (!obstacles.TryGetValue(poly, out currentValue)) { obstacles.Add(poly, dist); } else if (currentValue > dist) { obstacles[poly] = dist; } }
static CdtEdge CreateEdgeOnOrderedCouple(CdtSite upperPoint, CdtSite lowerPoint) { Debug.Assert(Above(upperPoint.Point, lowerPoint.Point) == 1); return(new CdtEdge(upperPoint, lowerPoint)); }
static bool LocalInCircle(CdtSite v, CdtSite a, CdtSite b, CdtSite c, bool reverseTrangleWhenCompare) { return(reverseTrangleWhenCompare ? CdtSweeper.InCircle(v, a, c, b) : CdtSweeper.InCircle(v, a, b, c)); }
static CdtEdge Flip(CdtSite pi, CdtEdge edge) { Debug.Assert(!edge.IsAdjacent(pi)); Debug.Assert(edge.CcwTriangle.Contains(pi) || edge.CwTriangle.Contains(pi)); //get surrounding data CdtTriangle t, ot; if (edge.CcwTriangle.Contains(pi)) { t = edge.CcwTriangle; ot = edge.CwTriangle; } else { t = edge.CwTriangle; ot = edge.CcwTriangle; } Debug.Assert(t.Contains(pi)); var eIndex = t.Edges.Index(edge); var eOtherIndex = ot.Edges.Index(edge); Debug.Assert(eIndex > -1 && eOtherIndex > -1); var pl = ot.Sites[eOtherIndex + 2]; var edgeBeforPi = t.Edges[eIndex + 1]; var edgeBeforPl = ot.Edges[eOtherIndex + 1]; //changing t var newEdge = Cdt.GetOrCreateEdge(pi, pl); t.Sites[eIndex + 1] = pl; t.Edges[eIndex] = edgeBeforPl; t.Edges[eIndex + 1] = newEdge; //changing ot ot.Sites[eOtherIndex + 1] = pi; ot.Edges[eOtherIndex] = edgeBeforPi; ot.Edges[eOtherIndex + 1] = newEdge; //orient the new edge and the two edges that move from one triangle to another if (edgeBeforPl.lowerSite == pl) edgeBeforPl.CcwTriangle = t; else edgeBeforPl.CwTriangle = t; if (edgeBeforPi.lowerSite == pi) edgeBeforPi.CcwTriangle = ot; else edgeBeforPi.CwTriangle = ot; if (newEdge.upperSite == pi) { newEdge.CcwTriangle = ot; newEdge.CwTriangle = t; } else { newEdge.CcwTriangle = t; newEdge.CwTriangle = ot; } Debug.Assert(CheckTriangle(t)); Debug.Assert(CheckTriangle(t)); //ShowFlip(pi, t, ot); edge.upperSite.Edges.Remove(edge); //forget the edge return newEdge; }
CdtEdge GetPiercedEdgeInSiteTriangle(CdtTriangle t, CdtSite site, Point target) { var e = t.OppositeEdge(site); return PiercedEdgeQuery(e, site.Point, target, t); }
/// <summary> /// /// </summary> /// <param name="pi"></param> /// <param name="a">point on left side of the cone</param> /// <param name="b">the apex</param> /// <param name="c">point on the right side of the cone</param> static bool InCone(CdtSite pi, CdtSite a, CdtSite b, CdtSite c) { Debug.Assert(Point.GetTriangleOrientationWithNoEpsilon(a.Point,b.Point,c.Point)==TriangleOrientation.Counterclockwise); return Point.GetTriangleOrientationWithNoEpsilon(a.Point, pi.Point, b.Point) == TriangleOrientation.Clockwise && Point.GetTriangleOrientationWithNoEpsilon(b.Point, pi.Point, c.Point) == TriangleOrientation.Clockwise; }
void ProjectToFront(CdtSite site, out RBNode<CdtFrontElement> frontElement) { frontElement = front.FindLast(s => s.X <= site.Point.X); }
/// <summary> /// in the trianlge, which is always oriented counterclockwise, the edge starts at site /// </summary> /// <param name="site"></param> /// <param name="edge"></param> void BindEdgeToTriangle(CdtSite site, CdtEdge edge) { if (site == edge.upperSite) edge.CcwTriangle = this; else edge.CwTriangle = this; }
void AddP1AndP2() { var box = Rectangle.CreateAnEmptyBox(); foreach (var site in PointsToSites.Keys) box.Add(site); var delx = box.Width / 3; var dely = box.Height / 3; P1 = new CdtSite(box.LeftBottom + new Point(-delx, -dely)); P2 = new CdtSite(box.RightBottom + new Point(delx, -dely)); }
internal bool Contains(CdtSite cdtSite) { return(Sites.Contains(cdtSite)); }
static void ShowFlip(CdtSite pi, CdtTriangle t, CdtTriangle ot) { List<DebugCurve> ls=new List<DebugCurve>(); ls.Add(new DebugCurve(new Ellipse(2,2, pi.Point))); for(int i=0;i<3;i++) { var e=t.Edges[i]; ls.Add(new DebugCurve(100, 1, "red", new LineSegment(e.upperSite.Point,e.lowerSite.Point))); } for (int i = 0; i < 3; i++) { var e = ot.Edges[i]; ls.Add(new DebugCurve(100, 1, "blue", new LineSegment(e.upperSite.Point, e.lowerSite.Point))); } ls.Add(new DebugCurve(Circumcircle(t.Sites[0].Point, t.Sites[1].Point, t.Sites[2].Point))); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(ls); }
void AddSiteToRightPolygon(CdtSite site) { AddSiteToPolygonWithCheck(site, rightPolygon); }
void LegalizeEdgeForOtherCcwTriangle(CdtSite pi, CdtEdge edge) { var i = edge.CcwTriangle.Edges.Index(edge); if (IsIllegal(pi, edge.lowerSite, edge.CcwTriangle.Sites[i + 2], edge.upperSite)) { CdtEdge e = Flip(pi, edge); LegalizeEdge(pi, e.CwTriangle.OppositeEdge(pi)); LegalizeEdge(pi, e.CcwTriangle.OppositeEdge(pi)); } }
static internal CdtEdge GetOrCreateEdge(CdtSite a, CdtSite b) { if (Above(a.Point, b.Point) == 1) { var e = a.EdgeBetweenUpperSiteAndLowerSite(b); if (e != null) return e; return CreateEdgeOnOrderedCouple(a, b); } else { var e = b.EdgeBetweenUpperSiteAndLowerSite(a); if (e != null) return e; return CreateEdgeOnOrderedCouple(b, a); } }
static CdtEdge CreateEdgeOnOrderedCouple(CdtSite upperPoint, CdtSite lowerPoint) { Debug.Assert(Above(upperPoint.Point, lowerPoint.Point) == 1); return new CdtEdge(upperPoint, lowerPoint); }
static int OnComparison(CdtSite a, CdtSite b) { return(Above(a.Point, b.Point)); }
static int OnComparison(CdtSite a, CdtSite b) { return Above(a.Point, b.Point); }
void TriangulatePolygon(int start, int end, List <CdtSite> polygon, CdtSite a, CdtSite b, bool reverseTrangleWhenCompare) { // if(CdtSweeper.db) // CdtSweeper.ShowFront(triangles,front, Enumerable.Range(start, end-start+1).Select(i=> new Ellipse(10,10,polygon[i].Point)).ToArray(), new[]{new LineSegment(a.Point,b.Point)}); var c = polygon[start]; int cIndex = start; for (int i = start + 1; i <= end; i++) { var v = polygon[i]; if (LocalInCircle(v, a, b, c, reverseTrangleWhenCompare)) { cIndex = i; c = v; } } var t = new CdtTriangle(a, b, c, createEdgeDelegate); triangles.Insert(t); addedTriangles.Add(t); if (start < cIndex) { TriangulatePolygon(start, cIndex - 1, polygon, a, c, reverseTrangleWhenCompare); } if (cIndex < end) { TriangulatePolygon(cIndex + 1, end, polygon, c, b, reverseTrangleWhenCompare); } }
List<DebugCurve> ShowIllegalEdge(CdtEdge edge, CdtSite pi, int i) { List<DebugCurve> ls = new List<DebugCurve>(); ls.Add(new DebugCurve(new Ellipse(2, 2, pi.Point))); for (int j = 0; j < 3; j++) { var ee = edge.CcwTriangle.Edges[j]; ls.Add(new DebugCurve(j == i ? "red" : "blue", new LineSegment(ee.upperSite.Point, ee.lowerSite.Point))); } ls.Add(new DebugCurve(100,1, "black", Circumcircle(edge.CcwTriangle.Sites[0].Point,edge.CcwTriangle.Sites[1].Point,edge.CcwTriangle.Sites[2].Point))); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(ls); return ls; }