public double Distance(Vector2d point) { Vector2d PmC = point - Center; double lengthPmC = PmC.Length; if (lengthPmC > MathUtil.Epsilon) { Vector2d dv = PmC / lengthPmC; double theta = Math.Atan2(dv.y, dv.x); if (theta < AngleStartDeg || theta > AngleEndDeg) { theta = MathUtil.Clamp(theta, AngleStartDeg * MathUtil.Deg2Rad, AngleEndDeg * MathUtil.Deg2Rad); double c = Math.Cos(theta), s = Math.Sin(theta); Vector2d pos = new Vector2d(Center.x + Radius * c, Center.y + Radius * s); return(pos.Distance(point)); } else { return(Math.Abs(lengthPmC - Radius)); } } else { return(Radius); } }
public double Distance(Vector2d point) { Vector2d PmC = point - Center; double lengthPmC = PmC.Length; if (lengthPmC > MathUtil.Epsilon) { Vector2d dv = PmC / lengthPmC; double theta = Math.Atan2(dv.y, dv.x) * MathUtil.Rad2Deg; if (!(theta >= AngleStartDeg && theta <= AngleEndDeg)) { double ctheta = MathUtil.ClampAngleDeg(theta, AngleStartDeg, AngleEndDeg); double radians = ctheta * MathUtil.Deg2Rad; double c = Math.Cos(radians), s = Math.Sin(radians); Vector2d pos = new Vector2d(Center.x + Radius * c, Center.y + Radius * s); return(pos.Distance(point)); } else { return(Math.Abs(lengthPmC - Radius)); } } else { return(Radius); } }
/// <summary> /// find nearest boundary vertex, within searchRadius /// </summary> protected int find_nearest_boundary_vertex(Vector2d pt, double searchRadius, int ignore_vid = -1) { KeyValuePair <int, double> found = PointHash.FindNearestInRadius(pt, searchRadius, (b) => { return(pt.Distance(Graph.GetVertex(b))); }, (vid) => { return(Graph.IsBoundaryVertex(vid) == false || vid == ignore_vid); }); if (found.Key == PointHash.InvalidValue) { return(-1); } return(found.Key); }
private static int MergeAppendVertex(DGraph2 graph, Vector2d vertex, double mergeThreshold) { for (int i = 0; i < graph.VertexCount; i++) { double d = vertex.Distance(graph.GetVertex(i)); if (d < mergeThreshold) { return(i); } } return(graph.AppendVertex(vertex)); }
/// <summary> /// compute length of path through graph /// </summary> public static double PathLength(DGraph2 graph, IList <int> pathVertices) { double len = 0; int N = pathVertices.Count; Vector2d prev = graph.GetVertex(pathVertices[0]), next = Vector2d.Zero; for (int i = 1; i < N; ++i) { next = graph.GetVertex(pathVertices[i]); len += prev.Distance(next); prev = next; } return(len); }
public void CollapseDegenerateEdges(double fDegenLenThresh = MathUtil.Epsilonf) { bool done = false; int max_passes = 100; int pass_count = 0; while (done == false && pass_count++ < max_passes) { done = true; int N = Graph.MaxEdgeID; for (int eid = 0; eid < N; eid++) { if (!Graph.IsEdge(eid)) { continue; } if (FixedEdgeFilterF(eid)) { continue; } Index2i ev = Graph.GetEdgeV(eid); Vector2d va = Graph.GetVertex(ev.a); Vector2d vb = Graph.GetVertex(ev.b); if (va.Distance(vb) < fDegenLenThresh) { int keep = ev.a; int remove = ev.b; DGraph2.EdgeCollapseInfo collapseInfo; if (Graph.CollapseEdge(keep, remove, out collapseInfo) == MeshResult.Ok) { done = false; } } } ; } }
public double SignedDistance(Vector2d pt) { double d = Center.Distance(pt); return(d - Radius); }
override public MeshGenerator Generate() { if (Polygon == null) { Polygon = Polygon2d.MakeCircle(1.0f, 8); } int NV = Vertices.Count; int Slices = Polygon.VertexCount; int nRings = (ClosedLoop && NoSharedVertices) ? NV + 1 : NV; int nRingSize = (NoSharedVertices) ? Slices + 1 : Slices; int nCapVertices = (NoSharedVertices) ? Slices + 1 : 1; if (Capped == false || ClosedLoop == true) { nCapVertices = 0; } vertices = new VectorArray3d(nRings * nRingSize + 2 * nCapVertices); uv = new VectorArray2f(vertices.Count); normals = new VectorArray3f(vertices.Count); int quad_strips = (ClosedLoop) ? NV : NV - 1; int nSpanTris = quad_strips * (2 * Slices); int nCapTris = (Capped && ClosedLoop == false) ? 2 * Slices : 0; triangles = new IndexArray3i(nSpanTris + nCapTris); Frame3f fCur = new Frame3f(Frame); Vector3d dv = CurveUtils.GetTangent(Vertices, 0, ClosedLoop); fCur.Origin = (Vector3f)Vertices[0]; fCur.AlignAxis(2, (Vector3f)dv); Frame3f fStart = new Frame3f(fCur); double circumference = Polygon.ArcLength; double pathLength = CurveUtils.ArcLength(Vertices, ClosedLoop); double accum_path_u = 0; // generate tube for (int ri = 0; ri < nRings; ++ri) { int vi = ri % NV; // propagate frame Vector3d tangent = CurveUtils.GetTangent(Vertices, vi, ClosedLoop); fCur.Origin = (Vector3f)Vertices[vi]; fCur.AlignAxis(2, (Vector3f)tangent); // generate vertices int nStartR = ri * nRingSize; double accum_ring_v = 0; for (int j = 0; j < nRingSize; ++j) { int k = nStartR + j; Vector2d pv = Polygon.Vertices[j % Slices]; Vector2d pvNext = Polygon.Vertices[(j + 1) % Slices]; Vector3d v = fCur.FromPlaneUV((Vector2f)pv, 2); vertices[k] = v; uv[k] = new Vector2f(accum_path_u, accum_ring_v); accum_ring_v += (pv.Distance(pvNext) / circumference); Vector3f n = (Vector3f)(v - fCur.Origin).Normalized; normals[k] = n; } int viNext = (ri + 1) % NV; double d = Vertices[vi].Distance(Vertices[viNext]); accum_path_u += d / pathLength; } // generate triangles int ti = 0; int nStop = (ClosedLoop && NoSharedVertices == false) ? nRings : (nRings - 1); for (int ri = 0; ri < nStop; ++ri) { int r0 = ri * nRingSize; int r1 = r0 + nRingSize; if (ClosedLoop && ri == nStop - 1 && NoSharedVertices == false) { r1 = 0; } for (int k = 0; k < nRingSize - 1; ++k) { triangles.Set(ti++, r0 + k, r0 + k + 1, r1 + k + 1, Clockwise); triangles.Set(ti++, r0 + k, r1 + k + 1, r1 + k, Clockwise); } if (NoSharedVertices == false) // last quad if we aren't sharing vertices { int M = nRingSize - 1; triangles.Set(ti++, r0 + M, r0, r1, Clockwise); triangles.Set(ti++, r0 + M, r1, r1 + M, Clockwise); } } if (Capped && ClosedLoop == false) { Vector2d c = (OverrideCapCenter) ? CapCenter : Polygon.Bounds.Center; // add endcap verts int nBottomC = nRings * nRingSize; vertices[nBottomC] = fStart.FromPlaneUV((Vector2f)c, 2); uv[nBottomC] = new Vector2f(0.5f, 0.5f); normals[nBottomC] = -fStart.Z; startCapCenterIndex = nBottomC; int nTopC = nBottomC + 1; vertices[nTopC] = fCur.FromPlaneUV((Vector2f)c, 2); uv[nTopC] = new Vector2f(0.5f, 0.5f); normals[nTopC] = fCur.Z; endCapCenterIndex = nTopC; if (NoSharedVertices) { // duplicate first loop and make a fan w/ bottom-center int nExistingB = 0; int nStartB = nTopC + 1; for (int k = 0; k < Slices; ++k) { vertices[nStartB + k] = vertices[nExistingB + k]; Vector2d vuv = ((Polygon[k] - c).Normalized + Vector2d.One) * 0.5; uv[nStartB + k] = (Vector2f)vuv; normals[nStartB + k] = normals[nBottomC]; } append_disc(Slices, nBottomC, nStartB, true, Clockwise, ref ti); // duplicate second loop and make fan int nExistingT = nRingSize * (nRings - 1); int nStartT = nStartB + Slices; for (int k = 0; k < Slices; ++k) { vertices[nStartT + k] = vertices[nExistingT + k]; uv[nStartT + k] = uv[nStartB + k]; normals[nStartT + k] = normals[nTopC]; } append_disc(Slices, nTopC, nStartT, true, !Clockwise, ref ti); } else { append_disc(Slices, nBottomC, 0, true, Clockwise, ref ti); append_disc(Slices, nTopC, nRingSize * (nRings - 1), true, !Clockwise, ref ti); } } return(this); }
// (sequentially) find each triangle that path point lies in, and insert a vertex for // that point into mesh. void insert_corners(HashSet <int> MeshVertsOnCurve) { PrimalQuery2d query = new PrimalQuery2d(PointF); if (UseTriSpatial) { int count = Mesh.TriangleCount + Curve.VertexCount; int bins = 32; if (count < 25) { bins = 8; } else if (count < 100) { bins = 16; } AxisAlignedBox3d bounds3 = Mesh.CachedBounds; AxisAlignedBox2d bounds2 = new AxisAlignedBox2d(bounds3.Min.xy, bounds3.Max.xy); triSpatial = new TriangleBinsGrid2d(bounds2, bins); foreach (int tid in Mesh.TriangleIndices()) { spatial_add_triangle(tid); } } Func <int, Vector2d, bool> inTriangleF = (tid, pos) => { Index3i tv = Mesh.GetTriangle(tid); int query_result = query.ToTriangleUnsigned(pos, tv.a, tv.b, tv.c); return(query_result == -1 || query_result == 0); }; CurveVertices = new int[Curve.VertexCount]; for (int i = 0; i < Curve.VertexCount; ++i) { Vector2d vInsert = Curve[i]; bool inserted = false; // find the triangle that contains this curve point int contain_tid = DMesh3.InvalidID; if (triSpatial != null) { contain_tid = triSpatial.FindContainingTriangle(vInsert, inTriangleF); } else { foreach (int tid in Mesh.TriangleIndices()) { Index3i tv = Mesh.GetTriangle(tid); // [RMS] using unsigned query here because we do not need to care about tri CW/CCW orientation // (right? otherwise we have to explicitly invert mesh. Nothing else we do depends on tri orientation) //int query_result = query.ToTriangle(vInsert, tv.a, tv.b, tv.c); int query_result = query.ToTriangleUnsigned(vInsert, tv.a, tv.b, tv.c); if (query_result == -1 || query_result == 0) { contain_tid = tid; break; } } } // if we found one, insert the point via face-poke or edge-split, // unless it is exactly at existing vertex, in which case we can re-use it if (contain_tid != DMesh3.InvalidID) { Index3i tv = Mesh.GetTriangle(contain_tid); Vector3d bary = MathUtil.BarycentricCoords(vInsert, PointF(tv.a), PointF(tv.b), PointF(tv.c)); // SpatialEpsilon is our zero-tolerance, so merge if we are closer than that bool is_existing_v; int vid = insert_corner_from_bary(i, contain_tid, bary, 0.01, 100 * SpatialEpsilon, out is_existing_v); if (vid > 0) { CurveVertices[i] = vid; if (is_existing_v) { MeshVertsOnCurve.Add(vid); } inserted = true; } } // if we did not find containing triangle, // try matching with any existing vertices. // This can happen if curve point is right on mesh border... if (inserted == false) { foreach (int vid in Mesh.VertexIndices()) { Vector2d v = PointF(vid); if (vInsert.Distance(v) < SpatialEpsilon) { CurveVertices[i] = vid; MeshVertsOnCurve.Add(vid); inserted = true; } } } // TODO: also case where curve point is right on mesh border edge, // and so it ends up being outside all triangles? if (inserted == false) { throw new Exception("MeshInsertUVPolyCurve.insert_corners: curve vertex " + i.ToString() + " is not inside or on any mesh triangle!"); } } }