void compute_trimmed_mesh()
        {
            // curve is on base leg, map to deformed leg
            // [TODO] really should be doing this via deformation, rather than nearest-point
            DCurve3 curve = new DCurve3(CurveSource.GetICurve());

            for (int i = 0; i < curve.VertexCount; ++i)
            {
                curve[i] = MeshQueries.NearestPointFrame(cachedInputMesh, cachedInputMeshSpatial, curve[i]).Origin;
            }

            TrimmedMesh = new DMesh3(cachedInputMesh);
            TrimmedMesh.EnableTriangleGroups(0);

            AxisAlignedBox3d bounds = TrimmedMesh.CachedBounds;

            // try to find seed based on raycast, which doesn't always work.
            // Note that seed is the seed for the *eroded* region, not the kept region
            Vector3d basePt  = bounds.Center + 10 * bounds.Extents.y * Vector3d.AxisY;
            int      hit_tid = cachedInputMeshSpatial.FindNearestHitTriangle(new Ray3d(basePt, -Vector3d.AxisY));
            Vector3d seed    = cachedInputMesh.GetTriCentroid(hit_tid);

            if (flip_trim_side)
            {
                basePt  = bounds.Center - 10 * bounds.Extents.y * Vector3d.AxisY;
                hit_tid = cachedInputMeshSpatial.FindNearestHitTriangle(new Ray3d(basePt, Vector3d.AxisY));
                seed    = cachedInputMesh.GetTriCentroid(hit_tid);
            }

            MeshTrimLoop trim = new MeshTrimLoop(TrimmedMesh, curve, seed, cachedInputMeshSpatial);

            trim.Trim();

            if (TrimmedMesh.HasVertexColors == false)
            {
                TrimmedMesh.EnableVertexColors(SocketVertexColor);
            }
            else
            {
                foreach (int vid in TrimmedMesh.VertexIndices())
                {
                    TrimmedMesh.SetVertexColor(vid, SocketVertexColor);
                }
            }

            MeshTransforms.FromFrame(TrimmedMesh, cachedInputsTransform);
        }
        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);
        }
Exemplo n.º 3
0
        public void EndStroke()
        {
            if (CurrentStroke.Count >= 2)
            {
                DMesh3 mesh = Target.Mesh;

                TransformSequence toScene = SceneTransforms.ObjectToSceneXForm(Target);

                List <int> tris1 = new List <int>(), tris2 = new List <int>();
                Ray3f      first = CurrentStroke[0], last = CurrentStroke[CurrentStroke.Count - 1];

                Vector3f v0 = PlaneFrameS.RayPlaneIntersection(first.Origin, first.Direction, 2);
                Vector3f v1 = PlaneFrameS.RayPlaneIntersection(last.Origin, last.Direction, 2);

                Vector3f planeN = Vector3f.Cross(first.Direction, last.Direction);
                Frame3f  planeF = new Frame3f((v0 + v1) / 2, planeN);

                foreach (int tid in mesh.TriangleIndices())
                {
                    Vector3f c = (Vector3f)mesh.GetTriCentroid(tid);
                    c = toScene.TransformP(c);
                    if (planeF.DistanceToPlaneSigned(c, 2) < 0)
                    {
                        tris1.Add(tid);
                    }
                    else
                    {
                        tris2.Add(tid);
                    }
                }

                double area1 = MeshMeasurements.AreaT(mesh, tris1);
                double area2 = MeshMeasurements.AreaT(mesh, tris2);

                lastSelection = new MeshFaceSelection(mesh);
                lastSelection.Select((area1 > area2) ? tris2 : tris1);
                lastSelection.LocalOptimize();

                if (OnStrokeCompletedF != null)
                {
                    OnStrokeCompletedF(Target, lastSelection);
                }
            }

            CurrentStroke.Clear();
        }
