internal override void Cut(double t1, double t2, com.epl.geometry.SegmentBuffer subSegmentBuffer) { if (subSegmentBuffer == null) { throw new System.ArgumentException(); } subSegmentBuffer.CreateLine(); // Make sure buffer contains Line class. com.epl.geometry.Segment subSegment = subSegmentBuffer.Get(); subSegment.AssignVertexDescription(m_description); com.epl.geometry.Point2D point = new com.epl.geometry.Point2D(); GetCoord2D(t1, point); subSegment.SetStartXY(point.x, point.y); GetCoord2D(t2, point); subSegment.SetEndXY(point.x, point.y); for (int iattr = 1, nattr = m_description.GetAttributeCount(); iattr < nattr; iattr++) { int semantics = m_description._getSemanticsImpl(iattr); int ncomps = com.epl.geometry.VertexDescription.GetComponentCount(semantics); for (int ordinate = 0; ordinate < ncomps; ordinate++) { double value1 = GetAttributeAsDbl(t1, semantics, ordinate); subSegment.SetStartAttribute(semantics, ordinate, value1); double value2 = GetAttributeAsDbl(t2, semantics, ordinate); subSegment.SetEndAttribute(semantics, ordinate, value2); } } }
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; }
public virtual void Intersect(double tolerance, com.epl.geometry.Point pt_intersector_point, int point_rank, double point_weight, bool b_intersecting) { pt_intersector_point.CopyTo(m_point); if (m_input_segments.Count != 1) { throw com.epl.geometry.GeometryException.GeometryInternalError(); } m_tolerance = tolerance; com.epl.geometry.SegmentIntersector.IntersectionPart part1 = m_input_segments[0]; if (b_intersecting || part1.seg._isIntersectingPoint(pt_intersector_point.GetXY(), tolerance, true)) { if (part1.seg.GetType().Value() == com.epl.geometry.Geometry.GeometryType.Line) { com.epl.geometry.Line line_1 = (com.epl.geometry.Line)(part1.seg); double t1 = line_1.GetClosestCoordinate(pt_intersector_point.GetXY(), false); m_param_1[0] = t1; // For each point of intersection, we calculate a weighted point // based on the ranks and weights of the endpoints and the // interior. int rank1 = part1.rank_interior; double weight1 = 1.0; if (t1 == 0) { rank1 = part1.rank_start; weight1 = part1.weight_start; } else { if (t1 == 1.0) { rank1 = part1.rank_end; weight1 = part1.weight_end; } } int rank2 = point_rank; double weight2 = point_weight; double ptWeight; com.epl.geometry.Point2D pt = new com.epl.geometry.Point2D(); if (rank1 == rank2) { // for equal ranks use weighted sum com.epl.geometry.Point2D pt_1 = new com.epl.geometry.Point2D(); line_1.GetCoord2D(t1, pt_1); com.epl.geometry.Point2D pt_2 = pt_intersector_point.GetXY(); ptWeight = weight1 + weight2; double t = weight2 / ptWeight; com.epl.geometry.MathUtils.Lerp(pt_1, pt_2, t, pt); } else { // for non-equal ranks, the higher rank wins if (rank1 > rank2) { pt = new com.epl.geometry.Point2D(); line_1.GetCoord2D(t1, pt); ptWeight = weight1; } else { pt = pt_intersector_point.GetXY(); ptWeight = weight2; } } // Split the line_1, making sure the endpoints are adusted to // the weighted double t0 = 0; int i0 = -1; int count = 1; for (int i = 0; i <= count; i++) { double t = i < count ? m_param_1[i] : 1.0; if (t != t0) { com.epl.geometry.SegmentBuffer seg_buffer = NewSegmentBuffer_(); line_1.Cut(t0, t, seg_buffer); if (i0 != -1) { seg_buffer.Get().SetStartXY(pt); } if (i != count) { seg_buffer.Get().SetEndXY(pt); } t0 = t; m_result_segments_1.Add(NewIntersectionPart_(seg_buffer.Get())); } i0 = i; } m_point.SetXY(pt); return; } throw com.epl.geometry.GeometryException.GeometryInternalError(); } }
public override com.epl.geometry.Segment Cut(double t1, double t2) { com.epl.geometry.SegmentBuffer segmentBuffer = new com.epl.geometry.SegmentBuffer(); Cut(t1, t2, segmentBuffer); return(segmentBuffer.Get()); }
// Performs the intersection public virtual bool Intersect(double tolerance, bool b_intersecting) { if (m_input_segments.Count != 2) { throw com.epl.geometry.GeometryException.GeometryInternalError(); } m_tolerance = tolerance; double small_tolerance_sqr = com.epl.geometry.MathUtils.Sqr(tolerance * 0.01); bool bigmove = false; com.epl.geometry.SegmentIntersector.IntersectionPart part1 = m_input_segments[0]; com.epl.geometry.SegmentIntersector.IntersectionPart part2 = m_input_segments[1]; if (b_intersecting || (part1.seg._isIntersecting(part2.seg, tolerance, true) & 5) != 0) { if (part1.seg.GetType().Value() == com.epl.geometry.Geometry.GeometryType.Line) { com.epl.geometry.Line line_1 = (com.epl.geometry.Line)part1.seg; if (part2.seg.GetType().Value() == com.epl.geometry.Geometry.GeometryType.Line) { com.epl.geometry.Line line_2 = (com.epl.geometry.Line)part2.seg; int count = com.epl.geometry.Line._intersectLineLine(line_1, line_2, null, m_param_1, m_param_2, tolerance); if (count == 0) { System.Diagnostics.Debug.Assert((count > 0)); throw com.epl.geometry.GeometryException.GeometryInternalError(); } com.epl.geometry.Point2D[] points = new com.epl.geometry.Point2D[9]; for (int i = 0; i < count; i++) { // For each point of intersection, we calculate a // weighted point // based on the ranks and weights of the endpoints and // the interior. double t1 = m_param_1[i]; double t2 = m_param_2[i]; int rank1 = part1.rank_interior; double weight1 = 1.0; if (t1 == 0) { rank1 = part1.rank_start; weight1 = part1.weight_start; } else { if (t1 == 1.0) { rank1 = part1.rank_end; weight1 = part1.weight_end; } } int rank2 = part2.rank_interior; double weight2 = 1.0; if (t2 == 0) { rank2 = part2.rank_start; weight2 = part2.weight_start; } else { if (t2 == 1.0) { rank2 = part2.rank_end; weight2 = part2.weight_end; } } double ptWeight; com.epl.geometry.Point2D pt = new com.epl.geometry.Point2D(); if (rank1 == rank2) { // for equal ranks use weighted sum com.epl.geometry.Point2D pt_1 = new com.epl.geometry.Point2D(); line_1.GetCoord2D(t1, pt_1); com.epl.geometry.Point2D pt_2 = new com.epl.geometry.Point2D(); line_2.GetCoord2D(t2, pt_2); ptWeight = weight1 + weight2; double t = weight2 / ptWeight; com.epl.geometry.MathUtils.Lerp(pt_1, pt_2, t, pt); if (com.epl.geometry.Point2D.SqrDistance(pt, pt_1) + com.epl.geometry.Point2D.SqrDistance(pt, pt_2) > small_tolerance_sqr) { bigmove = true; } } else { // for non-equal ranks, the higher rank wins if (rank1 > rank2) { line_1.GetCoord2D(t1, pt); ptWeight = weight1; com.epl.geometry.Point2D pt_2 = new com.epl.geometry.Point2D(); line_2.GetCoord2D(t2, pt_2); if (com.epl.geometry.Point2D.SqrDistance(pt, pt_2) > small_tolerance_sqr) { bigmove = true; } } else { line_2.GetCoord2D(t2, pt); ptWeight = weight2; com.epl.geometry.Point2D pt_1 = new com.epl.geometry.Point2D(); line_1.GetCoord2D(t1, pt_1); if (com.epl.geometry.Point2D.SqrDistance(pt, pt_1) > small_tolerance_sqr) { bigmove = true; } } } points[i] = pt; } // Split the line_1, making sure the endpoints are adusted // to the weighted double t0 = 0; int i0 = -1; for (int i_1 = 0; i_1 <= count; i_1++) { double t = i_1 < count ? m_param_1[i_1] : 1.0; if (t != t0) { com.epl.geometry.SegmentBuffer seg_buffer = NewSegmentBuffer_(); line_1.Cut(t0, t, seg_buffer); if (i0 != -1) { seg_buffer.Get().SetStartXY(points[i0]); } if (i_1 != count) { seg_buffer.Get().SetEndXY(points[i_1]); } t0 = t; m_result_segments_1.Add(NewIntersectionPart_(seg_buffer.Get())); } i0 = i_1; } int[] indices = new int[9]; for (int i_2 = 0; i_2 < count; i_2++) { indices[i_2] = i_2; } if (count > 1) { if (m_param_2[0] > m_param_2[1]) { double t = m_param_2[0]; m_param_2[0] = m_param_2[1]; m_param_2[1] = t; int i_3 = indices[0]; indices[0] = indices[1]; indices[1] = i_3; } } // Split the line_2 t0 = 0; i0 = -1; for (int i_4 = 0; i_4 <= count; i_4++) { double t = i_4 < count ? m_param_2[i_4] : 1.0; if (t != t0) { com.epl.geometry.SegmentBuffer seg_buffer = NewSegmentBuffer_(); line_2.Cut(t0, t, seg_buffer); if (i0 != -1) { int ind = indices[i0]; seg_buffer.Get().SetStartXY(points[ind]); } if (i_4 != count) { int ind = indices[i_4]; seg_buffer.Get().SetEndXY(points[ind]); } t0 = t; m_result_segments_2.Add(NewIntersectionPart_(seg_buffer.Get())); } i0 = i_4; } return(bigmove); } throw com.epl.geometry.GeometryException.GeometryInternalError(); } throw com.epl.geometry.GeometryException.GeometryInternalError(); } return(false); }