internal double GetTriangleAnglesQuality(g3.DMesh3 mesh) { Vector3d v0 = Vector3d.Zero, v1 = Vector3d.Zero, v2 = Vector3d.Zero; mesh.GetTriVertices(meshIndex, ref v0, ref v1, ref v2); Vector3d anglesD = Vector3d.Zero; Vector3d e00 = (v1 - v0); e00.Normalize(); Vector3d e01 = (v2 - v0); e01.Normalize(); anglesD.x = Vector3d.AngleD(e00, e01); Vector3d e10 = (v0 - v1); e10.Normalize(); Vector3d e11 = (v2 - v1); e11.Normalize(); anglesD.y = Vector3d.AngleD(e10, e11); anglesD.z = 180 - anglesD.x - anglesD.y; double resultA = Math.Min(Math.Min(Math.Abs(anglesD.x - 90) / 10.0, Math.Abs(anglesD.y - 90) / 10.0), Math.Abs(anglesD.z - 90) / 10.0); double resultB = Math.Abs(anglesD.x - 60) / 30.0 + Math.Abs(anglesD.y - 60) / 30.0 + Math.Abs(anglesD.z - 60) / 30.0; double result = Math.Min(resultA, resultB); return(Math.Pow(result, 3)); }
internal double CompuateAverageArea(g3.DMesh3 mesh) { double area = this.TriangleArea(mesh); foreach (var n in neighbors) { area += n.TriangleArea(mesh); } area /= (neighbors.Count + 1); return(area); }
internal bool Randomize(g3.DMesh3 mesh, DMeshAABBTree3 tree, Random r, double max, double moveTries, double average) { bool result = false; for (int i = 0; i < moveTries; i++) { result |= this.RandomAdjust(mesh, tree, r, max, moveTries, average); //foreach (var n in neighbors) // result |= n.RandomAdjust(mesh, tree, r, max, moveTries, average); } return(result); }
public static g3.DMesh3 ConvertToD3Mesh(Rhino.Geometry.Mesh mesh) { g3.DMesh3 ret = new g3.DMesh3(true, false, false, false); if (mesh.Normals.Count < mesh.Vertices.Count) { mesh.Normals.ComputeNormals(); } if (mesh.Normals.Count != mesh.Vertices.Count) { return(ret); } for (int i = 0; i < mesh.Vertices.Count; i++) { var vertex = new g3.NewVertexInfo(); vertex.n = new g3.Vector3f(mesh.Normals[i].X, mesh.Normals[i].Y, mesh.Normals[i].Z); vertex.v = new g3.Vector3d(mesh.Vertices[i].X, mesh.Vertices[i].Y, mesh.Vertices[i].Z); ret.AppendVertex(vertex); } foreach (var mf in mesh.Faces) { if (mf.IsQuad) { double dist1 = mesh.Vertices[mf.A].DistanceTo(mesh.Vertices[mf.C]); double dist2 = mesh.Vertices[mf.B].DistanceTo(mesh.Vertices[mf.D]); if (dist1 > dist2) { ret.AppendTriangle(mf.A, mf.B, mf.D); ret.AppendTriangle(mf.B, mf.C, mf.D); } else { ret.AppendTriangle(mf.A, mf.B, mf.C); ret.AppendTriangle(mf.A, mf.C, mf.D); } } else { ret.AppendTriangle(mf.A, mf.B, mf.C); } } return(ret); }
double GetNormalQuality(g3.DMesh3 mesh, g3.Vector3d target, int depth) { if (depth == 0) { return(1 - (mesh.GetTriNormal(meshIndex).Dot(target))); } double amount = GetNormalQuality(mesh, target, 0); foreach (var n in neighbors) { amount += GetNormalQuality(mesh, target, depth - 1); } return(amount); }
internal double GetTriangleTotalAnglesQualityHelper(g3.DMesh3 mesh, int depth) { double total = GetTriangleAnglesQuality(mesh); if (depth == 0) { return(total); } foreach (var n in neighbors) { total += GetTriangleTotalAnglesQualityHelper(mesh, depth - 1); } return(total / (neighbors.Count + 1)); }
internal double HowCloseToTargetArea(g3.DMesh3 mesh, double targetArea, int depth) { double area = Math.Pow(Math.Abs(this.TriangleArea(mesh) - targetArea) / targetArea, 3) * 3; if (depth == 0) { return(area); } foreach (var n in neighbors) { area += n.HowCloseToTargetArea(mesh, targetArea, depth - 1); } return(area / (neighbors.Count + 1)); }
public static Rhino.Geometry.Mesh ConvertToRhinoMesh(g3.DMesh3 largeMesh) { var mesh = new g3.DMesh3(); mesh.CompactCopy(largeMesh); Rhino.Geometry.Mesh ret = new Rhino.Geometry.Mesh(); foreach (var p in mesh.Vertices()) { ret.Vertices.Add(new Rhino.Geometry.Point3d(p.x, p.y, p.z)); } ret.Normals.Count = ret.Vertices.Count; for (int i = 0; i < ret.Vertices.Count; i++) { var n = mesh.GetVertexNormal(i); ret.Normals[i] = new Rhino.Geometry.Vector3f(n.x, n.y, n.z); } foreach (var f in mesh.Triangles()) { if (f.a >= 0 && f.a < ret.Vertices.Count && f.b >= 0 && f.b < ret.Vertices.Count && f.c >= 0 && f.c < ret.Vertices.Count) { ret.Faces.AddFace(new Rhino.Geometry.MeshFace(f.a, f.b, f.c)); } else { Rhino.RhinoApp.WriteLine("Error Triangle:" + f.a + "," + f.b + ",", +f.c); } } ret.Normals.ComputeNormals(); return(ret); }
public DSubmesh3(DMesh3 mesh, IEnumerable <int> subTriangles, int nTriEstimate = 0) { BaseMesh = mesh; compute(subTriangles, nTriEstimate); }
public static DMesh3 RemeshMesh(g3.DMesh3 mesh, float minEdgeLength, float maxEdgeLength, float contraintAngle, float smoothSpeed, int smoothPasses, List <Line3d> constrainedLines) { // construct mesh projection target DMesh3 meshCopy = new DMesh3(mesh); DMeshAABBTree3 tree = new DMeshAABBTree3(meshCopy); tree.Build(); MeshProjectionTarget target = new MeshProjectionTarget() { Mesh = meshCopy, Spatial = tree }; MeshConstraints cons = new MeshConstraints(); EdgeRefineFlags useFlags = EdgeRefineFlags.NoFlip; foreach (int eid in mesh.EdgeIndices()) { double fAngle = MeshUtil.OpeningAngleD(mesh, eid); Index2i ev = mesh.GetEdgeV(eid); if (fAngle > contraintAngle) { cons.SetOrUpdateEdgeConstraint(eid, new EdgeConstraint(useFlags)); // TODO Ids based off of ?? What? int nSetID0 = (mesh.GetVertex(ev[0]).y > 1) ? 1 : 2; int nSetID1 = (mesh.GetVertex(ev[1]).y > 1) ? 1 : 2; cons.SetOrUpdateVertexConstraint(ev[0], new VertexConstraint(true, nSetID0)); cons.SetOrUpdateVertexConstraint(ev[1], new VertexConstraint(true, nSetID1)); } Vector3d p1 = mesh.GetVertex(ev.a); Vector3d p2 = mesh.GetVertex(ev.b); foreach (var v in constrainedLines) { if (p1.CompareTo(v.Origin) == 0) { Vector3d p = v.PointAt(1.0); if (p2.CompareTo(p) == 0) { cons.SetOrUpdateEdgeConstraint(eid, EdgeConstraint.FullyConstrained); break; } } } foreach (var v in constrainedLines) { if (p2.CompareTo(v.Origin) == 0) { Vector3d p = v.PointAt(1.0); if (p1.CompareTo(p) == 0) { cons.SetOrUpdateEdgeConstraint(eid, EdgeConstraint.FullyConstrained); break; } } } } Remesher r = new Remesher(mesh); r.SetExternalConstraints(cons); r.SetProjectionTarget(target); r.Precompute(); r.EnableFlips = r.EnableSplits = r.EnableCollapses = true; r.MinEdgeLength = minEdgeLength; //0.1f; r.MaxEdgeLength = maxEdgeLength; // 0.2f; r.EnableSmoothing = true; r.SmoothSpeedT = smoothSpeed; // .5; for (int k = 0; k < smoothPasses; ++k) // smoothPasses = 20 { r.BasicRemeshPass(); } return(mesh); }
// public static DMesh3 RemeshMeshNew(g3.DMesh3 mesh, float minEdgeLength, float maxEdgeLength, float contraintAngle, float smoothSpeed, int smoothPasses, g3.DMesh3 projectMeshInput = null, float projectAmount = 1.0f, float projectedDistance = float.MaxValue) { g3.DMesh3 projectMesh = projectMeshInput; if (projectMesh == null) { projectMesh = mesh; } DMesh3 projectMeshCopy = new DMesh3(projectMesh); DMeshAABBTree3 treeProject = new DMeshAABBTree3(projectMeshCopy); treeProject.Build(); GopherMeshProjectionTarget targetProject = new GopherMeshProjectionTarget() { Mesh = projectMeshCopy, Spatial = treeProject, amount = projectAmount, maxDistance = projectedDistance }; MeshConstraints cons = new MeshConstraints(); EdgeRefineFlags useFlags = EdgeRefineFlags.NoFlip; foreach (int eid in mesh.EdgeIndices()) { double fAngle = MeshUtil.OpeningAngleD(mesh, eid); if (fAngle > contraintAngle) { cons.SetOrUpdateEdgeConstraint(eid, new EdgeConstraint(useFlags)); Index2i ev = mesh.GetEdgeV(eid); //int nSetID0 = (mesh.GetVertex(ev[0]).y > 1) ? 1 : 2; //int nSetID1 = (mesh.GetVertex(ev[1]).y > 1) ? 1 : 2; cons.SetOrUpdateVertexConstraint(ev[0], new VertexConstraint(true)); cons.SetOrUpdateVertexConstraint(ev[1], new VertexConstraint(true)); } } // TODO Constrain Vertices too far away foreach (int vid in mesh.VertexIndices()) { var v = mesh.GetVertex(vid); //v.Distance() //targetProject.Project() } Remesher rProjected = new Remesher(mesh); rProjected.SetExternalConstraints(cons); rProjected.SetProjectionTarget(targetProject); rProjected.Precompute(); rProjected.EnableFlips = rProjected.EnableSplits = rProjected.EnableCollapses = true; rProjected.MinEdgeLength = minEdgeLength; //0.1f; rProjected.MaxEdgeLength = maxEdgeLength; // 0.2f; rProjected.EnableSmoothing = true; rProjected.SmoothSpeedT = smoothSpeed; // .5; if (projectMeshInput != null) { float bestSmoothPassProjectAmount = projectAmount / smoothPasses; float testbestSmoothPassProjectAmount = float.MaxValue; for (float smoothPassProjectAmount = -.1f; smoothPassProjectAmount < 1.1f; smoothPassProjectAmount += 0.005f) { double test = 0; for (int i = 0; i < smoothPasses; i++) { test = 1.0 * smoothPassProjectAmount + test * (1 - smoothPassProjectAmount); } if (Math.Abs(test - projectAmount) < Math.Abs(testbestSmoothPassProjectAmount - projectAmount)) { bestSmoothPassProjectAmount = (float)smoothPassProjectAmount; testbestSmoothPassProjectAmount = (float)test; } } targetProject.amount = bestSmoothPassProjectAmount; targetProject.maxDistance = projectedDistance; for (int k = 0; k < smoothPasses; ++k) // smoothPasses = 20 { rProjected.BasicRemeshPass(); } } else { for (int k = 0; k < smoothPasses; ++k) // smoothPasses = 20 { rProjected.BasicRemeshPass(); } } return(mesh); }
public LaplacianMeshDeformer(DMesh3 mesh) { Mesh = mesh; Util.gDevAssert(mesh.IsCompact); }
internal double TriangleArea(g3.DMesh3 mesh) { return(mesh.GetTriArea(meshIndex)); }
public MeshBoundaryLoops(DMesh3 mesh) { this.Mesh = mesh; Compute(); }
public MeshProjectionTarget(DMesh3 mesh, ISpatial spatial) { Mesh = mesh; Spatial = spatial; }
static List <int> walk_edge_span_forward(DMesh3 mesh, int start_edge, int start_pivot_v, HashSet <int> EdgeSet, out bool bClosedLoop) { bClosedLoop = false; List <int> edgeSpan = new List <int>(); edgeSpan.Add(start_edge); // we update this as we step //int cur_edge = start_edge; int cur_pivot_v = start_pivot_v; int stop_pivot_v = IndexUtil.find_edge_other_v(mesh.GetEdgeV(start_edge), start_pivot_v); Util.gDevAssert(stop_pivot_v != DMesh3.InvalidID); bool done = false; while (!done) { // fink outgoing edge in set and connected to current pivot vtx int next_edge = -1; foreach (int nbr_edge in mesh.VtxEdgesItr(cur_pivot_v)) { if (EdgeSet.Contains(nbr_edge)) { next_edge = nbr_edge; break; } } // could not find - must be done span if (next_edge == -1) { done = true; break; } // figure out next pivot vtx (is 'other' from current pivot on next edge) Index2i next_edge_v = mesh.GetEdgeV(next_edge); if (next_edge_v.a == cur_pivot_v) { cur_pivot_v = next_edge_v.b; } else if (next_edge_v.b == cur_pivot_v) { cur_pivot_v = next_edge_v.a; } else { throw new Exception("walk_edge_span_forward: found valid next edge but not connected to previous vertex??"); } edgeSpan.Add(next_edge); EdgeSet.Remove(next_edge); // if this happens, we closed a loop if (cur_pivot_v == stop_pivot_v) { done = true; bClosedLoop = true; } } return(edgeSpan); }
public MeshIsoCurves(DMesh3 mesh, Func <Vector3d, double> valueF) { Mesh = mesh; ValueF = valueF; }
public Remesher(DMesh3 m) : base(m) { }
public IndexHashSet BaseBorderV; // list of border vertex indices on base mesh public DSubmesh3(DMesh3 mesh, int[] subTriangles) { BaseMesh = mesh; compute(subTriangles, subTriangles.Length); }
public DMeshIntersectionTarget(DMesh3 mesh, ISpatial spatial) { Mesh = mesh; Spatial = spatial; }
internal bool RandomAdjust(g3.DMesh3 mesh, DMeshAABBTree3 tree, Random r, double max, double moveTries, double targetArea) { bool moved = false; if (this.locked) { return(false); } for (int i = 0; i < moveTries; i++) { var v0 = mesh.GetVertex(vertex_index.a); var v1 = mesh.GetVertex(vertex_index.b); var v2 = mesh.GetVertex(vertex_index.c); var v0_old = mesh.GetVertex(vertex_index.a); var v1_old = mesh.GetVertex(vertex_index.b); var v2_old = mesh.GetVertex(vertex_index.c); v0.x += (r.NextDouble() * max * 2 - max); v0.y += (r.NextDouble() * max * 2 - max); v0.z += (r.NextDouble() * max * 2 - max); v1.x += (r.NextDouble() * max * 2 - max); v1.y += (r.NextDouble() * max * 2 - max); v1.z += (r.NextDouble() * max * 2 - max); v2.x += (r.NextDouble() * max * 2 - max); v2.y += (r.NextDouble() * max * 2 - max); v2.z += (r.NextDouble() * max * 2 - max); int tNearestID = tree.FindNearestTriangle(v0); DistPoint3Triangle3 q = MeshQueries.TriangleDistance(tree.Mesh, tNearestID, v0); v0 = q.TriangleClosest; tNearestID = tree.FindNearestTriangle(v1); q = MeshQueries.TriangleDistance(tree.Mesh, tNearestID, v1); v1 = q.TriangleClosest; tNearestID = tree.FindNearestTriangle(v2); q = MeshQueries.TriangleDistance(tree.Mesh, tNearestID, v2); v2 = q.TriangleClosest; double oldArea = (HowCloseToTargetArea(mesh, targetArea, 2) / targetArea) * 3; double oldAngleQuality = GetTriangleTotalAnglesQualityHelper(mesh, 2); var n = mesh.GetTriNormal(meshIndex); double oldNormalQuality = GetNormalQuality(mesh, n, 2) * 6; mesh.SetVertex(vertex_index.a, v0); mesh.SetVertex(vertex_index.b, v1); mesh.SetVertex(vertex_index.c, v2); double newArea = (HowCloseToTargetArea(mesh, targetArea, 2) / targetArea) * 3; double newAngleQuality = GetTriangleTotalAnglesQualityHelper(mesh, 2); double newNormalQuality = GetNormalQuality(mesh, n, 2) * 6; if ((oldArea + oldAngleQuality + oldNormalQuality) < (newArea + newAngleQuality + newNormalQuality)) { mesh.SetVertex(vertex_index.a, v0_old); mesh.SetVertex(vertex_index.b, v1_old); mesh.SetVertex(vertex_index.c, v2_old); } else { moved = true; } } return(moved); }
public static bool RandomizeMesh(g3.DMesh3 mesh, out g3.DMesh3 outputMesh, double amount, double moveTries) { System.Collections.Generic.SortedDictionary <int, MeshNode> faces = new System.Collections.Generic.SortedDictionary <int, MeshNode>(); int index = 0; foreach (var meshFaceIndex in mesh.TriangleIndices()) { var frame = mesh.GetTriFrame(meshFaceIndex); g3.Index3i neighbors = mesh.GetTriNeighbourTris(meshFaceIndex); g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex); faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index)); } foreach (var f in faces) { f.Value.neighbors.Clear(); f.Value.neighbors.Capacity = 3; for (int i = 0; i < 3; ++i) { int fn = f.Value.neighbors_index[i]; if (fn >= 0) { f.Value.neighbors.Add(faces[fn]); } } if (f.Value.neighbors.Count < 3) { f.Value.locked = true; foreach (var n in f.Value.neighbors) { n.locked = true; } } } DMesh3 projectMeshCopy = new DMesh3(mesh); outputMesh = new DMesh3(mesh); if (faces.Count == 0) { return(false); } DMeshAABBTree3 treeProject = new DMeshAABBTree3(projectMeshCopy); treeProject.Build(); Random r = new Random(); bool result = false; //for (int i = 0; i < moveTries; i++) //{ double faceArea = 0; foreach (var f in faces) { faceArea += f.Value.TriangleArea(outputMesh); } faceArea /= faces.Count; foreach (var f in faces) { result |= f.Value.Randomize(outputMesh, treeProject, r, amount, moveTries, faceArea); } double newFaceArea = 0; foreach (var f in faces) { newFaceArea += f.Value.TriangleArea(outputMesh); } newFaceArea /= faces.Count; return(result); }
public MeshConnectedComponents(DMesh3 mesh) { Mesh = mesh; Components = new List <Component>(); }
public bool Fill() { compute_polygon(); // translate/scale fill loops to unit box. This will improve // accuracy in the calcs below... Vector2d shiftOrigin = Bounds.Center; double scale = 1.0 / Bounds.MaxDim; SpansPoly.Translate(-shiftOrigin); SpansPoly.Scale(scale * Vector2d.One, Vector2d.Zero); Dictionary <PlanarComplex.Element, int> ElemToLoopMap = new Dictionary <PlanarComplex.Element, int>(); // generate planar mesh that we will insert polygons into MeshGenerator meshgen; float planeW = 1.5f; int nDivisions = 0; if (FillTargetEdgeLen < double.MaxValue && FillTargetEdgeLen > 0) { int n = (int)((planeW / (float)scale) / FillTargetEdgeLen) + 1; nDivisions = (n <= 1) ? 0 : n; } if (nDivisions == 0) { meshgen = new TrivialRectGenerator() { IndicesMap = new Index2i(1, 2), Width = planeW, Height = planeW, }; } else { meshgen = new GriddedRectGenerator() { IndicesMap = new Index2i(1, 2), Width = planeW, Height = planeW, EdgeVertices = nDivisions }; } DMesh3 FillMesh = meshgen.Generate().MakeDMesh(); FillMesh.ReverseOrientation(); // why?!? int[] polyVertices = null; // insert each poly MeshInsertUVPolyCurve insert = new MeshInsertUVPolyCurve(FillMesh, SpansPoly); ValidationStatus status = insert.Validate(MathUtil.ZeroTolerancef * scale); bool failed = true; if (status == ValidationStatus.Ok) { if (insert.Apply()) { insert.Simplify(); polyVertices = insert.CurveVertices; failed = false; } } if (failed) { return(false); } // remove any triangles not contained in gpoly // [TODO] degenerate triangle handling? may be 'on' edge of gpoly... List <int> removeT = new List <int>(); foreach (int tid in FillMesh.TriangleIndices()) { Vector3d v = FillMesh.GetTriCentroid(tid); if (SpansPoly.Contains(v.xy) == false) { removeT.Add(tid); } } foreach (int tid in removeT) { FillMesh.RemoveTriangle(tid, true, false); } //Util.WriteDebugMesh(FillMesh, "c:\\scratch\\CLIPPED_MESH.obj"); // transform fill mesh back to 3d MeshTransforms.PerVertexTransform(FillMesh, (v) => { Vector2d v2 = v.xy; v2 /= scale; v2 += shiftOrigin; return(to3D(v2)); }); //Util.WriteDebugMesh(FillMesh, "c:\\scratch\\PLANAR_MESH_WITH_LOOPS.obj"); //Util.WriteDebugMesh(MeshEditor.Combine(FillMesh, Mesh), "c:\\scratch\\FILLED_MESH.obj"); // figure out map between new mesh and original edge loops // [TODO] if # of verts is different, we can still find correspondence, it is just harder // [TODO] should check that edges (ie sequential verts) are boundary edges on fill mesh // if not, can try to delete nbr tris to repair IndexMap mergeMapV = new IndexMap(true); if (MergeFillBoundary && polyVertices != null) { throw new NotImplementedException("PlanarSpansFiller: merge fill boundary not implemented!"); //int[] fillLoopVerts = polyVertices; //int NV = fillLoopVerts.Length; //PlanarComplex.Element sourceElem = (pi == 0) ? gsolid.Outer : gsolid.Holes[pi - 1]; //int loopi = ElemToLoopMap[sourceElem]; //EdgeLoop sourceLoop = Loops[loopi].edgeLoop; //for (int k = 0; k < NV; ++k) { // Vector3d fillV = FillMesh.GetVertex(fillLoopVerts[k]); // Vector3d sourceV = Mesh.GetVertex(sourceLoop.Vertices[k]); // if (fillV.Distance(sourceV) < MathUtil.ZeroTolerancef) // mergeMapV[fillLoopVerts[k]] = sourceLoop.Vertices[k]; //} } // append this fill to input mesh MeshEditor editor = new MeshEditor(Mesh); int[] mapV; editor.AppendMesh(FillMesh, mergeMapV, out mapV, Mesh.AllocateTriangleGroup()); // [TODO] should verify that we actually merged the loops... return(true); }
// compute distance from point to triangle ti in mesh, with minimal extra objects/etc // TODO: take in current-max-distance so we can early-out? public static double TriDistanceSqr(DMesh3 mesh, int ti, Vector3d point) { Vector3d V0 = Vector3d.Zero, V1 = Vector3d.Zero, V2 = Vector3d.Zero; mesh.GetTriVertices(ti, ref V0, ref V1, ref V2); Vector3d diff = V0 - point; Vector3d edge0 = V1 - V0; Vector3d edge1 = V2 - V0; double a00 = edge0.LengthSquared; double a01 = edge0.Dot(edge1); double a11 = edge1.LengthSquared; double b0 = diff.Dot(edge0); double b1 = diff.Dot(edge1); double c = diff.LengthSquared; double det = Math.Abs(a00 * a11 - a01 * a01); double s = a01 * b1 - a11 * b0; double t = a01 * b0 - a00 * b1; double sqrDistance; if (s + t <= det) { if (s < 0) { if (t < 0) // region 4 { if (b0 < 0) { t = 0; if (-b0 >= a00) { s = 1; sqrDistance = a00 + (2) * b0 + c; } else { s = -b0 / a00; sqrDistance = b0 * s + c; } } else { s = 0; if (b1 >= 0) { t = 0; sqrDistance = c; } else if (-b1 >= a11) { t = 1; sqrDistance = a11 + (2) * b1 + c; } else { t = -b1 / a11; sqrDistance = b1 * t + c; } } } else // region 3 { s = 0; if (b1 >= 0) { t = 0; sqrDistance = c; } else if (-b1 >= a11) { t = 1; sqrDistance = a11 + (2) * b1 + c; } else { t = -b1 / a11; sqrDistance = b1 * t + c; } } } else if (t < 0) // region 5 { t = 0; if (b0 >= 0) { s = 0; sqrDistance = c; } else if (-b0 >= a00) { s = 1; sqrDistance = a00 + (2) * b0 + c; } else { s = -b0 / a00; sqrDistance = b0 * s + c; } } else // region 0 // minimum at interior point { double invDet = (1) / det; s *= invDet; t *= invDet; sqrDistance = s * (a00 * s + a01 * t + (2) * b0) + t * (a01 * s + a11 * t + (2) * b1) + c; } } else { double tmp0, tmp1, numer, denom; if (s < 0) // region 2 { tmp0 = a01 + b0; tmp1 = a11 + b1; if (tmp1 > tmp0) { numer = tmp1 - tmp0; denom = a00 - (2) * a01 + a11; if (numer >= denom) { s = 1; t = 0; sqrDistance = a00 + (2) * b0 + c; } else { s = numer / denom; t = 1 - s; sqrDistance = s * (a00 * s + a01 * t + (2) * b0) + t * (a01 * s + a11 * t + (2) * b1) + c; } } else { s = 0; if (tmp1 <= 0) { t = 1; sqrDistance = a11 + (2) * b1 + c; } else if (b1 >= 0) { t = 0; sqrDistance = c; } else { t = -b1 / a11; sqrDistance = b1 * t + c; } } } else if (t < 0) // region 6 { tmp0 = a01 + b1; tmp1 = a00 + b0; if (tmp1 > tmp0) { numer = tmp1 - tmp0; denom = a00 - (2) * a01 + a11; if (numer >= denom) { t = 1; s = 0; sqrDistance = a11 + (2) * b1 + c; } else { t = numer / denom; s = 1 - t; sqrDistance = s * (a00 * s + a01 * t + (2) * b0) + t * (a01 * s + a11 * t + (2) * b1) + c; } } else { t = 0; if (tmp1 <= 0) { s = 1; sqrDistance = a00 + (2) * b0 + c; } else if (b0 >= 0) { s = 0; sqrDistance = c; } else { s = -b0 / a00; sqrDistance = b0 * s + c; } } } else // region 1 { numer = a11 + b1 - a01 - b0; if (numer <= 0) { s = 0; t = 1; sqrDistance = a11 + (2) * b1 + c; } else { denom = a00 - (2) * a01 + a11; if (numer >= denom) { s = 1; t = 0; sqrDistance = a00 + (2) * b0 + c; } else { s = numer / denom; t = 1 - s; sqrDistance = s * (a00 * s + a01 * t + (2) * b0) + t * (a01 * s + a11 * t + (2) * b1) + c; } } } } if (sqrDistance < 0) { sqrDistance = 0; } return(sqrDistance); }
public GraphSupportGenerator(DMesh3 mesh, DMeshAABBTree3 spatial, double cellSize) { Mesh = mesh; MeshSpatial = spatial; CellSize = cellSize; }
public Remesher(DMesh3 m) { mesh = m; }
//public static void VoronoiMesh(List<g3.PolyLine3d> mesh, out List<g3.Line3d> listLines, out List<g3.PolyLine3d> listPolylines) //{ // System.Collections.Generic.SortedDictionary<int, MeshNode> faces = new System.Collections.Generic.SortedDictionary<int, MeshNode>(); // int index = 0; // foreach (var meshFaceIndex in mesh.TriangleIndices()) // { // var frame = mesh.GetTriFrame(meshFaceIndex); // g3.Index3i neighbors = mesh.GetTriNeighbourTris(meshFaceIndex); // g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex); // faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index)); // } // foreach (var f in faces) // { // f.Value.neighbors.Clear(); // f.Value.neighbors.Capacity = 3; // for (int i = 0; i < 3; ++i) // { // int fn = f.Value.neighbors_index[i]; // if (fn >= 0) // f.Value.neighbors.Add(faces[fn]); // } // if (f.Value.neighbors.Count < 3) // { // f.Value.locked = true; // foreach (var n in f.Value.neighbors) // n.locked = true; // } // } // outputMesh = new g3.DMesh3(g3.MeshComponents.None); // listLines = new List<g3.Line3d>(); // listPolylines = new List<g3.PolyLine3d>(); // foreach (var f in faces) // { // outputMesh.AppendVertex(f.Value.frame.Origin); // } // HashSet<int> processedPoints = new HashSet<int>(); // foreach (var f in faces) // { // for (int i = 0; i < 3; i++) // { // List<int> outputLine = new List<int>(); // if (processedPoints.Contains(f.Value.vertex_index[i])) // continue; // int checkVertex = f.Value.vertex_index[i]; // MeshNode currentFaces = f.Value; // MeshNode prevFace = null; // bool fullLoop = false; // while (true) // { // for (int j = 0; j < currentFaces.neighbors.Count; j++) // { // var neighbor = currentFaces.neighbors[j]; // if (neighbor.UsesVertex(checkVertex)) // { // if (neighbor == prevFace) // continue; // if (neighbor == f.Value) // { // fullLoop = true; // break; // Found full loop // } // outputLine.Add(neighbor.index); // prevFace = currentFaces; // currentFaces = neighbor; // j = -1; // } // } // break; // } // if (fullLoop) // { // processedPoints.Add(checkVertex); // var polyline = new g3.PolyLine3d(); // if (outputLine.Count > 2) // { // g3.Vector3d centerPoint = f.Value.frame.Origin; // foreach (var p in outputLine) // centerPoint += outputMesh.GetVertex(p); // centerPoint /= (outputLine.Count + 1); // int center = outputMesh.AppendVertex(centerPoint); // var pS = outputMesh.GetVertex(f.Value.index); // var p0 = outputMesh.GetVertex(outputLine[0]); // var pE = outputMesh.GetVertex(outputLine[outputLine.Count - 1]); // var normal = mesh.GetTriNormal(f.Value.meshIndex); // polyline.AppendVertex(pS); // polyline.AppendVertex(p0); // listLines.Add(new g3.Line3d(pS, p0 - pS)); // var n = MathUtil.Normal(centerPoint, pS, p0); // bool reverseTri = n.Dot(normal) < 0; // if (!reverseTri) // outputMesh.AppendTriangle(center, f.Value.index, outputLine[0]); // else // outputMesh.AppendTriangle(center, outputLine[0], f.Value.index); // for (int j = 0; j < outputLine.Count - 1; j++) // { // var p1 = outputMesh.GetVertex(outputLine[j]); // var p2 = outputMesh.GetVertex(outputLine[j + 1]); // listLines.Add(new g3.Line3d(p1, p2 - p1)); // polyline.AppendVertex(p2); // if (!reverseTri) // outputMesh.AppendTriangle(center, outputLine[j], outputLine[j + 1]); // else // outputMesh.AppendTriangle(center, outputLine[j + 1], outputLine[j]); // } // polyline.AppendVertex(pS); // listLines.Add(new g3.Line3d(pE, pS - pE)); // listPolylines.Add(polyline); // if (!reverseTri) // outputMesh.AppendTriangle(center, outputLine[outputLine.Count - 1], f.Value.index); // else // outputMesh.AppendTriangle(center, f.Value.index, outputLine[outputLine.Count - 1]); // } // } // } // } //} public static void VoronoiMesh(g3.DMesh3 mesh, out g3.DMesh3 outputMesh, out List <g3.Line3d> listLines, out List <g3.PolyLine3d> listPolylines) { System.Collections.Generic.SortedDictionary <int, MeshNode> faces = new System.Collections.Generic.SortedDictionary <int, MeshNode>(); int index = 0; foreach (var meshFaceIndex in mesh.TriangleIndices()) { var frame = mesh.GetTriFrame(meshFaceIndex); g3.Index3i neighbors = mesh.GetTriNeighbourTris(meshFaceIndex); g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex); faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index)); } foreach (var f in faces) { f.Value.neighbors.Clear(); f.Value.neighbors.Capacity = 3; for (int i = 0; i < 3; ++i) { int fn = f.Value.neighbors_index[i]; if (fn >= 0) { f.Value.neighbors.Add(faces[fn]); } } if (f.Value.neighbors.Count < 3) { f.Value.locked = true; foreach (var n in f.Value.neighbors) { n.locked = true; } } } outputMesh = new g3.DMesh3(g3.MeshComponents.None); listLines = new List <g3.Line3d>(); listPolylines = new List <g3.PolyLine3d>(); foreach (var f in faces) { outputMesh.AppendVertex(f.Value.frame.Origin); } HashSet <int> processedPoints = new HashSet <int>(); foreach (var f in faces) { for (int i = 0; i < 3; i++) { List <int> outputLine = new List <int>(); if (processedPoints.Contains(f.Value.vertex_index[i])) { continue; } int checkVertex = f.Value.vertex_index[i]; MeshNode currentFaces = f.Value; MeshNode prevFace = null; bool fullLoop = false; while (true) { for (int j = 0; j < currentFaces.neighbors.Count; j++) { var neighbor = currentFaces.neighbors[j]; if (neighbor.UsesVertex(checkVertex)) { if (neighbor == prevFace) { continue; } if (neighbor == f.Value) { fullLoop = true; break; // Found full loop } outputLine.Add(neighbor.index); prevFace = currentFaces; currentFaces = neighbor; j = -1; } } break; } if (fullLoop) { processedPoints.Add(checkVertex); var polyline = new g3.PolyLine3d(); if (outputLine.Count > 2) { g3.Vector3d centerPoint = f.Value.frame.Origin; foreach (var p in outputLine) { centerPoint += outputMesh.GetVertex(p); } centerPoint /= (outputLine.Count + 1); int center = outputMesh.AppendVertex(centerPoint); var pS = outputMesh.GetVertex(f.Value.index); var p0 = outputMesh.GetVertex(outputLine[0]); var pE = outputMesh.GetVertex(outputLine[outputLine.Count - 1]); var normal = mesh.GetTriNormal(f.Value.meshIndex); polyline.AppendVertex(pS); polyline.AppendVertex(p0); listLines.Add(new g3.Line3d(pS, p0 - pS)); var n = MathUtil.Normal(centerPoint, pS, p0); bool reverseTri = n.Dot(normal) < 0; if (!reverseTri) { outputMesh.AppendTriangle(center, f.Value.index, outputLine[0]); } else { outputMesh.AppendTriangle(center, outputLine[0], f.Value.index); } for (int j = 0; j < outputLine.Count - 1; j++) { var p1 = outputMesh.GetVertex(outputLine[j]); var p2 = outputMesh.GetVertex(outputLine[j + 1]); listLines.Add(new g3.Line3d(p1, p2 - p1)); polyline.AppendVertex(p2); if (!reverseTri) { outputMesh.AppendTriangle(center, outputLine[j], outputLine[j + 1]); } else { outputMesh.AppendTriangle(center, outputLine[j + 1], outputLine[j]); } } polyline.AppendVertex(pS); listLines.Add(new g3.Line3d(pE, pS - pE)); listPolylines.Add(polyline); if (!reverseTri) { outputMesh.AppendTriangle(center, outputLine[outputLine.Count - 1], f.Value.index); } else { outputMesh.AppendTriangle(center, f.Value.index, outputLine[outputLine.Count - 1]); } } } } } }
protected override Result RunCommand(RhinoDoc doc, RunMode mode) { bool bHavePreselectedObjects = false; const ObjectType geometryFilter = ObjectType.MeshFace; OptionDouble minEdgeLengthOption = new OptionDouble(minEdgeLength, 0.001, 200); OptionDouble maxEdgeLengthOption = new OptionDouble(maxEdgeLength, 0.001, 200); OptionDouble constriantAngleOption = new OptionDouble(constriantAngle, 0.001, 360); OptionInteger smoothStepsOptions = new OptionInteger(smoothSteps, 0, 100); OptionDouble smoothSpeedOption = new OptionDouble(smoothSpeed, 0.01, 1.0); OptionDouble projectAmountOption = new OptionDouble(projectedAmount, 0.01, 1.0); OptionDouble projectedDistanceOption = new OptionDouble(projectedDistance, 0.01, 100000.0); GetObject go = new GetObject(); go.SetCommandPrompt("Select mesh faces to project onto another mesh"); go.GeometryFilter = geometryFilter; go.AddOptionDouble("ConstraintAngle", ref constriantAngleOption); go.AddOptionDouble("MinEdge", ref minEdgeLengthOption); go.AddOptionDouble("MaxEdge", ref maxEdgeLengthOption); go.AddOptionInteger("SmoothSteps", ref smoothStepsOptions); go.AddOptionDouble("SmoothSpeed", ref smoothSpeedOption); go.GroupSelect = true; go.SubObjectSelect = true; for (; ;) { GetResult faceres = go.GetMultiple(1, 0); if (faceres == GetResult.Option) { go.EnablePreSelect(false, true); continue; } else if (go.CommandResult() != Result.Success) { return(go.CommandResult()); } if (go.ObjectsWerePreselected) { bHavePreselectedObjects = true; go.EnablePreSelect(false, true); continue; } break; } minEdgeLength = minEdgeLengthOption.CurrentValue; maxEdgeLength = maxEdgeLengthOption.CurrentValue; constriantAngle = constriantAngleOption.CurrentValue; smoothSteps = smoothStepsOptions.CurrentValue; smoothSpeed = smoothSpeedOption.CurrentValue; //System.Collections.Generic.List<System.Guid> meshes = new System.Collections.Generic.List<System.Guid>(); System.Guid rhinoMesh = System.Guid.Empty; System.Collections.Generic.List <int> removeFaces = new System.Collections.Generic.List <int>(); g3.DMesh3 projectFaces = new g3.DMesh3(true, false, false, false); Rhino.Geometry.Mesh rhinoInputMesh = new Rhino.Geometry.Mesh(); for (int i = 0; i < go.ObjectCount; i++) { ObjRef obj = go.Object(i); if (rhinoMesh == System.Guid.Empty) { rhinoMesh = obj.ObjectId; rhinoInputMesh = obj.Mesh(); for (int j = 0; j < rhinoInputMesh.Vertices.Count; j++) { var vertex = new g3.NewVertexInfo(); vertex.n = new g3.Vector3f(rhinoInputMesh.Normals[j].X, rhinoInputMesh.Normals[j].Y, rhinoInputMesh.Normals[j].Z); vertex.v = new g3.Vector3d(rhinoInputMesh.Vertices[j].X, rhinoInputMesh.Vertices[j].Y, rhinoInputMesh.Vertices[j].Z); projectFaces.AppendVertex(vertex); } } var m = rhinoInputMesh; if (rhinoMesh != obj.ObjectId) { continue; } removeFaces.Add(obj.GeometryComponentIndex.Index); var mf = rhinoInputMesh.Faces[obj.GeometryComponentIndex.Index]; if (mf.IsQuad) { double dist1 = m.Vertices[mf.A].DistanceTo(m.Vertices[mf.C]); double dist2 = m.Vertices[mf.B].DistanceTo(m.Vertices[mf.D]); if (dist1 > dist2) { projectFaces.AppendTriangle(mf.A, mf.B, mf.D); projectFaces.AppendTriangle(mf.B, mf.C, mf.D); } else { projectFaces.AppendTriangle(mf.A, mf.B, mf.C); projectFaces.AppendTriangle(mf.A, mf.C, mf.D); } } else { projectFaces.AppendTriangle(mf.A, mf.B, mf.C); } } if (rhinoInputMesh == null) { return(Result.Failure); } removeFaces.Sort(); removeFaces.Reverse(); foreach (var removeFace in removeFaces) { rhinoInputMesh.Faces.RemoveAt(removeFace); } rhinoInputMesh.Compact(); GetObject goProjected = new GetObject(); goProjected.EnablePreSelect(false, true); goProjected.SetCommandPrompt("Select mesh to project to"); goProjected.GeometryFilter = ObjectType.Mesh; goProjected.AddOptionDouble("ConstraintAngle", ref constriantAngleOption); goProjected.AddOptionDouble("MinEdge", ref minEdgeLengthOption); goProjected.AddOptionDouble("MaxEdge", ref maxEdgeLengthOption); goProjected.AddOptionInteger("SmoothSteps", ref smoothStepsOptions); goProjected.AddOptionDouble("SmoothSpeed", ref smoothSpeedOption); goProjected.AddOptionDouble("ProjectAmount", ref projectAmountOption); goProjected.AddOptionDouble("ProjectDistance", ref projectedDistanceOption); goProjected.GroupSelect = true; goProjected.SubObjectSelect = false; goProjected.EnableClearObjectsOnEntry(false); goProjected.EnableUnselectObjectsOnExit(false); for (; ;) { GetResult resProject = goProjected.Get(); if (resProject == GetResult.Option) { continue; } else if (goProjected.CommandResult() != Result.Success) { return(goProjected.CommandResult()); } break; } minEdgeLength = minEdgeLengthOption.CurrentValue; maxEdgeLength = maxEdgeLengthOption.CurrentValue; constriantAngle = constriantAngleOption.CurrentValue; smoothSteps = smoothStepsOptions.CurrentValue; smoothSpeed = smoothSpeedOption.CurrentValue; projectedAmount = projectAmountOption.CurrentValue; projectedDistance = projectedDistanceOption.CurrentValue; if (bHavePreselectedObjects) { // Normally, pre-selected objects will remain selected, when a // command finishes, and post-selected objects will be unselected. // This this way of picking, it is possible to have a combination // of pre-selected and post-selected. So, to make sure everything // "looks the same", lets unselect everything before finishing // the command. for (int i = 0; i < go.ObjectCount; i++) { RhinoObject rhinoObject = go.Object(i).Object(); if (null != rhinoObject) { rhinoObject.Select(false); } } doc.Views.Redraw(); } bool result = false; if (goProjected.ObjectCount < 1) { return(Result.Failure); } var rhinoMeshProject = goProjected.Object(0).Mesh(); if (rhinoMeshProject == null || !rhinoMeshProject.IsValid) { return(Result.Failure); } var meshProjected = GopherUtil.ConvertToD3Mesh(rhinoMeshProject); var res = GopherUtil.RemeshMesh(projectFaces, (float)minEdgeLength, (float)maxEdgeLength, (float)constriantAngle, (float)smoothSpeed, smoothSteps, meshProjected, (float)projectedAmount, (float)projectedDistance); var newRhinoMesh = GopherUtil.ConvertToRhinoMesh(res); if (newRhinoMesh != null && newRhinoMesh.IsValid) { newRhinoMesh.Append(rhinoInputMesh); result |= doc.Objects.Replace(rhinoMesh, newRhinoMesh); } doc.Views.Redraw(); return(Result.Success); }
public PlanarSpansFiller(DMesh3 mesh, IList <EdgeSpan> spans) { Mesh = mesh; FillSpans = new List <EdgeSpan>(spans); Bounds = AxisAlignedBox2d.Empty; }