Exemplo n.º 4
0
        public static void test_remove_change_apply()
        {
            DMesh3   testMesh = TestUtil.LoadTestInputMesh("bunny_solid.obj");
            DMesh3   copy     = new DMesh3(testMesh);
            Vector3d c        = testMesh.CachedBounds.Center;

            MeshFaceSelection selection = new MeshFaceSelection(testMesh);

            foreach (int tid in testMesh.TriangleIndices())
            {
                if (testMesh.GetTriCentroid(tid).x > c.x)
                {
                    selection.Select(tid);
                }
            }

            RemoveTrianglesMeshChange change = new RemoveTrianglesMeshChange();

            change.InitializeFromApply(testMesh, selection);

            testMesh.CheckValidity(true);
            change.Apply(copy);
            copy.CheckValidity(true);

            if (!copy.IsSameMesh(testMesh, true))
            {
                System.Console.WriteLine("FAILED copy.IsSameMesh() 1");
            }

            change.Revert(testMesh);
            testMesh.CheckValidity(false);
            change.Revert(copy);
            copy.CheckValidity(false);

            if (!copy.IsSameMesh(testMesh, true))
            {
                System.Console.WriteLine("FAILED copy.IsSameMesh() 1");
            }

            System.Console.WriteLine("test_remove_change_apply ok");
        }
Exemplo n.º 5
0
        private bool IsInRange(DMesh3 mesh, int triIndexOriginal, int triIndex, double rangeSquared)
        {
            var triOriginal = mesh.GetTriCentroid(triIndexOriginal);
            var tri         = mesh.GetTriangle(triIndex);
            var v1          = mesh.GetVertex(tri.a);
            var v2          = mesh.GetVertex(tri.b);
            var v3          = mesh.GetVertex(tri.c);

            if (v1.DistanceSquared(triOriginal) < rangeSquared)
            {
                return(true);
            }
            if (v2.DistanceSquared(triOriginal) < rangeSquared)
            {
                return(true);
            }
            if (v3.DistanceSquared(triOriginal) < rangeSquared)
            {
                return(true);
            }
            return(false);
        }
Exemplo n.º 6
0
        public void InitializeGeodesicDistance(Vector3d source, int source_tid)
        {
            DijkstraGraphDistance dist = new DijkstraGraphDistance(Mesh.MaxTriangleID, false,
                                                                   (tid) => { return(Mesh.IsTriangle(tid)); },
                                                                   (a, b) => { return((float)Mesh.GetTriCentroid(a).Distance(Mesh.GetTriCentroid(b))); },
                                                                   Mesh.TriTrianglesItr);

            dist.AddSeed(source_tid, (float)Mesh.GetTriCentroid(source_tid).Distance(source));

            //Index3i tri = Mesh.GetTriangle(source_tid);
            //for (int j = 0; j < 3; ++j) {
            //    dist.AddSeed(tri[j], (float)Mesh.GetVertex(tri[j]).Distance(source));
            //}

            dist.TrackOrder = true;
            dist.Compute();

            List <int> order = dist.GetOrder();

            tri_ordering = new OrderedTri[order.Count];
            for (int k = 0; k < order.Count; ++k)
            {
                tri_ordering[k].tid    = order[k];
                tri_ordering[k].scalar = dist.GetDistance(order[k]);
            }

            tid_to_order_idx = new int[Mesh.MaxTriangleID];
            for (int k = 0; k < order.Count; ++k)
            {
                tid_to_order_idx[order[k]] = k;
            }


            // rebuild chunks data structures
            update_ordered_chunks();
        }
