void smooth_and_remesh(MeshFaceSelection tris) { if (EnableLaplacianSmooth) { LaplacianMeshSmoother.RegionSmooth(Mesh, tris, 2, 2, false); } if (RemeshAfterSmooth) { tris.ExpandToOneRingNeighbours(2); tris.LocalOptimize(true, true); MeshProjectionTarget target = MeshProjectionTarget.Auto(Mesh, tris, 5); RegionRemesher remesh2 = new RegionRemesher(Mesh, tris); remesh2.SetTargetEdgeLength(TargetEdgeLength); remesh2.SmoothSpeedT = 1.0; remesh2.SetProjectionTarget(target); if (ConfigureRemesherF != null) { ConfigureRemesherF(remesh2, false); } for (int k = 0; k < 10; ++k) { remesh2.BasicRemeshPass(); } remesh2.BackPropropagate(); FillTriangles = remesh2.CurrentBaseTriangles; } else { FillTriangles = tris.ToArray(); } }
void smooth_and_remesh_preserve(MeshFaceSelection tris, bool bFinal) { if (EnableLaplacianSmooth) { LaplacianMeshSmoother.RegionSmooth(Mesh, tris, 2, 2, true); } if (RemeshAfterSmooth) { MeshProjectionTarget target = (bFinal) ? MeshProjectionTarget.Auto(Mesh, tris, 5) : null; RegionRemesher remesh2 = new RegionRemesher(Mesh, tris); remesh2.SetTargetEdgeLength(TargetEdgeLength); remesh2.SmoothSpeedT = 1.0; remesh2.SetProjectionTarget(target); if (ConfigureRemesherF != null) { ConfigureRemesherF(remesh2, false); } for (int k = 0; k < 10; ++k) { remesh2.BasicRemeshPass(); } remesh2.BackPropropagate(); FillTriangles = remesh2.CurrentBaseTriangles; } else { FillTriangles = tris.ToArray(); } }
protected override void SolveInstance(IGH_DataAccess DA) { DMesh3_goo dMsh_goo = null; double w = 1; DA.GetData(0, ref dMsh_goo); DA.GetData(1, ref w); DMesh3 dMsh_copy = new DMesh3(dMsh_goo.Value, true); LaplacianMeshSmoother smoother = new LaplacianMeshSmoother(dMsh_copy); foreach (int vid in dMsh_copy.VertexIndices()) { if (smoother.IsConstrained(vid) == false) { smoother.SetConstraint(vid, dMsh_copy.GetVertex(vid), w); } } bool success = smoother.SolveAndUpdateMesh(); bool isValid = dMsh_copy.CheckValidity(); if (!success) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Laplacian smooth seems to have failed. Please check..."); } if (!isValid) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Mesh seems to have been corrupted during smoothing. Please check..."); } DA.SetData(0, dMsh_copy); }
public bool Compute() { PlanarMesh = BuildPlanarMesh(false); InflatedMesh = ComputeInflation(PlanarMesh); DMesh3 remeshed = GenerateRemesh(InflatedMesh); Flatten(remeshed); ResultMesh = ComputeInflation(remeshed); MeshBoundaryLoops loops = new MeshBoundaryLoops(ResultMesh); DMesh3 otherSide = new DMesh3(ResultMesh); foreach (int vid in otherSide.VertexIndices()) { Vector3d v = otherSide.GetVertex(vid); v.z = -v.z; otherSide.SetVertex(vid, v); } otherSide.ReverseOrientation(); MeshEditor editor = new MeshEditor(ResultMesh); int[] mapVArray; editor.AppendMesh(otherSide, out mapVArray); IndexMap mapV = new IndexMap(mapVArray); foreach (EdgeLoop loop in loops) { int[] otherLoop = (int[])loop.Vertices.Clone(); IndexUtil.Apply(otherLoop, mapV); editor.StitchLoop(loop.Vertices, otherLoop); } Remesher remesh = new Remesher(ResultMesh); remesh.SetTargetEdgeLength(TargetEdgeLength); remesh.SmoothSpeedT = 0.25f; for (int k = 0; k < 10; ++k) { remesh.BasicRemeshPass(); } ResultMesh = new DMesh3(ResultMesh, true); LaplacianMeshSmoother smoother = new LaplacianMeshSmoother(ResultMesh); foreach (int vid in ResultMesh.VertexIndices()) { smoother.SetConstraint(vid, ResultMesh.GetVertex(vid), 0.5f, false); } smoother.SolveAndUpdateMesh(); return(true); }
public virtual void Update() { if (MeshSource == null) { throw new Exception("EnclosedRegionOffsetOp: must set valid MeshSource to compute!"); } if (MeshSource.HasSpatial == false) { throw new Exception("EnclosedRegionOffsetOp: MeshSource must have spatial data structure!"); } IMesh imesh = MeshSource.GetIMesh(); if (imesh.HasVertexNormals == false) { throw new Exception("EnclosedRegionOffsetOp: input mesh does not have surface normals..."); } if (imesh is DMesh3 == false) { throw new Exception("RegionOffsetOp: in current implementation, input mesh must be a DMesh3. Ugh."); } DMesh3 mesh = imesh as DMesh3; ISpatial spatial = MeshSource.GetSpatial(); DCurve3 curve = new DCurve3(CurveSource.GetICurve()); MeshFacesFromLoop loop = new MeshFacesFromLoop(mesh, curve, spatial); // extract submesh RegionOperator op = new RegionOperator(mesh, loop.InteriorTriangles); DMesh3 submesh = op.Region.SubMesh; // find boundary verts and nbr ring HashSet <int> boundaryV = new HashSet <int>(MeshIterators.BoundaryEdgeVertices(submesh)); HashSet <int> boundaryNbrs = new HashSet <int>(); foreach (int vid in boundaryV) { foreach (int nbrvid in submesh.VtxVerticesItr(vid)) { if (boundaryV.Contains(nbrvid) == false) { boundaryNbrs.Add(nbrvid); } } } // [TODO] maybe should be not using vertex normal here? // use an averaged normal, or a constant for patch? // offset mesh if requested if (Math.Abs(offset_distance) > 0.0001) { foreach (int vid in submesh.VertexIndices()) { if (boundaryV.Contains(vid)) { continue; } // if inner ring is non-zero, then it gets preserved below, and // creates a crease... //double dist = boundaryNbrs.Contains(vid) ? (offset_distance / 2) : offset_distance; double dist = boundaryNbrs.Contains(vid) ? 0 : offset_distance; submesh.SetVertex(vid, submesh.GetVertex(vid) + (float)dist * submesh.GetVertexNormal(vid)); } } //double t = MathUtil.Clamp(1.0 - SmoothAlpha, 0.1, 1.0); double t = 1.0 - SmoothAlpha; t = t * t; double boundary_t = 5.0; double ring_t = 1.0; // smooth submesh, with boundary-ring constraints LaplacianMeshSmoother smoother = new LaplacianMeshSmoother(submesh); foreach (int vid in submesh.VertexIndices()) { if (boundaryV.Contains(vid)) { smoother.SetConstraint(vid, submesh.GetVertex(vid), boundary_t, true); } else if (boundaryNbrs.Contains(vid)) { smoother.SetConstraint(vid, submesh.GetVertex(vid), ring_t); } else { smoother.SetConstraint(vid, submesh.GetVertex(vid), t); } } smoother.SolveAndUpdateMesh(); // turn into displacement vectors Displacement.Clear(); Displacement.Resize(mesh.MaxVertexID); foreach (int subvid in op.Region.SubMesh.VertexIndices()) { Vector3d subv = op.Region.SubMesh.GetVertex(subvid); int basevid = op.Region.SubToBaseV[subvid]; Vector3d basev = op.Region.BaseMesh.GetVertex(basevid); Displacement[basevid] = subv - basev; } result_valid = true; }
DMesh3 ComputeInflation(DMesh3 planarMesh) { DMesh3 mesh = new DMesh3(planarMesh); DijkstraGraphDistance dist = new DijkstraGraphDistance( mesh.MaxVertexID, false, (vid) => { return(mesh.IsVertex(vid)); }, (a, b) => { return((float)mesh.GetVertex(a).Distance(mesh.GetVertex(b))); }, mesh.VtxVerticesItr); foreach (int vid in MeshIterators.BoundaryVertices(mesh)) { dist.AddSeed(vid, 0); } dist.Compute(); float max_dist = dist.MaxDistance; float[] distances = new float[mesh.MaxVertexID]; foreach (int vid in mesh.VertexIndices()) { distances[vid] = dist.GetDistance(vid); } List <int> local_maxima = new List <int>(); foreach (int vid in MeshIterators.InteriorVertices(mesh)) { float d = distances[vid]; bool is_maxima = true; foreach (int nbrid in mesh.VtxVerticesItr(vid)) { if (distances[nbrid] > d) { is_maxima = false; } } if (is_maxima) { local_maxima.Add(vid); } } // smooth distances (really should use cotan here!!) float smooth_alpha = 0.1f; int smooth_rounds = 5; foreach (int ri in Interval1i.Range(smooth_rounds)) { foreach (int vid in mesh.VertexIndices()) { float cur = distances[vid]; float centroid = 0; int nbr_count = 0; foreach (int nbrid in mesh.VtxVerticesItr(vid)) { centroid += distances[nbrid]; nbr_count++; } centroid /= nbr_count; distances[vid] = (1 - smooth_alpha) * cur + (smooth_alpha) * centroid; } } Vector3d normal = Vector3d.AxisZ; foreach (int vid in mesh.VertexIndices()) { if (dist.IsSeed(vid)) { continue; } float h = distances[vid]; // [RMS] there are different options here... h = 2 * (float)Math.Sqrt(h); float offset = h; Vector3d d = mesh.GetVertex(vid); mesh.SetVertex(vid, d + (Vector3d)(offset * normal)); } DMesh3 compacted = new DMesh3(); var compactInfo = compacted.CompactCopy(mesh); IndexUtil.Apply(local_maxima, compactInfo.MapV); mesh = compacted; MeshVertexSelection boundary_sel = new MeshVertexSelection(mesh); HashSet <int> boundaryV = new HashSet <int>(MeshIterators.BoundaryVertices(mesh)); boundary_sel.Select(boundaryV); boundary_sel.ExpandToOneRingNeighbours(); LaplacianMeshSmoother smoother = new LaplacianMeshSmoother(mesh); foreach (int vid in boundary_sel) { if (boundaryV.Contains(vid)) { smoother.SetConstraint(vid, mesh.GetVertex(vid), 100.0f, true); } else { smoother.SetConstraint(vid, mesh.GetVertex(vid), 10.0f, false); } } foreach (int vid in local_maxima) { smoother.SetConstraint(vid, mesh.GetVertex(vid), 50, false); } bool ok = smoother.SolveAndUpdateMesh(); Util.gDevAssert(ok); List <int> intVerts = new List <int>(MeshIterators.InteriorVertices(mesh)); MeshIterativeSmooth smooth = new MeshIterativeSmooth(mesh, intVerts.ToArray(), true); smooth.SmoothType = MeshIterativeSmooth.SmoothTypes.Cotan; smooth.Rounds = 10; smooth.Alpha = 0.1f; smooth.Smooth(); return(mesh); }