/// <summary>Adds a new segment to this multipath.</summary> /// <param name="segment">The segment to be added to this mulitpath.</param> /// <param name="bStartNewPath">TRUE if a new path will be added.</param> public virtual void AddSegment(com.epl.geometry.Segment segment, bool bStartNewPath) { m_impl.AddSegment(segment, bStartNewPath); }
internal virtual com.epl.geometry.Geometry TryFastIntersectPolylinePolygon_(com.epl.geometry.Polyline polyline, com.epl.geometry.Polygon polygon) { com.epl.geometry.MultiPathImpl polylineImpl = (com.epl.geometry.MultiPathImpl)polyline._getImpl(); com.epl.geometry.MultiPathImpl polygonImpl = (com.epl.geometry.MultiPathImpl)polygon._getImpl(); double tolerance = com.epl.geometry.InternalUtils.CalculateToleranceFromGeometry(m_spatial_reference, polygon, false); com.epl.geometry.Envelope2D clipEnvelope = new com.epl.geometry.Envelope2D(); { polygonImpl.QueryEnvelope2D(clipEnvelope); com.epl.geometry.Envelope2D env1 = new com.epl.geometry.Envelope2D(); polylineImpl.QueryEnvelope2D(env1); env1.Inflate(2.0 * tolerance, 2.0 * tolerance); clipEnvelope.Intersect(env1); System.Diagnostics.Debug.Assert((!clipEnvelope.IsEmpty())); } clipEnvelope.Inflate(10 * tolerance, 10 * tolerance); if (true) { double tol = 0; com.epl.geometry.Geometry clippedPolyline = com.epl.geometry.Clipper.Clip(polyline, clipEnvelope, tol, 0.0); polyline = (com.epl.geometry.Polyline)clippedPolyline; polylineImpl = (com.epl.geometry.MultiPathImpl)polyline._getImpl(); } com.epl.geometry.AttributeStreamOfInt32 clipResult = new com.epl.geometry.AttributeStreamOfInt32(0); int unresolvedSegments = -1; com.epl.geometry.GeometryAccelerators accel = polygonImpl._getAccelerators(); if (accel != null) { com.epl.geometry.RasterizedGeometry2D rgeom = accel.GetRasterizedGeometry(); if (rgeom != null) { unresolvedSegments = 0; clipResult.Reserve(polylineImpl.GetPointCount() + polylineImpl.GetPathCount()); com.epl.geometry.Envelope2D seg_env = new com.epl.geometry.Envelope2D(); com.epl.geometry.SegmentIteratorImpl iter = polylineImpl.QuerySegmentIterator(); while (iter.NextPath()) { while (iter.HasNextSegment()) { com.epl.geometry.Segment seg = iter.NextSegment(); seg.QueryEnvelope2D(seg_env); com.epl.geometry.RasterizedGeometry2D.HitType hit = rgeom.QueryEnvelopeInGeometry(seg_env); if (hit == com.epl.geometry.RasterizedGeometry2D.HitType.Inside) { clipResult.Add(1); } else { if (hit == com.epl.geometry.RasterizedGeometry2D.HitType.Outside) { clipResult.Add(0); } else { clipResult.Add(-1); unresolvedSegments++; } } } } } } if (polygon.GetPointCount() > 5) { double tol = 0; com.epl.geometry.Geometry clippedPolygon = com.epl.geometry.Clipper.Clip(polygon, clipEnvelope, tol, 0.0); polygon = (com.epl.geometry.Polygon)clippedPolygon; polygonImpl = (com.epl.geometry.MultiPathImpl)polygon._getImpl(); accel = polygonImpl._getAccelerators(); } //update accelerators if (unresolvedSegments < 0) { unresolvedSegments = polylineImpl.GetSegmentCount(); } // Some heuristics to decide if it makes sense to go with fast intersect // vs going with the regular planesweep. double totalPoints = (double)(polylineImpl.GetPointCount() + polygonImpl.GetPointCount()); double thisAlgorithmComplexity = ((double)unresolvedSegments * polygonImpl.GetPointCount()); // assume the worst case. double planesweepComplexity = System.Math.Log(totalPoints) * totalPoints; double empiricConstantFactorPlaneSweep = 4; if (thisAlgorithmComplexity > planesweepComplexity * empiricConstantFactorPlaneSweep) { // Based on the number of input points, we deduced that the // plansweep performance should be better than the brute force // performance. return null; } // resort to planesweep if quadtree does not help com.epl.geometry.QuadTreeImpl polygonQuadTree = null; com.epl.geometry.SegmentIteratorImpl polygonIter = polygonImpl.QuerySegmentIterator(); // Some logic to decide if it makes sense to build a quadtree on the // polygon segments if (accel != null && accel.GetQuadTree() != null) { polygonQuadTree = accel.GetQuadTree(); } if (polygonQuadTree == null && polygonImpl.GetPointCount() > 20) { polygonQuadTree = com.epl.geometry.InternalUtils.BuildQuadTree(polygonImpl); } com.epl.geometry.Polyline result_polyline = (com.epl.geometry.Polyline)polyline.CreateInstance(); com.epl.geometry.MultiPathImpl resultPolylineImpl = (com.epl.geometry.MultiPathImpl)result_polyline._getImpl(); com.epl.geometry.QuadTreeImpl.QuadTreeIteratorImpl qIter = null; com.epl.geometry.SegmentIteratorImpl polylineIter = polylineImpl.QuerySegmentIterator(); double[] @params = new double[9]; com.epl.geometry.AttributeStreamOfDbl intersections = new com.epl.geometry.AttributeStreamOfDbl(0); com.epl.geometry.SegmentBuffer segmentBuffer = new com.epl.geometry.SegmentBuffer(); int start_index = -1; int inCount = 0; int segIndex = 0; bool bOptimized = clipResult.Size() > 0; // The algorithm is like that: // Loop through all the segments of the polyline. // For each polyline segment, intersect it with each of the polygon // segments. // If no intersections found then, // If the polyline segment is completely inside, it is added to the // result polyline. // If it is outside, it is thrown out. // If it intersects, then cut the polyline segment to pieces and test // each part of the intersected result. // The cut pieces will either have one point inside, or one point // outside, or the middle point inside/outside. // int polylinePathIndex = -1; while (polylineIter.NextPath()) { polylinePathIndex = polylineIter.GetPathIndex(); int stateNewPath = 0; int stateAddSegment = 1; int stateManySegments = 2; int stateManySegmentsContinuePath = 2; int stateManySegmentsNewPath = 3; int state = stateNewPath; start_index = -1; inCount = 0; while (polylineIter.HasNextSegment()) { int clipStatus = bOptimized ? (int)clipResult.Get(segIndex) : -1; segIndex++; com.epl.geometry.Segment polylineSeg = polylineIter.NextSegment(); if (clipStatus < 0) { System.Diagnostics.Debug.Assert((clipStatus == -1)); // Analyse polyline segment for intersection with the // polygon. if (polygonQuadTree != null) { if (qIter == null) { qIter = polygonQuadTree.GetIterator(polylineSeg, tolerance); } else { qIter.ResetIterator(polylineSeg, tolerance); } int path_index = -1; for (int ind = qIter.Next(); ind != -1; ind = qIter.Next()) { polygonIter.ResetToVertex(polygonQuadTree.GetElement(ind)); // path_index path_index = polygonIter.GetPathIndex(); com.epl.geometry.Segment polygonSeg = polygonIter.NextSegment(); // intersect polylineSeg and polygonSeg. int count = polylineSeg.Intersect(polygonSeg, null, @params, null, tolerance); for (int i = 0; i < count; i++) { intersections.Add(@params[i]); } } } else { // no quadtree built polygonIter.ResetToFirstPath(); while (polygonIter.NextPath()) { while (polygonIter.HasNextSegment()) { com.epl.geometry.Segment polygonSeg = polygonIter.NextSegment(); // intersect polylineSeg and polygonSeg. int count = polylineSeg.Intersect(polygonSeg, null, @params, null, tolerance); for (int i = 0; i < count; i++) { intersections.Add(@params[i]); } } } } if (intersections.Size() > 0) { // intersections detected. intersections.Sort(0, intersections.Size()); // std::sort(intersections.begin(), // intersections.end()); double t0 = 0; intersections.Add(1.0); int status = -1; for (int i = 0, n = intersections.Size(); i < n; i++) { double t = intersections.Get(i); if (t == t0) { continue; } bool bWholeSegment = false; com.epl.geometry.Segment resSeg; if (t0 != 0 || t != 1.0) { polylineSeg.Cut(t0, t, segmentBuffer); resSeg = segmentBuffer.Get(); } else { resSeg = polylineSeg; bWholeSegment = true; } if (state >= stateManySegments) { resultPolylineImpl.AddSegmentsFromPath(polylineImpl, polylinePathIndex, start_index, inCount, state == stateManySegmentsNewPath); if (AnalyseClipSegment_(polygon, resSeg.GetStartXY(), tolerance) != 1) { if (AnalyseClipSegment_(polygon, resSeg, tolerance) != 1) { return null; } } //someting went wrong we'll falback to slower but robust planesweep code. resultPolylineImpl.AddSegment(resSeg, false); state = stateAddSegment; inCount = 0; } else { status = AnalyseClipSegment_(polygon, resSeg, tolerance); switch (status) { case 1: { if (!bWholeSegment) { resultPolylineImpl.AddSegment(resSeg, state == stateNewPath); state = stateAddSegment; } else { if (state < stateManySegments) { start_index = polylineIter.GetStartPointIndex() - polylineImpl.GetPathStart(polylinePathIndex); inCount = 1; if (state == stateNewPath) { state = stateManySegmentsNewPath; } else { System.Diagnostics.Debug.Assert((state == stateAddSegment)); state = stateManySegmentsContinuePath; } } else { inCount++; } } break; } case 0: { state = stateNewPath; start_index = -1; inCount = 0; break; } default: { return null; } } } // may happen if a segment // coincides with the border. t0 = t; } } else { clipStatus = AnalyseClipSegment_(polygon, polylineSeg.GetStartXY(), tolerance); // simple // case // no // intersection. // Both // points // must // be // inside. if (clipStatus < 0) { System.Diagnostics.Debug.Assert((clipStatus >= 0)); return null; } // something goes wrong, resort to // planesweep System.Diagnostics.Debug.Assert((AnalyseClipSegment_(polygon, polylineSeg.GetEndXY(), tolerance) == clipStatus)); if (clipStatus == 1) { // the whole segment inside if (state < stateManySegments) { System.Diagnostics.Debug.Assert((inCount == 0)); start_index = polylineIter.GetStartPointIndex() - polylineImpl.GetPathStart(polylinePathIndex); if (state == stateNewPath) { state = stateManySegmentsNewPath; } else { System.Diagnostics.Debug.Assert((state == stateAddSegment)); state = stateManySegmentsContinuePath; } } inCount++; } else { System.Diagnostics.Debug.Assert((state < stateManySegments)); start_index = -1; inCount = 0; } } intersections.Clear(false); } else { // clip status is determined by other means if (clipStatus == 0) { // outside System.Diagnostics.Debug.Assert((AnalyseClipSegment_(polygon, polylineSeg, tolerance) == 0)); System.Diagnostics.Debug.Assert((start_index < 0)); System.Diagnostics.Debug.Assert((inCount == 0)); continue; } if (clipStatus == 1) { System.Diagnostics.Debug.Assert((AnalyseClipSegment_(polygon, polylineSeg, tolerance) == 1)); if (state == stateNewPath) { state = stateManySegmentsNewPath; start_index = polylineIter.GetStartPointIndex() - polylineImpl.GetPathStart(polylinePathIndex); } else { if (state == stateAddSegment) { state = stateManySegmentsContinuePath; start_index = polylineIter.GetStartPointIndex() - polylineImpl.GetPathStart(polylinePathIndex); } else { System.Diagnostics.Debug.Assert((state >= stateManySegments)); } } inCount++; continue; } } } if (state >= stateManySegments) { resultPolylineImpl.AddSegmentsFromPath(polylineImpl, polylinePathIndex, start_index, inCount, state == stateManySegmentsNewPath); start_index = -1; } } return result_polyline; }