protected override void ApplyCurrentStamp(Frame3f vCenter, int tid, DijkstraGraphDistance dj, VectorDisplacement map) { Vector3d n = Mesh.GetTriNormal(tid); List <int> order = dj.GetOrder(); int N = order.Count; for (int k = 0; k < N; ++k) { int vid = order[k]; //double d = dj.GetDistance(vid); double d = (Mesh.GetVertex(vid) - vCenter.Origin).Length; double t = MathUtil.Clamp(d / Radius, 0.0, 1.0); t = MathUtil.WyvillFalloff01(t); Vector3d offset = Power * t * n; if (Invert) { map[vid] = map[vid] - offset; } else { map[vid] = map[vid] + offset; } } }
public static void test_dijkstra() { DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj"); int max_y = 0; foreach (int vid in mesh.VertexIndices()) { if (mesh.GetVertex(vid).y > mesh.GetVertex(max_y).y) { max_y = vid; } } Func <int, int, float> VertexDistanceF = (v1, v2) => { return((float)mesh.GetVertex(v1).Distance(mesh.GetVertex(v2))); }; DijkstraGraphDistance dist = new DijkstraGraphDistance(mesh.MaxVertexID, false, mesh.IsVertex, VertexDistanceF, mesh.VtxVerticesItr); dist.AddSeed(max_y, 0); dist.Compute(); TestUtil.SetColorsFromScalarF(mesh, dist.GetDistance, new Vector2f(0, dist.MaxDistance)); TestUtil.WriteTestOutputMeshes(new List <IMesh>() { mesh, TestUtil.MakeMarker(mesh.GetVertex(max_y), 1, Colorf.Red) }, "dijkstra_colormap.obj", false, true); }
public static EdgeSpan find_edge_path(DMesh3 mesh, int v0, int v1) { if (v0 == v1) { throw new Exception("same vertices!"); } int eid = mesh.FindEdge(v0, v1); if (eid >= 0) { return(EdgeSpan.FromEdges(mesh, new List <int>() { eid })); } DijkstraGraphDistance dist = DijkstraGraphDistance.MeshVertices(mesh); //DijkstraGraphDistance dist = DijkstraGraphDistance.MeshVerticesSparse(mesh); dist.AddSeed(v0, 0); dist.ComputeToNode(v1); List <int> vpath = new List <int>(); bool bOK = dist.GetPathToSeed(v1, vpath); Util.gDevAssert(bOK); vpath.Reverse(); return(EdgeSpan.FromVertices(mesh, vpath)); }
public override void Apply(Frame3f vNextPos, int tid) { if (MapSourceF == null) { f3.DebugUtil.Log("[VectorDisplacementBaseBrush] .MapSourceF is null!"); return; } VectorDisplacement use_map = MapSourceF(); if (use_map == null || use_map.Count != Mesh.MaxVertexID) { return; } DijkstraGraphDistance dj = Dijkstra; dj.Reset(); Index3i ti = Mesh.GetTriangle(tid); Vector3d c = Mesh.GetTriCentroid(tid); dj.AddSeed(ti.a, (float)Mesh.GetVertex(ti.a).Distance(c)); dj.AddSeed(ti.b, (float)Mesh.GetVertex(ti.b).Distance(c)); dj.AddSeed(ti.c, (float)Mesh.GetVertex(ti.c).Distance(c)); double compute_Dist = MathUtil.SqrtTwo * Radius; dj.ComputeToMaxDistance((float)compute_Dist); ApplyCurrentStamp(vNextPos, tid, dj, use_map); mesh_changed(); }
protected override void ApplyCurrentStamp(Frame3f vCenter, int tid, DijkstraGraphDistance dj, VectorDisplacement map) { Vector3d c = Vector3d.Zero, v = Vector3d.Zero, o = vCenter.Origin; double r = Radius; List <int> order = dj.GetOrder(); int N = order.Count; for (int k = 0; k < N; ++k) { int vid = order[k]; v = Mesh.GetVertex(vid); double d = v.Distance(ref o); double t = MathUtil.Clamp(d / r, 0.0, 1.0); t = 1 - t * t; t = t * t * t; //t = MathUtil.WyvillFalloff01(t); v = map[vid]; c = Vector3d.Zero; int n = 0; foreach (int nbrid in Mesh.VtxVerticesItr(vid)) { c += map[nbrid]; n++; } c /= n; map[vid] = Vector3d.Lerp(ref v, ref c, SmoothPower * t); } }
protected override void ApplyCurrentStamp(Frame3f vCenter, int tid, DijkstraGraphDistance dj, DVector <Vector3d> Displacements, HashSet <int> ModifiedV) { List <int> order = dj.GetOrder(); int N = order.Count; for (int k = 0; k < N; ++k) { int vid = order[k]; Vector3d v = Mesh.GetVertex(vid); double d = v.Distance(vCenter.Origin); double t = MathUtil.Clamp(d / Radius, 0.0, 1.0); t = MathUtil.WyvillFalloff01(t); Vector3d c = Vector3d.Zero; Mesh.VtxOneRingCentroid(vid, ref c); t *= Power; Vector3d s = Vector3d.Lerp(ref v, ref c, t); Displacements[vid] = s; ModifiedV.Add(vid); } }
void compute_inner_wall() { if (DebugStep <= 0) { SocketMesh = new DMesh3(TrimmedMesh); return; } InnerMesh = new DMesh3(TrimmedMesh); // compute flare band Func <int, double> flareOffsetF = (vid) => { return(0); }; if (flare_offset > 0 && flare_band_width > 0) { MeshBoundaryLoops loops = new MeshBoundaryLoops(InnerMesh); if (loops.Count != 1) { goto done_inner_wall; } DijkstraGraphDistance dist = DijkstraGraphDistance.MeshVertices(InnerMesh); dist.TrackOrder = true; foreach (int vid in loops[0].Vertices) { dist.AddSeed(vid, 0); } dist.ComputeToMaxDistance(1.25f * (float)flare_band_width); flareOffsetF = (viD) => { float d = dist.GetDistance(viD); if (d < flare_band_width) { double t = d / flare_band_width; t = 1 - t * t; t = t * t * t; return(t * flare_offset); } return(0); }; } gParallel.ForEach(InnerMesh.VertexIndices(), (vid) => { Vector3d v = InnerMesh.GetVertex(vid); Vector3d n = InnerMesh.GetVertexNormal(vid); double offset = inner_offset + flareOffsetF(vid); InnerMesh.SetVertex(vid, v + offset * n); }); done_inner_wall: MeshNormals.QuickCompute(InnerMesh); }
protected override void ApplyCurrentStamp(Frame3f vCenter, int tid, DijkstraGraphDistance dj, VectorDisplacement map) { List <int> order = dj.GetOrder(); int N = order.Count; for (int k = 0; k < N; ++k) { int vid = order[k]; double d = (Mesh.GetVertex(vid) - vCenter.Origin).Length; double t = MathUtil.Clamp(d / Radius, 0.0, 1.0); t = Power * MathUtil.WyvillFalloff01(t); map[vid] = Vector3d.Lerp(map[vid], Vector3d.Zero, t); } }
public static void profile_dijkstra_2b_reuse(int N = 500) { DMesh3 mesh = TestUtil.LoadTestInputMesh("sphere_50k_verts.obj"); Func <int, int, float> VertexDistanceF = (v1, v2) => { return((float)mesh.GetVertex(v1).Distance(mesh.GetVertex(v2))); }; LocalProfiler profiler = new LocalProfiler(); DijkstraGraphDistance dist_sparse = new DijkstraGraphDistance(mesh.MaxVertexID, true, mesh.IsVertex, VertexDistanceF, mesh.VtxVerticesItr); for (int k = 0; k < N; ++k) { profiler.Start("dijkstra_sparse"); dist_sparse.Reset(); dist_sparse.AddSeed(0, 0); dist_sparse.Compute(); profiler.StopAndAccumulate("dijkstra_sparse"); } GC.Collect(); DijkstraGraphDistance dist_dense = new DijkstraGraphDistance(mesh.MaxVertexID, false, mesh.IsVertex, VertexDistanceF, mesh.VtxVerticesItr); for (int k = 0; k < N; ++k) { profiler.Start("dijkstra_dense"); dist_dense.Reset(); dist_dense.AddSeed(0, 0); dist_dense.Compute(); profiler.StopAndAccumulate("dijkstra_dense"); } profiler.DivideAllAccumulated(N); System.Console.WriteLine(profiler.AllAccumulatedTimes()); }
public void InitializeGeodesicDistance(Vector3d source, int source_tid) { DijkstraGraphDistance dist = new DijkstraGraphDistance(Mesh.MaxTriangleID, false, (tid) => { return(Mesh.IsTriangle(tid)); }, (a, b) => { return((float)Mesh.GetTriCentroid(a).Distance(Mesh.GetTriCentroid(b))); }, Mesh.TriTrianglesItr); dist.AddSeed(source_tid, (float)Mesh.GetTriCentroid(source_tid).Distance(source)); //Index3i tri = Mesh.GetTriangle(source_tid); //for (int j = 0; j < 3; ++j) { // dist.AddSeed(tri[j], (float)Mesh.GetVertex(tri[j]).Distance(source)); //} dist.TrackOrder = true; dist.Compute(); List <int> order = dist.GetOrder(); tri_ordering = new OrderedTri[order.Count]; for (int k = 0; k < order.Count; ++k) { tri_ordering[k].tid = order[k]; tri_ordering[k].scalar = dist.GetDistance(order[k]); } tid_to_order_idx = new int[Mesh.MaxTriangleID]; for (int k = 0; k < order.Count; ++k) { tid_to_order_idx[order[k]] = k; } // rebuild chunks data structures update_ordered_chunks(); }
public override void Apply(Frame3f vNextPos, int tid) { if (Mesh.MaxVertexID > Displacements.Length) { Displacements.resize(Mesh.MaxVertexID); } ModifiedV.Clear(); DijkstraGraphDistance dj = Dijkstra; dj.Reset(); Index3i ti = Mesh.GetTriangle(tid); Vector3d c = Mesh.GetTriCentroid(tid); dj.AddSeed(ti.a, (float)Mesh.GetVertex(ti.a).Distance(c)); dj.AddSeed(ti.b, (float)Mesh.GetVertex(ti.b).Distance(c)); dj.AddSeed(ti.c, (float)Mesh.GetVertex(ti.c).Distance(c)); double compute_Dist = MathUtil.SqrtTwo * Radius; dj.ComputeToMaxDistance((float)compute_Dist); ApplyCurrentStamp(vNextPos, tid, dj, Displacements, ModifiedV); }
public virtual void Update() { if (MeshSource == null) { throw new Exception("PlaneBandExpansionOp: must set valid MeshSource to compute!"); } IMesh imesh = MeshSource.GetIMesh(); if (imesh.HasVertexNormals == false) { throw new Exception("PlaneBandExpansionOp: 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; IList <int> faces = IndexSource.GetIndices(); // [RMS] this is all f'n ugly! MeshVertexSelection selection = new MeshVertexSelection(mesh); selection.SelectTriangleVertices(faces); // ugly List <Vector2d> seeds = new List <Vector2d>(); foreach (int vid in selection) { foreach (int nbrvid in mesh.VtxVerticesItr(vid)) { if (selection.IsSelected(nbrvid) == false) { seeds.Add(new Vector2d(vid, 0)); break; } } } Func <int, int, float> distanceF = (a, b) => { return((float)mesh.GetVertex(a).Distance(mesh.GetVertex(b))); }; Func <int, bool> nodeF = (vid) => { return(selection.IsSelected(vid)); }; DijkstraGraphDistance dijkstra = new DijkstraGraphDistance(mesh.MaxVertexID, true, nodeF, distanceF, mesh.VtxVerticesItr, seeds); dijkstra.Compute(); float maxDist = dijkstra.MaxDistance; Displacement.Clear(); Displacement.Resize(mesh.MaxVertexID); // todo: can do this in parallel... foreach (int vid in selection) { //Vector3d v = mesh.GetVertex(vid); // [TODO]... double dist = maxDist - dijkstra.GetDistance(vid); double falloff = MathUtil.WyvillFalloff(dist, maxDist * 0.0, maxDist); Vector3d n = mesh.GetVertexNormal(vid); n = n - n.Dot(normal) * normal; n.Normalize(); Displacement[vid] = falloff * offset_distance * n; } // smooth it? result_valid = true; }
void generate_graph(DenseGrid3f supportGrid, DenseGridTrilinearImplicit distanceField) { int ni = supportGrid.ni, nj = supportGrid.nj, nk = supportGrid.nk; float dx = (float)CellSize; Vector3f origin = this.GridOrigin; // parameters for initializing cost grid float MODEL_SPACE = 0.01f; // needs small positive so that points on triangles count as inside (eg on ground plane) //float MODEL_SPACE = 2.0f*(float)CellSize; float CRAZY_DISTANCE = 99999.0f; bool UNIFORM_DISTANCE = true; float MAX_DIST = 10 * (float)CellSize; // parameters for sorting seeds Vector3i center_idx = new Vector3i(ni / 2, 0, nk / 2); // middle //Vector3i center_idx = new Vector3i(0, 0, 0); // corner bool reverse_per_layer = true; DenseGrid3f costGrid = new DenseGrid3f(supportGrid); foreach (Vector3i ijk in costGrid.Indices()) { Vector3d cell_center = new Vector3f(ijk.x * dx, ijk.y * dx, ijk.z * dx) + origin; float f = (float)distanceField.Value(ref cell_center); if (f <= MODEL_SPACE) { f = CRAZY_DISTANCE; } else if (UNIFORM_DISTANCE) { f = 1.0f; } else if (f > MAX_DIST) { f = MAX_DIST; } costGrid[ijk] = f; } // Find seeds on each layer, sort, and add to accumulated bottom-up seeds list. // This sorting has an *enormous* effect on the support generation. List <Vector3i> seeds = new List <Vector3i>(); List <Vector3i> layer_seeds = new List <Vector3i>(); for (int j = 0; j < nj; ++j) { layer_seeds.Clear(); for (int k = 0; k < nk; ++k) { for (int i = 0; i < ni; ++i) { if (supportGrid[i, j, k] == SUPPORT_TIP_BASE) { layer_seeds.Add(new Vector3i(i, j, k)); } } } layer_seeds.Sort((a, b) => { Vector3i pa = a; pa.y = 0; Vector3i pb = b; pb.y = 0; int sa = (pa - center_idx).LengthSquared, sb = (pb - center_idx).LengthSquared; return(sa.CompareTo(sb)); }); // reversing sort order is intresting? if (reverse_per_layer) { layer_seeds.Reverse(); } seeds.AddRange(layer_seeds); } HashSet <Vector3i> seed_indices = new HashSet <Vector3i>(seeds); // gives very different results... if (ProcessBottomUp == false) { seeds.Reverse(); } // for linear index a, is this a node we allow in graph? (ie graph bounds) Func <int, bool> node_filter_f = (a) => { Vector3i ai = costGrid.to_index(a); // why not y check?? return(ai.x > 0 && ai.z > 0 && ai.x != ni - 1 && ai.y != nj - 1 && ai.z != nk - 1); }; // distance from linear index a to linear index b // this defines the cost field we want to find shortest path through Func <int, int, float> node_dist_f = (a, b) => { Vector3i ai = costGrid.to_index(a), bi = costGrid.to_index(b); if (bi.y >= ai.y) // b.y should always be a.y-1 { return(float.MaxValue); } float sg = supportGrid[bi]; // don't connect to tips //if (sg == SUPPORT_TIP_BASE || sg == SUPPORT_TIP_TOP) // return float.MaxValue; if (sg == SUPPORT_TIP_TOP) { return(float.MaxValue); } if (sg < 0) { return(-999999); // if b is already used, we will terminate there, so this is a good choice } // otherwise cost is sqr-grid-distance + costGrid value (which is basically distance to surface) float c = costGrid[b]; float f = (float)(Math.Sqrt((bi - ai).LengthSquared) * CellSize); //float f = 0; return(c + f); }; // which linear-index nbrs to consider for linear index a Func <int, IEnumerable <int> > neighbour_f = (a) => { Vector3i ai = costGrid.to_index(a); return(down_neighbours(ai, costGrid)); }; // when do we terminate Func <int, bool> terminate_f = (a) => { Vector3i ai = costGrid.to_index(a); // terminate if we hit existing support path if (seed_indices.Contains(ai) == false && supportGrid[ai] < 0) { return(true); } // terminate if we hit ground plane if (ai.y == 0) { return(true); } return(false); }; DijkstraGraphDistance dijkstra = new DijkstraGraphDistance(ni * nj * nk, false, node_filter_f, node_dist_f, neighbour_f); dijkstra.TrackOrder = true; List <int> path = new List <int>(); Graph = new DGraph3(); Dictionary <Vector3i, int> CellToGraph = new Dictionary <Vector3i, int>(); TipVertices = new HashSet <int>(); TipBaseVertices = new HashSet <int>(); GroundVertices = new HashSet <int>(); // seeds are tip-base points for (int k = 0; k < seeds.Count; ++k) { // add seed point (which is a tip-base vertex) as seed for dijkstra prop int seed = costGrid.to_linear(seeds[k]); dijkstra.Reset(); dijkstra.AddSeed(seed, 0); // compute to termination (ground, existing node, etc) int base_node = dijkstra.ComputeToNode(terminate_f); if (base_node < 0) { base_node = dijkstra.GetOrder().Last(); } // extract the path path.Clear(); dijkstra.GetPathToSeed(base_node, path); int N = path.Count; // first point on path is termination point. // create vertex for it if we have not yet Vector3i basept_idx = supportGrid.to_index(path[0]); int basept_vid; if (CellToGraph.TryGetValue(basept_idx, out basept_vid) == false) { Vector3d curv = get_cell_center(basept_idx); if (basept_idx.y == 0) { curv.y = 0; } basept_vid = Graph.AppendVertex(curv); if (basept_idx.y == 0) { GroundVertices.Add(basept_vid); } CellToGraph[basept_idx] = basept_vid; } int cur_vid = basept_vid; // now walk up path and create vertices as necessary for (int i = 0; i < N; ++i) { int idx = path[i]; if (supportGrid[idx] >= 0) { supportGrid[idx] = SUPPORT_GRID_USED; } if (i > 0) { Vector3i next_idx = supportGrid.to_index(path[i]); int next_vid; if (CellToGraph.TryGetValue(next_idx, out next_vid) == false) { Vector3d nextv = get_cell_center(next_idx); next_vid = Graph.AppendVertex(nextv); CellToGraph[next_idx] = next_vid; } Graph.AppendEdge(cur_vid, next_vid); cur_vid = next_vid; } } // seed was tip-base so we should always get back there. Then we // explicitly add tip-top and edge to it. if (supportGrid[path[N - 1]] == SUPPORT_TIP_BASE) { Vector3i vec_idx = supportGrid.to_index(path[N - 1]); TipBaseVertices.Add(CellToGraph[vec_idx]); Vector3i tip_idx = vec_idx + Vector3i.AxisY; int tip_vid; if (CellToGraph.TryGetValue(tip_idx, out tip_vid) == false) { Vector3d tipv = get_cell_center(tip_idx); tip_vid = Graph.AppendVertex(tipv); CellToGraph[tip_idx] = tip_vid; Graph.AppendEdge(cur_vid, tip_vid); TipVertices.Add(tip_vid); } } } /* * Snap tips to surface */ gParallel.ForEach(TipVertices, (tip_vid) => { bool snapped = false; Vector3d v = Graph.GetVertex(tip_vid); Frame3f hitF; // try shooting ray straight up. if that hits, and point is close, we use it if (MeshQueries.RayHitPointFrame(Mesh, MeshSpatial, new Ray3d(v, Vector3d.AxisY), out hitF)) { if (v.Distance(hitF.Origin) < 2 * CellSize) { v = hitF.Origin; snapped = true; } } // if that failed, try straight down if (!snapped) { if (MeshQueries.RayHitPointFrame(Mesh, MeshSpatial, new Ray3d(v, -Vector3d.AxisY), out hitF)) { if (v.Distance(hitF.Origin) < CellSize) { v = hitF.Origin; snapped = true; } } } // if it missed, or hit pt was too far, find nearest point and try that if (!snapped) { hitF = MeshQueries.NearestPointFrame(Mesh, MeshSpatial, v); if (v.Distance(hitF.Origin) < 2 * CellSize) { v = hitF.Origin; snapped = true; } // can this ever fail? tips should always be within 2 cells... } if (snapped) { Graph.SetVertex(tip_vid, v); } }); }
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); }
/// <summary> /// Subclass implements this /// </summary> protected abstract void ApplyCurrentStamp(Frame3f vCenter, int tid, DijkstraGraphDistance dj, VectorDisplacement map);
protected override void mesh_changed() { dist = null; }
/// <summary> /// Subclass implements this /// </summary> protected abstract void ApplyCurrentStamp(Frame3f vCenter, int tid, DijkstraGraphDistance dj, DVector <Vector3d> Displacements, HashSet <int> ModifiedV);