Exemplo n.º 7
0
        public virtual bool Apply()
        {
            DMesh3 testAgainstMesh = Mesh;

            if (InsideMode == CalculationMode.RayParity)
            {
                MeshBoundaryLoops loops = new MeshBoundaryLoops(testAgainstMesh);
                if (loops.Count > 0)
                {
                    testAgainstMesh = new DMesh3(Mesh);
                    foreach (var loop in loops)
                    {
                        if (Cancelled())
                        {
                            return(false);
                        }
                        SimpleHoleFiller filler = new SimpleHoleFiller(testAgainstMesh, loop);
                        filler.Fill();
                    }
                }
            }

            DMeshAABBTree3 spatial = (Spatial != null && testAgainstMesh == Mesh) ?
                                     Spatial : new DMeshAABBTree3(testAgainstMesh, true);

            if (InsideMode == CalculationMode.AnalyticWindingNumber)
            {
                spatial.WindingNumber(Vector3d.Zero);
            }
            else if (InsideMode == CalculationMode.FastWindingNumber)
            {
                spatial.FastWindingNumber(Vector3d.Zero);
            }

            if (Cancelled())
            {
                return(false);
            }

            // ray directions
            List <Vector3d> ray_dirs = null; int NR = 0;

            if (InsideMode == CalculationMode.SimpleOcclusionTest)
            {
                ray_dirs = new List <Vector3d>();
                ray_dirs.Add(Vector3d.AxisX); ray_dirs.Add(-Vector3d.AxisX);
                ray_dirs.Add(Vector3d.AxisY); ray_dirs.Add(-Vector3d.AxisY);
                ray_dirs.Add(Vector3d.AxisZ); ray_dirs.Add(-Vector3d.AxisZ);
                NR = ray_dirs.Count;
            }

            Func <Vector3d, bool> isOccludedF = (pt) => {
                if (InsideMode == CalculationMode.RayParity)
                {
                    return(spatial.IsInside(pt));
                }
                else if (InsideMode == CalculationMode.AnalyticWindingNumber)
                {
                    return(spatial.WindingNumber(pt) > WindingIsoValue);
                }
                else if (InsideMode == CalculationMode.FastWindingNumber)
                {
                    return(spatial.FastWindingNumber(pt) > WindingIsoValue);
                }
                else
                {
                    for (int k = 0; k < NR; ++k)
                    {
                        int hit_tid = spatial.FindNearestHitTriangle(new Ray3d(pt, ray_dirs[k]));
                        if (hit_tid == DMesh3.InvalidID)
                        {
                            return(false);
                        }
                    }
                    return(true);
                }
            };

            bool cancel = false;

            BitArray vertices = null;

            if (PerVertex)
            {
                vertices = new BitArray(Mesh.MaxVertexID);

                MeshNormals normals = null;
                if (Mesh.HasVertexNormals == false)
                {
                    normals = new MeshNormals(Mesh);
                    normals.Compute();
                }

                gParallel.ForEach(Mesh.VertexIndices(), (vid) => {
                    if (cancel)
                    {
                        return;
                    }
                    if (vid % 10 == 0)
                    {
                        cancel = Cancelled();
                    }

                    Vector3d c    = Mesh.GetVertex(vid);
                    Vector3d n    = (normals == null) ? Mesh.GetVertexNormal(vid) : normals[vid];
                    c            += n * NormalOffset;
                    vertices[vid] = isOccludedF(c);
                });
            }
            if (Cancelled())
            {
                return(false);
            }

            RemovedT = new List <int>();
            SpinLock removeLock = new SpinLock();

            gParallel.ForEach(Mesh.TriangleIndices(), (tid) => {
                if (cancel)
                {
                    return;
                }
                if (tid % 10 == 0)
                {
                    cancel = Cancelled();
                }

                bool inside = false;
                if (PerVertex)
                {
                    Index3i tri = Mesh.GetTriangle(tid);
                    inside      = vertices[tri.a] || vertices[tri.b] || vertices[tri.c];
                }
                else
                {
                    Vector3d c = Mesh.GetTriCentroid(tid);
                    Vector3d n = Mesh.GetTriNormal(tid);
                    c         += n * NormalOffset;
                    inside     = isOccludedF(c);
                }

                if (inside)
                {
                    bool taken = false;
                    removeLock.Enter(ref taken);
                    RemovedT.Add(tid);
                    removeLock.Exit();
                }
            });

            if (Cancelled())
            {
                return(false);
            }

            if (RemovedT.Count > 0)
            {
                MeshEditor editor = new MeshEditor(Mesh);
                bool       bOK    = editor.RemoveTriangles(RemovedT, true);
                RemoveFailed = (bOK == false);
            }

            return(true);
        }
