public void Initialize_AutoFitBox()
        {
            DMeshSO TargetMeshSO = TargetSO as DMeshSO;

            // initialize w/ auto-fit box
            DMesh3         mesh    = TargetMeshSO.Mesh;
            DMeshAABBTree3 spatial = TargetMeshSO.Spatial;

            meshBounds = mesh.CachedBounds;

            create_preview_so();

            ContOrientedBox3 boxFitter = new ContOrientedBox3(
                new RemapItr <Vector3d, int>(mesh.TriangleIndices(), (tid) => { return(mesh.GetTriCentroid(tid)); }),
                new RemapItr <double, int>(mesh.TriangleIndices(), (tid) => { return(mesh.GetTriArea(tid)); }));
            //DebugUtil.EmitDebugBox("fitbox", boxFitter.Box, Colorf.Red, TargetSO.RootGameObject, false);
            Box3d fitBox  = boxFitter.Box;
            int   longest = 0;

            if (fitBox.Extent.y > fitBox.Extent.x)
            {
                longest = 1;
            }
            if (fitBox.Extent.z > fitBox.Extent[longest])
            {
                longest = 2;
            }
            Vector3d vTop    = fitBox.Center + fitBox.Extent[longest] * fitBox.Axis(longest);
            Vector3d vBottom = fitBox.Center - fitBox.Extent[longest] * fitBox.Axis(longest);

            int base_tid = spatial.FindNearestTriangle(vBottom);
            int top_tid  = spatial.FindNearestTriangle(vTop);

            if (vTop.y < vBottom.y)
            {
                int tmp = base_tid; base_tid = top_tid; top_tid = tmp;
            }
            Vector3d vBasePt = mesh.GetTriCentroid(base_tid);
            Vector3d vTopPt  = mesh.GetTriCentroid(top_tid);


            int      other1 = (longest + 1) % 3, other2 = (longest + 2) % 3;
            int      front_tid = spatial.FindNearestHitTriangle(new Ray3d(fitBox.Center, fitBox.Axis(other1)));
            Vector3d vFrontPt  = mesh.GetTriCentroid(front_tid);

            int      back_tid = spatial.FindNearestHitTriangle(new Ray3d(fitBox.Center, -fitBox.Axis(other1)));
            Vector3d vBackPt  = mesh.GetTriCentroid(back_tid);

            int      right_tid = spatial.FindNearestHitTriangle(new Ray3d(fitBox.Center, fitBox.Axis(other2)));
            Vector3d vRightPt  = mesh.GetTriCentroid(right_tid);

            int      left_tid = spatial.FindNearestHitTriangle(new Ray3d(fitBox.Center, -fitBox.Axis(other2)));
            Vector3d vLeftPt  = mesh.GetTriCentroid(left_tid);

            initialFrontPt = (Vector3f)vFrontPt;

            SetPointPosition_Internal(BasePointID, MeshQueries.SurfaceFrame(mesh, base_tid, vBasePt), CoordSpace.ObjectCoords);
            SetPointPosition_Internal(FrontPointID, MeshQueries.SurfaceFrame(mesh, front_tid, vFrontPt), CoordSpace.ObjectCoords);
            SetPointPosition(TopPointID, MeshQueries.SurfaceFrame(mesh, top_tid, vTopPt), CoordSpace.ObjectCoords);
        }
Beispiel #2
0
        public static void TestIsoCurve()
        {
            var              meshSO  = OG.Scan.SO;
            DMesh3           mesh    = new DMesh3(meshSO.Mesh);
            DMeshAABBTree3   spatial = new DMeshAABBTree3(mesh, true);
            AxisAlignedBox3d bounds  = mesh.CachedBounds;

            Frame3f plane = new Frame3f(bounds.Center);

            Func <Vector3d, double> planeSignedDistanceF = (v) => {
                return((v - plane.Origin).Dot(plane.Y));
            };

            Func <Vector3d, double> sphereDistF = (v) => {
                double d = v.Distance(plane.Origin);
                return(d - 50.0);
            };

            MeshIsoCurves iso = new MeshIsoCurves(mesh, sphereDistF);

            iso.Compute();

            DGraph3Util.Curves curves = DGraph3Util.ExtractCurves(iso.Graph);

            foreach (DCurve3 c in curves.Loops)
            {
                List <Vector3d> verts = new List <Vector3d>(c.Vertices);
                for (int i = 0; i < verts.Count; ++i)
                {
                    verts[i] = verts[i] + 0.5 * mesh.GetTriNormal(spatial.FindNearestTriangle(verts[i]));
                }
                DebugUtil.EmitDebugCurve("curve", verts.ToArray(), true, 1, Colorf.Red, Colorf.Red, meshSO.RootGameObject, false);
            }

            foreach (DCurve3 c in curves.Paths)
            {
                List <Vector3d> verts = new List <Vector3d>(c.Vertices);
                for (int i = 0; i < verts.Count; ++i)
                {
                    verts[i] = verts[i] + 0.5 * mesh.GetTriNormal(spatial.FindNearestTriangle(verts[i]));
                }
                DebugUtil.EmitDebugCurve("curve", verts.ToArray(), false, 1, Colorf.Blue, Colorf.Blue, meshSO.RootGameObject, false);
            }

            //foreach ( Segment3d seg in iso.Graph.Segments()) {
            //    Vector3d a = seg.P0 + 1.0 * mesh.GetTriNormal(spatial.FindNearestTriangle(seg.P0));
            //    Vector3d b = seg.P1 + 1.0 * mesh.GetTriNormal(spatial.FindNearestTriangle(seg.P1));

            //    DebugUtil.EmitDebugLine("seg", a, b, 1.0f, Colorf.Red, meshSO.RootGameObject, false);
            //}
        }
