/// <summary> /// Resample curve so that: /// - if opening angle at vertex is > sharp_thresh, we emit two more vertices at +/- corner_t, where the t is used in prev/next lerps /// - if opening angle is > flat_thresh, we skip the vertex entirely (simplification) /// This is mainly useful to get nicer polylines to use as the basis for (eg) creating 3D tubes, rendering, etc /// /// [TODO] skip tiny segments? /// </summary> public DCurve3 ResampleSharpTurns(double sharp_thresh = 90, double flat_thresh = 189, double corner_t = 0.01) { int NV = vertices.Count; DCurve3 resampled = new DCurve3() { Closed = this.Closed }; double prev_t = 1.0 - corner_t; for (int k = 0; k < NV; ++k) { double open_angle = Math.Abs(OpeningAngleDeg(k)); if (open_angle > flat_thresh && k > 0) { // ignore skip this vertex } else if (open_angle > sharp_thresh) { resampled.AppendVertex(vertices[k]); } else { Vector3d n = vertices[(k + 1) % NV]; Vector3d p = vertices[k == 0 ? NV - 1 : k - 1]; resampled.AppendVertex(Vector3d.Lerp(p, vertices[k], prev_t)); resampled.AppendVertex(vertices[k]); resampled.AppendVertex(Vector3d.Lerp(vertices[k], n, corner_t)); } } return(resampled); }
/// <summary> /// Creates g3.DCurve from Vector3[] /// </summary> /// <param name="curve">DCurve</param> /// <param name="verteces">Vextor3[]</param> /// <param name="bClosed">whether the line is closed</param> public static void Vector3(this g3.DCurve3 curve, Vector3[] verteces, bool bClosed) { curve.ClearVertices(); curve.Closed = bClosed; foreach (Vector3 vertex in verteces) { curve.AppendVertex(vertex); } }
public void Make(DCurve3 c) { int nV = vertices.Count; for (int i = 0; i < nV; ++i) { c.AppendVertex(vertices[i]); } c.Closed = closed; }
public static DCurve3 ExtractLoopV(IMesh mesh, int[] vertices) { DCurve3 curve = new DCurve3(); for (int i = 0; i < vertices.Length; ++i) { curve.AppendVertex(mesh.GetVertex(vertices[i])); } curve.Closed = true; return(curve); }
public static DCurve3 ExtractLoopV(IMesh mesh, IEnumerable <int> vertices) { DCurve3 curve = new DCurve3(); foreach (int vid in vertices) { curve.AppendVertex(mesh.GetVertex(vid)); } curve.Closed = true; return(curve); }
public static void Restore(DCurve3 curve, BinaryReader reader) { curve.Closed = reader.ReadBoolean(); int count = reader.ReadInt32(); for (int i = 0; i < count; ++i) { double x = reader.ReadDouble(); double y = reader.ReadDouble(); double z = reader.ReadDouble(); curve.AppendVertex(new Vector3d(x, y, z)); } }
/// <summary> /// Decompose graph into simple polylines and polygons. /// </summary> public static Curves ExtractCurves(DGraph3 graph) { Curves c = new Curves(); c.Loops = new List <DCurve3>(); c.Paths = new List <DCurve3>(); HashSet <int> used = new HashSet <int>(); // find boundary and junction vertices HashSet <int> boundaries = new HashSet <int>(); HashSet <int> junctions = new HashSet <int>(); foreach (int vid in graph.VertexIndices()) { if (graph.IsBoundaryVertex(vid)) { boundaries.Add(vid); } if (graph.IsJunctionVertex(vid)) { junctions.Add(vid); } } // walk paths from boundary vertices foreach (int start_vid in boundaries) { int vid = start_vid; int eid = graph.GetVtxEdges(vid)[0]; if (used.Contains(eid)) { continue; } DCurve3 path = new DCurve3() { Closed = false }; path.AppendVertex(graph.GetVertex(vid)); while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; path.AppendVertex(graph.GetVertex(vid)); if (boundaries.Contains(vid) || junctions.Contains(vid)) { break; // done! } } c.Paths.Add(path); } // ok we should be done w/ boundary verts now... boundaries.Clear(); foreach (int start_vid in junctions) { foreach (int outgoing_eid in graph.VtxEdgesItr(start_vid)) { if (used.Contains(outgoing_eid)) { continue; } int vid = start_vid; int eid = outgoing_eid; DCurve3 path = new DCurve3() { Closed = false }; path.AppendVertex(graph.GetVertex(vid)); while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; path.AppendVertex(graph.GetVertex(vid)); if (eid == int.MaxValue || junctions.Contains(vid)) { break; // done! } } // we could end up back at our start junction vertex! if (vid == start_vid) { path.RemoveVertex(path.VertexCount - 1); path.Closed = true; c.Loops.Add(path); // need to mark incoming edge as used...but is it valid now? //Util.gDevAssert(eid != int.MaxValue); if (eid != int.MaxValue) { used.Add(eid); } } else { c.Paths.Add(path); } } } // all that should be left are continuous loops... foreach (int start_eid in graph.EdgeIndices()) { if (used.Contains(start_eid)) { continue; } int eid = start_eid; Index2i ev = graph.GetEdgeV(eid); int vid = ev.a; DCurve3 poly = new DCurve3() { Closed = true }; poly.AppendVertex(graph.GetVertex(vid)); while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; poly.AppendVertex(graph.GetVertex(vid)); if (eid == int.MaxValue || junctions.Contains(vid)) { throw new Exception("how did this happen??"); } if (used.Contains(eid)) { break; } } poly.RemoveVertex(poly.VertexCount - 1); c.Loops.Add(poly); } return(c); }
/// <summary> /// Decompose graph into simple polylines and polygons. /// </summary> public static Curves ExtractCurves(DGraph3 graph, bool bWantLoopIndices = false, Func <int, bool> CurveOrientationF = null) { var c = new Curves(); c.Loops = new List <DCurve3>(); c.Paths = new List <DCurve3>(); if (bWantLoopIndices) { c.LoopEdges = new List <List <int> >(); c.PathEdges = new List <List <int> >(); } var used = new HashSet <int>(); // find boundary and junction vertices var boundaries = new HashSet <int>(); var junctions = new HashSet <int>(); foreach (int vid in graph.VertexIndices()) { if (graph.IsBoundaryVertex(vid)) { boundaries.Add(vid); } if (graph.IsJunctionVertex(vid)) { junctions.Add(vid); } } // walk paths from boundary vertices foreach (int start_vid in boundaries) { int vid = start_vid; int eid = graph.GetVtxEdges(vid)[0]; if (used.Contains(eid)) { continue; } bool reverse = (CurveOrientationF != null) ? CurveOrientationF(eid) : false; var path = new DCurve3() { Closed = false }; List <int> pathE = (bWantLoopIndices) ? new List <int>() : null; path.AppendVertex(graph.GetVertex(vid)); if (pathE != null) { pathE.Add(eid); } while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; path.AppendVertex(graph.GetVertex(vid)); if (boundaries.Contains(vid) || junctions.Contains(vid)) { break; // done! } if (pathE != null) { pathE.Add(eid); } } if (reverse) { path.Reverse(); } c.Paths.Add(path); if (pathE != null) { Util.gDevAssert(pathE.Count == path.VertexCount - 1); if (reverse) { pathE.Reverse(); } c.PathEdges.Add(pathE); } } // ok we should be done w/ boundary verts now... //boundaries.Clear(); c.BoundaryV = boundaries; foreach (int start_vid in junctions) { foreach (int outgoing_eid in graph.VtxEdgesItr(start_vid)) { if (used.Contains(outgoing_eid)) { continue; } int vid = start_vid; int eid = outgoing_eid; bool reverse = (CurveOrientationF != null) ? CurveOrientationF(eid) : false; var path = new DCurve3() { Closed = false }; List <int> pathE = (bWantLoopIndices) ? new List <int>() : null; path.AppendVertex(graph.GetVertex(vid)); if (pathE != null) { pathE.Add(eid); } while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; path.AppendVertex(graph.GetVertex(vid)); if (eid == int.MaxValue || junctions.Contains(vid)) { break; // done! } if (pathE != null) { pathE.Add(eid); } } // we could end up back at our start junction vertex! if (vid == start_vid) { path.RemoveVertex(path.VertexCount - 1); path.Closed = true; if (reverse) { path.Reverse(); } c.Loops.Add(path); if (pathE != null) { Util.gDevAssert(pathE.Count == path.VertexCount); if (reverse) { pathE.Reverse(); } c.LoopEdges.Add(pathE); } // need to mark incoming edge as used...but is it valid now? //Util.gDevAssert(eid != int.MaxValue); if (eid != int.MaxValue) { used.Add(eid); } } else { if (reverse) { path.Reverse(); } c.Paths.Add(path); if (pathE != null) { Util.gDevAssert(pathE.Count == path.VertexCount - 1); if (reverse) { pathE.Reverse(); } c.PathEdges.Add(pathE); } } } } c.JunctionV = junctions; // all that should be left are continuous loops... foreach (int start_eid in graph.EdgeIndices()) { if (used.Contains(start_eid)) { continue; } int eid = start_eid; Index2i ev = graph.GetEdgeV(eid); int vid = ev.a; bool reverse = (CurveOrientationF != null) ? CurveOrientationF(eid) : false; var poly = new DCurve3() { Closed = true }; List <int> polyE = (bWantLoopIndices) ? new List <int>() : null; poly.AppendVertex(graph.GetVertex(vid)); if (polyE != null) { polyE.Add(eid); } while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; poly.AppendVertex(graph.GetVertex(vid)); if (polyE != null) { polyE.Add(eid); } if (eid == int.MaxValue || junctions.Contains(vid)) { throw new Exception("how did this happen??"); } if (used.Contains(eid)) { break; } } poly.RemoveVertex(poly.VertexCount - 1); if (reverse) { poly.Reverse(); } c.Loops.Add(poly); if (polyE != null) { polyE.RemoveAt(polyE.Count - 1); Util.gDevAssert(polyE.Count == poly.VertexCount); if (reverse) { polyE.Reverse(); } c.LoopEdges.Add(polyE); } } return(c); }