public Polygon GetPolygon(int edgeSubdivisions, float curvature) { Connector connector = new Connector (); for (int k=0; k<segments.Count; k++) { Segment s = segments [k]; if (!s.deleted) { if (edgeSubdivisions>1) { connector.AddRange (s.Subdivide(edgeSubdivisions, curvature)); } else { connector.Add (s); } } } return connector.ToPolygonFromLargestLineStrip (); }
public Polygon GetPolygon(int edgeSubdivisions, float curvature) { Connector connector = new Connector(); for (int k = 0; k < segments.Count; k++) { Segment s = segments [k]; if (!s.deleted) { if (edgeSubdivisions > 1) { connector.AddRange(s.Subdivide(edgeSubdivisions, curvature)); } else { connector.Add(s); } } } return(connector.ToPolygonFromLargestLineStrip()); }
Polygon ComputeInternal(PolygonOp operation) { Polygon result = null; sortedEvents = new List <SweepEvent>(); // Init event queue eventQueue = new EventQueue(); // Test 1 for trivial result case if (subject.contours.Count * clipping.contours.Count == 0) { if (operation == PolygonOp.DIFFERENCE) { result = subject; } else if (operation == PolygonOp.UNION || operation == PolygonOp.XOR) { result = (subject.contours.Count == 0) ? clipping : subject; } return(result); } // Test 2 for trivial result case Rectangle subjectBB = subject.boundingBox; Rectangle clippingBB = clipping.boundingBox; if (!subjectBB.Intersects(clippingBB)) { if (operation == PolygonOp.DIFFERENCE) { result = subject; } if (operation == PolygonOp.UNION || operation == PolygonOp.XOR) { result = subject; foreach (Contour c in clipping.contours) { result.AddContour(c); } } return(result); } // Add each segment to the eventQueue, sorted from left to right. for (int k = 0; k < subject.contours.Count; k++) { Contour sCont = subject.contours[k]; int sContPointsCount = sCont.points.Count; for (int pParse1 = 0; pParse1 < sContPointsCount; pParse1++) { ProcessSegment(sCont.GetSegment(pParse1), PolygonType.SUBJECT); } } for (int k = 0; k < clipping.contours.Count; k++) { Contour cCont = clipping.contours[k]; int cContPointsCount = cCont.points.Count; for (int pParse2 = 0; pParse2 < cContPointsCount; pParse2++) { ProcessSegment(cCont.GetSegment(pParse2), PolygonType.CLIPPING); } } Connector connector = new Connector(); // This is the SweepLine. That is, we go through all the polygon edges // by sweeping from left to right. SweepEventSet S = new SweepEventSet(); double MINMAX_X = Math.Min(subjectBB.right, clippingBB.right) + Point.PRECISION; SweepEvent prev, next; int panicCounter = 0; // This is a safety check to prevent infinite loops (very rare but could happen due to floating-point issues with a high number of points) while (!eventQueue.isEmpty) { if (panicCounter++ > 10000) { Debug.Log("PANIC!"); break; } prev = null; next = null; SweepEvent e = eventQueue.Dequeue(); if ((operation == PolygonOp.INTERSECTION && e.p.x > MINMAX_X) || (operation == PolygonOp.DIFFERENCE && e.p.x > subjectBB.right + Point.PRECISION)) { return(connector.ToPolygonFromLargestLineStrip()); } if (operation == PolygonOp.UNION && e.p.x > MINMAX_X) { // add all the non-processed line segments to the result if (!e.isLeft) { connector.Add(e.segment); } while (!eventQueue.isEmpty) { e = eventQueue.Dequeue(); if (!e.isLeft) { connector.Add(e.segment); } } return(connector.ToPolygonFromLargestLineStrip()); } if (e.isLeft) // the line segment must be inserted into S { int pos = S.Insert(e); prev = (pos > 0) ? S.eventSet[pos - 1] : null; next = (pos < S.eventSet.Count - 1) ? S.eventSet[pos + 1] : null; if (prev == null) { e.inside = e.inOut = false; } else if (prev.edgeType != EdgeType.NORMAL) { if (pos - 2 < 0) // e overlaps with prev // Not sure how to handle the case when pos - 2 < 0, but judging // from the C++ implementation this looks like how it should be handled. { e.inside = e.inOut = false; if (prev.polygonType != e.polygonType) { e.inside = true; } else { e.inOut = true; } } else { SweepEvent prevTwo = S.eventSet[pos - 2]; if (prev.polygonType == e.polygonType) { e.inOut = !prev.inOut; e.inside = !prevTwo.inOut; } else { e.inOut = !prevTwo.inOut; e.inside = !prev.inOut; } } } else if (e.polygonType == prev.polygonType) { e.inside = prev.inside; e.inOut = !prev.inOut; } else { e.inside = !prev.inOut; e.inOut = prev.inside; } // Process a possible intersection between "e" and its next neighbor in S if (next != null) { PossibleIntersection(e, next); } // Process a possible intersection between "e" and its previous neighbor in S if (prev != null) { PossibleIntersection(prev, e); } } else // the line segment must be removed from S // Get the next and previous line segments to "e" in S { int otherPos = -1; for (int evt = 0; evt < S.eventSet.Count; evt++) { if (e.otherSE.Equals(S.eventSet[evt])) { otherPos = evt; break; } } if (otherPos != -1) { prev = (otherPos > 0) ? S.eventSet[otherPos - 1] : null; next = (otherPos < S.eventSet.Count - 1) ? S.eventSet[otherPos + 1] : null; } switch (e.edgeType) { case EdgeType.NORMAL: switch (operation) { case PolygonOp.INTERSECTION: if (e.otherSE.inside) { connector.Add(e.segment); } break; case PolygonOp.UNION: if (!e.otherSE.inside) { connector.Add(e.segment); } break; case PolygonOp.DIFFERENCE: if ((e.polygonType == PolygonType.SUBJECT && !e.otherSE.inside) || (e.polygonType == PolygonType.CLIPPING && e.otherSE.inside)) { connector.Add(e.segment); } break; case PolygonOp.XOR: connector.Add(e.segment); break; } break; case EdgeType.SAME_TRANSITION: if (operation == PolygonOp.INTERSECTION || operation == PolygonOp.UNION) { connector.Add(e.segment); } break; case EdgeType.DIFFERENT_TRANSITION: if (operation == PolygonOp.DIFFERENCE) { connector.Add(e.segment); } break; } if (otherPos != -1) { S.Remove(S.eventSet[otherPos]); } if (next != null && prev != null) { PossibleIntersection(prev, next); } } } return(connector.ToPolygonFromLargestLineStrip()); }
void SurfaceSegmentForSurface(Segment s, Connector connector) { // trace the line until roughness is exceeded double dist = s.magnitude; // (float)Math.Sqrt ( (p1.x-p0.x)*(p1.x-p0.x) + (p1.y-p0.y)*(p1.y-p0.y)); Point direction = s.end - s.start; int numSteps = (int)(dist / MIN_VERTEX_DISTANCE); Point t0 = s.start; float h0 = _terrain.SampleHeight(transform.TransformPoint(t0.vector3)); Point ta = t0; float h1; for (int i=1;i<numSteps;i++) { Point t1 = s.start + direction * i / numSteps; h1 = _terrain.SampleHeight(transform.TransformPoint(t1.vector3)); if (h0 < h1 || h0-h1 > effectiveRoughness) { //-effectiveRoughness) { if (t0!=ta) { Segment s0 = new Segment(t0, ta, s.border); connector.Add (s0); Segment s1 = new Segment(ta, t1, s.border); connector.Add (s1); } else { Segment s0 = new Segment(t0, t1, s.border); connector.Add (s0); } t0 = t1; h0 = h1; } ta = t1; } // Add last point Segment finalSeg = new Segment(t0, s.end, s.border); connector.Add (finalSeg); }
Polygon ComputeInternal(PolygonOp operation) { Polygon result = null; sortedEvents = new List<SweepEvent>(); // Init event queue eventQueue = new EventQueue(); // Test 1 for trivial result case if (subject.contours.Count * clipping.contours.Count == 0) { if (operation == PolygonOp.DIFFERENCE) result = subject; else if (operation == PolygonOp.UNION || operation == PolygonOp.XOR) result = (subject.contours.Count == 0) ? clipping : subject; return result; } // Test 2 for trivial result case Rectangle subjectBB = subject.boundingBox; Rectangle clippingBB = clipping.boundingBox; if (!subjectBB.Intersects(clippingBB)) { if (operation == PolygonOp.DIFFERENCE) result = subject; if (operation == PolygonOp.UNION || operation == PolygonOp.XOR) { result = subject; foreach(Contour c in clipping.contours) result.AddContour(c); } return result; } // Add each segment to the eventQueue, sorted from left to right. for(int k=0;k<subject.contours.Count;k++) { Contour sCont = subject.contours[k]; for (int pParse1=0;pParse1<sCont.points.Count;pParse1++) ProcessSegment(sCont.GetSegment(pParse1), PolygonType.SUBJECT); } for(int k=0;k<clipping.contours.Count;k++) { Contour cCont = clipping.contours[k]; for (int pParse2=0;pParse2<cCont.points.Count;pParse2++) ProcessSegment(cCont.GetSegment(pParse2), PolygonType.CLIPPING); } Connector connector = new Connector(); // This is the SweepLine. That is, we go through all the polygon edges // by sweeping from left to right. SweepEventSet S = new SweepEventSet(); double MINMAX_X = Math.Min(subjectBB.right, clippingBB.right) + Point.PRECISION; SweepEvent prev, next; int panicCounter = 0; // This is a safety check to prevent infinite loops (very rare but could happen due to floating-point issues with a high number of points) while (!eventQueue.isEmpty) { if (panicCounter++>10000) { Debug.Log("PANIC!"); break; } prev = null; next = null; SweepEvent e = eventQueue.Dequeue(); if ((operation == PolygonOp.INTERSECTION && e.p.x > MINMAX_X) || (operation == PolygonOp.DIFFERENCE && e.p.x > subjectBB.right + Point.PRECISION)) return connector.ToPolygonFromLargestLineStrip(); if (operation == PolygonOp.UNION && e.p.x > MINMAX_X) { // add all the non-processed line segments to the result if (!e.isLeft) connector.Add(e.segment); while (!eventQueue.isEmpty) { e = eventQueue.Dequeue(); if (!e.isLeft) connector.Add(e.segment); } return connector.ToPolygonFromLargestLineStrip(); } if (e.isLeft) { // the line segment must be inserted into S int pos = S.Insert(e); prev = (pos > 0) ? S.eventSet[pos - 1] : null; next = (pos < S.eventSet.Count - 1) ? S.eventSet[pos + 1] : null; if (prev == null) { e.inside = e.inOut = false; } else if (prev.edgeType != EdgeType.NORMAL) { if (pos - 2 < 0) { // e overlaps with prev // Not sure how to handle the case when pos - 2 < 0, but judging // from the C++ implementation this looks like how it should be handled. e.inside = e.inOut = false; if (prev.polygonType != e.polygonType) e.inside = true; else e.inOut = true; } else { SweepEvent prevTwo = S.eventSet[pos - 2]; if (prev.polygonType == e.polygonType) { e.inOut = !prev.inOut; e.inside = !prevTwo.inOut; } else { e.inOut = !prevTwo.inOut; e.inside = !prev.inOut; } } } else if (e.polygonType == prev.polygonType) { e.inside = prev.inside; e.inOut = !prev.inOut; } else { e.inside = !prev.inOut; e.inOut = prev.inside; } // Process a possible intersection between "e" and its next neighbor in S if (next != null) PossibleIntersection(e, next); // Process a possible intersection between "e" and its previous neighbor in S if (prev != null) PossibleIntersection(prev, e); } else { // the line segment must be removed from S // Get the next and previous line segments to "e" in S int otherPos = -1; for (int evt=0;evt<S.eventSet.Count;evt++) { if (e.otherSE.Equals(S.eventSet[evt])) { otherPos = evt; break; } } if (otherPos != -1) { prev = (otherPos > 0) ? S.eventSet[otherPos - 1] : null; next = (otherPos < S.eventSet.Count - 1) ? S.eventSet[otherPos + 1] : null; } switch (e.edgeType) { case EdgeType.NORMAL: switch (operation) { case PolygonOp.INTERSECTION: if (e.otherSE.inside) connector.Add(e.segment); break; case PolygonOp.UNION: if (!e.otherSE.inside) connector.Add(e.segment); break; case PolygonOp.DIFFERENCE: if ((e.polygonType == PolygonType.SUBJECT && !e.otherSE.inside) || (e.polygonType == PolygonType.CLIPPING && e.otherSE.inside)) connector.Add(e.segment); break; case PolygonOp.XOR: connector.Add (e.segment); break; } break; case EdgeType.SAME_TRANSITION: if (operation == PolygonOp.INTERSECTION || operation == PolygonOp.UNION) connector.Add(e.segment); break; case EdgeType.DIFFERENT_TRANSITION: if (operation == PolygonOp.DIFFERENCE) connector.Add(e.segment); break; } if (otherPos != -1) S.Remove(S.eventSet[otherPos]); if (next != null && prev != null) PossibleIntersection(prev, next); } } return connector.ToPolygonFromLargestLineStrip(); }