Beispiel #3
0
        public override void AppendVertex(Vector3d v)
        {
            base.AppendVertex(v);

            // map v to mesh
            v = SceneTransforms.SceneToObjectP(Target, v);

            // TODO encode vertices by normals ??
            DMesh3           Mesh    = Target.Mesh;
            DMeshAABBTree3   Spatial = Target.Spatial;
            SurfaceVertexRef r       = new SurfaceVertexRef();

            r.tid = Spatial.FindNearestTriangle(v);
            Frame3f f  = Mesh.GetTriFrame(r.tid);
            Index3i tv = Mesh.GetTriangle(r.tid);

            for (int j = 0; j < 3; ++j)
            {
                f.Origin = (Vector3f)Mesh.GetVertex(tv[j]);
                Vector3d dv = f.ToFrameP(v);
                r.offsets[j] = dv;
            }
            SurfacePoints.Add(r);
            if (Curve.VertexCount != SurfacePoints.Count)
            {
                throw new Exception("SurfaceCurvePreview: counts are out of sync!!");
            }
        }
Beispiel #4
0
        public static void test_AABBTree_TriDist(int meshCase = 0)
        {
            DMesh3         mesh = MakeSpatialTestMesh(meshCase);
            DMeshAABBTree3 tree = new DMeshAABBTree3(mesh);

            tree.Build();

            AxisAlignedBox3d bounds = mesh.CachedBounds;
            Vector3d         ext    = bounds.Extents;
            Vector3d         c      = bounds.Center;

            Random rand = new Random(316136327);

            int N = 10000;

            for (int ii = 0; ii < N; ++ii)
            {
                Vector3d p = new Vector3d(
                    c.x + (4 * ext.x * (2 * rand.NextDouble() - 1)),
                    c.y + (4 * ext.y * (2 * rand.NextDouble() - 1)),
                    c.z + (4 * ext.z * (2 * rand.NextDouble() - 1)));

                int tNearBrute = MeshQueries.FindNearestTriangle_LinearSearch(mesh, p);
                int tNearTree  = tree.FindNearestTriangle(p);

                DistPoint3Triangle3 qBrute = MeshQueries.TriangleDistance(mesh, tNearBrute, p);
                DistPoint3Triangle3 qTree  = MeshQueries.TriangleDistance(mesh, tNearTree, p);

                if (Math.Abs(qBrute.DistanceSquared - qTree.DistanceSquared) > MathUtil.ZeroTolerance)
                {
                    Util.gBreakToDebugger();
                }
            }
        }
Beispiel #5
0
        DMesh3 compute_partial_hole(Vector3d start, Vector3d end, double tol)
        {
            DMesh3         origMesh    = MeshSource.GetDMeshUnsafe();
            DMeshAABBTree3 origSpatial = MeshSource.GetSpatial() as DMeshAABBTree3;

            DMesh3 cutMesh = new DMesh3(origMesh);

            Polygon2d polygon = Polygon2d.MakeCircle(hole_size / 2, hole_subdivisions);

            Vector3f axis = (Vector3f)(start - end).Normalized;

            int     start_tid   = origSpatial.FindNearestTriangle(start);
            Frame3f start_frame = origMesh.GetTriFrame(start_tid);

            start_frame.Origin = (Vector3f)start;
            start_frame.AlignAxis(2, axis);

            int end_tid = origSpatial.FindNearestTriangle(end);
            //Frame3f end_frame = origMesh.GetTriFrame(end_tid); end_frame.Origin = (Vector3f)end;
            Frame3f end_frame = start_frame; end_frame.Origin = (Vector3f)end;

            // [TODO] we don't need to Simplify here...is more robust?

            MeshInsertProjectedPolygon start_insert = new MeshInsertProjectedPolygon(cutMesh, polygon, start_frame, start_tid);
            bool start_ok = start_insert.Insert();

            if (start_ok == false)
            {
                throw new Exception("CutPolygonHoleOp.compute_partial_hole: start or end insertion failed!");
            }

            EdgeLoop outLoop = start_insert.InsertedLoop;

            MeshExtrudeLoop extrude = new MeshExtrudeLoop(cutMesh, outLoop);

            extrude.PositionF = (v, n, vid) => {
                cutMesh.GetVertex(vid);
                return(end_frame.ProjectToPlane((Vector3f)v, 2));
            };
            extrude.Extrude();

            SimpleHoleFiller filler = new SimpleHoleFiller(cutMesh, extrude.NewLoop);

            filler.Fill();

            return(cutMesh);
        }
