// do full tree traversal below iBox to make sure that all child points are contained
        void debug_check_child_points_in_box(int iBox)
        {
            AxisAlignedBox3d box = get_box(iBox);
            var t = new TreeTraversal()
            {
                NextPointF = (vID) =>
                {
                    Vector3d v = points.GetVertex(vID);
                    if (box.Contains(v) == false)
                    {
                        Util.gBreakToDebugger();
                    }
                }
            };

            tree_traversal(iBox, 0, t);
        }
Exemple #2
0
        double box_ray_intersect_t(int iBox, Ray3d ray)
        {
            Vector3d                c    = box_centers[iBox];
            Vector3d                e    = box_extents[iBox];
            AxisAlignedBox3d        box  = new AxisAlignedBox3d(c - e, c + e);
            IntrRay3AxisAlignedBox3 intr = new IntrRay3AxisAlignedBox3(ray, box);

            if (intr.Find())
            {
                return(intr.RayParam0);
            }
            else
            {
                Debug.Assert(intr.Result != IntersectionResult.InvalidQuery);
                return(double.MaxValue);
            }
        }
Exemple #3
0
        // accumulate point counts and track each box-parent index.
        // also checks that points are contained in boxes
        private void test_coverage(int[] point_counts, int[] parent_indices, int iBox)
        {
            int idx = box_to_index[iBox];

            debug_check_child_points_in_box(iBox);

            if (idx < points_end)
            {
                // point-list case, array is [N t1 t2 ... tN]
                int n = index_list[idx];
                AxisAlignedBox3d box = get_box(iBox);
                for (int i = 1; i <= n; ++i)
                {
                    int vi = index_list[idx + i];
                    point_counts[vi]++;
                    Vector3d v = points.GetVertex(vi);
                    if (!box.Contains(v))
                    {
                        Util.gBreakToDebugger();
                    }
                }
            }
            else
            {
                int i0 = index_list[idx];
                if (i0 < 0)
                {
                    // negative index means we only have one 'child' box to descend into
                    i0 = (-i0) - 1;
                    parent_indices[i0] = iBox;
                    test_coverage(point_counts, parent_indices, i0);
                }
                else
                {
                    // positive index, two sequential child box indices to descend into
                    i0 = i0 - 1;
                    parent_indices[i0] = iBox;
                    test_coverage(point_counts, parent_indices, i0);
                    int i1 = index_list[idx + 1];
                    i1 = i1 - 1;
                    parent_indices[i1] = iBox;
                    test_coverage(point_counts, parent_indices, i1);
                }
            }
        }
