public List <Vector2d> FindIntersections(Polygon2d o) { List <Vector2d> v = new List <Vector2d>(); if (!this.GetBounds().Intersects(o.GetBounds())) { return(v); } foreach (Segment2d seg in SegmentItr()) { foreach (Segment2d oseg in o.SegmentItr()) { // this computes test twice for intersections, but seg.intersects doesn't // create any new objects so it should be much faster for majority of segments (should profile!) if (seg.Intersects(oseg)) { IntrSegment2Segment2 intr = new IntrSegment2Segment2(seg, oseg); if (intr.Find()) { v.Add(intr.Point0); if (intr.Quantity == 2) { v.Add(intr.Point1); } } } } } return(v); }
/// <summary> /// find set of edges in graph that intersect with edge [a,b] /// </summary> protected bool find_intersecting_edges(ref Vector2d a, ref Vector2d b, List <Intersection> hits, double tol = 0) { int num_hits = 0; Vector2d x = Vector2d.Zero, y = Vector2d.Zero; foreach (int eid in Graph.EdgeIndices()) { Graph.GetEdgeV(eid, ref x, ref y); int sidex = Segment2d.WhichSide(ref a, ref b, ref x, tol); int sidey = Segment2d.WhichSide(ref a, ref b, ref y, tol); if (sidex == sidey && sidex != 0) { continue; // both pts on same side } IntrSegment2Segment2 intr = new IntrSegment2Segment2(new Segment2d(x, y), new Segment2d(a, b)); if (intr.Find()) { hits.Add(new Intersection() { eid = eid, sidex = sidex, sidey = sidey, intr = intr }); num_hits++; } } return(num_hits > 0); }
public List <Vector2d> FindIntersections(Polygon2d o) { List <Vector2d> v = new List <Vector2d>(); if (!this.GetBounds().Intersects(o.GetBounds())) { return(v); } foreach (Segment2d seg in SegmentItr()) { foreach (Segment2d oseg in o.SegmentItr()) { IntrSegment2Segment2 intr = new IntrSegment2Segment2(seg, oseg); if (intr.Find()) { v.Add(intr.Point0); if (intr.Quantity == 2) { v.Add(intr.Point1); } break; } } } return(v); }
/// <summary> /// Find any segment in set that intersects input segment. /// Returns intersection test, and index of segment /// </summary> public IntrSegment2Segment2 FindAnyIntersection(Segment2d seg, out int iSegment) { int N = Segments.Count; for (iSegment = 0; iSegment < N; ++iSegment) { var intr = new IntrSegment2Segment2(seg, Segments[iSegment]); if (intr.Find()) { return(intr); } } return(null); }
public bool Intersects(Polygon2d o) { if (!this.GetBounds().Intersects(o.GetBounds())) { return(false); } foreach (Segment2d seg in SegmentItr()) { foreach (Segment2d oseg in o.SegmentItr()) { IntrSegment2Segment2 intr = new IntrSegment2Segment2(seg, oseg); if (intr.Find()) { return(true); } } } return(false); }
public void FindAllIntersections(Segment2d seg, List <double> segmentTs, List <int> indices = null, List <IntrSegment2Segment2> tests = null, bool bOnlySimple = true) { int N = Segments.Count; for (int i = 0; i < N; ++i) { // want to make sure we do not miss any hits, even if it means // we get duplicates... var intr = new IntrSegment2Segment2(seg, Segments[i]) { IntervalThreshold = MathUtil.ZeroTolerance }; if (intr.Find()) { if (bOnlySimple && intr.IsSimpleIntersection == false) { continue; } if (tests != null) { tests.Add(intr); } if (indices != null) { indices.Add(i); } if (segmentTs != null) { segmentTs.Add(intr.Parameter0); if (!intr.IsSimpleIntersection) { segmentTs.Add(intr.Parameter1); } } } } }
public virtual bool Apply() { HashSet <int> OnCurveVerts = new HashSet <int>(); // original vertices that were epsilon-coincident w/ curve vertices insert_corners(OnCurveVerts); // [RMS] not using this? //HashSet<int> corner_v = new HashSet<int>(CurveVertices); // not sure we need to track all of these HashSet <int> ZeroEdges = new HashSet <int>(); HashSet <int> ZeroVertices = new HashSet <int>(); OnCutEdges = new HashSet <int>(); HashSet <int> NewEdges = new HashSet <int>(); HashSet <int> NewCutVertices = new HashSet <int>(); sbyte[] signs = new sbyte[2 * Mesh.MaxVertexID + 2 * Curve.VertexCount]; HashSet <int> segTriangles = new HashSet <int>(); HashSet <int> segVertices = new HashSet <int>(); HashSet <int> segEdges = new HashSet <int>(); // loop over segments, insert each one in sequence int N = (IsLoop) ? Curve.VertexCount : Curve.VertexCount - 1; for (int si = 0; si < N; ++si) { int i0 = si; int i1 = (si + 1) % Curve.VertexCount; Segment2d seg = new Segment2d(Curve[i0], Curve[i1]); int i0_vid = CurveVertices[i0]; int i1_vid = CurveVertices[i1]; // If these vertices are already connected by an edge, we can just continue. int existing_edge = Mesh.FindEdge(i0_vid, i1_vid); if (existing_edge != DMesh3.InvalidID) { add_cut_edge(existing_edge); continue; } if (triSpatial != null) { segTriangles.Clear(); segVertices.Clear(); segEdges.Clear(); AxisAlignedBox2d segBounds = new AxisAlignedBox2d(seg.P0); segBounds.Contain(seg.P1); segBounds.Expand(MathUtil.ZeroTolerancef * 10); triSpatial.FindTrianglesInRange(segBounds, segTriangles); IndexUtil.TrianglesToVertices(Mesh, segTriangles, segVertices); IndexUtil.TrianglesToEdges(Mesh, segTriangles, segEdges); } int MaxVID = Mesh.MaxVertexID; IEnumerable <int> vertices = Interval1i.Range(MaxVID); if (triSpatial != null) { vertices = segVertices; } // compute edge-crossing signs // [TODO] could walk along mesh from a to b, rather than computing for entire mesh? if (signs.Length < MaxVID) { signs = new sbyte[2 * MaxVID]; } gParallel.ForEach(vertices, (vid) => { if (Mesh.IsVertex(vid)) { if (vid == i0_vid || vid == i1_vid) { signs[vid] = 0; } else { Vector2d v2 = PointF(vid); // tolerance defines band in which we will consider values to be zero signs[vid] = (sbyte)seg.WhichSide(v2, SpatialEpsilon); } } else { signs[vid] = sbyte.MaxValue; } }); // have to skip processing of new edges. If edge id // is > max at start, is new. Otherwise if in NewEdges list, also new. // (need both in case we re-use an old edge index) int MaxEID = Mesh.MaxEdgeID; NewEdges.Clear(); NewCutVertices.Clear(); NewCutVertices.Add(i0_vid); NewCutVertices.Add(i1_vid); // cut existing edges with segment IEnumerable <int> edges = Interval1i.Range(MaxEID); if (triSpatial != null) { edges = segEdges; } foreach (int eid in edges) { if (Mesh.IsEdge(eid) == false) { continue; } if (eid >= MaxEID || NewEdges.Contains(eid)) { continue; } // cannot cut boundary edges? if (Mesh.IsBoundaryEdge(eid)) { continue; } Index2i ev = Mesh.GetEdgeV(eid); int eva_sign = signs[ev.a]; int evb_sign = signs[ev.b]; // [RMS] should we be using larger epsilon here? If we don't track OnCurveVerts explicitly, we // need to at least use same epsilon we passed to insert_corner_from_bary...do we still also // need that to catch the edges we split in the poke? bool eva_in_segment = false; if (eva_sign == 0) { eva_in_segment = OnCurveVerts.Contains(ev.a) || Math.Abs(seg.Project(PointF(ev.a))) < (seg.Extent + SpatialEpsilon); } bool evb_in_segment = false; if (evb_sign == 0) { evb_in_segment = OnCurveVerts.Contains(ev.b) || Math.Abs(seg.Project(PointF(ev.b))) < (seg.Extent + SpatialEpsilon); } // If one or both vertices are on-segment, we have special case. // If just one vertex is on the segment, we can skip this edge. // If both vertices are on segment, then we can just re-use this edge. if (eva_in_segment || evb_in_segment) { if (eva_in_segment && evb_in_segment) { ZeroEdges.Add(eid); add_cut_edge(eid); NewCutVertices.Add(ev.a); NewCutVertices.Add(ev.b); } else { int zvid = eva_in_segment ? ev.a : ev.b; ZeroVertices.Add(zvid); NewCutVertices.Add(zvid); } continue; } // no crossing if (eva_sign * evb_sign > 0) { continue; } // compute segment/segment intersection Vector2d va = PointF(ev.a); Vector2d vb = PointF(ev.b); Segment2d edge_seg = new Segment2d(va, vb); IntrSegment2Segment2 intr = new IntrSegment2Segment2(seg, edge_seg); intr.Compute(); if (intr.Type == IntersectionType.Segment) { // [RMS] we should have already caught this above, so if it happens here it is probably spurious? // we should have caught this case above, but numerics are different so it might occur again ZeroEdges.Add(eid); NewCutVertices.Add(ev.a); NewCutVertices.Add(ev.b); add_cut_edge(eid); continue; } else if (intr.Type != IntersectionType.Point) { continue; // no intersection } Vector2d x = intr.Point0; double t = Math.Sqrt(x.DistanceSquared(va) / va.DistanceSquared(vb)); // this case happens if we aren't "on-segment" but after we do the test the intersection pt // is within epsilon of one end of the edge. This is a spurious t-intersection and we // can ignore it. Some other edge should exist that picks up this vertex as part of it. // [TODO] what about if this edge is degenerate? bool x_in_segment = Math.Abs(edge_seg.Project(x)) < (edge_seg.Extent - SpatialEpsilon); if (!x_in_segment) { continue; } Index2i et = Mesh.GetEdgeT(eid); spatial_remove_triangles(et.a, et.b); // split edge at this segment DMesh3.EdgeSplitInfo splitInfo; MeshResult result = Mesh.SplitEdge(eid, out splitInfo, t); if (result != MeshResult.Ok) { throw new Exception("MeshInsertUVSegment.Apply: SplitEdge failed - " + result.ToString()); //return false; } // move split point to intersection position SetPointF(splitInfo.vNew, x); NewCutVertices.Add(splitInfo.vNew); NewEdges.Add(splitInfo.eNewBN); NewEdges.Add(splitInfo.eNewCN); spatial_add_triangles(et.a, et.b); spatial_add_triangles(splitInfo.eNewT2, splitInfo.eNewT3); // some splits - but not all - result in new 'other' edges that are on // the polypath. We want to keep track of these edges so we can extract loop later. Index2i ecn = Mesh.GetEdgeV(splitInfo.eNewCN); if (NewCutVertices.Contains(ecn.a) && NewCutVertices.Contains(ecn.b)) { add_cut_edge(splitInfo.eNewCN); } // since we don't handle bdry edges this should never be false, but maybe we will handle bdry later... if (splitInfo.eNewDN != DMesh3.InvalidID) { NewEdges.Add(splitInfo.eNewDN); Index2i edn = Mesh.GetEdgeV(splitInfo.eNewDN); if (NewCutVertices.Contains(edn.a) && NewCutVertices.Contains(edn.b)) { add_cut_edge(splitInfo.eNewDN); } } } } // extract the cut paths if (EnableCutSpansAndLoops) { find_cut_paths(OnCutEdges); } return(true); } // Apply()
public virtual bool Apply() { insert_corners(); // [RMS] not using this? //HashSet<int> corner_v = new HashSet<int>(CurveVertices); // not sure we need to track all of these HashSet <int> ZeroEdges = new HashSet <int>(); HashSet <int> ZeroVertices = new HashSet <int>(); OnCutEdges = new HashSet <int>(); // loop over segments, insert each one in sequence int N = (IsLoop) ? Curve.VertexCount : Curve.VertexCount - 1; for (int si = 0; si < N; ++si) { int i0 = si; int i1 = (si + 1) % Curve.VertexCount; Segment2d seg = new Segment2d(Curve[i0], Curve[i1]); int i0_vid = CurveVertices[i0]; int i1_vid = CurveVertices[i1]; // If these vertices are already connected by an edge, we can just continue. int existing_edge = Mesh.FindEdge(i0_vid, i1_vid); if (existing_edge != DMesh3.InvalidID) { OnCutEdges.Add(existing_edge); continue; } // compute edge-crossing signs // [TODO] could walk along mesh from a to b, rather than computing for entire mesh? int MaxVID = Mesh.MaxVertexID; int[] signs = new int[MaxVID]; gParallel.ForEach(Interval1i.Range(MaxVID), (vid) => { if (Mesh.IsVertex(vid)) { if (vid == i0_vid || vid == i1_vid) { signs[vid] = 0; } else { Vector2d v2 = PointF(vid); // tolerance defines band in which we will consider values to be zero signs[vid] = seg.WhichSide(v2, MathUtil.ZeroTolerance); } } else { signs[vid] = int.MaxValue; } }); // have to skip processing of new edges. If edge id // is > max at start, is new. Otherwise if in NewEdges list, also new. // (need both in case we re-use an old edge index) int MaxEID = Mesh.MaxEdgeID; HashSet <int> NewEdges = new HashSet <int>(); HashSet <int> NewCutVertices = new HashSet <int>(); NewCutVertices.Add(i0_vid); NewCutVertices.Add(i1_vid); // cut existing edges with segment for (int eid = 0; eid < MaxEID; ++eid) { if (Mesh.IsEdge(eid) == false) { continue; } if (eid >= MaxEID || NewEdges.Contains(eid)) { continue; } // cannot cut boundary edges? if (Mesh.IsBoundaryEdge(eid)) { continue; } Index2i ev = Mesh.GetEdgeV(eid); int eva_sign = signs[ev.a]; int evb_sign = signs[ev.b]; bool eva_in_segment = false; if (eva_sign == 0) { eva_in_segment = Math.Abs(seg.Project(PointF(ev.a))) < (seg.Extent + MathUtil.ZeroTolerance); } bool evb_in_segment = false; if (evb_sign == 0) { evb_in_segment = Math.Abs(seg.Project(PointF(ev.b))) < (seg.Extent + MathUtil.ZeroTolerance); } // If one or both vertices are on-segment, we have special case. // If just one vertex is on the segment, we can skip this edge. // If both vertices are on segment, then we can just re-use this edge. if (eva_in_segment || evb_in_segment) { if (eva_in_segment && evb_in_segment) { ZeroEdges.Add(eid); OnCutEdges.Add(eid); } else { ZeroVertices.Add(eva_in_segment ? ev.a : ev.b); } continue; } // no crossing if (eva_sign * evb_sign > 0) { continue; } // compute segment/segment intersection Vector2d va = PointF(ev.a); Vector2d vb = PointF(ev.b); Segment2d edge_seg = new Segment2d(va, vb); IntrSegment2Segment2 intr = new IntrSegment2Segment2(seg, edge_seg); intr.Compute(); if (intr.Type == IntersectionType.Segment) { // [RMS] we should have already caught this above, so if it happens here it is probably spurious? // we should have caught this case above, but numerics are different so it might occur again ZeroEdges.Add(eid); OnCutEdges.Add(eid); continue; } else if (intr.Type != IntersectionType.Point) { continue; // no intersection } Vector2d x = intr.Point0; // this case happens if we aren't "on-segment" but after we do the test the intersection pt // is within epsilon of one end of the edge. This is a spurious t-intersection and we // can ignore it. Some other edge should exist that picks up this vertex as part of it. // [TODO] what about if this edge is degenerate? bool x_in_segment = Math.Abs(edge_seg.Project(x)) < (edge_seg.Extent - MathUtil.ZeroTolerance); if (!x_in_segment) { continue; } // split edge at this segment DMesh3.EdgeSplitInfo splitInfo; MeshResult result = Mesh.SplitEdge(eid, out splitInfo); if (result != MeshResult.Ok) { throw new Exception("MeshInsertUVSegment.Cut: failed in SplitEdge"); //return false; } // move split point to intersection position SetPointF(splitInfo.vNew, x); NewCutVertices.Add(splitInfo.vNew); NewEdges.Add(splitInfo.eNewBN); NewEdges.Add(splitInfo.eNewCN); // some splits - but not all - result in new 'other' edges that are on // the polypath. We want to keep track of these edges so we can extract loop later. Index2i ecn = Mesh.GetEdgeV(splitInfo.eNewCN); if (NewCutVertices.Contains(ecn.a) && NewCutVertices.Contains(ecn.b)) { OnCutEdges.Add(splitInfo.eNewCN); } // since we don't handle bdry edges this should never be false, but maybe we will handle bdry later... if (splitInfo.eNewDN != DMesh3.InvalidID) { NewEdges.Add(splitInfo.eNewDN); Index2i edn = Mesh.GetEdgeV(splitInfo.eNewDN); if (NewCutVertices.Contains(edn.a) && NewCutVertices.Contains(edn.b)) { OnCutEdges.Add(splitInfo.eNewDN); } } } } //MeshEditor editor = new MeshEditor(Mesh); //foreach (int eid in OnCutEdges) // editor.AppendBox(new Frame3f(Mesh.GetEdgePoint(eid, 0.5)), 0.1f); //Util.WriteDebugMesh(Mesh, string.Format("C:\\git\\geometry3SharpDemos\\geometry3Test\\test_output\\after_inserted.obj")); // extract the cut paths if (EnableCutSpansAndLoops) { find_cut_paths(OnCutEdges); } return(true); } // Apply()