Beispiel #6
0
    private void OnDrawGizmos()
    {
        if (binarySpacePartition == null)
        {
            Start();
        }

        // Draw a line between the probe and the closest triangle vertex via the BSP...
        Vector3 queryPoint = probe.position;

        if (drawNaiveClosestPoint)
        {
            Profiler.BeginSample("Naive Closest Point on Mesh");
            float naiveMinDist = 1000f; Vector3 naiveMinPos = Vector3.one;
            for (int i = 0; i < meshTriangles.Length; i += 3)
            {
                Vector3 trianglePoint = Constraints.ConstrainToTriangle(queryPoint,
                                                                        meshVertices[meshTriangles[i + 0]],
                                                                        meshVertices[meshTriangles[i + 1]],
                                                                        meshVertices[meshTriangles[i + 2]]);
                float dist1 = Vector3.Distance(queryPoint, trianglePoint);
                if (dist1 < naiveMinDist)
                {
                    naiveMinDist = dist1; naiveMinPos = trianglePoint;
                }
            }
            Gizmos.color = Color.red;
            Gizmos.DrawLine(queryPoint, naiveMinPos);
            Gizmos.DrawSphere(naiveMinPos, 0.005f);

            Profiler.EndSample();
        }

        Profiler.BeginSample("BSP Closest Point on Mesh", this);
        Gizmos.color = Color.white;
        Vector3 bspMinPos = Vector3.zero; float bspMinSqDist = 100000f;

        binarySpacePartition.QueryClosestPointRecursive(queryPoint, ref bspMinPos, ref bspMinSqDist);
        Gizmos.DrawLine(queryPoint, bspMinPos);
        Gizmos.DrawSphere(bspMinPos, 0.005f);
        Profiler.EndSample();

#if G3_USING_UNITY
        if (g3MeshTree != null && g3MeshTree.IsValid)
        {
            Profiler.BeginSample("D3 Closest Point on Mesh", this);
            Gizmos.color = Color.magenta;
            int     nearestTri     = g3MeshTree.FindNearestTriangle(new g3.Vector3d(queryPoint.x, queryPoint.y, queryPoint.z));
            Vector3 trianglePointt = Constraints.ConstrainToTriangle(queryPoint,
                                                                     meshVertices[meshTriangles[(nearestTri * 3)]],
                                                                     meshVertices[meshTriangles[(nearestTri * 3) + 1]],
                                                                     meshVertices[meshTriangles[(nearestTri * 3) + 2]]);
            Gizmos.DrawLine(queryPoint, trianglePointt);
            Gizmos.DrawSphere(trianglePointt, 0.005f);
            Profiler.EndSample();
        }
#endif
    }
Beispiel #7
0
        DMesh3 compute_through_hole(Vector3d start, Vector3d end, double tol)
        {
            DMesh3         origMesh    = MeshSource.GetDMeshUnsafe();
            DMeshAABBTree3 origSpatial = MeshSource.GetSpatial() as DMeshAABBTree3;

            DMesh3 cutMesh = new DMesh3(origMesh);

            Polygon2d polygon = Polygon2d.MakeCircle(hole_size / 2, hole_subdivisions);

            Vector3f axis = (Vector3f)(start - end).Normalized;

            int     start_tid   = origSpatial.FindNearestTriangle(start);
            Frame3f start_frame = origMesh.GetTriFrame(start_tid);

            start_frame.Origin = (Vector3f)start;
            start_frame.AlignAxis(2, axis);

            int end_tid = origSpatial.FindNearestTriangle(end);
            //Frame3f end_frame = origMesh.GetTriFrame(end_tid); end_frame.Origin = (Vector3f)end;
            Frame3f end_frame = start_frame; end_frame.Origin = (Vector3f)end;

            MeshInsertProjectedPolygon start_insert = new MeshInsertProjectedPolygon(cutMesh, polygon, start_frame, start_tid);
            bool start_ok = start_insert.Insert();

            MeshInsertProjectedPolygon end_insert = new MeshInsertProjectedPolygon(cutMesh, polygon, end_frame, end_tid);
            bool end_ok = end_insert.Insert();

            if (start_ok == false || end_ok == false)
            {
                throw new Exception("CutPolygonHoleOp.compute_through_hole: start or end insertion failed!");
            }

            MeshEditor editor = new MeshEditor(cutMesh);
            EdgeLoop   l0     = start_insert.InsertedLoop;
            EdgeLoop   l1     = end_insert.InsertedLoop;

            l1.Reverse();
            editor.StitchLoop(l0.Vertices, l1.Vertices);

            return(cutMesh);
        }
Beispiel #8
0
    //If the position is too close to shell, returns the direction to move away from it to try again. Returns null if not too close
    internal Vector3d?GetAwayFromShellDirection(CuttingInfo info, DMeshAABBTree3 tree, Vector3d position)
    {
        tree.TriangleFilterF = i => tree.Mesh.GetTriangleGroup(i) != info.data.ColorNum;

        int near_tid = tree.FindNearestTriangle(position, info.data.minDepth); //TODO scale the max dist by SDF or so

        if (near_tid != DMesh3.InvalidID)
        {
            return(-tree.Mesh.GetTriNormal(near_tid));
        }

        return(null);
    }
Beispiel #9
0
        public static Vector3d NearestPoint(this DMeshAABBTree3 tree, Vector3d point)
        {
            var tid = tree.FindNearestTriangle(point);

            if (tid == DMesh3.InvalidID)
            {
                return(new Vector3d());
            }

            var dist = MeshQueries.TriangleDistance(tree.Mesh, tid, point);

            return(dist.TriangleClosest);
        }
Beispiel #10
0
    internal bool CheckPositionValid(DMesh3 mesh, Vector3d position, int colorToExclude)
    {
        var spatial = new DMeshAABBTree3(mesh);

        spatial.Build();

        spatial.TriangleFilterF = i => mesh.GetTriangleGroup(i) != colorToExclude;

        int near_tid = spatial.FindNearestTriangle(position, 9f);

        if (near_tid != DMesh3.InvalidID)
        {
            return(false);
        }

        return(true);
    }