Exemple #4
0
        public AxisAlignedBox3d ToAABB()
        {
            // [TODO] probably more efficient way to do this...at minimum can move center-shift
            // to after the containments...
            Vector3d         extAxis0 = Extent.x * AxisX;
            Vector3d         extAxis1 = Extent.y * AxisY;
            Vector3d         extAxis2 = Extent.z * AxisZ;
            AxisAlignedBox3d result   = new AxisAlignedBox3d(Center - extAxis0 - extAxis1 - extAxis2);

            result.Contain(Center + extAxis0 - extAxis1 - extAxis2);
            result.Contain(Center + extAxis0 + extAxis1 - extAxis2);
            result.Contain(Center - extAxis0 + extAxis1 - extAxis2);
            result.Contain(Center - extAxis0 - extAxis1 + extAxis2);
            result.Contain(Center + extAxis0 - extAxis1 + extAxis2);
            result.Contain(Center + extAxis0 + extAxis1 + extAxis2);
            result.Contain(Center - extAxis0 + extAxis1 + extAxis2);
            return(result);
        }
        static public bool DoClipping(ref double t0, ref double t1,
                                      Vector3d origin, Vector3d direction,
                                      AxisAlignedBox3d box, bool solid, ref int quantity,
                                      ref Vector3d point0, ref Vector3d point1,
                                      ref IntersectionType intrType)
        {
            Vector3d BOrigin = origin - box.Center;
            Vector3d extent  = box.Extents;

            double saveT0 = t0, saveT1 = t1;
            bool   notAllClipped =
                Clip(+direction.x, -BOrigin.x - extent.x, ref t0, ref t1) &&
                Clip(-direction.x, +BOrigin.x - extent.x, ref t0, ref t1) &&
                Clip(+direction.y, -BOrigin.y - extent.y, ref t0, ref t1) &&
                Clip(-direction.y, +BOrigin.y - extent.y, ref t0, ref t1) &&
                Clip(+direction.z, -BOrigin.z - extent.z, ref t0, ref t1) &&
                Clip(-direction.z, +BOrigin.z - extent.z, ref t0, ref t1);

            if (notAllClipped && (solid || t0 != saveT0 || t1 != saveT1))
            {
                if (t1 > t0)
                {
                    intrType = IntersectionType.Segment;
                    quantity = 2;
                    point0   = origin + t0 * direction;
                    point1   = origin + t1 * direction;
                }
                else
                {
                    intrType = IntersectionType.Point;
                    quantity = 1;
                    point0   = origin + t0 * direction;
                }
            }
            else
            {
                quantity = 0;
                intrType = IntersectionType.Empty;
            }

            return(intrType != IntersectionType.Empty);
        }
        public static AxisAlignedBox3d BoundsV(IMesh mesh, IEnumerable <int> vertexIndices, Func <Vector3d, Vector3d> TransformF = null)
        {
            AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty;

            if (TransformF == null)
            {
                foreach (int vid in vertexIndices)
                {
                    bounds.Contain(mesh.GetVertex(vid));
                }
            }
            else
            {
                foreach (int vid in vertexIndices)
                {
                    bounds.Contain(TransformF(mesh.GetVertex(vid)));
                }
            }
            return(bounds);
        }
        public void Sample(BoundedImplicitFunction3d f, double expandRadius = 0)
        {
            AxisAlignedBox3d bounds = f.Bounds();

            Vector3d expand  = expandRadius * Vector3d.One;
            Vector3i gridMin = Indexer.ToGrid(bounds.Min - expand),
                     gridMax = Indexer.ToGrid(bounds.Max + expand) + Vector3i.One;

            gridMin = GridBounds.ClampExclusive(gridMin);
            gridMax = GridBounds.ClampExclusive(gridMax);

            AxisAlignedBox3i gridbox = new AxisAlignedBox3i(gridMin, gridMax);

            switch (CombineMode)
            {
            case CombineModes.DistanceMinUnion:
                sample_min(f, gridbox.IndicesInclusive());
                break;
            }
        }
        public static AxisAlignedBox3d Bounds(DMesh3 mesh, Func <Vector3d, Vector3d> TransformF)
        {
            AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty;

            if (TransformF == null)
            {
                foreach (Vector3d v in mesh.Vertices())
                {
                    bounds.Contain(v);
                }
            }
            else
            {
                foreach (Vector3d v in mesh.Vertices())
                {
                    Vector3d vT = TransformF(v);
                    bounds.Contain(ref vT);
                }
            }
            return(bounds);
        }
        public static AxisAlignedBox3d Bounds(IMesh mesh, Func <Vector3d, Vector3d> TransformF)
        {
            AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty;

            if (TransformF == null)
            {
                foreach (int vID in mesh.VertexIndices())
                {
                    bounds.Contain(mesh.GetVertex(vID));
                }
            }
            else
            {
                foreach (int vID in mesh.VertexIndices())
                {
                    Vector3d vT = TransformF(mesh.GetVertex(vID));
                    bounds.Contain(ref vT);
                }
            }
            return(bounds);
        }
Exemple #10
0
        /// <summary>
        /// Find intersection of ray with AABB, without having to construct any new classes.
        /// Returns ray T-value of first intersection (or double.MaxVlaue on miss)
        /// </summary>
        public static bool FindRayIntersectT(ref Ray3d ray, ref AxisAlignedBox3d box, out double RayParam)
        {
            double           RayParam0 = 0.0;
            double           RayParam1 = double.MaxValue;
            int              Quantity  = 0;
            Vector3d         Point0    = Vector3d.Zero;
            Vector3d         Point1    = Vector3d.Zero;
            IntersectionType Type      = IntersectionType.Empty;

            IntrLine3AxisAlignedBox3.DoClipping(ref RayParam0, ref RayParam1, ref ray.Origin, ref ray.Direction, ref box,
                                                true, ref Quantity, ref Point0, ref Point1, ref Type);

            if (Type != IntersectionType.Empty)
            {
                RayParam = RayParam0;
                return(true);
            }
            else
            {
                RayParam = double.MaxValue;
                return(false);
            }
        }
        /// <summary>
        /// calculate extents of mesh along axes of frame, with optional transform
        /// </summary>
        public static AxisAlignedBox3d BoundsInFrame(DMesh3 mesh, Frame3f frame, Func <Vector3d, Vector3d> TransformF = null)
        {
            AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty;

            if (TransformF == null)
            {
                foreach (Vector3d v in mesh.Vertices())
                {
                    Vector3d fv = frame.ToFrameP(v);
                    bounds.Contain(ref fv);
                }
            }
            else
            {
                foreach (Vector3d v in mesh.Vertices())
                {
                    Vector3d vT = TransformF(v);
                    Vector3d fv = frame.ToFrameP(ref vT);
                    bounds.Contain(ref fv);
                }
            }
            return(bounds);
        }
