internal static bool IsClockwiseRing(com.epl.geometry.MultiPathImpl polygon, int iring) { int high_point_index = polygon.GetHighestPointIndex(iring); int path_start = polygon.GetPathStart(iring); int path_end = polygon.GetPathEnd(iring); com.epl.geometry.Point2D q = polygon.GetXY(high_point_index); com.epl.geometry.Point2D p; com.epl.geometry.Point2D r; if (high_point_index == path_start) { p = polygon.GetXY(path_end - 1); r = polygon.GetXY(path_start + 1); } else { if (high_point_index == path_end - 1) { p = polygon.GetXY(high_point_index - 1); r = polygon.GetXY(path_start); } else { p = polygon.GetXY(high_point_index - 1); r = polygon.GetXY(high_point_index + 1); } } int orientation = com.epl.geometry.Point2D.OrientationRobust(p, q, r); if (orientation == 0) { return(polygon.CalculateRingArea2D(iring) > 0.0); } return(orientation == -1); }
public void ResetToVertex(int vertexIndex, int _pathIndex) { if (m_currentPathIndex >= 0 && m_currentPathIndex < m_parent.GetPathCount()) { // check if we // are in // the // current // path int start = _getPathBegin(); if (vertexIndex >= start && vertexIndex < m_parent.GetPathEnd(m_currentPathIndex)) { m_currentSegmentIndex = -1; m_nextSegmentIndex = vertexIndex - start; return; } } int path_index; if (_pathIndex >= 0 && _pathIndex < m_parent.GetPathCount() && vertexIndex >= m_parent.GetPathStart(_pathIndex) && vertexIndex < m_parent.GetPathEnd(_pathIndex)) { path_index = _pathIndex; } else { path_index = m_parent.GetPathIndexFromPointIndex(vertexIndex); } m_nextPathIndex = path_index + 1; m_currentPathIndex = path_index; m_currentSegmentIndex = -1; m_nextSegmentIndex = vertexIndex - m_parent.GetPathStart(path_index); m_segmentCount = _getSegmentCount(path_index); m_pathBegin = m_parent.GetPathStart(m_currentPathIndex); }
public SegmentIteratorImpl(com.epl.geometry.MultiPathImpl parent, int pointIndex) { if (pointIndex < 0 || pointIndex >= parent.GetPointCount()) { throw new System.IndexOutOfRangeException(); } m_currentSegmentIndex = -1; int path = parent.GetPathIndexFromPointIndex(pointIndex); m_nextSegmentIndex = pointIndex - parent.GetPathStart(path); m_nextPathIndex = path + 1; m_currentPathIndex = path; m_parent = parent; m_segmentCount = _getSegmentCount(m_currentPathIndex); m_bCirculator = false; m_currentSegment = null; m_pathBegin = m_parent.GetPathStart(m_currentPathIndex); m_dummyPoint = new com.epl.geometry.Point2D(); }
public SegmentIteratorImpl(com.epl.geometry.MultiPathImpl parent, int pathIndex, int segmentIndex) { if (pathIndex < 0 || pathIndex >= parent.GetPathCount() || segmentIndex < 0) { throw new System.IndexOutOfRangeException(); } int d = parent.IsClosedPath(pathIndex) ? 0 : 1; if (segmentIndex >= parent.GetPathSize(pathIndex) - d) { throw new System.IndexOutOfRangeException(); } m_currentSegmentIndex = -1; m_nextSegmentIndex = segmentIndex; m_currentPathIndex = pathIndex; m_nextPathIndex = m_nextSegmentIndex + 1; m_parent = parent; m_segmentCount = _getSegmentCount(m_nextPathIndex); m_bCirculator = false; m_currentSegment = null; m_pathBegin = m_parent.GetPathStart(m_currentPathIndex); m_dummyPoint = new com.epl.geometry.Point2D(); }
/// <summary>Returns the start index of the path.</summary> /// <param name="pathIndex">The index of the path to return the start index from.</param> /// <returns>The start index of the path.</returns> public virtual int GetPathStart(int pathIndex) { return(m_impl.GetPathStart(pathIndex)); }
/// <summary>Returns true if the given path of the input MultiPath is convex.</summary> /// <remarks> /// Returns true if the given path of the input MultiPath is convex. Returns false otherwise. /// \param multi_path The MultiPath to check if the path is convex. /// \param path_index The path of the MultiPath to check if its convex. /// </remarks> internal static bool IsPathConvex(com.epl.geometry.MultiPath multi_path, int path_index, com.epl.geometry.ProgressTracker progress_tracker) { com.epl.geometry.MultiPathImpl mimpl = (com.epl.geometry.MultiPathImpl)multi_path._getImpl(); int path_start = mimpl.GetPathStart(path_index); int path_end = mimpl.GetPathEnd(path_index); bool bxyclosed = !mimpl.IsClosedPath(path_index) && mimpl.IsClosedPathInXYPlane(path_index); com.epl.geometry.AttributeStreamOfDbl position = (com.epl.geometry.AttributeStreamOfDbl)(mimpl.GetAttributeStreamRef(com.epl.geometry.VertexDescription.Semantics.POSITION)); int position_start = 2 * path_start; int position_end = 2 * path_end; if (bxyclosed) { position_end -= 2; } if (position_end - position_start < 6) { return(true); } // This matches the logic for case 1 of the tree hull algorithm. The idea is inductive. We assume we have a convex hull pt_0,...,pt_m, and we see if // a new point (pt_pivot) is among the transitive tournament for pt_0, knowing that pt_pivot comes after pt_m. // We check three conditions: // 1) pt_m->pt_pivot->pt_0 is clockwise (closure across the boundary is convex) // 2) pt_1->pt_pivot->pt_0 is clockwise (the first step forward is convex) (pt_1 is the next point after pt_0) // 3) pt_m->pt_pivot->pt_m_prev is clockwise (the first step backwards is convex) (pt_m_prev is the previous point before pt_m) // If all three of the above conditions are clockwise, then pt_pivot is among the transitive tournament for pt_0, and therefore the polygon pt_0, ..., pt_m, pt_pivot is convex. com.epl.geometry.Point2D pt_0 = new com.epl.geometry.Point2D(); com.epl.geometry.Point2D pt_m = new com.epl.geometry.Point2D(); com.epl.geometry.Point2D pt_pivot = new com.epl.geometry.Point2D(); position.Read(position_start, pt_0); position.Read(position_start + 2, pt_m); position.Read(position_start + 4, pt_pivot); // Initial inductive step com.epl.geometry.ECoordinate det_ec = Determinant_(pt_m, pt_pivot, pt_0); if (det_ec.IsFuzzyZero() || !IsClockwise_(det_ec.Value())) { return(false); } com.epl.geometry.Point2D pt_1 = new com.epl.geometry.Point2D(pt_m.x, pt_m.y); com.epl.geometry.Point2D pt_m_prev = new com.epl.geometry.Point2D(); // Assume that pt_0,...,pt_m is convex. Check if the next point, pt_pivot, maintains the convex invariant. for (int i = position_start + 6; i < position_end; i += 2) { pt_m_prev.SetCoords(pt_m); pt_m.SetCoords(pt_pivot); position.Read(i, pt_pivot); det_ec = Determinant_(pt_m, pt_pivot, pt_0); if (det_ec.IsFuzzyZero() || !IsClockwise_(det_ec.Value())) { return(false); } det_ec = Determinant_(pt_1, pt_pivot, pt_0); if (det_ec.IsFuzzyZero() || !IsClockwise_(det_ec.Value())) { return(false); } det_ec = Determinant_(pt_m, pt_pivot, pt_m_prev); if (det_ec.IsFuzzyZero() || !IsClockwise_(det_ec.Value())) { return(false); } } return(true); }
private static int ExportMultiPathToESRIShape(bool bPolygon, int exportFlags, com.epl.geometry.MultiPath multipath, System.IO.BinaryWriter shapeBuffer) { com.epl.geometry.MultiPathImpl multipathImpl = (com.epl.geometry.MultiPathImpl)multipath._getImpl(); bool bExportZs = multipathImpl.HasAttribute(com.epl.geometry.VertexDescription.Semantics.Z) && (exportFlags & com.epl.geometry.ShapeExportFlags.ShapeExportStripZs) == 0; bool bExportMs = multipathImpl.HasAttribute(com.epl.geometry.VertexDescription.Semantics.M) && (exportFlags & com.epl.geometry.ShapeExportFlags.ShapeExportStripMs) == 0; bool bExportIDs = multipathImpl.HasAttribute(com.epl.geometry.VertexDescription.Semantics.ID) && (exportFlags & com.epl.geometry.ShapeExportFlags.ShapeExportStripIDs) == 0; bool bHasCurves = multipathImpl.HasNonLinearSegments(); bool bArcViewNaNs = (exportFlags & com.epl.geometry.ShapeExportFlags.ShapeExportTrueNaNs) == 0; int partCount = multipathImpl.GetPathCount(); int pointCount = multipathImpl.GetPointCount(); if (!bPolygon) { for (int ipart = 0; ipart < partCount; ipart++) { if (multipath.IsClosedPath(ipart)) { pointCount++; } } } else { pointCount += partCount; } int size = (4) + (4 * 8) + (4) + (4) + (partCount * 4) + pointCount * 2 * 8; /* type */ /* envelope */ /* part count */ /* point count */ /* start indices */ /* xy coordinates */ if (bExportZs) { size += (2 * 8) + (pointCount * 8); } /* min max */ /* zs */ if (bExportMs) { size += (2 * 8) + (pointCount * 8); } /* min max */ /* ms */ if (bExportIDs) { size += pointCount * 4; } /* ids */ if (bHasCurves) { } // to-do: curves if (size >= com.epl.geometry.NumberUtils.IntMax()) { throw new com.epl.geometry.GeometryException("invalid call"); } if (shapeBuffer == null) { return(size); } else { if (((System.IO.MemoryStream)shapeBuffer.BaseStream).Capacity < size) { throw new com.epl.geometry.GeometryException("buffer is too small"); } } int offset = 0; // Determine the shape type int type; if (!bExportZs && !bExportMs) { if (bExportIDs || bHasCurves) { type = bPolygon ? com.epl.geometry.ShapeType.ShapeGeneralPolygon : com.epl.geometry.ShapeType.ShapeGeneralPolyline; if (bExportIDs) { type |= com.epl.geometry.ShapeModifiers.ShapeHasIDs; } if (bHasCurves) { type |= com.epl.geometry.ShapeModifiers.ShapeHasCurves; } } else { type = bPolygon ? com.epl.geometry.ShapeType.ShapePolygon : com.epl.geometry.ShapeType.ShapePolyline; } } else { if (bExportZs && !bExportMs) { if (bExportIDs || bHasCurves) { type = bPolygon ? com.epl.geometry.ShapeType.ShapeGeneralPolygon : com.epl.geometry.ShapeType.ShapeGeneralPolyline; type |= com.epl.geometry.ShapeModifiers.ShapeHasZs; if (bExportIDs) { type |= com.epl.geometry.ShapeModifiers.ShapeHasIDs; } if (bHasCurves) { type |= com.epl.geometry.ShapeModifiers.ShapeHasCurves; } } else { type = bPolygon ? com.epl.geometry.ShapeType.ShapePolygonZ : com.epl.geometry.ShapeType.ShapePolylineZ; } } else { if (bExportMs && !bExportZs) { if (bExportIDs || bHasCurves) { type = bPolygon ? com.epl.geometry.ShapeType.ShapeGeneralPolygon : com.epl.geometry.ShapeType.ShapeGeneralPolyline; type |= com.epl.geometry.ShapeModifiers.ShapeHasMs; if (bExportIDs) { type |= com.epl.geometry.ShapeModifiers.ShapeHasIDs; } if (bHasCurves) { type |= com.epl.geometry.ShapeModifiers.ShapeHasCurves; } } else { type = bPolygon ? com.epl.geometry.ShapeType.ShapePolygonM : com.epl.geometry.ShapeType.ShapePolylineM; } } else { if (bExportIDs || bHasCurves) { type = bPolygon ? com.epl.geometry.ShapeType.ShapeGeneralPolygon : com.epl.geometry.ShapeType.ShapeGeneralPolyline; type |= com.epl.geometry.ShapeModifiers.ShapeHasZs | com.epl.geometry.ShapeModifiers.ShapeHasMs; if (bExportIDs) { type |= com.epl.geometry.ShapeModifiers.ShapeHasIDs; } if (bHasCurves) { type |= com.epl.geometry.ShapeModifiers.ShapeHasCurves; } } else { type = bPolygon ? com.epl.geometry.ShapeType.ShapePolygonZM : com.epl.geometry.ShapeType.ShapePolylineZM; } } } } // write type shapeBuffer.Write(type); offset += 4; // write Envelope com.epl.geometry.Envelope2D env = new com.epl.geometry.Envelope2D(); multipathImpl.QueryEnvelope2D(env); // calls _VerifyAllStreams shapeBuffer.Write(env.xmin); offset += 8; shapeBuffer.Write(env.ymin); offset += 8; shapeBuffer.Write(env.xmax); offset += 8; shapeBuffer.Write(env.ymax); offset += 8; // write part count shapeBuffer.Write(partCount); offset += 4; // to-do: return error if larger than 2^32 - 1 // write pointCount shapeBuffer.Write(pointCount); offset += 4; // write start indices for each part int pointIndexDelta = 0; for (int ipart = 0; ipart < partCount; ipart++) { int istart = multipathImpl.GetPathStart(ipart) + pointIndexDelta; shapeBuffer.Write(istart); offset += 4; if (bPolygon || multipathImpl.IsClosedPath(ipart)) { pointIndexDelta++; } } if (pointCount > 0) { // write xy coordinates com.epl.geometry.AttributeStreamBase positionStream = multipathImpl.GetAttributeStreamRef(com.epl.geometry.VertexDescription.Semantics.POSITION); com.epl.geometry.AttributeStreamOfDbl position = (com.epl.geometry.AttributeStreamOfDbl)positionStream; for (int ipart = 0; ipart < partCount; ipart++) { int partStart = multipathImpl.GetPathStart(ipart); int partEnd = multipathImpl.GetPathEnd(ipart); for (int i = partStart; i < partEnd; i++) { double x = position.Read(2 * i); double y = position.Read(2 * i + 1); shapeBuffer.Write(x); offset += 8; shapeBuffer.Write(y); offset += 8; } // If the part is closed, then we need to duplicate the start // point if (bPolygon || multipathImpl.IsClosedPath(ipart)) { double x = position.Read(2 * partStart); double y = position.Read(2 * partStart + 1); shapeBuffer.Write(x); offset += 8; shapeBuffer.Write(y); offset += 8; } } } // write Zs if (bExportZs) { com.epl.geometry.Envelope1D zInterval = multipathImpl.QueryInterval(com.epl.geometry.VertexDescription.Semantics.Z, 0); shapeBuffer.Write(bArcViewNaNs ? com.epl.geometry.Interop.TranslateToAVNaN(zInterval.vmin) : zInterval.vmin); offset += 8; shapeBuffer.Write(bArcViewNaNs ? com.epl.geometry.Interop.TranslateToAVNaN(zInterval.vmax) : zInterval.vmax); offset += 8; if (pointCount > 0) { if (multipathImpl._attributeStreamIsAllocated(com.epl.geometry.VertexDescription.Semantics.Z)) { com.epl.geometry.AttributeStreamOfDbl zs = (com.epl.geometry.AttributeStreamOfDbl)multipathImpl.GetAttributeStreamRef(com.epl.geometry.VertexDescription.Semantics.Z); for (int ipart = 0; ipart < partCount; ipart++) { int partStart = multipathImpl.GetPathStart(ipart); int partEnd = multipathImpl.GetPathEnd(ipart); for (int i = partStart; i < partEnd; i++) { double z = zs.Read(i); shapeBuffer.Write(bArcViewNaNs ? com.epl.geometry.Interop.TranslateToAVNaN(z) : z); offset += 8; } // If the part is closed, then we need to duplicate the // start z if (bPolygon || multipathImpl.IsClosedPath(ipart)) { double z = zs.Read(partStart); shapeBuffer.Write(z); offset += 8; } } } else { double z = com.epl.geometry.VertexDescription.GetDefaultValue(com.epl.geometry.VertexDescription.Semantics.Z); if (bArcViewNaNs) { z = com.epl.geometry.Interop.TranslateToAVNaN(z); } for (int i = 0; i < pointCount; i++) { shapeBuffer.Write(z); } offset += 8; } } } // write Ms if (bExportMs) { com.epl.geometry.Envelope1D mInterval = multipathImpl.QueryInterval(com.epl.geometry.VertexDescription.Semantics.M, 0); shapeBuffer.Write(bArcViewNaNs ? com.epl.geometry.Interop.TranslateToAVNaN(mInterval.vmin) : mInterval.vmin); offset += 8; shapeBuffer.Write(bArcViewNaNs ? com.epl.geometry.Interop.TranslateToAVNaN(mInterval.vmax) : mInterval.vmax); offset += 8; if (pointCount > 0) { if (multipathImpl._attributeStreamIsAllocated(com.epl.geometry.VertexDescription.Semantics.M)) { com.epl.geometry.AttributeStreamOfDbl ms = (com.epl.geometry.AttributeStreamOfDbl)multipathImpl.GetAttributeStreamRef(com.epl.geometry.VertexDescription.Semantics.M); for (int ipart = 0; ipart < partCount; ipart++) { int partStart = multipathImpl.GetPathStart(ipart); int partEnd = multipathImpl.GetPathEnd(ipart); for (int i = partStart; i < partEnd; i++) { double m = ms.Read(i); shapeBuffer.Write(bArcViewNaNs ? com.epl.geometry.Interop.TranslateToAVNaN(m) : m); offset += 8; } // If the part is closed, then we need to duplicate the // start m if (bPolygon || multipathImpl.IsClosedPath(ipart)) { double m = ms.Read(partStart); shapeBuffer.Write(m); offset += 8; } } } else { double m = com.epl.geometry.VertexDescription.GetDefaultValue(com.epl.geometry.VertexDescription.Semantics.M); if (bArcViewNaNs) { m = com.epl.geometry.Interop.TranslateToAVNaN(m); } for (int i = 0; i < pointCount; i++) { shapeBuffer.Write(m); } offset += 8; } } } // write Curves if (bHasCurves) { } // to-do: We'll finish this later // write IDs if (bExportIDs) { if (pointCount > 0) { if (multipathImpl._attributeStreamIsAllocated(com.epl.geometry.VertexDescription.Semantics.ID)) { com.epl.geometry.AttributeStreamOfInt32 ids = (com.epl.geometry.AttributeStreamOfInt32)multipathImpl.GetAttributeStreamRef(com.epl.geometry.VertexDescription.Semantics.ID); for (int ipart = 0; ipart < partCount; ipart++) { int partStart = multipathImpl.GetPathStart(ipart); int partEnd = multipathImpl.GetPathEnd(ipart); for (int i = partStart; i < partEnd; i++) { int id = ids.Read(i); shapeBuffer.Write(id); offset += 4; } // If the part is closed, then we need to duplicate the // start id if (bPolygon || multipathImpl.IsClosedPath(ipart)) { int id = ids.Read(partStart); shapeBuffer.Write(id); offset += 4; } } } else { int id = (int)com.epl.geometry.VertexDescription.GetDefaultValue(com.epl.geometry.VertexDescription.Semantics.ID); for (int i = 0; i < pointCount; i++) { shapeBuffer.Write(id); } offset += 4; } } } return(offset); }
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; }
private void GeneralizePath(com.epl.geometry.MultiPathImpl mpsrc, int ipath, com.epl.geometry.MultiPathImpl mpdst, com.epl.geometry.Line lineHelper) { if (mpsrc.GetPathSize(ipath) < 2) { return; } int start = mpsrc.GetPathStart(ipath); int end = mpsrc.GetPathEnd(ipath) - 1; com.epl.geometry.AttributeStreamOfDbl xy = (com.epl.geometry.AttributeStreamOfDbl)mpsrc.GetAttributeStreamRef(com.epl.geometry.VertexDescription.Semantics.POSITION); bool bClosed = mpsrc.IsClosedPath(ipath); com.epl.geometry.AttributeStreamOfInt32 stack = new com.epl.geometry.AttributeStreamOfInt32(0); stack.Reserve(mpsrc.GetPathSize(ipath) + 1); com.epl.geometry.AttributeStreamOfInt32 resultStack = new com.epl.geometry.AttributeStreamOfInt32(0); resultStack.Reserve(mpsrc.GetPathSize(ipath) + 1); stack.Add(bClosed ? start : end); stack.Add(start); com.epl.geometry.Point2D pt = new com.epl.geometry.Point2D(); while (stack.Size() > 1) { int i1 = stack.GetLast(); stack.RemoveLast(); int i2 = stack.GetLast(); mpsrc.GetXY(i1, pt); lineHelper.SetStartXY(pt); mpsrc.GetXY(i2, pt); lineHelper.SetEndXY(pt); int mid = FindGreatestDistance(lineHelper, pt, xy, i1, i2, end); if (mid >= 0) { stack.Add(mid); stack.Add(i1); } else { resultStack.Add(i1); } } if (!bClosed) { resultStack.Add(stack.Get(0)); } int rs_size = resultStack.Size(); int path_size = mpsrc.GetPathSize(ipath); if (rs_size == path_size && rs_size == stack.Size()) { mpdst.AddPath(mpsrc, ipath, true); } else { if (resultStack.Size() > 0) { if (m_bRemoveDegenerateParts && resultStack.Size() <= 2) { if (bClosed || resultStack.Size() == 1) { return; } double d = com.epl.geometry.Point2D.Distance(mpsrc.GetXY(resultStack.Get(0)), mpsrc.GetXY(resultStack.Get(1))); if (d <= m_maxDeviation) { return; } } com.epl.geometry.Point point = new com.epl.geometry.Point(); for (int i = 0, n = resultStack.Size(); i < n; i++) { mpsrc.GetPointByVal(resultStack.Get(i), point); if (i == 0) { mpdst.StartPath(point); } else { mpdst.LineTo(point); } } if (bClosed) { for (int i_1 = resultStack.Size(); i_1 < 3; i_1++) { mpdst.LineTo(point); } mpdst.ClosePathWithLine(); } } } }
internal static com.epl.geometry.MultiPoint CalculatePolylineBoundary_(object impl, com.epl.geometry.ProgressTracker progress_tracker, bool only_check_non_empty_boundary, bool[] not_empty) { if (not_empty != null) { not_empty[0] = false; } com.epl.geometry.MultiPathImpl mpImpl = (com.epl.geometry.MultiPathImpl)impl; com.epl.geometry.MultiPoint dst = null; if (!only_check_non_empty_boundary) { dst = new com.epl.geometry.MultiPoint(mpImpl.GetDescription()); } if (!mpImpl.IsEmpty()) { com.epl.geometry.AttributeStreamOfInt32 indices = new com.epl.geometry.AttributeStreamOfInt32(0); indices.Reserve(mpImpl.GetPathCount() * 2); for (int ipath = 0, nPathCount = mpImpl.GetPathCount(); ipath < nPathCount; ipath++) { int path_size = mpImpl.GetPathSize(ipath); if (path_size > 0 && !mpImpl.IsClosedPathInXYPlane(ipath)) { // closed // paths // of // polyline // do // not // contribute // to // the // boundary. int start = mpImpl.GetPathStart(ipath); indices.Add(start); int end = mpImpl.GetPathEnd(ipath) - 1; indices.Add(end); } } if (indices.Size() > 0) { com.epl.geometry.BucketSort sorter = new com.epl.geometry.BucketSort(); com.epl.geometry.AttributeStreamOfDbl xy = (com.epl.geometry.AttributeStreamOfDbl)(mpImpl.GetAttributeStreamRef(com.epl.geometry.VertexDescription.Semantics.POSITION)); sorter.Sort(indices, 0, indices.Size(), new com.epl.geometry.Boundary.MultiPathImplBoundarySorter(xy)); com.epl.geometry.Point2D ptPrev = new com.epl.geometry.Point2D(); xy.Read(2 * indices.Get(0), ptPrev); int ind = 0; int counter = 1; com.epl.geometry.Point point = new com.epl.geometry.Point(); com.epl.geometry.Point2D pt = new com.epl.geometry.Point2D(); for (int i = 1, n = indices.Size(); i < n; i++) { xy.Read(2 * indices.Get(i), pt); if (pt.IsEqual(ptPrev)) { if (indices.Get(ind) > indices.Get(i)) { // remove duplicate point indices.Set(ind, com.epl.geometry.NumberUtils.IntMax()); ind = i; } else { // just for the heck of it, have the first // point in the order to be added to the // boundary. indices.Set(i, com.epl.geometry.NumberUtils.IntMax()); } counter++; } else { if ((counter & 1) == 0) { // remove boundary point indices.Set(ind, com.epl.geometry.NumberUtils.IntMax()); } else { if (only_check_non_empty_boundary) { if (not_empty != null) { not_empty[0] = true; } return(null); } } ptPrev.SetCoords(pt); ind = i; counter = 1; } } if ((counter & 1) == 0) { // remove the point indices.Set(ind, com.epl.geometry.NumberUtils.IntMax()); } else { if (only_check_non_empty_boundary) { if (not_empty != null) { not_empty[0] = true; } return(null); } } if (!only_check_non_empty_boundary) { indices.Sort(0, indices.Size()); for (int i_1 = 0, n = indices.Size(); i_1 < n; i_1++) { if (indices.Get(i_1) == com.epl.geometry.NumberUtils.IntMax()) { break; } mpImpl.GetPointByVal(indices.Get(i_1), point); dst.Add(point); } } } } if (only_check_non_empty_boundary) { return(null); } return(dst); }