Beispiel #11
0
        // for each From[i], find closest point on TargetSurface
        void update_to()
        {
            double max_dist = double.MaxValue;

            bool bNormals = (UseNormals && Source.HasVertexNormals);

            Interval1i range = Interval1i.Range(From.Length);

            gParallel.ForEach(range, (vi) => {
                int tid = TargetSurface.FindNearestTriangle(From[vi], max_dist);
                if (tid == NGonsCore.geometry3Sharp.mesh.DMesh3.InvalidID)
                {
                    Weights[vi] = 0;
                    return;
                }

                DistPoint3Triangle3 d = MeshQueries.TriangleDistance(TargetSurface.Mesh, tid, From[vi]);
                if (d.DistanceSquared > MaxAllowableDistance * MaxAllowableDistance)
                {
                    Weights[vi] = 0;
                    return;
                }

                To[vi]      = d.TriangleClosest;
                Weights[vi] = 1.0f;

                if (bNormals)
                {
                    Vector3F fromN = Rotation * Source.GetVertexNormal(vi);
                    Vector3F toN   = (Vector3F)TargetSurface.Mesh.GetTriNormal(tid);
                    float fDot     = fromN.Dot(toN);
                    Debug.Assert(math.MathUtil.IsFinite(fDot));
                    if (fDot < 0)
                    {
                        Weights[vi] = 0;
                    }
                    else
                    {
                        Weights[vi] += Math.Sqrt(fDot);
                    }
                }
            });
        }
Beispiel #12
0
    internal Vector3d?GetInsideShell(DMeshAABBTree3 tree, Vector3d position, int colorToExclude)
    {
        tree.TriangleFilterF = i => tree.Mesh.GetTriangleGroup(i) != colorToExclude;

        int near_tid = tree.FindNearestTriangle(position, 30f);

        if (near_tid != DMesh3.InvalidID)
        {
            //var nearTri = mesh.GetTriangle(near_tid);
            return(tree.Mesh.GetTriCentroid(near_tid) - position);
        }
        else
        {
            Debug.Log("Get Inside: Too far away");
            StaticFunctions.ErrorMessage("Extrusion/Depth setting of a color is too much, might extrude outside of shell");
        }

        return(null);
    }
Beispiel #13
0
        public virtual bool FindNearest(Vector3d point, double maxDist, out SORayHit nearest, CoordSpace eInCoords)
        {
            nearest = null;
            if (enable_spatial == false)
            {
                return(false);
            }

            if (spatial == null)
            {
                spatial = new DMeshAABBTree3(mesh);
                spatial.Build();
            }

            // convert to local
            Vector3f local_pt = SceneTransforms.TransformTo((Vector3f)point, this, eInCoords, CoordSpace.ObjectCoords);

            if (mesh.CachedBounds.Distance(local_pt) > maxDist)
            {
                return(false);
            }

            int tid = spatial.FindNearestTriangle(local_pt);

            if (tid != DMesh3.InvalidID)
            {
                DistPoint3Triangle3 dist = MeshQueries.TriangleDistance(mesh, tid, local_pt);

                nearest          = new SORayHit();
                nearest.fHitDist = (float)Math.Sqrt(dist.DistanceSquared);

                Frame3f f_local = new Frame3f(dist.TriangleClosest, mesh.GetTriNormal(tid));
                Frame3f f       = SceneTransforms.TransformTo(f_local, this, CoordSpace.ObjectCoords, eInCoords);

                nearest.hitPos    = f.Origin;
                nearest.hitNormal = f.Z;
                nearest.hitGO     = RootGameObject;
                nearest.hitSO     = this;
                return(true);
            }
            return(false);
        }