Exemple #12
0
        public void Compute()
        {
            // figure out origin & dimensions
            AxisAlignedBox3d bounds = Mesh.CachedBounds;

            float fBufferWidth = 2 * ExactBandWidth * CellSize;

            grid_origin = (Vector3f)bounds.Min - fBufferWidth * Vector3f.One - (Vector3f)ExpandBounds;
            Vector3f max = (Vector3f)bounds.Max + fBufferWidth * Vector3f.One + (Vector3f)ExpandBounds;
            int      ni  = (int)((max.x - grid_origin.x) / CellSize) + 1;
            int      nj  = (int)((max.y - grid_origin.y) / CellSize) + 1;
            int      nk  = (int)((max.z - grid_origin.z) / CellSize) + 1;

            grid = new DenseGrid3f();
            if (UseParallel)
            {
                make_level_set3_parallel(grid_origin, CellSize, ni, nj, nk, grid, ExactBandWidth);
            }
            else
            {
                make_level_set3(grid_origin, CellSize, ni, nj, nk, grid, ExactBandWidth);
            }
        }
Exemple #13
0
        protected bool check_for_cracks(DMesh3 mesh, out int boundary_edge_count, double crack_tol = MathUtil.ZeroTolerancef)
        {
            boundary_edge_count = 0;
            var boundary_verts = new MeshVertexSelection(mesh);

            foreach (int eid in mesh.BoundaryEdgeIndices())
            {
                Index2i ev = mesh.GetEdgeV(eid);
                boundary_verts.Select(ev.a); boundary_verts.Select(ev.b);
                boundary_edge_count++;
            }
            if (boundary_verts.Count == 0)
            {
                return(false);
            }

            AxisAlignedBox3d bounds = mesh.CachedBounds;
            var borderV             = new PointHashGrid3d <int>(bounds.MaxDim / 128, -1);

            foreach (int vid in boundary_verts)
            {
                Vector3d v      = mesh.GetVertex(vid);
                var      result = borderV.FindNearestInRadius(v, crack_tol, (existing_vid) =>
                {
                    return(v.Distance(mesh.GetVertex(existing_vid)));
                });
                if (result.Key != -1)
                {
                    return(true);                               // we found a crack vertex!
                }

                borderV.InsertPoint(vid, v);
            }

            // found no cracks
            return(false);
        }
Exemple #14
0
 public bool Intersects(AxisAlignedBox3d box)
 {
     return(!((box.Max.x <= Min.x) || (box.Min.x >= Max.x) ||
              (box.Max.y <= Min.y) || (box.Min.y >= Max.y) ||
              (box.Max.z <= Min.z) || (box.Min.z >= Max.z)));
 }
 public IntrLine3AxisAlignedBox3(Line3d l, AxisAlignedBox3d b)
 {
     line = l; box = b;
 }
