public static void poke_test() { DMesh3 mesh = TestUtil.LoadTestInputMesh("plane_250v.obj"); //DMesh3 mesh = TestUtil.LoadTestInputMesh("sphere_bowtie_groups.obj"); mesh.CheckValidity(); int NT = mesh.TriangleCount; for (int i = 0; i < NT; i += 5) { Vector3d n = mesh.GetTriNormal(i); DMesh3.PokeTriangleInfo pokeinfo; MeshResult result = mesh.PokeTriangle(i, out pokeinfo); Vector3d v = mesh.GetVertex(pokeinfo.new_vid); v += 0.25f * n; mesh.SetVertex(pokeinfo.new_vid, v); mesh.CheckValidity(); } //TestUtil.WriteTestOutputMesh(mesh, "poke_test_result.obj"); }
/// <summary> /// Find regions of the input meshes that are horizontal, returns binned by Z-value. /// Currently only finds upward-facing regions. /// </summary> protected Dictionary <double, List <PlanarRegion> > FindPlanarZRegions(double minDimension, double dotNormalTol = 0.999) { Dictionary <double, List <PlanarRegion> > Regions = new Dictionary <double, List <PlanarRegion> >(); SpinLock region_lock = new SpinLock(); gParallel.ForEach(Meshes, (sliceMesh) => { if (sliceMesh.options.IsCavity == false) { return; } DMesh3 mesh = sliceMesh.mesh; HashSet <int> planar_tris = new HashSet <int>(); foreach (int tid in mesh.TriangleIndices()) { Vector3d n = mesh.GetTriNormal(tid); double dot = n.Dot(Vector3d.AxisZ); if (dot > dotNormalTol) { planar_tris.Add(tid); } } MeshConnectedComponents regions = new MeshConnectedComponents(mesh); regions.FilterF = planar_tris.Contains; regions.FindConnectedT(); foreach (var c in regions) { AxisAlignedBox3d bounds = MeshMeasurements.BoundsT(mesh, c.Indices); if (bounds.Width > minDimension && bounds.Height > minDimension) { double z = Math.Round(bounds.Center.z, PrecisionDigits); PlanarRegion planar = new PlanarRegion() { Mesh = mesh, Z = z, Triangles = c.Indices }; bool taken = false; region_lock.Enter(ref taken); List <PlanarRegion> zregions; if (Regions.TryGetValue(z, out zregions)) { zregions.Add(planar); } else { zregions = new List <PlanarRegion>() { planar }; Regions[z] = zregions; } region_lock.Exit(); } } }); return(Regions); }
/// <summary> /// Find intersection of *WORLD* ray with Mesh /// </summary> override public bool FindRayIntersection(Ray3f rayW, out SORayHit hit) { hit = null; if (enable_spatial == false) { return(false); } if (spatial == null) { spatial = new DMeshAABBTree3(mesh); spatial.Build(); } // convert ray to local Frame3f f = new Frame3f(rayW.Origin, rayW.Direction); f = SceneTransforms.TransformTo(f, this, CoordSpace.WorldCoords, CoordSpace.ObjectCoords); Ray3d local_ray = new Ray3d(f.Origin, f.Z); int hit_tid = spatial.FindNearestHitTriangle(local_ray); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, local_ray); Frame3f hitF = new Frame3f(local_ray.PointAt(intr.RayParameter), mesh.GetTriNormal(hit_tid)); hitF = SceneTransforms.TransformTo(hitF, this, CoordSpace.ObjectCoords, CoordSpace.WorldCoords); hit = new SORayHit(); hit.hitPos = hitF.Origin; hit.hitNormal = hitF.Z; hit.hitIndex = hit_tid; hit.fHitDist = hit.hitPos.Distance(rayW.Origin); // simpler than transforming! hit.hitGO = RootGameObject; hit.hitSO = this; return(true); } return(false); }
/// <summary> /// Find intersection of *WORLD* ray with Mesh /// </summary> override public bool FindRayIntersection(Ray3f rayW, out SORayHit hit) { hit = null; if (enable_spatial == false) { return(false); } validate_spatial(); // convert ray to local FScene scene = this.GetScene(); Ray3f rayS = scene.ToSceneRay(rayW); Ray3d local_ray = SceneTransforms.SceneToObject(this, rayS); int hit_tid = spatial.FindNearestHitTriangle(local_ray); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, local_ray); Vector3f hitPos = (Vector3f)local_ray.PointAt(intr.RayParameter); hitPos = SceneTransforms.ObjectToSceneP(this, hitPos); hitPos = scene.ToWorldP(hitPos); Vector3f hitNormal = (Vector3f)mesh.GetTriNormal(hit_tid); hitNormal = SceneTransforms.ObjectToSceneN(this, hitNormal); hitNormal = scene.ToWorldN(hitNormal); hit = new SORayHit(); hit.hitPos = hitPos; hit.hitNormal = hitNormal; hit.hitIndex = hit_tid; hit.fHitDist = hit.hitPos.Distance(rayW.Origin); // simpler than transforming! hit.hitGO = RootGameObject; hit.hitSO = this; return(true); } return(false); }
protected override void OnPointUpdated(ControlPoint pt, Frame3f prevFrameS, bool isFirst) { DMesh3 mesh = InputMeshSO.Mesh; DMeshAABBTree3 spatial = InputMeshSO.Spatial; Vector3f ptO = SceneTransforms.SceneToObjectP(InputMeshSO, pt.currentFrameS.Origin); Frame3f frameO = MeshQueries.NearestPointFrame(mesh, spatial, ptO, true); Vector3d dir = -frameO.Z; if (hole_direction != HoleDirections.Normal) { Vector3f axis = Vector3f.AxisX; if (hole_direction == HoleDirections.AxisY) { axis = Vector3f.AxisY; } else if (hole_direction == HoleDirections.AxisZ) { axis = Vector3f.AxisZ; } axis = SceneTransforms.SceneToObjectN(InputMeshSO, axis); dir = (dir.Dot(axis) < 0) ? -axis : axis; } //dir.Normalize(); LastUpdateRay = new Ray3d(frameO.Origin, dir); List <int> hitTris = new List <int>(); int hit_tris = spatial.FindAllHitTriangles(LastUpdateRay, hitTris); double max_t = 0; foreach (int tid in hitTris) { Vector3d n = mesh.GetTriNormal(tid); if (n.Dot(LastUpdateRay.Direction) < 0) { continue; } IntrRay3Triangle3 rayhit = MeshQueries.TriangleIntersection(InputMeshSO.Mesh, tid, LastUpdateRay); max_t = rayhit.RayParameter; break; } if (max_t <= 0) { return; } LastThroughDepth = max_t; update_current_hole_type(); }
UseFillType classify_hole() { return(UseFillType.MinimalFill); #if false int NV = FillLoop.VertexCount; int NE = FillLoop.EdgeCount; Vector3d size = FillLoop.ToCurve().GetBoundingBox().Diagonal; NormalHistogram hist = new NormalHistogram(4096, true); for (int k = 0; k < NE; ++k) { int eid = FillLoop.Edges[k]; Index2i et = Mesh.GetEdgeT(eid); Vector3d n = Mesh.GetTriNormal(et.a); hist.Count(n, 1.0, true); } if (hist.UsedBins.Count == 1) { return(UseFillType.PlanarFill); } //int nontrivial_bins = 0; //foreach ( int bin in hist.UsedBins ) { // if (hist.Counts[bin] > 8) // nontrivial_bins++; //} //if (nontrivial_bins > 0) // return UseFillType.PlanarSpansFill; return(UseFillType.SmoothFill); #endif }
public static void test_normals() { // check that frames are ok DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj"); foreach (int tid in mesh.TriangleIndices()) { Vector3f n = (Vector3f)mesh.GetTriNormal(tid); for (int j = 0; j < 3; ++j) { Frame3f f = mesh.GetTriFrame(tid, j); if (Math.Abs(f.X.Dot(f.Y)) > MathUtil.ZeroTolerancef || Math.Abs(f.X.Dot(f.Z)) > MathUtil.ZeroTolerancef || Math.Abs(f.Y.Dot(f.Z)) > MathUtil.ZeroTolerancef) { throw new Exception("argh"); } Vector3f fn = f.Z; if (fn.Dot(n) < 0.99) { throw new Exception("shit"); } } } MeshNormals.QuickCompute(mesh); foreach (int vid in mesh.VertexIndices()) { Vector3f n = mesh.GetVertexNormal(vid); for (int j = 1; j <= 2; ++j) { Frame3f f = mesh.GetVertexFrame(vid, (j == 1) ? true : false); Vector3f fn = f.GetAxis(j); if (Math.Abs(f.X.Dot(f.Y)) > MathUtil.ZeroTolerancef || Math.Abs(f.X.Dot(f.Z)) > MathUtil.ZeroTolerancef || Math.Abs(f.Y.Dot(f.Z)) > MathUtil.ZeroTolerancef) { throw new Exception("argh"); } if (fn.Dot(n) < 0.99) { throw new Exception("shit2"); } } } }
protected override void SolveInstance(IGH_DataAccess DA) { DMesh3_goo goo = null; DA.GetData(0, ref goo); DMesh3 mesh = new DMesh3(goo.Value); List <Rhino.Geometry.Vector3d> vecs = new List <Rhino.Geometry.Vector3d>(); foreach (var ind in mesh.TriangleIndices()) { vecs.Add(mesh.GetTriNormal(ind).ToRhinoVec()); } DA.SetDataList(0, vecs); }
private static Vector3d GetAveragedNormal(DMesh3 mesh, int vertex) { MeshFaceSelection selection = new MeshFaceSelection(mesh); var surroundingTris = new List <int>(); mesh.GetVtxTriangles(vertex, surroundingTris, false); selection.FloodFill(surroundingTris.ToArray(), i => IsInRange(mesh, vertex, i, 3)); Vector3d cumulative = Vector3d.Zero; foreach (var i in selection) { cumulative += mesh.GetTriNormal(i); } var normal = cumulative / selection.Count; return(normal); }
// [RMS] this is not working right now... override public bool FindRayIntersection(Ray3f ray, out SORayHit hit) { hit = null; if (enable_spatial == false) { return(false); } if (spatial == null) { spatial = new DMeshAABBTree3(mesh); spatial.Build(); } Transform xform = ((GameObject)RootGameObject).transform; // convert ray to local Ray3d local_ray = new Ray3d(); local_ray.Origin = xform.InverseTransformPoint(ray.Origin); local_ray.Direction = xform.InverseTransformDirection(ray.Direction); local_ray.Direction.Normalize(); int hit_tid = spatial.FindNearestHitTriangle(local_ray); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, local_ray); hit = new SORayHit(); hit.fHitDist = (float)intr.RayParameter; hit.hitPos = xform.TransformPoint((Vector3f)local_ray.PointAt(intr.RayParameter)); hit.hitNormal = xform.TransformDirection((Vector3f)mesh.GetTriNormal(hit_tid)); hit.hitGO = RootGameObject; hit.hitSO = this; return(true); } return(false); }
public static UnityMesh ToUnityMesh(this DMesh3 dMesh, bool bNorm = true, bool bUV = false, bool bCol = false) { bNorm &= dMesh.HasVertexNormals; bUV &= dMesh.HasVertexUVs; bCol &= dMesh.HasVertexColors; int[] vertexMap = new int[dMesh.VerticesBuffer.Length]; int[] triangleMap = new int[dMesh.TrianglesBuffer.Length]; int[] triangles = new int[dMesh.TriangleCount * 3]; List <Vector3d> vertices = new List <Vector3d>(); List <Vector3f> normals = new List <Vector3f>(); List <Vector2f> uv = new List <Vector2f>(); List <Colorf> colors = new List <Colorf>(); List <int> vertexUseCount = new List <int>(); NewVertexInfo vInfo = new NewVertexInfo(new Vector3d(), new Vector3f(), new Vector3f(), new Vector2f()); IEnumerator e = dMesh.TrianglesRefCounts.GetEnumerator(); int ti = 0; while (e.MoveNext()) { int iRef = (int)e.Current; Index3i triangle = dMesh.GetTriangle(iRef); triangleMap[iRef] = ti; for (int i = 0; i < 3; i++) { int vertIndex = triangle[i]; if (vertexMap[vertIndex] == 0) { vertexUseCount.Add(1); dMesh.GetVertex(vertIndex, ref vInfo, bNorm, bCol, bUV); vertices.Add(new Vector3f((float)vInfo.v.x, (float)vInfo.v.y, (float)vInfo.v.z)); vertexMap[vertIndex] = vertices.Count - 1; if (bNorm) { normals.Add(vInfo.n); } if (bUV) { uv.Add(vInfo.uv); } if (bCol) { colors.Add(new Colorf(vInfo.c.x, vInfo.c.y, vInfo.c.z)); } } else { vertexUseCount[vertexMap[vertIndex]]++; } triangles[ti * 3 + i] = vertexMap[vertIndex]; } ti++; } UnityMesh uMesh = new UnityMesh(vertexUseCount.ToArray(), triangles, vertices, normals, uv, colors); // Triangle normals and neighbors. e = dMesh.TrianglesRefCounts.GetEnumerator(); while (e.MoveNext()) { int iRef = (int)e.Current; int[] nb = dMesh.GetTriNeighbourTris(iRef).array; int[] neighbors = new int[3]; for (int i = 0; i < 3; i++) { neighbors[i] = (nb[i] != -1) ? triangleMap[nb[i]] : -1; } uMesh.AddTriangleInfo(triangleMap[iRef], (Vector3f)dMesh.GetTriNormal(iRef), neighbors); } return(uMesh); }
// NO DOES NOT WORK. DOES NOT FIND EDGE SPANS THAT ARE IN PLANE BUT HAVE DIFFERENT NORMAL! // NEED TO COLLECT UP SPANS USING NORMAL HISTOGRAM NORMALS! // ALSO NEED TO ACTUALLY CHECK FOR COPLANARITY, NOT JUST SAME NORMAL!! Dictionary <Vector3d, List <EdgeSpan> > find_coplanar_span_sets(DMesh3 mesh, EdgeLoop loop) { double dot_thresh = 0.999; var span_sets = new Dictionary <Vector3d, List <EdgeSpan> >(); int NV = loop.Vertices.Length; int NE = loop.Edges.Length; var edge_normals = new Vector3d[NE]; for (int k = 0; k < NE; ++k) { edge_normals[k] = mesh.GetTriNormal(mesh.GetEdgeT(loop.Edges[k]).a); } // find coplanar verts // [RMS] this is wrong, if normals vary smoothly enough we will mark non-coplanar spans as coplanar bool[] vert_coplanar = new bool[NV]; int nc = 0; for (int k = 0; k < NV; ++k) { int prev = (k == 0) ? NV - 1 : k - 1; if (edge_normals[k].Dot(ref edge_normals[prev]) > dot_thresh) { vert_coplanar[k] = true; nc++; } } if (nc < 2) { return(null); } int iStart = 0; while (vert_coplanar[iStart]) { iStart++; } int iPrev = iStart; int iCur = iStart + 1; while (iCur != iStart) { if (vert_coplanar[iCur] == false) { iPrev = iCur; iCur = (iCur + 1) % NV; continue; } var edges = new List <int>() { loop.Edges[iPrev] }; int span_start_idx = iCur; while (vert_coplanar[iCur]) { edges.Add(loop.Edges[iCur]); iCur = (iCur + 1) % NV; } if (edges.Count > 1) { Vector3d span_n = edge_normals[span_start_idx]; var span = EdgeSpan.FromEdges(mesh, edges); span.CheckValidity(); foreach (var pair in span_sets) { if (pair.Key.Dot(ref span_n) > dot_thresh) { span_n = pair.Key; break; } } List <EdgeSpan> found; if (span_sets.TryGetValue(span_n, out found) == false) { span_sets[span_n] = new List <EdgeSpan>() { span }; } else { found.Add(span); } } } return(span_sets); }
public virtual bool Apply() { DMesh3 testAgainstMesh = Mesh; if (InsideMode == CalculationMode.RayParity) { MeshBoundaryLoops loops = new MeshBoundaryLoops(testAgainstMesh); if (loops.Count > 0) { testAgainstMesh = new DMesh3(Mesh); foreach (var loop in loops) { if (Cancelled()) { return(false); } SimpleHoleFiller filler = new SimpleHoleFiller(testAgainstMesh, loop); filler.Fill(); } } } DMeshAABBTree3 spatial = (Spatial != null && testAgainstMesh == Mesh) ? Spatial : new DMeshAABBTree3(testAgainstMesh, true); if (InsideMode == CalculationMode.AnalyticWindingNumber) { spatial.WindingNumber(Vector3d.Zero); } else if (InsideMode == CalculationMode.FastWindingNumber) { spatial.FastWindingNumber(Vector3d.Zero); } if (Cancelled()) { return(false); } // ray directions List <Vector3d> ray_dirs = null; int NR = 0; if (InsideMode == CalculationMode.SimpleOcclusionTest) { ray_dirs = new List <Vector3d>(); ray_dirs.Add(Vector3d.AxisX); ray_dirs.Add(-Vector3d.AxisX); ray_dirs.Add(Vector3d.AxisY); ray_dirs.Add(-Vector3d.AxisY); ray_dirs.Add(Vector3d.AxisZ); ray_dirs.Add(-Vector3d.AxisZ); NR = ray_dirs.Count; } Func <Vector3d, bool> isOccludedF = (pt) => { if (InsideMode == CalculationMode.RayParity) { return(spatial.IsInside(pt)); } else if (InsideMode == CalculationMode.AnalyticWindingNumber) { return(spatial.WindingNumber(pt) > WindingIsoValue); } else if (InsideMode == CalculationMode.FastWindingNumber) { return(spatial.FastWindingNumber(pt) > WindingIsoValue); } else { for (int k = 0; k < NR; ++k) { int hit_tid = spatial.FindNearestHitTriangle(new Ray3d(pt, ray_dirs[k])); if (hit_tid == DMesh3.InvalidID) { return(false); } } return(true); } }; bool cancel = false; BitArray vertices = null; if (PerVertex) { vertices = new BitArray(Mesh.MaxVertexID); MeshNormals normals = null; if (Mesh.HasVertexNormals == false) { normals = new MeshNormals(Mesh); normals.Compute(); } gParallel.ForEach(Mesh.VertexIndices(), (vid) => { if (cancel) { return; } if (vid % 10 == 0) { cancel = Cancelled(); } Vector3d c = Mesh.GetVertex(vid); Vector3d n = (normals == null) ? Mesh.GetVertexNormal(vid) : normals[vid]; c += n * NormalOffset; vertices[vid] = isOccludedF(c); }); } if (Cancelled()) { return(false); } RemovedT = new List <int>(); SpinLock removeLock = new SpinLock(); gParallel.ForEach(Mesh.TriangleIndices(), (tid) => { if (cancel) { return; } if (tid % 10 == 0) { cancel = Cancelled(); } bool inside = false; if (PerVertex) { Index3i tri = Mesh.GetTriangle(tid); inside = vertices[tri.a] || vertices[tri.b] || vertices[tri.c]; } else { Vector3d c = Mesh.GetTriCentroid(tid); Vector3d n = Mesh.GetTriNormal(tid); c += n * NormalOffset; inside = isOccludedF(c); } if (inside) { bool taken = false; removeLock.Enter(ref taken); RemovedT.Add(tid); removeLock.Exit(); } }); if (Cancelled()) { return(false); } if (RemovedT.Count > 0) { MeshEditor editor = new MeshEditor(Mesh); bool bOK = editor.RemoveTriangles(RemovedT, true); RemoveFailed = (bOK == false); } return(true); }
public static void test_AABBTree_RayHit(int meshCase = 8) { DMesh3 mesh = MakeSpatialTestMesh(meshCase); DMeshAABBTree3 tree = new DMeshAABBTree3(mesh); tree.Build(); tree.TestCoverage(); AxisAlignedBox3d bounds = mesh.CachedBounds; Vector3d ext = bounds.Extents; Vector3d c = bounds.Center; double r = bounds.DiagonalLength / 4; Random rand = new Random(316136327); tree.FindNearestHitTriangle( new Ray3f(100 * Vector3f.One, Vector3f.One)); // test rays out from center of box, and rays in towards it // (should all hit for standard test cases) int hits = 0; int N = (meshCase > 7) ? 1000 : 10000; #if true for (int ii = 0; ii < N; ++ii) { if (ii % 100 == 0) { System.Console.WriteLine("{0} / {1}", ii, N); } Vector3d p = (ii < N / 2) ? c : c + 2 * r * rand.Direction(); Vector3d d = (ii < N / 2) ? rand.Direction() : (c - p).Normalized; Ray3d ray = new Ray3d(p, d); int tNearBrute = MeshQueries.FindHitTriangle_LinearSearch(mesh, ray); int tNearTree = tree.FindNearestHitTriangle(ray); //System.Console.WriteLine("{0} - {1}", tNearBrute, tree.TRI_TEST_COUNT); if (tNearBrute == DMesh3.InvalidID) { Debug.Assert(tNearBrute == tNearTree); continue; } ++hits; IntrRay3Triangle3 qBrute = MeshQueries.TriangleIntersection(mesh, tNearBrute, ray); IntrRay3Triangle3 qTree = MeshQueries.TriangleIntersection(mesh, tNearTree, ray); double dotBrute = mesh.GetTriNormal(tNearBrute).Dot(ray.Direction); double dotTree = mesh.GetTriNormal(tNearTree).Dot(ray.Direction); Debug.Assert(Math.Abs(qBrute.RayParameter - qTree.RayParameter) < MathUtil.ZeroTolerance); } Debug.Assert(hits == N); System.Console.WriteLine("in/out rays: {0} hits out of {1} rays", hits, N); #endif // random rays hits = 0; for (int ii = 0; ii < N; ++ii) { if (ii % 100 == 0) { System.Console.WriteLine("{0} / {1}", ii, N); } Vector3d target = c + rand.PointInRange(r); Vector3d o = c + rand.PointInRange(10 * r); Ray3d ray = new Ray3d(o, (target - o).Normalized); int tNearBrute = MeshQueries.FindHitTriangle_LinearSearch(mesh, ray); int tNearTree = tree.FindNearestHitTriangle(ray); //System.Console.WriteLine("{0} - {1}", tNearBrute, tree.TRI_TEST_COUNT); if (tNearBrute == DMesh3.InvalidID) { Debug.Assert(tNearBrute == tNearTree); continue; } ++hits; IntrRay3Triangle3 qBrute = MeshQueries.TriangleIntersection(mesh, tNearBrute, ray); IntrRay3Triangle3 qTree = MeshQueries.TriangleIntersection(mesh, tNearTree, ray); double dotBrute = mesh.GetTriNormal(tNearBrute).Dot(ray.Direction); double dotTree = mesh.GetTriNormal(tNearTree).Dot(ray.Direction); Debug.Assert(Math.Abs(qBrute.RayParameter - qTree.RayParameter) < MathUtil.ZeroTolerance); } System.Console.WriteLine("random rays: hit {0} of {1} rays", hits, N); }