Exemplo n.º 8
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);
        }
Exemplo n.º 9
0
 public Vector3d GetVertex(int i)
 {
     return(Mesh.GetTriCentroid(i));
 }
        protected void merge_loops(DMesh3 mesh, EdgeLoop cutLoop, EdgeLoop connectorLoop, bool is_outer)
        {
            /*
             * To join the loops, we are going to first make a circle, then snap both
             * open loops to that circle. Then we sample a set of vertices on the circle
             * and remesh the loops while also snapping them to the circle vertices.
             * The result is two perfectly-matching edge loops.
             */

            //AxisAlignedBox3d cutLoopBounds =
            //    BoundsUtil.Bounds(cutLoop.Vertices, (vid) => { return mesh.GetVertex(vid); });

            AxisAlignedBox3d cutLoopBounds       = cutLoop.GetBounds();
            AxisAlignedBox3d connectorLoopBounds = connectorLoop.GetBounds();
            Vector3d         midPt = (cutLoopBounds.Center + connectorLoopBounds.Center) * 0.5;
            double           midY  = midPt.y;

            // this mess construcst the circle and the sampled version
            Frame3f           circFrame       = new Frame3f(midPt);
            Circle3d          circ            = new Circle3d(circFrame, connectorLoopBounds.Width * 0.5, 1);
            DistPoint3Circle3 dist            = new DistPoint3Circle3(Vector3d.Zero, circ);
            DCurve3           sampled         = new DCurve3();
            double            target_edge_len = TargetMeshEdgeLength;
            int N = (int)(circ.ArcLength / target_edge_len);

            for (int k = 0; k < N; ++k)
            {
                sampled.AppendVertex(circ.SampleT((double)k / (double)N));
            }

            MergeProjectionTarget circleTarget = new MergeProjectionTarget()
            {
                Mesh = mesh, CircleDist = dist, CircleLoop = sampled
            };

            EdgeLoop[] loops = new EdgeLoop[2] {
                cutLoop, connectorLoop
            };
            EdgeLoop[] outputLoops = new EdgeLoop[2];   // loops after this remeshing/etc (but might be missing some verts/edges!)
            for (int li = 0; li < 2; ++li)
            {
                EdgeLoop loop = loops[li];

                // snap the loop verts onto the analytic circle
                foreach (int vid in loop.Vertices)
                {
                    Vector3d v = mesh.GetVertex(vid);
                    dist.Point = new Vector3d(v.x, midY, v.z);
                    mesh.SetVertex(vid, dist.Compute().CircleClosest);
                }

                if (DebugStep <= 5)
                {
                    continue;
                }

                // remesh around the edge loop while we snap it to the sampled circle verts
                EdgeLoopRemesher loopRemesh = new EdgeLoopRemesher(mesh, loop)
                {
                    LocalSmoothingRings = 3
                };
                loopRemesh.EnableParallelProjection = false;
                loopRemesh.SetProjectionTarget(circleTarget);
                loopRemesh.SetTargetEdgeLength(TargetMeshEdgeLength);
                loopRemesh.SmoothSpeedT = 0.5f;
                for (int k = 0; k < 5; ++k)
                {
                    loopRemesh.BasicRemeshPass();
                }
                loopRemesh.SmoothSpeedT = 0;
                for (int k = 0; k < 2; ++k)
                {
                    loopRemesh.BasicRemeshPass();
                }
                EdgeLoop newLoop = loopRemesh.OutputLoop;
                outputLoops[li] = newLoop;

                if (DebugStep <= 6)
                {
                    continue;
                }

                // hard snap the loop vertices to the sampled circle verts
                foreach (int vid in newLoop.Vertices)
                {
                    Vector3d v = mesh.GetVertex(vid);
                    v = circleTarget.Project(v, vid);
                    mesh.SetVertex(vid, v);
                }

                // [TODO] we could re-order newLoop verts/edges to match the sampled verts order,
                // then the pair of loops would be consistently ordered (currently no guarantee)

                if (DebugStep <= 7)
                {
                    continue;
                }

                // collapse any degenerate edges on loop (just in case)
                // DANGER: if this actually happens, then outputLoops[li] has some invalid verts/edges!
                foreach (int eid in newLoop.Edges)
                {
                    if (mesh.IsEdge(eid))
                    {
                        Index2i  ev = mesh.GetEdgeV(eid);
                        Vector3d a = mesh.GetVertex(ev.a), b = mesh.GetVertex(ev.b);
                        if (a.Distance(b) < TargetMeshEdgeLength * 0.001)
                        {
                            DMesh3.EdgeCollapseInfo collapse;
                            mesh.CollapseEdge(ev.a, ev.b, out collapse);
                        }
                    }
                }
            }

            if (DebugStep <= 7)
            {
                return;
            }


            /*
             * Ok now we want to merge the loops and make them nice
             */

            // would be more efficient to find loops and stitch them...
            MergeCoincidentEdges merge = new MergeCoincidentEdges(mesh);

            merge.Apply();

            // fill any fail-holes??

            // remesh merge region
            MeshVertexSelection remesh_roi_v = new MeshVertexSelection(mesh);

            remesh_roi_v.Select(outputLoops[0].Vertices);
            remesh_roi_v.Select(outputLoops[1].Vertices);
            remesh_roi_v.ExpandToOneRingNeighbours(5);
            MeshFaceSelection remesh_roi = new MeshFaceSelection(mesh, remesh_roi_v, 1);

            remesh_roi.LocalOptimize(true, true);

            IProjectionTarget projTarget = null;

            if (is_outer)
            {
                projTarget = new NoPenetrationProjectionTarget()
                {
                    Spatial = this.OuterOffsetMeshSpatial
                };
            }
            else
            {
                projTarget = new NoPenetrationProjectionTarget()
                {
                    Spatial = this.InnerOffsetMeshSpatial
                };
            }

            RegionRemesher join_remesh =
                RegionRemesher.QuickRemesh(mesh, remesh_roi.ToArray(), TargetMeshEdgeLength, 0.5, 5, projTarget);

            if (DebugStep <= 8)
            {
                return;
            }


            if (false && is_outer)
            {
                Func <int, bool> filterF = (tid) => {
                    return(mesh.GetTriCentroid(tid).y > connectorLoopBounds.Max.y);
                };

                MeshFaceSelection tris = new MeshFaceSelection(mesh);
                foreach (int tid in join_remesh.CurrentBaseTriangles)
                {
                    if (filterF(tid))
                    {
                        tris.Select(tid);
                    }
                }
                tris.ExpandToOneRingNeighbours(5, filterF);

                MeshVertexSelection verts  = new MeshVertexSelection(mesh, tris);
                MeshIterativeSmooth smooth = new MeshIterativeSmooth(mesh, verts.ToArray(), true);
                smooth.Alpha    = 1.0f;
                smooth.Rounds   = 25;
                smooth.ProjectF = (v, n, vid) => { return(projTarget.Project(v)); };
                smooth.Smooth();
            }


            // [RMS] this smooths too far. we basically only want to smooth 'up' from top of socket...
            //LaplacianMeshSmoother.RegionSmooth(mesh, join_remesh.CurrentBaseTriangles, 1, 10);

            // need to post-enforce thickness, which we aren't doing above - we could though
        }
Exemplo n.º 11
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");
        }
Exemplo n.º 12
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();
        }