Exemple #16
0
        protected virtual DMesh3 BuildMesh_TolerantWeld(STLSolid solid, double weld_tolerance)
        {
            var builder = new DMesh3Builder();

            builder.AppendNewMesh(false, false, false, false);

            DVectorArray3f vertices = solid.Vertices;
            int            N        = vertices.Count;

            int[] mapV = new int[N];


            AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty;

            for (int i = 0; i < N; ++i)
            {
                bounds.Contain(vertices[i]);
            }

            // [RMS] because we are only searching within tiny radius, there is really no downside to
            // using lots of bins here, except memory usage. If we don't, and the mesh has a ton of triangles
            // very close together (happens all the time on big meshes!), then this step can start
            // to take an *extremely* long time!
            int num_bins = 256;

            if (N > 100000)
            {
                num_bins = 512;
            }

            if (N > 1000000)
            {
                num_bins = 1024;
            }

            if (N > 2000000)
            {
                num_bins = 2048;
            }

            if (N > 5000000)
            {
                num_bins = 4096;
            }

            var uniqueV = new PointHashGrid3d <int>(bounds.MaxDim / (float)num_bins, -1);
            var pos     = new Vector3f[N];

            for (int vi = 0; vi < N; ++vi)
            {
                Vector3f v = vertices[vi];

                var pair = uniqueV.FindNearestInRadius(v, weld_tolerance, (vid) =>
                {
                    return(v.Distance(pos[vid]));
                });
                if (pair.Key == -1)
                {
                    int vid = builder.AppendVertex(v.x, v.y, v.z);
                    uniqueV.InsertPoint(vid, v);
                    mapV[vi] = vid;
                    pos[vid] = v;
                }
                else
                {
                    mapV[vi] = pair.Key;
                }
            }

            append_mapped_triangles(solid, builder, mapV);
            return(builder.Meshes[0]);
        }
        // (sequentially) find each triangle that path point lies in, and insert a vertex for
        // that point into mesh.
        void insert_corners(HashSet <int> MeshVertsOnCurve)
        {
            PrimalQuery2d query = new PrimalQuery2d(PointF);

            if (UseTriSpatial)
            {
                int count = Mesh.TriangleCount + Curve.VertexCount;
                int bins  = 32;
                if (count < 25)
                {
                    bins = 8;
                }
                else if (count < 100)
                {
                    bins = 16;
                }
                AxisAlignedBox3d bounds3 = Mesh.CachedBounds;
                AxisAlignedBox2d bounds2 = new AxisAlignedBox2d(bounds3.Min.xy, bounds3.Max.xy);
                triSpatial = new TriangleBinsGrid2d(bounds2, bins);
                foreach (int tid in Mesh.TriangleIndices())
                {
                    spatial_add_triangle(tid);
                }
            }

            Func <int, Vector2d, bool> inTriangleF = (tid, pos) => {
                Index3i tv           = Mesh.GetTriangle(tid);
                int     query_result = query.ToTriangleUnsigned(pos, tv.a, tv.b, tv.c);
                return(query_result == -1 || query_result == 0);
            };

            CurveVertices = new int[Curve.VertexCount];
            for (int i = 0; i < Curve.VertexCount; ++i)
            {
                Vector2d vInsert  = Curve[i];
                bool     inserted = false;

                int contain_tid = DMesh3.InvalidID;
                if (triSpatial != null)
                {
                    contain_tid = triSpatial.FindContainingTriangle(vInsert, inTriangleF);
                }
                else
                {
                    foreach (int tid in Mesh.TriangleIndices())
                    {
                        Index3i tv = Mesh.GetTriangle(tid);
                        // [RMS] using unsigned query here because we do not need to care about tri CW/CCW orientation
                        //   (right? otherwise we have to explicitly invert mesh. Nothing else we do depends on tri orientation)
                        //int query_result = query.ToTriangle(vInsert, tv.a, tv.b, tv.c);
                        int query_result = query.ToTriangleUnsigned(vInsert, tv.a, tv.b, tv.c);
                        if (query_result == -1 || query_result == 0)
                        {
                            contain_tid = tid;
                            break;
                        }
                    }
                }

                if (contain_tid != DMesh3.InvalidID)
                {
                    Index3i  tv   = Mesh.GetTriangle(contain_tid);
                    Vector3d bary = MathUtil.BarycentricCoords(vInsert, PointF(tv.a), PointF(tv.b), PointF(tv.c));
                    // SpatialEpsilon is our zero-tolerance, so merge if we are closer than that
                    bool is_existing_v;
                    int  vid = insert_corner_from_bary(i, contain_tid, bary, 0.01, 100 * SpatialEpsilon, out is_existing_v);
                    if (vid > 0)      // this should be always happening..
                    {
                        CurveVertices[i] = vid;
                        if (is_existing_v)
                        {
                            MeshVertsOnCurve.Add(vid);
                        }
                        inserted = true;
                    }
                    else
                    {
                        throw new Exception("MeshInsertUVPolyCurve.insert_corners: failed to insert vertex " + i.ToString());
                    }
                }

                if (inserted == false)
                {
                    throw new Exception("MeshInsertUVPolyCurve.insert_corners: curve vertex "
                                        + i.ToString() + " is not inside or on any mesh triangle!");
                }
            }
        }
