public void MakeMesh(DMesh3 m) { int nV = vertices.Count; for (int i = 0; i < nV; ++i) { NewVertexInfo ni = new NewVertexInfo() { v = vertices[i] }; if ( WantNormals ) { ni.bHaveN = true; ni.n = normals[i]; } if ( WantUVs ) { ni.bHaveUV = true; ni.uv = uv[i]; } int vID = m.AppendVertex(ni); Util.gDevAssert(vID == i); } int nT = triangles.Count; if (WantGroups && groups != null && groups.Length == nT) { for (int i = 0; i < nT; ++i) m.AppendTriangle(triangles[i], groups[i]); } else { for (int i = 0; i < nT; ++i) m.AppendTriangle(triangles[i]); } }
// [RMS] estimate can be zero void compute(IEnumerable <int> triangles, int tri_count_est) { int est_verts = tri_count_est / 2; SubMesh = new DMesh3(BaseMesh.Components & WantComponents); BaseSubmeshV = new IndexFlagSet(BaseMesh.MaxVertexID, est_verts); BaseToSubV = new IndexMap(BaseMesh.MaxVertexID, est_verts); SubToBaseV = new DVector <int>(); if (ComputeTriMaps) { BaseToSubT = new IndexMap(BaseMesh.MaxTriangleID, tri_count_est); SubToBaseT = new DVector <int>(); } foreach (int tid in triangles) { if (!BaseMesh.IsTriangle(tid)) { throw new Exception("DSubmesh3.compute: triangle " + tid + " does not exist in BaseMesh!"); } Index3i base_t = BaseMesh.GetTriangle(tid); Index3i new_t = Index3i.Zero; int gid = BaseMesh.GetTriangleGroup(tid); for (int j = 0; j < 3; ++j) { int base_v = base_t[j]; int sub_v = -1; if (BaseSubmeshV[base_v] == false) { sub_v = SubMesh.AppendVertex(BaseMesh, base_v); BaseSubmeshV[base_v] = true; BaseToSubV[base_v] = sub_v; SubToBaseV.insert(base_v, sub_v); } else { sub_v = BaseToSubV[base_v]; } new_t[j] = sub_v; } if (OverrideGroupID >= 0) { gid = OverrideGroupID; } int sub_tid = SubMesh.AppendTriangle(new_t, gid); if (ComputeTriMaps) { BaseToSubT[tid] = sub_tid; SubToBaseT.insert(tid, sub_tid); } } }
public virtual bool Extrude(int group_id = -1) { // duplicate loop vertices int NV = Loop.Vertices.Length; NewLoop = new EdgeLoop(Mesh); NewLoop.Vertices = new int[NV]; for (int i = 0; i < NV; ++i) { int vid = Loop.Vertices[i]; NewLoop.Vertices[i] = Mesh.AppendVertex(Mesh, vid); } // move to offset positions for (int i = 0; i < NV; ++i) { Vector3d v = Mesh.GetVertex(Loop.Vertices[i]); Vector3f n = Mesh.GetVertexNormal(Loop.Vertices[i]); Vector3d new_v = PositionF(v, n, i); Mesh.SetVertex(NewLoop.Vertices[i], new_v); } // stitch interior MeshEditor edit = new MeshEditor(Mesh); NewTriangles = edit.StitchLoop(Loop.Vertices, NewLoop.Vertices, group_id); return(true); }
public virtual bool Fill(int group_id = -1) { if (Loop.Vertices.Length < 3) { return(false); } // this just needs one triangle if (Loop.Vertices.Length == 3) { Index3i tri = new Index3i(Loop.Vertices[0], Loop.Vertices[2], Loop.Vertices[1]); int new_tid = Mesh.AppendTriangle(tri, group_id); if (new_tid < 0) { return(false); } NewTriangles = new int[1] { new_tid }; NewVertex = DMesh3.InvalidID; return(true); } // [TODO] 4-case? could check nbr normals to figure out best internal edge... // compute centroid Vector3d c = Vector3d.Zero; for (int i = 0; i < Loop.Vertices.Length; ++i) { c += Mesh.GetVertex(Loop.Vertices[i]); } c *= 1.0 / Loop.Vertices.Length; // add centroid vtx NewVertex = Mesh.AppendVertex(c); // stitch triangles MeshEditor editor = new MeshEditor(Mesh); try { NewTriangles = editor.AddTriangleFan_OrderedVertexLoop(NewVertex, Loop.Vertices, group_id); } catch { NewTriangles = null; } // if fill failed, back out vertex-add if (NewTriangles == null) { Mesh.RemoveVertex(NewVertex, true, false); NewVertex = DMesh3.InvalidID; return(false); } else { return(true); } }
// // DMesh3 construction utilities // /// <summary> /// ultimate generic mesh-builder, pass it arrays of floats/doubles, or lists /// of Vector3d, or anything in-between. Will figure out how to interpret /// /// This static function attempts to retain a manifold mesh, if you need finer /// control use the concrete class. /// /// Number of issues encountered adding verices or triangls are stored in the /// mesh metadata. Metadata can be cleared once the returning object is evaluated. /// </summary> public static DMesh3 Build <VType, TType, NType>(IEnumerable <VType> Vertices, IEnumerable <TType> Triangles, IEnumerable <NType> Normals = null, IEnumerable <int> TriGroups = null) { DMesh3 mesh = new DMesh3(Normals != null, false, false, TriGroups != null); // build outcomes are stored in the metadata to avoid changes to the function signature // int iAppendTriangleIssues = 0; Vector3d[] v = BufferUtil.ToVector3d(Vertices); for (int i = 0; i < v.Length; ++i) { mesh.AppendVertex(v[i]); } if (Normals != null) { Vector3f[] n = BufferUtil.ToVector3f(Normals); if (n.Length != v.Length) { throw new Exception("DMesh3Builder.Build: incorrect number of normals provided"); } for (int i = 0; i < n.Length; ++i) { mesh.SetVertexNormal(i, n[i]); } } Index3i[] t = BufferUtil.ToIndex3i(Triangles); for (int i = 0; i < t.Length; ++i) { var last = mesh.AppendTriangle(t[i]); if (last == DMesh3.InvalidID || last == DMesh3.NonManifoldID) { iAppendTriangleIssues++; } } if (TriGroups != null) { List <int> groups = new List <int>(TriGroups); if (groups.Count != t.Length) { throw new Exception("DMesh3Builder.Build: incorect number of triangle groups"); } for (int i = 0; i < t.Length; ++i) { mesh.SetTriangleGroup(i, groups[i]); } } mesh.AttachMetadata("AppendTriangleIssues", iAppendTriangleIssues); return(mesh); }
public void Generate() { append_mesh(); AxisAlignedBox3i bounds = Voxels.GridBounds; bounds.Max -= Vector3i.One; int[] vertices = new int[4]; foreach (Vector3i nz in Voxels.NonZeros()) { check_counts_or_append(6, 2); Box3d cube = Box3d.UnitZeroCentered; cube.Center = (Vector3d)nz; for (int fi = 0; fi < 6; ++fi) { // checks dependent on neighbours Index3i nbr = nz + gIndices.GridOffsets6[fi]; if (bounds.Contains(nbr)) { if (SkipInteriorFaces && Voxels.Get(nbr)) { continue; } } else if (CapAtBoundary == false) { continue; } int ni = gIndices.BoxFaceNormals[fi]; Vector3f n = (Vector3f)(Math.Sign(ni) * cube.Axis(Math.Abs(ni) - 1)); NewVertexInfo vi = new NewVertexInfo(Vector3d.Zero, n); if (ColorSourceF != null) { vi.c = ColorSourceF(nz); vi.bHaveC = true; } for (int j = 0; j < 4; ++j) { vi.v = cube.Corner(gIndices.BoxFaces[fi, j]); vertices[j] = cur_mesh.AppendVertex(vi); } Index3i t0 = new Index3i(vertices[0], vertices[1], vertices[2], Clockwise); Index3i t1 = new Index3i(vertices[0], vertices[2], vertices[3], Clockwise); cur_mesh.AppendTriangle(t0); cur_mesh.AppendTriangle(t1); } } }
public virtual void MakeMesh(DMesh3 m) { int nV = vertices.Count; bool bWantNormals = WantNormals && normals != null && normals.Count == vertices.Count; if (bWantNormals) { m.EnableVertexNormals(Vector3f.AxisY); } bool bWantUVs = WantUVs && uv != null && uv.Count == vertices.Count; if (bWantUVs) { m.EnableVertexUVs(Vector2f.Zero); } for (int i = 0; i < nV; ++i) { var ni = new NewVertexInfo() { v = vertices[i] }; if (bWantNormals) { ni.bHaveN = true; ni.n = normals[i]; } if (bWantUVs) { ni.bHaveUV = true; ni.uv = uv[i]; } int vID = m.AppendVertex(ni); Util.gDevAssert(vID == i); } int nT = triangles.Count; if (WantGroups && groups != null && groups.Length == nT) { m.EnableTriangleGroups(); for (int i = 0; i < nT; ++i) { m.AppendTriangle(triangles[i], groups[i]); } } else { for (int i = 0; i < nT; ++i) { m.AppendTriangle(triangles[i]); } } }
// // DMesh3 construction utilities // /// <summary> /// ultimate generic mesh-builder, pass it arrays of floats/doubles, or lists /// of Vector3d, or anything in-between. Will figure out how to interpret /// </summary> public static DMesh3 Build <VType, TType, NType>(IEnumerable <VType> Vertices, IEnumerable <TType> Triangles, IEnumerable <NType> Normals = null, IEnumerable <int> TriGroups = null) { var mesh = new DMesh3(Normals != null, false, false, TriGroups != null); Vector3d[] v = BufferUtil.ToVector3d(Vertices); for (int i = 0; i < v.Length; ++i) { mesh.AppendVertex(v[i]); } if (Normals != null) { Vector3f[] n = BufferUtil.ToVector3f(Normals); if (n.Length != v.Length) { throw new Exception("DMesh3Builder.Build: incorrect number of normals provided"); } for (int i = 0; i < n.Length; ++i) { mesh.SetVertexNormal(i, n[i]); } } Index3i[] t = BufferUtil.ToIndex3i(Triangles); for (int i = 0; i < t.Length; ++i) { mesh.AppendTriangle(t[i]); } if (TriGroups != null) { var groups = new List <int>(TriGroups); if (groups.Count != t.Length) { throw new Exception("DMesh3Builder.Build: incorect number of triangle groups"); } for (int i = 0; i < t.Length; ++i) { mesh.SetTriangleGroup(i, groups[i]); } } return(mesh); }
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); }
public virtual int[] AddTriangleStrip(IList <Frame3f> frames, IList <Interval1d> spans, int group_id = -1) { int N = frames.Count; if (N != spans.Count) { throw new Exception("MeshEditor.AddTriangleStrip: spans list is not the same size!"); } int[] new_tris = new int[2 * (N - 1)]; int prev_a = -1, prev_b = -1; int i = 0, ti = 0; for (i = 0; i < N; ++i) { Frame3f f = frames[i]; Interval1d span = spans[i]; Vector3d va = f.Origin + (float)span.a * f.Y; Vector3d vb = f.Origin + (float)span.b * f.Y; // [TODO] could compute normals here... int a = Mesh.AppendVertex(va); int b = Mesh.AppendVertex(vb); if (prev_a != -1) { new_tris[ti++] = Mesh.AppendTriangle(prev_a, b, prev_b); new_tris[ti++] = Mesh.AppendTriangle(prev_a, a, b); } prev_a = a; prev_b = b; } return(new_tris); }
/// <summary> /// add vertex to mesh, with locking if we are computing in parallel /// </summary> int append_vertex(Vector3d v) { bool lock_taken = false; if (bParallel) { mesh_lock.Enter(ref lock_taken); } int vid = Mesh.AppendVertex(v); if (lock_taken) { mesh_lock.Exit(); } return(vid); }
void compute(IEnumerable <int> triangles, int tri_count) { int est_verts = tri_count / 2; SubMesh = new DMesh3(BaseMesh.Components & WantComponents); BaseSubmeshV = new IndexFlagSet(BaseMesh.MaxVertexID, est_verts); BaseToSubV = new IndexMap(BaseMesh.MaxVertexID, est_verts); SubToBaseV = new DVector <int>(); foreach (int ti in triangles) { Index3i base_t = BaseMesh.GetTriangle(ti); Index3i new_t = Index3i.Zero; int gid = BaseMesh.GetTriangleGroup(ti); for (int j = 0; j < 3; ++j) { int base_v = base_t[j]; int sub_v = -1; if (BaseSubmeshV[base_v] == false) { sub_v = SubMesh.AppendVertex(BaseMesh, base_v); BaseSubmeshV[base_v] = true; BaseToSubV[base_v] = sub_v; SubToBaseV.insert(base_v, sub_v); } else { sub_v = BaseToSubV[base_v]; } new_t[j] = sub_v; } SubMesh.AppendTriangle(new_t, gid); } }
// Assumption here is that Submesh has been modified, but boundary loop has // been preserved, and that old submesh has already been removed from this mesh. // So, we just have to append new vertices and then rewrite triangles // If new_tris or new_verts is non-null, we will return this info. // new_tris should be set to TriangleCount (ie it is not necessarily a map) // For new_verts, if we used an existing bdry vtx instead, we set the value to -(existing_index+1), // otherwise the value is new_index (+1 is to handle 0) // // Returns true if submesh successfully inserted, false if any triangles failed // (which happens if triangle would result in non-manifold mesh) public bool ReinsertSubmesh(DSubmesh3 sub, ref int[] new_tris, out IndexMap SubToNewV) { if (sub.BaseBorderV == null) { throw new Exception("MeshEditor.ReinsertSubmesh: Submesh does not have required boundary info. Call ComputeBoundaryInfo()!"); } DMesh3 submesh = sub.SubMesh; bool bAllOK = true; IndexFlagSet done_v = new IndexFlagSet(submesh.MaxVertexID, submesh.TriangleCount / 2); SubToNewV = new IndexMap(submesh.MaxVertexID, submesh.VertexCount); int nti = 0; int NT = submesh.MaxTriangleID; for (int ti = 0; ti < NT; ++ti) { if (submesh.IsTriangle(ti) == false) { continue; } Index3i sub_t = submesh.GetTriangle(ti); int gid = submesh.GetTriangleGroup(ti); Index3i new_t = Index3i.Zero; for (int j = 0; j < 3; ++j) { int sub_v = sub_t[j]; int new_v = -1; if (done_v[sub_v] == false) { // first check if this is a boundary vtx on submesh and maps to a bdry vtx on base mesh if (submesh.vertex_is_boundary(sub_v)) { int base_v = (sub_v < sub.SubToBaseV.size) ? sub.SubToBaseV[sub_v] : -1; if (base_v >= 0 && Mesh.IsVertex(base_v) && sub.BaseBorderV[base_v] == true) { // [RMS] this should always be true, but assert in tests to find out Debug.Assert(Mesh.vertex_is_boundary(base_v)); if (Mesh.vertex_is_boundary(base_v)) { new_v = base_v; } } } // if that didn't happen, append new vtx if (new_v == -1) { new_v = Mesh.AppendVertex(submesh, sub_v); } SubToNewV[sub_v] = new_v; done_v[sub_v] = true; } else { new_v = SubToNewV[sub_v]; } new_t[j] = new_v; } Debug.Assert(Mesh.FindTriangle(new_t.a, new_t.b, new_t.c) == DMesh3.InvalidID); int new_tid = Mesh.AppendTriangle(new_t, gid); Debug.Assert(new_tid != DMesh3.InvalidID && new_tid != DMesh3.NonManifoldID); if (!Mesh.IsTriangle(new_tid)) { bAllOK = false; } if (new_tris != null) { new_tris[nti++] = new_tid; } } return(bAllOK); }
/// <summary> /// Similar to the static <see cref="Build()"/> method below, but uses the /// <see cref="NonManifoldTriBehavior"/> and <see cref="AddTriangleFailBehaviors"/> properties /// to affect the meshing process and avoids exceptions, preferring feedback in the mesh metadata. /// </summary> public DMesh3 AppendMesh <VType, TType, NType>(IEnumerable <VType> Vertices, IEnumerable <TType> Triangles, IEnumerable <NType> Normals = null, IEnumerable <int> TriGroups = null) { // build outcomes are stored in the metadata to keep the function signature like the static method Build // int iAppendTriangleIssues = 0; bool addNormals = Normals != null; string NormalsMetadata = "None"; bool addTriGroups = TriGroups != null; string TriGroupsMetadata = "None"; // data preparation Vector3d[] v = BufferUtil.ToVector3d(Vertices); Vector3f[] n = null; if (addNormals) { n = BufferUtil.ToVector3f(Normals); if (n.Length != v.Length) { NormalsMetadata = "Error: incorrect number of normals provided, ignored."; addNormals = false; } } Index3i[] t = BufferUtil.ToIndex3i(Triangles); List <int> groups = null; if (addTriGroups) { groups = new List <int>(TriGroups); if (groups.Count != t.Length) { TriGroupsMetadata = "Error: incorrect number of groups provided, ignored."; addTriGroups = false; } } DMesh3 mesh = new DMesh3(addNormals, false, false, addTriGroups); AppendNewMesh(mesh); // vertices for (int i = 0; i < v.Length; ++i) { mesh.AppendVertex(v[i]); } // normals if (addNormals) { for (int i = 0; i < n.Length; ++i) { mesh.SetVertexNormal(i, n[i]); } NormalsMetadata = "Ok"; } // triangles for (int i = 0; i < t.Length; ++i) { var last = AppendTriangle(t[i]); if (last == DMesh3.InvalidID || last == DMesh3.NonManifoldID) { iAppendTriangleIssues++; } } // groups if (addTriGroups) { for (int i = 0; i < t.Length; ++i) { mesh.SetTriangleGroup(i, groups[i]); } TriGroupsMetadata = "Ok"; } // adding the metadata // mesh.AttachMetadata("AppendTriangleIssues", iAppendTriangleIssues); mesh.AttachMetadata("Normals", NormalsMetadata); mesh.AttachMetadata("TriGroups", TriGroupsMetadata); return(mesh); }
/// <summary> /// Disconnect the given triangles from their neighbours, by duplicating "boundary" vertices, ie /// vertices on edges for which one triangle is in-set and the other is not. /// If bComputeEdgePairs is true, we return list of old/new edge pairs (useful for stitching) /// [TODO] currently boundary-edge behaviour is to *not* duplicate boundary verts /// </summary> public bool SeparateTriangles(IEnumerable <int> triangles, bool bComputeEdgePairs, out List <Index2i> EdgePairs) { HashSet <int> in_set = new HashSet <int>(triangles); Dictionary <int, int> VertexMap = new Dictionary <int, int>(); EdgePairs = null; HashSet <int> edges = null; List <Index2i> OldEdgeVerts = null; if (bComputeEdgePairs) { EdgePairs = new List <Index2i>(); edges = new HashSet <int>(); OldEdgeVerts = new List <Index2i>(); } // duplicate vertices on edges that are on boundary of triangles roi foreach (int tid in triangles) { Index3i te = Mesh.GetTriEdges(tid); for (int j = 0; j < 3; ++j) { Index2i et = Mesh.GetEdgeT(te[j]); // [TODO] what about behavior where we want to also duplicate boundary verts?? if (et.b == DMesh3.InvalidID || (et.a == tid && in_set.Contains(et.b)) || (et.b == tid && in_set.Contains(et.a))) { te[j] = -1; } } for (int j = 0; j < 3; ++j) { if (te[j] == -1) { continue; } Index2i ev = Mesh.GetEdgeV(te[j]); if (VertexMap.ContainsKey(ev.a) == false) { VertexMap[ev.a] = Mesh.AppendVertex(Mesh, ev.a); } if (VertexMap.ContainsKey(ev.b) == false) { VertexMap[ev.b] = Mesh.AppendVertex(Mesh, ev.b); } if (bComputeEdgePairs && edges.Contains(te[j]) == false) { edges.Add(te[j]); OldEdgeVerts.Add(ev); EdgePairs.Add(new Index2i(te[j], -1)); } } } // update triangles foreach (int tid in triangles) { Index3i tv = Mesh.GetTriangle(tid); Index3i tv_new = tv; for (int j = 0; j < 3; ++j) { int newv; if (VertexMap.TryGetValue(tv[j], out newv)) { tv_new[j] = newv; } } if (tv_new != tv) { Mesh.SetTriangle(tid, tv_new); } } if (bComputeEdgePairs) { for (int k = 0; k < EdgePairs.Count; ++k) { Index2i old_ev = OldEdgeVerts[k]; int new_a = VertexMap[old_ev.a]; int new_b = VertexMap[old_ev.b]; int new_eid = Mesh.FindEdge(new_a, new_b); Util.gDevAssert(new_eid != DMesh3.InvalidID); EdgePairs[k] = new Index2i(EdgePairs[k].a, new_eid); } } return(true); }
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 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]); } } } } } }