Пример #1
0
    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);
        }
    }
Пример #2
0
        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);
        }
Пример #3
0
        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();
        }
Пример #4
0
        // 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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        // [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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }
Пример #10
0
    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);
    }
Пример #11
0
        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);
        }
Пример #12
0
    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);
    }
Пример #13
0
        /// <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);
            }
        }
Пример #14
0
        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);
        }
Пример #15
0
        // [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);
        }