Exemple #18
0
 public void Contain(AxisAlignedBox3d box)
 {
     Contain(box.Min);
     Contain(box.Max);
 }
 public IntrRay3AxisAlignedBox3(Ray3d r, AxisAlignedBox3d b)
 {
     ray = r; box = b;
 }
        /// <summary>
        /// test if ray intersects box.
        /// expandExtents allows you to scale box for hit-testing purposes.
        /// </summary>
        public static bool Intersects(ref Ray3d ray, ref AxisAlignedBox3d box, double expandExtents = 0)
        {
            Vector3d WdU    = Vector3d.Zero;
            Vector3d AWdU   = Vector3d.Zero;
            Vector3d DdU    = Vector3d.Zero;
            Vector3d ADdU   = Vector3d.Zero;
            Vector3d AWxDdU = Vector3d.Zero;
            double   RHS;

            Vector3d diff   = ray.Origin - box.Center;
            Vector3d extent = box.Extents + expandExtents;

            WdU[0]  = ray.Direction.x; // ray.Direction.Dot(Vector3d.AxisX);
            AWdU[0] = Math.Abs(WdU[0]);
            DdU[0]  = diff.x;          // diff.Dot(Vector3d.AxisX);
            ADdU[0] = Math.Abs(DdU[0]);
            if (ADdU[0] > extent.x && DdU[0] * WdU[0] >= (double)0)
            {
                return(false);
            }

            WdU[1]  = ray.Direction.y; // ray.Direction.Dot(Vector3d.AxisY);
            AWdU[1] = Math.Abs(WdU[1]);
            DdU[1]  = diff.y;          // diff.Dot(Vector3d.AxisY);
            ADdU[1] = Math.Abs(DdU[1]);
            if (ADdU[1] > extent.y && DdU[1] * WdU[1] >= (double)0)
            {
                return(false);
            }

            WdU[2]  = ray.Direction.z; // ray.Direction.Dot(Vector3d.AxisZ);
            AWdU[2] = Math.Abs(WdU[2]);
            DdU[2]  = diff.z;          // diff.Dot(Vector3d.AxisZ);
            ADdU[2] = Math.Abs(DdU[2]);
            if (ADdU[2] > extent.z && DdU[2] * WdU[2] >= (double)0)
            {
                return(false);
            }

            Vector3d WxD = ray.Direction.Cross(diff);

            AWxDdU[0] = Math.Abs(WxD.x); // Math.Abs(WxD.Dot(Vector3d.AxisX));
            RHS       = extent.y * AWdU[2] + extent.z * AWdU[1];
            if (AWxDdU[0] > RHS)
            {
                return(false);
            }

            AWxDdU[1] = Math.Abs(WxD.y); // Math.Abs(WxD.Dot(Vector3d.AxisY));
            RHS       = extent.x * AWdU[2] + extent.z * AWdU[0];
            if (AWxDdU[1] > RHS)
            {
                return(false);
            }

            AWxDdU[2] = Math.Abs(WxD.z); // Math.Abs(WxD.Dot(Vector3d.AxisZ));
            RHS       = extent.x * AWdU[1] + extent.y * AWdU[0];
            if (AWxDdU[2] > RHS)
            {
                return(false);
            }

            return(true);
        }