Beispiel #14
0
        public bool Insert()
        {
            Func <int, bool> is_contained_v = (vid) => {
                Vector3d v   = Mesh.GetVertex(vid);
                Vector2f vf2 = ProjectFrame.ToPlaneUV((Vector3f)v, 2);
                return(Polygon.Contains(vf2));
            };

            MeshVertexSelection vertexROI = new MeshVertexSelection(Mesh);
            Index3i             seedT     = Mesh.GetTriangle(SeedTriangle);

            // if a seed vert of seed triangle is containd in polygon, we will
            // flood-fill out from there, this gives a better ROI.
            // If not, we will try flood-fill from the seed triangles.
            List <int> seed_verts = new List <int>();

            for (int j = 0; j < 3; ++j)
            {
                if (is_contained_v(seedT[j]))
                {
                    seed_verts.Add(seedT[j]);
                }
            }
            if (seed_verts.Count == 0)
            {
                seed_verts.Add(seedT.a);
                seed_verts.Add(seedT.b);
                seed_verts.Add(seedT.c);
            }

            // flood-fill out from seed vertices until we have found all vertices
            // contained in polygon
            vertexROI.FloodFill(seed_verts.ToArray(), is_contained_v);

            // convert vertex ROI to face ROI
            MeshFaceSelection faceROI = new MeshFaceSelection(Mesh, vertexROI, 1);

            faceROI.ExpandToOneRingNeighbours();
            faceROI.FillEars(true);    // this might be a good idea...

            // construct submesh
            RegionOperator regionOp   = new RegionOperator(Mesh, faceROI);
            DSubmesh3      roiSubmesh = regionOp.Region;
            DMesh3         roiMesh    = roiSubmesh.SubMesh;

            // save 3D positions of unmodified mesh
            Vector3d[] initialPositions = new Vector3d[roiMesh.MaxVertexID];

            // map roi mesh to plane
            MeshTransforms.PerVertexTransform(roiMesh, roiMesh.VertexIndices(), (v, vid) => {
                Vector2f uv           = ProjectFrame.ToPlaneUV((Vector3f)v, 2);
                initialPositions[vid] = v;
                return(new Vector3d(uv.x, uv.y, 0));
            });

            // save a copy of 2D mesh and construct bvtree. we will use
            // this later to project back to 3d
            // [TODO] can we use a better spatial DS here, that takes advantage of 2D?
            DMesh3         projectMesh = new DMesh3(roiMesh);
            DMeshAABBTree3 projecter   = new DMeshAABBTree3(projectMesh, true);

            MeshInsertUVPolyCurve insertUV = new MeshInsertUVPolyCurve(roiMesh, Polygon);
            //insertUV.Validate()
            bool bOK = insertUV.Apply();

            if (!bOK)
            {
                throw new Exception("insertUV.Apply() failed");
            }

            if (SimplifyInsertion)
            {
                insertUV.Simplify();
            }

            int[] insertedPolyVerts = insertUV.CurveVertices;

            // grab inserted loop, assuming it worked
            EdgeLoop insertedLoop = null;

            if (insertUV.Loops.Count == 1)
            {
                insertedLoop = insertUV.Loops[0];
            }

            // find interior triangles
            List <int> interiorT = new List <int>();

            foreach (int tid in roiMesh.TriangleIndices())
            {
                Vector3d centroid = roiMesh.GetTriCentroid(tid);
                if (Polygon.Contains(centroid.xy))
                {
                    interiorT.Add(tid);
                }
            }
            if (RemovePolygonInterior)
            {
                MeshEditor editor = new MeshEditor(roiMesh);
                editor.RemoveTriangles(interiorT, true);
                InteriorTriangles = null;
            }
            else
            {
                InteriorTriangles = interiorT.ToArray();
            }


            // map back to 3d
            Vector3d a = Vector3d.Zero, b = Vector3d.Zero, c = Vector3d.Zero;

            foreach (int vid in roiMesh.VertexIndices())
            {
                // [TODO] somehow re-use exact positions from regionOp maps?

                // construct new 3D pos w/ barycentric interpolation
                Vector3d v   = roiMesh.GetVertex(vid);
                int      tid = projecter.FindNearestTriangle(v);
                Index3i  tri = projectMesh.GetTriangle(tid);
                projectMesh.GetTriVertices(tid, ref a, ref b, ref c);
                Vector3d bary = MathUtil.BarycentricCoords(ref v, ref a, ref b, ref c);
                Vector3d pos  = bary.x * initialPositions[tri.a] + bary.y * initialPositions[tri.b] + bary.z * initialPositions[tri.c];

                roiMesh.SetVertex(vid, pos);
            }

            bOK = BackPropagate(regionOp, insertedPolyVerts, insertedLoop);

            return(bOK);
        }
Beispiel #15
0
        public static void test_uv_insert_segment()
        {
            DMesh3 mesh = TestUtil.LoadTestInputMesh("plane_250v.obj");

            mesh.EnableVertexUVs(Vector2f.Zero);

            MeshTransforms.ConvertYUpToZUp(mesh);

            DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh);

            spatial.Build();
            int tid = spatial.FindNearestTriangle(Vector3d.Zero);

            //Polygon2d poly = Polygon2d.MakeRectangle(Vector2d.Zero, 5, 5);
            Polygon2d poly = Polygon2d.MakeCircle(5, 13);
            //PolyLine2d poly = new PolyLine2d( new Vector2d[] { -5 * Vector2d.One, 5 * Vector2d.One });


            //int tri_edge0 = mesh.GetTriEdge(tid, 0);
            //Index2i edge0_tris = mesh.GetEdgeT(tri_edge0);
            //Index2i edge0_verts = mesh.GetEdgeV(tri_edge0);
            //Vector3d v0 = mesh.GetVertex(edge0_verts.a), v1 = mesh.GetVertex(edge0_verts.b);
            //Vector3d c = mesh.GetTriCentroid(tid);
            //Polygon2d poly = new Polygon2d(new Vector2d[] {
            //    Vector2d.Lerp(v0.xy, v1.xy, -0.25),
            //    Vector2d.Lerp(v0.xy, v1.xy, 1.5),
            //    c.xy
            //});

            MeshInsertUVPolyCurve insert = new MeshInsertUVPolyCurve(mesh, poly);

            insert.Apply();



            Polygon2d     test_poly = new Polygon2d();
            List <double> distances = new List <double>();
            List <int>    nearests  = new List <int>();

            for (int i = 0; i < insert.Loops[0].VertexCount; ++i)
            {
                Vector2d v = mesh.GetVertex(insert.Loops[0].Vertices[i]).xy;
                test_poly.AppendVertex(v);
                int iNear; double fNear;
                distances.Add(poly.DistanceSquared(v, out iNear, out fNear));
                nearests.Add(iNear);
            }

            System.Console.WriteLine("inserted loop poly has {0} edges", insert.Loops[0].EdgeCount);

            // find a triangle connected to loop that is inside the polygon
            //   [TODO] maybe we could be a bit more robust about this? at least
            //   check if triangle is too degenerate...
            int seed_tri = -1;

            for (int i = 0; i < insert.Loops[0].EdgeCount; ++i)
            {
                Index2i  et   = mesh.GetEdgeT(insert.Loops[0].Edges[i]);
                Vector3d ca   = mesh.GetTriCentroid(et.a);
                bool     in_a = poly.Contains(ca.xy);
                Vector3d cb   = mesh.GetTriCentroid(et.b);
                bool     in_b = poly.Contains(cb.xy);
                if (in_a && in_b == false)
                {
                    seed_tri = et.a;
                    break;
                }
                else if (in_b && in_a == false)
                {
                    seed_tri = et.b;
                    break;
                }
            }
            Util.gDevAssert(seed_tri != -1);

            // flood-fill inside loop
            HashSet <int>     loopEdges = new HashSet <int>(insert.Loops[0].Edges);
            MeshFaceSelection sel       = new MeshFaceSelection(mesh);

            sel.FloodFill(seed_tri, null, (eid) => { return(loopEdges.Contains(eid) == false); });

            // delete inside loop
            MeshEditor editor = new MeshEditor(mesh);

            editor.RemoveTriangles(sel, true);


            MeshTransforms.ConvertZUpToYUp(mesh);

            TestUtil.WriteTestOutputMesh(mesh, "insert_uv_segment.obj");



            //OBJWriter writer = new OBJWriter();
            //var s = new System.IO.StreamWriter(Program.TEST_OUTPUT_PATH + "mesh_local_param.obj", false);
            //List<WriteMesh> wm = new List<WriteMesh>() { new WriteMesh(mesh) };
            //WriteOptions opt = new WriteOptions() {
            //    bCombineMeshes = false, bWriteGroups = false, bPerVertexColors = true, bPerVertexUVs = true,
            //    AsciiHeaderFunc = () => { return "mttllib checkerboard.mtl\r\nusemtl checkerboard\r\n"; }
            //};
            //writer.Write(s, wm, opt);
            //s.Close();
        }
