internal void MoveAllPointsDepthDependant(CuttingInfo info, DMesh3 newMesh, Dictionary <int, BacksideAlgorithm.PeprStatusVert> stati) { var tree = new DMeshAABBTree3(info.oldMesh, true); tree.TriangleFilterF = i => tree.Mesh.GetTriangleGroup(i) != info.data.ColorNum; foreach (var status in stati) { var shellPoint = newMesh.GetVertex(status.Value.idNewMeshOuter.Value); var normal = info.oldMesh.CalcVertexNormal(status.Value.idOldMeshOuter); var position = shellPoint + info.data.minDepth * normal; Ray3d ray = new Ray3d(shellPoint - normal * info.data.minDepth, -normal); //tiny shift to make sure it's not hitting itself int hit_tid = tree.FindNearestHitTriangle(ray); Debug.Log("Hit " + hit_tid); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(info.oldMesh, hit_tid, ray); double hit_dist = shellPoint.Distance(ray.PointAt(intr.RayParameter)); position = shellPoint - normal * hit_dist * (info.data.depth / 100); Debug.Log($"Hit Dist: {hit_dist}"); } else { StaticFunctions.ErrorMessage("Depth Dependant Calculation has encountered an error"); } info.mesh.SetVertex(status.Value.idOldMeshInner.Value, position); newMesh.SetVertex(status.Value.idNewMeshInner.Value, position); } }
public int FindNearestHitTriangle(Ray3d ray, double fMaxDist = double.MaxValue) { var save_filter = SourceSpatial.TriangleFilterF; SourceSpatial.TriangleFilterF = source_filter; int hit_source_tid = SourceSpatial.FindNearestHitTriangle(ray); SourceSpatial.TriangleFilterF = save_filter; int hit_edit_tid; IntrRay3Triangle3 edit_hit = find_added_hit(ref ray, out hit_edit_tid); if (hit_source_tid == DMesh3.InvalidID && hit_edit_tid == DMesh3.InvalidID) { return(DMesh3.InvalidID); } else if (hit_source_tid == DMesh3.InvalidID) { return(hit_edit_tid); } else if (hit_edit_tid == DMesh3.InvalidID) { return(hit_source_tid); } IntrRay3Triangle3 source_hit = (hit_source_tid != -1) ? MeshQueries.TriangleIntersection(SourceMesh, hit_source_tid, ray) : null; return((edit_hit.RayParameter < source_hit.RayParameter) ? hit_edit_tid : hit_source_tid); }
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(); }
// convenience function to construct a IntrRay3Triangle3 object for a mesh triangle public static IntrRay3Triangle3 TriangleIntersection(NGonsCore.geometry3Sharp.mesh.DMesh3 mesh, int ti, Ray3d ray) { if (!mesh.IsTriangle(ti)) { return(null); } Triangle3d tri = new Triangle3d(); mesh.GetTriVertices(ti, ref tri.V0, ref tri.V1, ref tri.V2); IntrRay3Triangle3 q = new IntrRay3Triangle3(ray, tri); q.Find(); return(q); }
/// <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); }
// [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 bool RayIntersect(Ray3d ray, out Vector3D vHit, out Vector3D vHitNormal) { vHit = Vector3D.Zero; vHitNormal = Vector3D.AxisX; int tHitID = Spatial.FindNearestHitTriangle(ray); if (tHitID == NGonsCore.geometry3Sharp.mesh.DMesh3.InvalidID) { return(false); } IntrRay3Triangle3 t = MeshQueries.TriangleIntersection(Mesh, tHitID, ray); vHit = ray.PointAt(t.RayParameter); if (UseFaceNormal == false && Mesh.HasVertexNormals) { vHitNormal = Mesh.GetTriBaryNormal(tHitID, t.TriangleBaryCoords.x, t.TriangleBaryCoords.y, t.TriangleBaryCoords.z); } else { vHitNormal = Mesh.GetTriNormal(tHitID); } return(true); }
public static int FindHitTriangle_LinearSearch(NGonsCore.geometry3Sharp.mesh.DMesh3 mesh, Ray3d ray) { int tNearestID = NGonsCore.geometry3Sharp.mesh.DMesh3.InvalidID; double fNearestT = double.MaxValue; Triangle3d tri = new Triangle3d(); foreach (int ti in mesh.TriangleIndices()) { // [TODO] optimize this mesh.GetTriVertices(ti, ref tri.V0, ref tri.V1, ref tri.V2); IntrRay3Triangle3 ray_tri_hit = new IntrRay3Triangle3(ray, tri); if (ray_tri_hit.Find()) { if (ray_tri_hit.RayParameter < fNearestT) { fNearestT = ray_tri_hit.RayParameter; tNearestID = ti; } } } return(tNearestID); }
internal Vector3d MovePointDepthDependant(CuttingInfo info, Vector3d shellPoint, Vector3d normal) { normal = normal.Normalized; var position = shellPoint + info.data.minDepth * normal;; var tree = new DMeshAABBTree3(info.oldMesh, true); Ray3d ray = new Ray3d(shellPoint, -normal); int hit_tid = tree.FindNearestHitTriangle(ray); Debug.Log("Hit " + hit_tid); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(info.oldMesh, hit_tid, ray); double hit_dist = shellPoint.Distance(ray.PointAt(intr.RayParameter)); position = shellPoint - normal * hit_dist * (info.data.depth / 100); Debug.Log($"Hit Dist: {hit_dist}"); } else { StaticFunctions.ErrorMessage("Depth Dependant Calculation failed"); } return(position); }
IntrRay3Triangle3 find_added_hit(ref Ray3d ray, out int hit_tid) { hit_tid = DMesh3.InvalidID; IntrRay3Triangle3 nearest = null; double dNearT = double.MaxValue; Triangle3d tri = new Triangle3d(); foreach (int tid in AddedT) { Index3i tv = EditMesh.GetTriangle(tid); tri.V0 = EditMesh.GetVertex(tv.a); tri.V1 = EditMesh.GetVertex(tv.b); tri.V2 = EditMesh.GetVertex(tv.c); IntrRay3Triangle3 intr = new IntrRay3Triangle3(ray, tri); if (intr.Find() && intr.RayParameter < dNearT) { dNearT = intr.RayParameter; hit_tid = tid; nearest = intr; } } return(nearest); }
int[] insert_points(Vector3d[] points, DMesh3 mesh) { int[] MapV = new int[points.Length]; HashSet <int> newV = new HashSet <int>(); for (int i = 0; i < points.Length; ++i) { MapV[i] = DMesh3.InvalidID; Vector3d pt = points[i]; pt.Normalize(); Ray3d ray = new Ray3d(Vector3d.Zero, pt); int hit_tid = MeshQueries.FindHitTriangle_LinearSearch(mesh, ray); if (hit_tid == DMesh3.InvalidID) { continue; } Index3i hit_tri = mesh.GetTriangle(hit_tid); IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, ray); Vector3d bary = intr.TriangleBaryCoords; bool done = false; for (int j = 0; j < 3 && done == false; ++j) { if (bary[j] > 0.9) { // hit-vertex case if (newV.Contains(hit_tri[j]) == false) { MapV[i] = hit_tri[j]; newV.Add(MapV[i]); done = true; } } else if (bary[j] < 0.1) { // hit-edge case DMesh3.EdgeSplitInfo split_info; MeshResult splitResult = mesh.SplitEdge(hit_tri[(j + 1) % 3], hit_tri[(j + 2) % 3], out split_info); if (splitResult == MeshResult.Ok) { MapV[i] = split_info.vNew; newV.Add(MapV[i]); mesh.SetVertex(split_info.vNew, points[i]); done = true; } } } if (done) { continue; } DMesh3.PokeTriangleInfo poke_info; MeshResult result = mesh.PokeTriangle(hit_tid, out poke_info); if (result == MeshResult.Ok) { MapV[i] = poke_info.new_vid; newV.Add(MapV[i]); mesh.SetVertex(poke_info.new_vid, points[i]); } } return(MapV); }
/// <summary> /// Cut a "partial" hole, ie we cut the mesh with the polygon once, and then /// extrude downwards to a planar version of the cut boundary. /// /// Currently only supports extruding downwards from topmost intersection. /// /// </summary> protected bool CutPartialHole(DMesh3 mesh, HoleInfo hi, Vector3d translate, bool bUpwards) { if (hi.IsVertical == false) { throw new Exception("unsupported!"); } Vector3d basePoint = CombinedBounds.Center - CombinedBounds.Extents.y * Vector3d.AxisY + translate; // do we need to compute spatial DS for each hole? not super efficient... DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true); Vector3d direction = (bUpwards) ? Vector3d.AxisY : -Vector3d.AxisY; Vector3d center = basePoint + new Vector3d(hi.XZOffset.x, 0, hi.XZOffset.y) - 10000 * direction; Ray3d ray = new Ray3d(center, direction); int hit_tid = spatial.FindNearestHitTriangle(ray); if (hit_tid == DMesh3.InvalidID) { return(false); } IntrRay3Triangle3 intersection = MeshQueries.TriangleIntersection(mesh, hit_tid, ray); Vector3d inter_pos = ray.PointAt(intersection.RayParameter); Frame3f projectFrame = new Frame3f(ray.Origin, ray.Direction); int nVerts = 32; if (hi.Vertices != 0) { nVerts = hi.Vertices; } double angleShiftRad = hi.AxisAngleD * MathUtil.Deg2Rad; Polygon2d circle = Polygon2d.MakeCircle(hi.Radius, nVerts, angleShiftRad); try { EdgeLoop loop = null; MeshInsertProjectedPolygon insert = new MeshInsertProjectedPolygon(mesh, circle, projectFrame, hit_tid) { SimplifyInsertion = false }; if (insert.Insert()) { loop = insert.InsertedLoop; // [RMS] do we need to simplify for this one? //if (loop.VertexCount > circle.VertexCount) // loop = simplify_loop(mesh, loop, circle.VertexCount); MeshEditor editor = new MeshEditor(mesh); Vector3d base_pos = inter_pos; base_pos.y = basePoint.y + hi.PartialHoleBaseHeight; int N = loop.VertexCount; int[] newLoop = new int[N]; for (int k = 0; k < N; ++k) { newLoop[k] = mesh.AppendVertex(mesh, loop.Vertices[k]); Vector3d cur_v = mesh.GetVertex(newLoop[k]); cur_v.y = base_pos.y; mesh.SetVertex(newLoop[k], cur_v); } int base_vid = mesh.AppendVertex(base_pos); int[] fan_tris = editor.AddTriangleFan_OrderedVertexLoop(base_vid, newLoop); FaceGroupUtil.SetGroupID(mesh, fan_tris, hi.PartialHoleGroupID); int[] stitch_tris = editor.StitchLoop(loop.Vertices, newLoop); // need to remesh fan region because otherwise we get pathological cases RegionRemesher remesh = new RegionRemesher(mesh, fan_tris); remesh.SetTargetEdgeLength(2.0); remesh.SmoothSpeedT = 1.0; remesh.PreventNormalFlips = true; for (int k = 0; k < 25; ++k) { remesh.BasicRemeshPass(); } //remesh.EnableCollapses = remesh.EnableFlips = remesh.EnableSplits = false; //for (int k = 0; k < 20; ++k) // remesh.BasicRemeshPass(); remesh.BackPropropagate(); return(true); } else { return(false); } } catch (Exception e) { f3.DebugUtil.Log("partial hole {0} failed!! {1}", hi.nHole, e.Message); return(false); } }
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); }
// [RMS] this only tests some basic cases... public static void test_RayBoxIntersect() { Random rand = new Random(316136327); // check that box hit works for (int ii = 0; ii < 1000; ++ii) { // generate random triangle Triangle3d t = new Triangle3d(rand.PointInRange(10), rand.PointInRange(10), rand.PointInRange(10)); AxisAlignedBox3d bounds = new AxisAlignedBox3d(t.V0); bounds.Contain(t.V1); bounds.Contain(t.V2); Vector3d c = (t.V0 + t.V1 + t.V2) / 3.0; for (int jj = 0; jj < 1000; ++jj) { Vector3d d = rand.Direction(); Ray3d ray = new Ray3d(c - 100 * d, d); IntrRay3AxisAlignedBox3 bhit = new IntrRay3AxisAlignedBox3(ray, bounds); Debug.Assert(bhit.Find()); IntrRay3Triangle3 thit = new IntrRay3Triangle3(ray, t); Debug.Assert(thit.Find()); Debug.Assert(bhit.RayParam0 < thit.RayParameter); } } int N = 100; for (int ii = 0; ii < N; ++ii) { // generate random boxes Vector3d c = rand.PointInRange(10); Vector3d e = rand.PositivePoint(); AxisAlignedBox3d aabox = new AxisAlignedBox3d(c - e, c + e); Box3d obox = new Box3d(c, Vector3d.AxisX, Vector3d.AxisY, Vector3d.AxisZ, e); double r = aabox.DiagonalLength; // center-out tests for (int jj = 0; jj < N; ++jj) { Ray3d ray = new Ray3d(c, rand.Direction()); assert_same_hit(aabox, obox, ray, true); } // outside-in tests for (int jj = 0; jj < N; ++jj) { Vector3d p = c + 2 * r * rand.Direction(); Ray3d ray = new Ray3d(p, (c - p).Normalized); assert_same_hit(aabox, obox, ray, true); } } // random rays int hits = 0; int InnerN = 1000; for (int ii = 0; ii < N; ++ii) { // generate random boxe Vector3d c = rand.PointInRange(10); Vector3d e = rand.PositivePoint(); // every tenth box, set an axis to degenerate if (ii % 10 == 0) { e[rand.Next() % 3] = 0; } AxisAlignedBox3d aabox = new AxisAlignedBox3d(c - e, c + e); Box3d obox = new Box3d(c, Vector3d.AxisX, Vector3d.AxisY, Vector3d.AxisZ, e); double r = aabox.DiagonalLength; TrivialBox3Generator boxgen = new TrivialBox3Generator() { Box = obox }; boxgen.Generate(); DMesh3 mesh = new DMesh3(); boxgen.MakeMesh(mesh); for (int i = 0; i < InnerN; ++i) { Vector3d target = c + rand.PointInRange(r); Vector3d o = c + rand.PointInRange(10 * r); Ray3d ray = new Ray3d(o, (target - o).Normalized); assert_same_hit(aabox, obox, ray, false); int hitT = MeshQueries.FindHitTriangle_LinearSearch(mesh, ray); bool bMeshHit = (hitT != DMesh3.InvalidID); if (bMeshHit) { ++hits; } IntrRay3AxisAlignedBox3 aabbhit = new IntrRay3AxisAlignedBox3(ray, aabox); Debug.Assert(aabbhit.Find() == bMeshHit); Debug.Assert(aabbhit.Test() == bMeshHit); } } System.Console.WriteLine("hit {0} of {1} rays", hits, N * InnerN); }