Exemple #21
0
        int split_point_set_midpoint(int[] pt_indices, Vector3d[] positions,
                                     int iStart, int iCount, int depth, int minIndexCount,
                                     boxes_set leafs, boxes_set nodes, out AxisAlignedBox3d box)
        {
            box = AxisAlignedBox3d.Empty;
            int iBox = -1;

            if (iCount < minIndexCount)
            {
                // append new points box
                iBox = leafs.iBoxCur++;
                leafs.box_to_index.insert(leafs.iIndicesCur, iBox);

                leafs.index_list.insert(iCount, leafs.iIndicesCur++);
                for (int i = 0; i < iCount; ++i)
                {
                    leafs.index_list.insert(pt_indices[iStart + i], leafs.iIndicesCur++);
                    box.Contain(points.GetVertex(pt_indices[iStart + i]));
                }

                leafs.box_centers.insert(box.Center, iBox);
                leafs.box_extents.insert(box.Extents, iBox);

                return(-(iBox + 1));
            }

            //compute interval along an axis and find midpoint
            int        axis     = depth % 3;
            Interval1d interval = Interval1d.Empty;

            for (int i = 0; i < iCount; ++i)
            {
                interval.Contain(positions[iStart + i][axis]);
            }
            double midpoint = interval.Center;

            int n0, n1;

            if (Math.Abs(interval.a - interval.b) > MathUtil.ZeroTolerance)
            {
                // we have to re-sort the centers & indices lists so that centers < midpoint
                // are first, so that we can recurse on the two subsets. We walk in from each side,
                // until we find two out-of-order locations, then we swap them.
                int l = 0;
                int r = iCount - 1;
                while (l < r)
                {
                    // [RMS] is <= right here? if v.axis == midpoint, then this loop
                    //   can get stuck unless one of these has an equality test. But
                    //   I did not think enough about if this is the right thing to do...
                    while (positions[iStart + l][axis] <= midpoint)
                    {
                        l++;
                    }
                    while (positions[iStart + r][axis] > midpoint)
                    {
                        r--;
                    }
                    if (l >= r)
                    {
                        break;      //done!
                    }
                    //swap
                    Vector3d tmpc = positions[iStart + l]; positions[iStart + l] = positions[iStart + r];  positions[iStart + r] = tmpc;
                    int      tmpt = pt_indices[iStart + l]; pt_indices[iStart + l] = pt_indices[iStart + r]; pt_indices[iStart + r] = tmpt;
                }

                n0 = l;
                n1 = iCount - n0;
                Debug.Assert(n0 >= 1 && n1 >= 1);
            }
            else
            {
                // interval is near-empty, so no point trying to do sorting, just split half and half
                n0 = iCount / 2;
                n1 = iCount - n0;
            }

            // create child boxes
            AxisAlignedBox3d box1;
            int child0 = split_point_set_midpoint(pt_indices, positions, iStart, n0, depth + 1, minIndexCount, leafs, nodes, out box);
            int child1 = split_point_set_midpoint(pt_indices, positions, iStart + n0, n1, depth + 1, minIndexCount, leafs, nodes, out box1);

            box.Contain(box1);

            // append new box
            iBox = nodes.iBoxCur++;
            nodes.box_to_index.insert(nodes.iIndicesCur, iBox);

            nodes.index_list.insert(child0, nodes.iIndicesCur++);
            nodes.index_list.insert(child1, nodes.iIndicesCur++);

            nodes.box_centers.insert(box.Center, iBox);
            nodes.box_extents.insert(box.Extents, iBox);

            return(iBox);
        }
Exemple #22
0
        public virtual void Generate()
        {
            AxisAlignedBox3d graphBox = Graph.CachedBounds;

            graphBox.Expand(2 * PostRadius);

            double cellSize = (SamplerCellSizeHint == 0) ? (PostRadius / 5) : SamplerCellSizeHint;
            ImplicitFieldSampler3d sampler = new ImplicitFieldSampler3d(graphBox, cellSize);

            ActualCellSize = cellSize;

            // sample segments into graph
            ImplicitLine3d line = new ImplicitLine3d()
            {
                Radius = PostRadius
            };

            foreach (int eid in Graph.EdgeIndices())
            {
                Index2i  ev = Graph.GetEdgeV(eid);
                Vector3d v0 = Graph.GetVertex(ev.a);
                Vector3d v1 = Graph.GetVertex(ev.b);
                double   r  = PostRadius;

                int upper_vid = (v0.y > v1.y) ? ev.a : ev.b;
                if (TipVertices.Contains(upper_vid))
                {
                    r = TipRadius;
                }

                line.Segment = new Segment3d(v0, v1);
                line.Radius  = r;
                sampler.Sample(line, line.Radius / 2);
            }

            foreach (int vid in GroundVertices)
            {
                Vector3d v = Graph.GetVertex(vid);
                sampler.Sample(new ImplicitSphere3d()
                {
                    Origin = v - (PostRadius / 2) * Vector3d.AxisY, Radius = GroundRadius
                });
            }


            ImplicitHalfSpace3d cutPlane = new ImplicitHalfSpace3d()
            {
                Origin = Vector3d.Zero, Normal = Vector3d.AxisY
            };
            ImplicitDifference3d cut = new ImplicitDifference3d()
            {
                A = sampler.ToImplicit(), B = cutPlane
            };

            MarchingCubes mc = new MarchingCubes()
            {
                Implicit = cut, Bounds = graphBox, CubeSize = PostRadius / 3
            };

            mc.Bounds.Min.y  = -2 * mc.CubeSize;
            mc.Bounds.Min.x -= 2 * mc.CubeSize; mc.Bounds.Min.z -= 2 * mc.CubeSize;
            mc.Bounds.Max.x += 2 * mc.CubeSize; mc.Bounds.Max.z += 2 * mc.CubeSize;
            mc.CancelF       = this.Cancelled;
            mc.Generate();

            ResultMesh = mc.Mesh;
        }