Beispiel #16
0
        public static void test_Winding()
        {
            Sphere3Generator_NormalizedCube gen = new Sphere3Generator_NormalizedCube()
            {
                EdgeVertices = 200
            };
            DMesh3 mesh = gen.Generate().MakeDMesh();
            //DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj");
            DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true);

            GC.Collect();

            double   maxdim = mesh.CachedBounds.MaxDim;
            Vector3d center = mesh.CachedBounds.Center;

            var pts        = TestUtil.RandomPoints3(100, new Random(31337), center, maxdim * 0.5);
            int num_inside = 0;

            foreach (Vector3d pt in pts)
            {
                bool   inside    = spatial.IsInside(pt);
                double distSqr   = MeshQueries.TriDistanceSqr(mesh, spatial.FindNearestTriangle(pt), pt);
                double ptDist    = pt.Length;
                double winding   = mesh.WindingNumber(pt);
                double winding_2 = spatial.WindingNumber(pt);
                if (Math.Abs(winding - winding_2) > 0.00001)
                {
                    System.Diagnostics.Debugger.Break();
                }
                bool winding_inside = Math.Abs(winding) > 0.5;
                if (inside != winding_inside)
                {
                    System.Diagnostics.Debugger.Break();
                }
                if (inside)
                {
                    num_inside++;
                }
            }
            System.Console.WriteLine("inside {0} / {1}", num_inside, pts.Length);

            // force rebuild for profiling code
            GC.Collect();

            LocalProfiler p = new LocalProfiler();

            pts = TestUtil.RandomPoints3(1000, new Random(31337), center, maxdim * 0.5);

            p.Start("full eval");
            double sum = 0;

            foreach (Vector3d pt in pts)
            {
                double winding = mesh.WindingNumber(pt);
                sum += winding;
            }
            p.StopAll();

            p.Start("tree build");
            spatial = new DMeshAABBTree3(mesh, true);
            spatial.WindingNumber(Vector3d.Zero);
            p.StopAll();

            GC.Collect();
            GC.Collect();

            p.Start("tree eval");
            sum = 0;
            foreach (Vector3d pt in pts)
            {
                double winding = spatial.WindingNumber(pt);
                sum += winding;
            }

            p.StopAll();

            System.Console.WriteLine(p.AllTimes());
        }