Exemple #23
0
        // (sequentially) find each triangle that path point lies in, and insert a vertex for
        // that point into mesh.
        void insert_corners(HashSet <int> MeshVertsOnCurve)
        {
            PrimalQuery2d query = new PrimalQuery2d(PointF);

            if (UseTriSpatial)
            {
                int count = Mesh.TriangleCount + Curve.VertexCount;
                int bins  = 32;
                if (count < 25)
                {
                    bins = 8;
                }
                else if (count < 100)
                {
                    bins = 16;
                }
                AxisAlignedBox3d bounds3 = Mesh.CachedBounds;
                AxisAlignedBox2d bounds2 = new AxisAlignedBox2d(bounds3.Min.xy, bounds3.Max.xy);
                triSpatial = new TriangleBinsGrid2d(bounds2, bins);
                foreach (int tid in Mesh.TriangleIndices())
                {
                    spatial_add_triangle(tid);
                }
            }

            Func <int, Vector2d, bool> inTriangleF = (tid, pos) => {
                Index3i tv           = Mesh.GetTriangle(tid);
                int     query_result = query.ToTriangleUnsigned(pos, tv.a, tv.b, tv.c);
                return(query_result == -1 || query_result == 0);
            };

            CurveVertices = new int[Curve.VertexCount];
            for (int i = 0; i < Curve.VertexCount; ++i)
            {
                Vector2d vInsert  = Curve[i];
                bool     inserted = false;

                // find the triangle that contains this curve point
                int contain_tid = DMesh3.InvalidID;
                if (triSpatial != null)
                {
                    contain_tid = triSpatial.FindContainingTriangle(vInsert, inTriangleF);
                }
                else
                {
                    foreach (int tid in Mesh.TriangleIndices())
                    {
                        Index3i tv = Mesh.GetTriangle(tid);
                        // [RMS] using unsigned query here because we do not need to care about tri CW/CCW orientation
                        //   (right? otherwise we have to explicitly invert mesh. Nothing else we do depends on tri orientation)
                        //int query_result = query.ToTriangle(vInsert, tv.a, tv.b, tv.c);
                        int query_result = query.ToTriangleUnsigned(vInsert, tv.a, tv.b, tv.c);
                        if (query_result == -1 || query_result == 0)
                        {
                            contain_tid = tid;
                            break;
                        }
                    }
                }

                // if we found one, insert the point via face-poke or edge-split,
                // unless it is exactly at existing vertex, in which case we can re-use it
                if (contain_tid != DMesh3.InvalidID)
                {
                    Index3i  tv   = Mesh.GetTriangle(contain_tid);
                    Vector3d bary = MathUtil.BarycentricCoords(vInsert, PointF(tv.a), PointF(tv.b), PointF(tv.c));
                    // SpatialEpsilon is our zero-tolerance, so merge if we are closer than that
                    bool is_existing_v;
                    int  vid = insert_corner_from_bary(i, contain_tid, bary, 0.01, 100 * SpatialEpsilon, out is_existing_v);
                    if (vid > 0)
                    {
                        CurveVertices[i] = vid;
                        if (is_existing_v)
                        {
                            MeshVertsOnCurve.Add(vid);
                        }
                        inserted = true;
                    }
                }

                // if we did not find containing triangle,
                // try matching with any existing vertices.
                // This can happen if curve point is right on mesh border...
                if (inserted == false)
                {
                    foreach (int vid in Mesh.VertexIndices())
                    {
                        Vector2d v = PointF(vid);
                        if (vInsert.Distance(v) < SpatialEpsilon)
                        {
                            CurveVertices[i] = vid;
                            MeshVertsOnCurve.Add(vid);
                            inserted = true;
                        }
                    }
                }

                // TODO: also case where curve point is right on mesh border edge,
                // and so it ends up being outside all triangles?


                if (inserted == false)
                {
                    throw new Exception("MeshInsertUVPolyCurve.insert_corners: curve vertex "
                                        + i.ToString() + " is not inside or on any mesh triangle!");
                }
            }
        }