Beispiel #17
0
        public static void test_uv_insert_string()
        {
            DMesh3 mesh = TestUtil.LoadTestInputMesh("plane_xy_25x25.obj");

            mesh.EnableVertexUVs(Vector2f.Zero);

            DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh);

            spatial.Build();
            int tid = spatial.FindNearestTriangle(Vector3d.Zero);

            PolygonFont2d font = PolygonFont2d.ReadFont("c:\\scratch\\font.bin");

            //List<GeneralPolygon2d> letter = new List<GeneralPolygon2d>(font.Characters.First().Value.Polygons);
            //double targetWidth = 20.0f;
            List <GeneralPolygon2d> letter = font.GetCharacter('a');
            double targetWidth             = 10.0f;

            AxisAlignedBox2d bounds  = font.MaxBounds;
            Vector2d         center  = bounds.Center;
            Vector2d         scale2d = (targetWidth / font.MaxBounds.Width) * new Vector2d(1, 1);


            for (int li = 0; li < letter.Count; ++li)
            {
                GeneralPolygon2d gp = new GeneralPolygon2d(letter[li]);
                gp.Scale(scale2d, center);
                gp.Translate(-center);
                letter[li] = gp;
            }


            List <MeshFaceSelection> letter_interiors = new List <MeshFaceSelection>();

            bool bSimplify = true;

            for (int li = 0; li < letter.Count; ++li)
            {
                GeneralPolygon2d gp = letter[li];

                MeshInsertUVPolyCurve outer = new MeshInsertUVPolyCurve(mesh, gp.Outer);
                Util.gDevAssert(outer.Validate() == ValidationStatus.Ok);
                outer.Apply();
                if (bSimplify)
                {
                    outer.Simplify();
                }

                List <MeshInsertUVPolyCurve> holes = new List <MeshInsertUVPolyCurve>(gp.Holes.Count);
                for (int hi = 0; hi < gp.Holes.Count; ++hi)
                {
                    MeshInsertUVPolyCurve insert = new MeshInsertUVPolyCurve(mesh, gp.Holes[hi]);
                    Util.gDevAssert(insert.Validate() == ValidationStatus.Ok);
                    insert.Apply();
                    if (bSimplify)
                    {
                        insert.Simplify();
                    }
                    holes.Add(insert);
                }


                // find a triangle connected to loop that is inside the polygon
                //   [TODO] maybe we could be a bit more robust about this? at least
                //   check if triangle is too degenerate...
                int      seed_tri   = -1;
                EdgeLoop outer_loop = outer.Loops[0];
                for (int i = 0; i < outer_loop.EdgeCount; ++i)
                {
                    if (!mesh.IsEdge(outer_loop.Edges[i]))
                    {
                        continue;
                    }

                    Index2i  et   = mesh.GetEdgeT(outer_loop.Edges[i]);
                    Vector3d ca   = mesh.GetTriCentroid(et.a);
                    bool     in_a = gp.Outer.Contains(ca.xy);
                    Vector3d cb   = mesh.GetTriCentroid(et.b);
                    bool     in_b = gp.Outer.Contains(cb.xy);
                    if (in_a && in_b == false)
                    {
                        seed_tri = et.a;
                        break;
                    }
                    else if (in_b && in_a == false)
                    {
                        seed_tri = et.b;
                        break;
                    }
                }
                Util.gDevAssert(seed_tri != -1);

                // make list of all outer & hole edges
                HashSet <int> loopEdges = new HashSet <int>(outer_loop.Edges);
                foreach (var insertion in holes)
                {
                    foreach (int eid in insertion.Loops[0].Edges)
                    {
                        loopEdges.Add(eid);
                    }
                }

                // flood-fill inside loop from seed triangle
                MeshFaceSelection sel = new MeshFaceSelection(mesh);
                sel.FloodFill(seed_tri, null, (eid) => { return(loopEdges.Contains(eid) == false); });
                letter_interiors.Add(sel);
            }

            // extrude regions
            Func <Vector3d, Vector3f, int, Vector3d> OffsetF = (v, n, i) => {
                return(v + Vector3d.AxisZ);
            };

            foreach (var interior in letter_interiors)
            {
                MeshExtrudeFaces extrude = new MeshExtrudeFaces(mesh, interior);
                extrude.ExtrudedPositionF = OffsetF;
                extrude.Extrude();
            }

            TestUtil.WriteTestOutputMesh(mesh, "insert_uv_string.obj");
        }
        public static void test_fast_winding_grid()
        {
            //Sphere3Generator_NormalizedCube gen = new Sphere3Generator_NormalizedCube() { EdgeVertices = 15, Radius = 5 };
            //CappedCylinderGenerator gen = new CappedCylinderGenerator() { };
            //TrivialBox3Generator gen = new TrivialBox3Generator() { Box = new Box3d(Vector3d.Zero, 5 * Vector3d.One) };
            //DMesh3 mesh = gen.Generate().MakeDMesh();
            //MeshTransforms.Translate(mesh, 5 * Vector3d.One);
            DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj");
            //DMesh3 mesh = TestUtil.LoadTestInputMesh("holey_bunny.obj");
            //DMesh3 mesh = TestUtil.LoadTestInputMesh("holey_bunny_2.obj");
            //DMesh3 mesh = TestUtil.LoadTestMesh("C:\\git\\gsOrthoVRApp\\sample_files\\scan_1_raw.obj");   // use iso 0.25
            //DMesh3 mesh = TestUtil.LoadTestMesh("C:\\scratch\\irongiant.stl");
            //DMesh3 mesh = TestUtil.LoadTestMesh("C:\\Users\\rms\\Dropbox\\meshes\\cars\\beetle.obj");
            //DMesh3 mesh = TestUtil.LoadTestMesh("c:\\scratch\\PigHead_rot90.obj");
            //DMesh3 mesh = TestUtil.LoadTestMesh("C:\\Projects\\nia_files\\testscan2.obj");

            //TestUtil.WriteTestOutputMesh(mesh, "xxx.obj");

            AxisAlignedBox3d meshBounds = mesh.CachedBounds;
            int    num_cells            = 256;
            double cell_size            = meshBounds.MaxDim / num_cells;

            float winding_iso = 0.35f;

            DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true);

            spatial.WindingNumber(Vector3d.Zero);

            DMeshAABBTreePro spatialPro = new DMeshAABBTreePro(mesh, true);

            spatialPro.FastWindingNumber(Vector3d.Zero);

            Func <Vector3d, double> exactWN     = (q) => { return(spatial.WindingNumber(q)); };
            Func <Vector3d, double> PerFacePtWN = (q) => { return(eval_point_wn(mesh, q)); };
            Func <Vector3d, double> fastWN      = (q) => { return(spatialPro.FastWindingNumber(q)); };

            //MeshScalarSamplingGrid mwnGrid = new MeshScalarSamplingGrid(mesh, cell_size, exactWN);
            //MeshScalarSamplingGrid mwnGrid = new MeshScalarSamplingGrid(mesh, cell_size, PerFacePtWN );
            MeshScalarSamplingGrid mwnGrid = new MeshScalarSamplingGrid(mesh, cell_size, fastWN);

            mwnGrid.IsoValue   = winding_iso;
            mwnGrid.DebugPrint = true;

            LocalProfiler p = new LocalProfiler();

            p.Start("grid");
            mwnGrid.Compute();
            p.Stop("grid");
            System.Console.WriteLine(p.AllTimes());


            MarchingCubes c = new MarchingCubes();

            c.Implicit = new SampledGridImplicit(mwnGrid);

            c.Bounds   = mesh.CachedBounds;
            c.CubeSize = c.Bounds.MaxDim / 128;

            //c.Bounds = mesh.CachedBounds;
            c.Bounds.Expand(c.CubeSize * 3);
            //c.CubeSize = cell_size * 0.5;
            //c.IsoValue = mwnGrid.WindingIsoValue;

            c.Generate();

            // reproject
            foreach (int vid in c.Mesh.VertexIndices())
            {
                Vector3d v = c.Mesh.GetVertex(vid);

                int tid = spatial.FindNearestTriangle(v, cell_size * MathUtil.SqrtTwo);
                if (tid != DMesh3.InvalidID)
                {
                    var query = MeshQueries.TriangleDistance(mesh, tid, v);
                    if (v.Distance(query.TriangleClosest) < cell_size * 1.5)
                    {
                        c.Mesh.SetVertex(vid, query.TriangleClosest);
                    }
                }
            }

            //MeshNormals.QuickCompute(c.Mesh);
            TestUtil.WriteTestOutputMesh(c.Mesh, "mwn_implicit.obj");
        }
            internal bool RandomAdjust(g3.DMesh3 mesh, DMeshAABBTree3 tree, Random r, double max, double moveTries, double targetArea)
            {
                bool moved = false;

                if (this.locked)
                {
                    return(false);
                }

                for (int i = 0; i < moveTries; i++)
                {
                    var v0 = mesh.GetVertex(vertex_index.a);
                    var v1 = mesh.GetVertex(vertex_index.b);
                    var v2 = mesh.GetVertex(vertex_index.c);

                    var v0_old = mesh.GetVertex(vertex_index.a);
                    var v1_old = mesh.GetVertex(vertex_index.b);
                    var v2_old = mesh.GetVertex(vertex_index.c);

                    v0.x += (r.NextDouble() * max * 2 - max);
                    v0.y += (r.NextDouble() * max * 2 - max);
                    v0.z += (r.NextDouble() * max * 2 - max);

                    v1.x += (r.NextDouble() * max * 2 - max);
                    v1.y += (r.NextDouble() * max * 2 - max);
                    v1.z += (r.NextDouble() * max * 2 - max);

                    v2.x += (r.NextDouble() * max * 2 - max);
                    v2.y += (r.NextDouble() * max * 2 - max);
                    v2.z += (r.NextDouble() * max * 2 - max);

                    int tNearestID        = tree.FindNearestTriangle(v0);
                    DistPoint3Triangle3 q = MeshQueries.TriangleDistance(tree.Mesh, tNearestID, v0);
                    v0 = q.TriangleClosest;

                    tNearestID = tree.FindNearestTriangle(v1);
                    q          = MeshQueries.TriangleDistance(tree.Mesh, tNearestID, v1);
                    v1         = q.TriangleClosest;

                    tNearestID = tree.FindNearestTriangle(v2);
                    q          = MeshQueries.TriangleDistance(tree.Mesh, tNearestID, v2);
                    v2         = q.TriangleClosest;

                    double oldArea = (HowCloseToTargetArea(mesh, targetArea, 2) / targetArea) * 3;

                    double oldAngleQuality = GetTriangleTotalAnglesQualityHelper(mesh, 2);

                    var n = mesh.GetTriNormal(meshIndex);

                    double oldNormalQuality = GetNormalQuality(mesh, n, 2) * 6;

                    mesh.SetVertex(vertex_index.a, v0);
                    mesh.SetVertex(vertex_index.b, v1);
                    mesh.SetVertex(vertex_index.c, v2);

                    double newArea          = (HowCloseToTargetArea(mesh, targetArea, 2) / targetArea) * 3;
                    double newAngleQuality  = GetTriangleTotalAnglesQualityHelper(mesh, 2);
                    double newNormalQuality = GetNormalQuality(mesh, n, 2) * 6;

                    if ((oldArea + oldAngleQuality + oldNormalQuality) < (newArea + newAngleQuality + newNormalQuality))
                    {
                        mesh.SetVertex(vertex_index.a, v0_old);
                        mesh.SetVertex(vertex_index.b, v1_old);
                        mesh.SetVertex(vertex_index.c, v2_old);
                    }
                    else
                    {
                        moved = true;
                    }
                }

                return(moved);
            }