Ejemplo n.º 1
0
 void OnEnable()
 {
     mInstance = (MeshEditor)target;
 }
Ejemplo n.º 2
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();
                    }
                }
            }

            DMeshAABBTreePro spatial = (Spatial != null && testAgainstMesh == Mesh) ?
                                       Spatial : new DMeshAABBTreePro(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);
        }
Ejemplo n.º 3
0
        protected virtual DMesh3 compute_inset(DMesh3 meshIn)
        {
            double unsigned_offset = Math.Abs(distance);

            DMeshAABBTree3 use_spatial = new DMeshAABBTree3(meshIn, true);

            if (is_invalidated())
            {
                return(null);
            }

            CachingMeshSDF sdf = new CachingMeshSDF(meshIn, grid_cell_size, use_spatial);

            sdf.MaxOffsetDistance = (float)unsigned_offset;
            sdf.CancelF           = is_invalidated;
            sdf.Initialize();
            if (is_invalidated())
            {
                return(null);
            }

            var sdf_iso = new CachingMeshSDFImplicit(sdf);
            // currently MCPro-Continuation does not work w/ non-zero
            //   isovalues, so we have to shift our target offset externally
            ImplicitOffset3d iso = new ImplicitOffset3d()
            {
                A = sdf_iso, Offset = -distance
            };

            MarchingCubesPro c = new MarchingCubesPro();

            c.Implicit = iso;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(distance + 3 * c.CubeSize);

            c.CancelF = is_invalidated;
            c.GenerateContinuation(offset_seeds(meshIn, -distance));
            if (is_invalidated())
            {
                return(null);
            }

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize * 0.5, 3, true);
            if (is_invalidated())
            {
                return(null);
            }

            if (min_component_volume > 0)
            {
                MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume);
            }
            if (is_invalidated())
            {
                return(null);
            }

            return(c.Mesh);
        }
Ejemplo n.º 4
0
        public virtual void Update()
        {
            base.begin_update();
            int start_timestamp = this.CurrentInputTimestamp;

            if (MeshSource == null)
            {
                throw new Exception("CombineMeshesOp: must set valid MeshSource to compute!");
            }

            ResultMesh = null;

            try {
                DMesh3 meshIn = new DMesh3(MeshSource.GetDMeshUnsafe());

                if (orient_nested_shells)
                {
                    MeshConnectedComponents comp = new MeshConnectedComponents(meshIn);
                    comp.FindConnectedT();
                    DSubmesh3Set subMeshes = new DSubmesh3Set(meshIn, comp);

                    List <DMesh3> curMeshes = new List <DMesh3>();
                    foreach (var submesh in subMeshes)
                    {
                        curMeshes.Add(submesh.SubMesh);
                    }

                    MeshSpatialSort sort = new MeshSpatialSort();
                    foreach (var mesh in curMeshes)
                    {
                        sort.AddMesh(mesh, mesh);
                    }
                    sort.Sort();

                    ResultMesh = new DMesh3();
                    MeshEditor editor = new MeshEditor(ResultMesh);
                    foreach (var solid in sort.Solids)
                    {
                        DMesh3 outer = solid.Outer.Mesh;
                        if (!is_outward_oriented(outer))
                        {
                            outer.ReverseOrientation();
                        }
                        editor.AppendMesh(outer, ResultMesh.AllocateTriangleGroup());

                        foreach (var hole in solid.Cavities)
                        {
                            if (hole.Mesh.CachedIsClosed && is_outward_oriented(hole.Mesh) == true)
                            {
                                hole.Mesh.ReverseOrientation();
                            }
                            editor.AppendMesh(hole.Mesh, ResultMesh.AllocateTriangleGroup());
                        }
                    }
                }
                else
                {
                    ResultMesh = meshIn;
                }

                base.complete_update();
            } catch (Exception e) {
                PostOnOperatorException(e);
                ResultMesh = base.make_failure_output(MeshSource.GetDMeshUnsafe());
                base.complete_update();
            }
        }
Ejemplo n.º 5
0
        bool remove_loners()
        {
            bool bOK = MeshEditor.RemoveIsolatedTriangles(Mesh);

            return(true);
        }
Ejemplo n.º 6
0
        // extracts all MeshFilter objects from input GameObject and appends them, then passes to
        // function MakeSOFunc (if null, creates basic MeshSO). Then optionally adds to Scene,
        // preserving existing 3D position if desired (default true)
        public static TransformableSO ImportExistingUnityGO(GameObject go, FScene scene,
                                                            bool bAddToScene = true, bool bKeepWorldPosition = true, bool bRecenterFrame = true,
                                                            Func <DMesh3, SOMaterial, TransformableSO> MakeSOFunc = null)
        {
            List <MeshFilter> filters  = new List <MeshFilter>();
            List <GameObject> children = new List <GameObject>()
            {
                go
            };

            UnityUtil.CollectAllChildren(go, children);
            foreach (var cgo in children)
            {
                if (cgo.GetComponent <MeshFilter>() != null)
                {
                    filters.Add(cgo.GetComponent <MeshFilter>());
                }
            }
            if (filters.Count == 0)
            {
                throw new Exception("SceneUtil.ImportExistingUnityGO: no meshes!!");
            }

            DMesh3     CombineMesh = new DMesh3(MeshComponents.VertexNormals | MeshComponents.VertexColors);
            MeshEditor editor      = new MeshEditor(CombineMesh);
            int        gid         = 0;

            foreach (MeshFilter mesh in filters)
            {
                fMesh uMesh = new fMesh(mesh.sharedMesh);
                using (var imesh = uMesh.CreateCachedIMesh()) {
                    editor.AppendMesh(imesh, ++gid);
                }
            }

            Vector3f scale = go.GetLocalScale();

            AxisAlignedBox3d bounds = CombineMesh.CachedBounds;  // bounds.Center is wrt local frame of input go

            // ie offset from origin in local coordinates

            // if we want to move frame to center of mesh, we have to re-center it at origin
            // in local coordinates
            if (bRecenterFrame)
            {
                MeshTransforms.Translate(CombineMesh, -bounds.Center.x, -bounds.Center.y, -bounds.Center.z);
            }

            TransformableSO newSO = (MakeSOFunc != null) ?
                                    MakeSOFunc(CombineMesh, scene.DefaultMeshSOMaterial)
                : new DMeshSO().Create(CombineMesh, scene.DefaultMeshSOMaterial);

            if (bAddToScene)
            {
                scene.AddSceneObject(newSO, false);
            }

            if (bKeepWorldPosition)
            {
                // compute world rotation/location. If we re-centered the mesh, we need
                // to offset by the transform we applied above in local coordinates
                // (hence we have to rotate & scale)
                if (go.transform.parent != null)
                {
                    throw new Exception("UnitySceneUtil.ImportExistingUnityGO: Not handling case where GO has a parent transform");
                }
                Frame3f  goFrameW = UnityUtil.GetGameObjectFrame(go, CoordSpace.WorldCoords);
                Vector3f originW  = goFrameW.Origin;
                if (bRecenterFrame)
                {
                    originW += goFrameW.Rotation * (scale * (Vector3f)bounds.Center);   // offset initial frame to be at center of mesh
                }
                // convert world frame and offset to scene coordinates
                Frame3f  goFrameS      = scene.ToSceneFrame(goFrameW);
                Vector3f boundsCenterS = scene.ToSceneP(originW);

                // translate new object to position in scene
                Frame3f curF = newSO.GetLocalFrame(CoordSpace.SceneCoords);
                curF.Origin += boundsCenterS;
                newSO.SetLocalFrame(curF, CoordSpace.SceneCoords);

                // apply rotation (around current origin)
                curF = newSO.GetLocalFrame(CoordSpace.SceneCoords);
                curF.RotateAround(curF.Origin, goFrameS.Rotation);
                newSO.SetLocalFrame(curF, CoordSpace.SceneCoords);

                // apply local scale
                newSO.SetLocalScale(scale);
            }

            return(newSO);
        }
Ejemplo n.º 7
0
        static void Main(string[] args)
        {
            CommandArgumentSet arguments = new CommandArgumentSet();

            arguments.Register("-tcount", int.MaxValue);
            arguments.Register("-percent", 50.0f);
            arguments.Register("-v", false);
            arguments.Register("-output", "");
            if (arguments.Parse(args) == false)
            {
                return;
            }

            if (arguments.Filenames.Count != 1)
            {
                print_usage();
                return;
            }
            string inputFilename = arguments.Filenames[0];

            if (!File.Exists(inputFilename))
            {
                System.Console.WriteLine("File {0} does not exist", inputFilename);
                return;
            }


            string outputFilename = Path.GetFileNameWithoutExtension(inputFilename);
            string format         = Path.GetExtension(inputFilename);

            outputFilename = outputFilename + ".reduced" + format;
            if (arguments.Saw("-output"))
            {
                outputFilename = arguments.Strings["-output"];
            }


            int triCount = int.MaxValue;

            if (arguments.Saw("-tcount"))
            {
                triCount = arguments.Integers["-tcount"];
            }

            float percent = 50.0f;

            if (arguments.Saw("-percent"))
            {
                percent = arguments.Floats["-percent"];
            }

            bool verbose = false;

            if (arguments.Saw("-v"))
            {
                verbose = arguments.Flags["-v"];
            }


            List <DMesh3> meshes;

            try {
                DMesh3Builder builder = new DMesh3Builder();
                IOReadResult  result  = StandardMeshReader.ReadFile(inputFilename, ReadOptions.Defaults, builder);
                if (result.code != IOCode.Ok)
                {
                    System.Console.WriteLine("Error reading {0} : {1}", inputFilename, result.message);
                    return;
                }
                meshes = builder.Meshes;
            } catch (Exception e) {
                System.Console.WriteLine("Exception reading {0} : {1}", inputFilename, e.Message);
                return;
            }
            if (meshes.Count == 0)
            {
                System.Console.WriteLine("file did not contain any valid meshes");
                return;
            }

            DMesh3 mesh = meshes[0];

            for (int k = 1; k < meshes.Count; ++k)
            {
                MeshEditor.Append(mesh, meshes[k]);
            }
            if (mesh.TriangleCount == 0)
            {
                System.Console.WriteLine("mesh does not contain any triangles");
                return;
            }

            if (verbose)
            {
                System.Console.WriteLine("initial mesh contains {0} triangles", mesh.TriangleCount);
            }

            Reducer r = new Reducer(mesh);

            if (triCount < int.MaxValue)
            {
                if (verbose)
                {
                    System.Console.Write("reducing to {0} triangles...", triCount);
                }
                r.ReduceToTriangleCount(triCount);
            }
            else
            {
                int nT = (int)((float)mesh.TriangleCount * percent / 100.0f);
                nT = MathUtil.Clamp(nT, 1, mesh.TriangleCount);
                if (verbose)
                {
                    System.Console.Write("reducing to {0} triangles...", nT);
                }
                r.ReduceToTriangleCount(nT);
            }

            if (verbose)
            {
                System.Console.WriteLine("done!");
            }

            try {
                IOWriteResult wresult =
                    StandardMeshWriter.WriteMesh(outputFilename, mesh, WriteOptions.Defaults);
                if (wresult.code != IOCode.Ok)
                {
                    System.Console.WriteLine("Error writing {0} : {1}", inputFilename, wresult.message);
                    return;
                }
            } catch (Exception e) {
                System.Console.WriteLine("Exception reading {0} : {1}", inputFilename, e.Message);
                return;
            }

            return;
        }
Ejemplo n.º 8
0
        public static void test_autorepair_thingi10k()
        {
            //const string THINGIROOT = "E:\\Thingi10K\\";
            string WRITEPATH = "E:\\Thingi10K\\repair_fails\\";

            //string[] files = File.ReadAllLines("E:\\Thingi10K\\current\\thingi10k_open.txt");
            string[] files = File.ReadAllLines("C:\\git\\gsGeometryTests\\test_output\\thingi10k_autorepair_failures.txt");
            //string[] files = new string[] {
            //    "E:\\Thingi10K\\raw_meshes\\37011.stl"
            //};
            SafeListBuilder <string> failures = new SafeListBuilder <string>();

            int count         = 0;
            int MAX_NUM_FILES = 10000;

            gParallel.ForEach(files, (filename) => {
                if (count > MAX_NUM_FILES)
                {
                    return;
                }

                int i = count;
                Interlocked.Increment(ref count);
                if (i % 10 == 0)
                {
                    System.Console.WriteLine("{0} / {1}", i, files.Length);
                }

                long start_ticks = DateTime.Now.Ticks;

                DMesh3Builder builder     = new DMesh3Builder();
                StandardMeshReader reader = new StandardMeshReader()
                {
                    MeshBuilder = builder
                };
                IOReadResult result = reader.Read(filename, ReadOptions.Defaults);
                if (result.code != IOCode.Ok)
                {
                    System.Console.WriteLine("{0} FAILED TO READ!", filename);
                    failures.SafeAdd(filename);
                    return;
                }

                DMesh3 mesh = builder.Meshes[0];
                for (int k = 1; k < builder.Meshes.Count; ++k)
                {
                    MeshEditor.Append(mesh, builder.Meshes[k]);
                }
                DMesh3 before = new DMesh3(mesh);


                try {
                    MeshAutoRepair repair = new MeshAutoRepair(mesh);
                    repair.Apply();
                } catch (Exception e) {
                    System.Console.WriteLine("EXCEPTION {0} : {1}", filename, e.Message);
                    failures.SafeAdd(filename);
                    return;
                }

                if (mesh.IsClosed() == false)
                {
                    failures.SafeAdd(filename);
                    Util.WriteDebugMesh(before, WRITEPATH + Path.GetFileNameWithoutExtension(filename) + ".obj");
                    Util.WriteDebugMesh(mesh, WRITEPATH + Path.GetFileNameWithoutExtension(filename) + ".failed.obj");
                    return;
                }
                else
                {
                    if (mesh.CheckValidity(false, FailMode.ReturnOnly) == false)
                    {
                        System.Console.WriteLine("INVALID {0}", filename);
                        failures.SafeAdd(filename);

                        Util.WriteDebugMesh(before, WRITEPATH + Path.GetFileNameWithoutExtension(filename) + ".obj");
                        Util.WriteDebugMesh(mesh, WRITEPATH + Path.GetFileNameWithoutExtension(filename) + ".invalid.obj");

                        return;
                    }
                }
            });


            //foreach (string failure in failures.Result) {
            //    System.Console.WriteLine("FAIL: {0}", failure);
            //}
            System.Console.WriteLine("repaired {0} of {1}", files.Length - failures.Result.Count, files.Length);

            TestUtil.WriteTestOutputStrings(make_strings(failures), "thingi10k_autorepair_failures_new.txt");
        }
Ejemplo n.º 9
0
        public Mesh Repair(Mesh sourceMesh, CancellationToken cancellationToken)
        {
            var inMesh = sourceMesh;

            try
            {
                if (WeldVertices)
                {
                    inMesh = sourceMesh.Copy(cancellationToken);
                    inMesh.CleanAndMerge();
                    if (!FaceOrientation &&
                        RemoveMode == RemoveModes.None &&
                        !WeldEdges &&
                        !FillHoles)
                    {
                        return(inMesh);
                    }
                }

                var    mesh              = inMesh.ToDMesh3();
                int    repeatCount       = 0;
                int    erosionIterations = 5;
                double repairTolerance   = MathUtil.ZeroTolerancef;
                double minEdgeLengthTol  = 0.0001;

repeat_all:

                if (FaceOrientation)
                {
                    // make sure orientation of connected components is consistent
                    // TODO: what about mobius strip problems?
                    RepairOrientation(mesh, cancellationToken, true);
                }

                if (RemoveMode != RemoveModes.None)
                {
                    // Remove parts of the mesh we don't want before we bother with anything else
                    // TODO: maybe we need to repair orientation first? if we want to use MWN (MeshWindingNumber)...
                    RemoveInside(mesh);
                    cancellationToken.ThrowIfCancellationRequested();
                }

                if (WeldEdges || FillHoles)
                {
                    // Do safe close-cracks to handle easy cases
                    RepairCracks(mesh, true, repairTolerance);

                    if (mesh.IsClosed())
                    {
                        goto all_done;
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    // Collapse tiny edges and then try easy cases again, and
                    // then allow for handling of ambiguous cases
                    CollapseAllDegenerateEdges(mesh, cancellationToken, repairTolerance * 0.5, true);
                    cancellationToken.ThrowIfCancellationRequested();

                    RepairCracks(mesh, true, 2 * repairTolerance);
                    cancellationToken.ThrowIfCancellationRequested();

                    RepairCracks(mesh, false, 2 * repairTolerance);
                    cancellationToken.ThrowIfCancellationRequested();

                    if (mesh.IsClosed())
                    {
                        goto all_done;
                    }

                    // Possibly we have joined regions with different orientation (is it?), fix that
                    // TODO: mobius strips again
                    RepairOrientation(mesh, cancellationToken, true);
                    cancellationToken.ThrowIfCancellationRequested();

                    // get rid of any remaining single-triangles before we start filling holes
                    MeshEditor.RemoveIsolatedTriangles(mesh);
                }

                if (FillHoles)
                {
                    // Ok, fill simple holes.
                    int nRemainingBowties = 0;
                    FillTrivialHoles(mesh, cancellationToken, out int nHoles, out bool bSawSpans);
                    cancellationToken.ThrowIfCancellationRequested();

                    if (mesh.IsClosed())
                    {
                        goto all_done;
                    }

                    // Now fill harder holes. If we saw spans, that means boundary loops could
                    // not be resolved in some cases, do we disconnect bowties and try again.
                    FillAnyHoles(mesh, cancellationToken, out nHoles, out bSawSpans);
                    cancellationToken.ThrowIfCancellationRequested();

                    if (bSawSpans)
                    {
                        DisconnectBowties(mesh, out nRemainingBowties);
                        FillAnyHoles(mesh, cancellationToken, out nHoles, out bSawSpans);
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    if (mesh.IsClosed())
                    {
                        goto all_done;
                    }

                    // We may have a closed mesh now but it might still have bowties (eg
                    // tetrahedra sharing vtx case). So disconnect those.
                    DisconnectBowties(mesh, out nRemainingBowties);
                    cancellationToken.ThrowIfCancellationRequested();

                    // If the mesh is not closed, we will do one more round to try again.
                    if (repeatCount == 0 && mesh.IsClosed() == false)
                    {
                        repeatCount++;
                        goto repeat_all;
                    }

                    // Ok, we didn't get anywhere on our first repeat. If we are still not
                    // closed, we will try deleting boundary triangles and repeating.
                    // Repeat this N times.
                    if (repeatCount <= erosionIterations && mesh.IsClosed() == false)
                    {
                        repeatCount++;
                        var bdry_faces = new MeshFaceSelection(mesh);
                        foreach (int eid in MeshIterators.BoundaryEdges(mesh))
                        {
                            bdry_faces.SelectEdgeTris(eid);
                        }

                        MeshEditor.RemoveTriangles(mesh, bdry_faces, true);
                        goto repeat_all;
                    }
                }

all_done:

                // and do a final clean up of the model
                if (FillHoles)
                {
                    // Remove tiny edges
                    if (minEdgeLengthTol > 0)
                    {
                        CollapseAllDegenerateEdges(mesh, cancellationToken, minEdgeLengthTol, false);
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    // finally do global orientation
                    RepairOrientation(mesh, cancellationToken, true);
                    cancellationToken.ThrowIfCancellationRequested();
                }

                return(mesh.ToMesh());
            }
            catch (OperationCanceledException)
            {
                return(inMesh);
            }
        }
Ejemplo n.º 10
0
        public static void test_write_solids()
        {
            //string FORMAT = ".obj";
            string FORMAT    = ".g3mesh";
            string WRITEPATH = "E:\\Thingi10K\\closed\\";

            string[] files = File.ReadAllLines("E:\\Thingi10K\\current\\thingi10k_closed.txt");
            SafeListBuilder <string> failures = new SafeListBuilder <string>();

            if (!Directory.Exists(WRITEPATH))
            {
                Directory.CreateDirectory(WRITEPATH);
            }

            int k = 0;

            gParallel.ForEach(files, (filename) => {
                int i = k;
                Interlocked.Increment(ref k);
                if (i % 500 == 0)
                {
                    System.Console.WriteLine("{0} : {1}", i, files.Length);
                }

                long start_ticks = DateTime.Now.Ticks;

                DMesh3Builder builder     = new DMesh3Builder();
                StandardMeshReader reader = new StandardMeshReader()
                {
                    MeshBuilder = builder
                };
                IOReadResult result = reader.Read(filename, ReadOptions.Defaults);
                if (result.code != IOCode.Ok)
                {
                    System.Console.WriteLine("{0} FAILED!", filename);
                    failures.SafeAdd(filename);
                    return;
                }

                DMesh3 combineMesh = new DMesh3();
                if (builder.Meshes.Count == 1)
                {
                    combineMesh = builder.Meshes[0];
                }
                else
                {
                    foreach (DMesh3 mesh in builder.Meshes)
                    {
                        MeshEditor.Append(combineMesh, mesh);
                    }
                }


                if (combineMesh.IsClosed() == false)
                {
                    MergeCoincidentEdges closeCracks = new MergeCoincidentEdges(combineMesh);
                    closeCracks.Apply();
                }

                if (combineMesh.IsClosed() == false)
                {
                    System.Console.WriteLine("NOT CLOSED: {0}", filename);
                    return;
                }

                string outPath = Path.Combine(WRITEPATH, Path.GetFileNameWithoutExtension(filename) + FORMAT);
                StandardMeshWriter.WriteMesh(outPath, combineMesh, WriteOptions.Defaults);
            });
        }
Ejemplo n.º 11
0
        public static void test_tube_generator()
        {
            Polygon2d  circle_path = Polygon2d.MakeCircle(50, 64);
            PolyLine2d arc_path    = new PolyLine2d(circle_path.Vertices.Take(circle_path.VertexCount / 2));
            Polygon2d  irreg_path  = new Polygon2d();

            for (int k = 0; k < circle_path.VertexCount; ++k)
            {
                irreg_path.AppendVertex(circle_path[k]);
                k += k / 2;
            }
            PolyLine2d irreg_arc_path = new PolyLine2d(irreg_path.Vertices.Take(circle_path.VertexCount - 1));

            Polygon2d square_profile = Polygon2d.MakeCircle(7, 32);

            square_profile.Translate(4 * Vector2d.One);
            //square_profile[0] = 20 * square_profile[0].Normalized;

            bool no_shared = true;

            WriteGeneratedMesh(
                new TubeGenerator(circle_path, Frame3f.Identity, square_profile)
            {
                WantUVs = true, NoSharedVertices = no_shared
            },
                "tubegen_loop_standarduv.obj");

            WriteGeneratedMesh(
                new TubeGenerator(irreg_path, Frame3f.Identity, square_profile)
            {
                WantUVs = true, NoSharedVertices = no_shared
            },
                "tubegen_irregloop_standarduv.obj");

            WriteGeneratedMesh(
                new TubeGenerator(arc_path, Frame3f.Identity, square_profile)
            {
                WantUVs = true, NoSharedVertices = no_shared
            },
                "tubegen_arc_standarduv.obj");

            WriteGeneratedMesh(
                new TubeGenerator(irreg_arc_path, Frame3f.Identity, square_profile)
            {
                WantUVs = true, NoSharedVertices = no_shared
            },
                "tubegen_irregarc_standarduv.obj");



            // append tube border around each hole of input mesh
            DMesh3            inMesh   = TestUtil.LoadTestInputMesh("n_holed_bunny.obj");
            Polygon2d         bdrycirc = Polygon2d.MakeCircle(0.25, 6);
            MeshBoundaryLoops loops    = new MeshBoundaryLoops(inMesh);

            foreach (EdgeLoop loop in loops)
            {
                DCurve3       curve = loop.ToCurve().ResampleSharpTurns();
                TubeGenerator gen   = new TubeGenerator(curve, bdrycirc)
                {
                    NoSharedVertices = false
                };
                MeshEditor.Append(inMesh, gen.Generate().MakeDMesh());
            }
            TestUtil.WriteTestOutputMesh(inMesh, "boundary_tubes.obj");
        }
Ejemplo n.º 12
0
 void Awake()
 {
     _target = target as MeshEditor;
     _target.LoadMesh();
     ReloadSerializedProperties();
 }
Ejemplo n.º 13
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();
        }
Ejemplo n.º 14
0
        protected virtual DMesh3 update_step_2(DMesh3 meshIn)
        {
            double unsigned_offset = Math.Abs(distance);
            int    exact_cells     = (int)(unsigned_offset / grid_cell_size) + 1;

            // only use spatial DS if we are computing enough cells
            bool compute_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial(
                input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z) != null;
            DMeshAABBTree3         use_spatial = (compute_spatial) ? new DMeshAABBTree3(meshIn, true) : null;
            MeshSignedDistanceGrid sdf         = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial)
            {
                ExactBandWidth = exact_cells
            };

            if (use_spatial != null)
            {
                sdf.NarrowBandMaxDistance = unsigned_offset + grid_cell_size;
                sdf.ComputeMode           = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill;
            }

            sdf.CancelF = is_invalidated;
            sdf.Compute();
            if (is_invalidated())
            {
                return(null);
            }

            var           iso = new DenseGridTrilinearImplicit(sdf.Grid, sdf.GridOrigin, sdf.CellSize);
            MarchingCubes c   = new MarchingCubes();

            c.Implicit = iso;

            if (op_type == OperationTypes.Close)
            {
                c.IsoValue = -distance;
            }
            else
            {
                c.IsoValue = distance;
            }

            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(distance + 3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.LerpSteps;
            c.RootModeSteps = 5;

            c.CancelF = is_invalidated;
            c.Generate();
            if (is_invalidated())
            {
                return(null);
            }

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize * 0.5, 3, true);
            if (is_invalidated())
            {
                return(null);
            }

            if (min_component_volume > 0)
            {
                MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume);
            }
            if (is_invalidated())
            {
                return(null);
            }

            return(c.Mesh);
        }
Ejemplo n.º 15
0
        async Task complete_import(string sFilename, DMesh3Builder builder, Action <string> onCompletedF)
        {
            AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty;

            foreach (DMesh3 mesh in builder.Meshes)
            {
                bounds.Contain(mesh.CachedBounds);
            }
            Vector3d centerPt = bounds.Center;
            Vector3d basePt   = centerPt - bounds.Height * 0.5f * Vector3d.AxisY;

            Vector3d vTranslate = basePt;
            await Task.Run(() => {
                foreach (DMesh3 mesh in builder.Meshes)
                {
                    MeshTransforms.Translate(mesh, -vTranslate);
                }
            });

            bool     bFirst        = (CC.Objects.PrintMeshes.Count == 0);
            Vector3d postTranslate = Vector3d.Zero;

            switch (CCPreferences.ImportTransformMode)
            {
            case CCPreferences.ImportTransformModes.AutoCenterAll:
                break;

            case CCPreferences.ImportTransformModes.AutoCenterFirst:
                if (bFirst)
                {
                    CCState.SceneImportTransform = vTranslate;
                }
                postTranslate = vTranslate - CCState.SceneImportTransform;
                break;

            case CCPreferences.ImportTransformModes.NoAutoCenter:
                postTranslate = vTranslate;
                break;
            }

            // compact input meshes
            await Task.Run(() => {
                gParallel.ForEach(builder.Meshes, (mesh) => {
                    MeshEditor.RemoveUnusedVertices(mesh);
                });
                gParallel.ForEach(Interval1i.Range(builder.Meshes.Count), (k) => {
                    if (builder.Meshes[k].IsCompact == false)
                    {
                        builder.Meshes[k] = new DMesh3(builder.Meshes[k], true);
                    }
                });
            });

            string sBaseName = Path.GetFileNameWithoutExtension(sFilename);

            foreach (DMesh3 mesh in builder.Meshes)
            {
                PrintMeshSO meshSO = new PrintMeshSO();
                meshSO.Create(mesh, CCMaterials.PrintMeshMaterial);
                meshSO.UpDirection = UpDirection.ZUp;

                Frame3f f = meshSO.GetLocalFrame(CoordSpace.ObjectCoords);
                f.Origin = f.Origin + (Vector3f)postTranslate;
                meshSO.SetLocalFrame(f, CoordSpace.ObjectCoords);

                // if only one mesh, we can keep a reference
                if (builder.Meshes.Count == 1)
                {
                    meshSO.SourceFilePath        = sFilename;
                    meshSO.LastReadFileTimestamp = File.GetLastWriteTime(SourceFilePath).Ticks;
                }

                meshSO.Name = UniqueNames.GetNext(sBaseName);

                CCActions.AddNewPrintMesh(meshSO);
            }

            if (onCompletedF != null)
            {
                onCompletedF(sFilename);
            }
        }
Ejemplo n.º 16
0
    private void OnPostRender()
    {
        List <MeshEditor> toDraw = new List <MeshEditor>();

        foreach (var controller in FindObjectsOfType <WandController>())
        {
            MeshEditor closest = null;
            float      dist    = float.MaxValue;
            foreach (var m in FindObjectsOfType <MeshEditor>())
            {
                if (m.gameObject.GetComponent <ObjectID>())
                {
                    m.gameObject.GetComponent <ObjectID>().OutlineRenderer.enabled = false;
                }
                var d = Vector3.Distance(controller.transform.position, m.transform.position);
                if (d < dist)
                {
                    dist    = d;
                    closest = m;
                }
            }
            if (closest != null && !toDraw.Contains(closest))
            {
                toDraw.Add(closest);
            }
        }

        foreach (var m in toDraw)
        {
            try
            {
                Material mat = new Material(Shader.Find("Sprites/Default"));
                mat.color = Color.green;
                Transform trans = m.transform;
                if (m.GetComponent <ObjectID>())
                {
                    m.GetComponent <ObjectID>().OutlineRenderer.enabled = true;
                }
                GL.PushMatrix();
                mat.SetPass(0);
                GL.Begin(GL.TRIANGLES);
                switch (ModeSelector.CurrentMode)
                {
                case ModeSelector.EditMode.VERTEX:
                    // Set your materials

                    foreach (var v in m.GetComponent <MeshFilter>().mesh.vertices)
                    {
                        GL.Vertex(trans.TransformPoint(v + (1 / trans.lossyScale.x) * new Vector3(0, 0.015f, 0)));
                        GL.Vertex(trans.TransformPoint(v + (1 / trans.lossyScale.x) * new Vector3(-.006f, -0.004f, 0)));
                        GL.Vertex(trans.TransformPoint(v + (1 / trans.lossyScale.x) * new Vector3(.006f, -0.004f, 0)));
                    }
                    break;

                case ModeSelector.EditMode.EDGE:
                    // Set your materials
                    if (m.Edges == null || m.Edges.Count == 0 || trans == null)
                    {
                        continue;
                    }
                    foreach (var e in m.Edges)
                    {
                        GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(0, 0.015f, 0)));
                        GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(-.006f, -0.004f, 0)));
                        GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(.006f, -0.004f, 0)));
                    }
                    break;

                case ModeSelector.EditMode.FACE:
                    if (m.GetComponent <ObjectID>())
                    {
                        m.GetComponent <ObjectID>().OutlineRenderer.material = FindObjectOfType <FaceTool>().OutlineMaterial;
                    }
                    if (m.Faces == null || m.Faces.Length == 0 || trans == null)
                    {
                        continue;
                    }
                    foreach (var f in m.Faces)
                    {
                        GL.Vertex(trans.TransformPoint(f.center + (1 / trans.lossyScale.x) * new Vector3(0, 0.015f, 0)));
                        GL.Vertex(trans.TransformPoint(f.center + (1 / trans.lossyScale.x) * new Vector3(-.006f, -0.004f, 0)));
                        GL.Vertex(trans.TransformPoint(f.center + (1 / trans.lossyScale.x) * new Vector3(.006f, -0.004f, 0)));
                    }
                    break;

                case ModeSelector.EditMode.OBJECT:

                    break;
                }
            }

            finally {
                GL.End();
                GL.PopMatrix();
            }
        }

        if (!DrawSelection)
        {
            return;
        }
        foreach (var e in FindObjectOfType <SelectionTool>().Selection)
        {
            try
            {
                Material mat = new Material(Shader.Find("Sprites/Default"));
                mat.color = Color.red;
                GL.PushMatrix();
                mat.SetPass(0);
                GL.Begin(GL.TRIANGLES);
                Transform trans = e.Editor.transform;
                if (e is MeshEditor.Edge)
                {
                    GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(0, 0.015f, 0)));
                    GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(-.009f, -0.006f, 0)));
                    GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(.009f, -0.006f, 0)));
                }
                else if (e is MeshEditor.VertexGroup)
                {
                    GL.Vertex((e as MeshEditor.VertexGroup).WorldPosition + (1 / 1.5f * trans.lossyScale.x) * new Vector3(0, 0.015f, 0));
                    GL.Vertex((e as MeshEditor.VertexGroup).WorldPosition + (1 / 1.5f * trans.lossyScale.x) * new Vector3(-.009f, -0.006f, 0));
                    GL.Vertex((e as MeshEditor.VertexGroup).WorldPosition + (1 / 1.5f * trans.lossyScale.x) * new Vector3(.009f, -0.006f, 0));
                }
                else if (e is MeshEditor.Face)
                {
                    GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(0, 0.015f, 0)));
                    GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(-.009f, -0.006f, 0)));
                    GL.Vertex(trans.TransformPoint(e.center + (1 / trans.lossyScale.x) * new Vector3(.009f, -0.006f, 0)));
                }
            }

            finally
            {
                GL.End();
                GL.PopMatrix();
            }
        }
    }
Ejemplo n.º 17
0
        protected virtual DMesh3 compute_wrap()
        {
            cache_input_sdfs();
            if (is_invalidated())
            {
                return(null);
            }

            BoundedImplicitFunction3d iso = null;

            if (op_type == OpTypes.Union)
            {
                iso = new ImplicitNaryUnion3d()
                {
                    Children = new List <BoundedImplicitFunction3d>(cached_isos)
                };
            }
            else if (op_type == OpTypes.Intersection)
            {
                iso = new ImplicitNaryIntersection3d()
                {
                    Children = new List <BoundedImplicitFunction3d>(cached_isos)
                };
            }
            else if (op_type == OpTypes.Difference)
            {
                iso = new ImplicitNaryDifference3d()
                {
                    A    = cached_isos[0],
                    BSet = new List <BoundedImplicitFunction3d>(cached_isos.Skip(1))
                };
            }

            MarchingCubes c = new MarchingCubes();

            c.Implicit = iso;
            c.IsoValue = 0;
            c.Bounds   = iso.Bounds();
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.Bisection;
            c.RootModeSteps = 5;

            c.CancelF = is_invalidated;
            c.Generate();
            if (is_invalidated())
            {
                return(null);
            }

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize / 2, 3, true);
            if (is_invalidated())
            {
                return(null);
            }

            if (min_component_volume > 0)
            {
                MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume);
            }
            if (is_invalidated())
            {
                return(null);
            }

            return(c.Mesh);
        }
Ejemplo n.º 18
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));
            };

            var     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.
            var 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
            var faceROI = new MeshFaceSelection(Mesh, vertexROI, 1);

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

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

            // save 3D positions of unmodified mesh
            var 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?
            var projectMesh = new DMesh3(roiMesh);
            var projecter   = new DMeshAABBTree3(projectMesh, true);

            var 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
            var 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)
            {
                var 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);
        }
Ejemplo n.º 19
0
        protected virtual DMesh3 compute_wrap()
        {
            DMesh3 meshIn = MeshSource.GetDMeshUnsafe();

            double unsigned_offset = Math.Abs(distance);

            if (cached_sdf == null ||
                unsigned_offset > cached_sdf_max_offset ||
                grid_cell_size != cached_sdf.CellSize)
            {
                DMeshAABBTree3 use_spatial = input_spatial;
                CachingMeshSDF sdf         = new CachingMeshSDF(meshIn, grid_cell_size, use_spatial);
                sdf.MaxOffsetDistance = 2 * (float)unsigned_offset;

                sdf.CancelF = is_invalidated;
                sdf.Initialize();
                if (is_invalidated())
                {
                    return(null);
                }

                cached_sdf            = sdf;
                cached_sdf_max_offset = unsigned_offset;
                cached_sdf_bounds     = meshIn.CachedBounds;
            }

            var grid_iso = new CachingMeshSDFImplicit(cached_sdf);
            // currently MCPro-Continuation does not work w/ non-zero
            //   isovalues, so we have to shift our target offset externally
            var iso = new ImplicitOffset3d()
            {
                A = grid_iso, Offset = distance
            };

            MarchingCubesPro c = new MarchingCubesPro();

            c.Implicit = iso;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(distance + 3 * c.CubeSize);

            c.CancelF = is_invalidated;
            c.GenerateContinuation(offset_seeds(meshIn, distance));
            if (is_invalidated())
            {
                return(null);
            }

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize * 0.5, 3, true);
            if (is_invalidated())
            {
                return(null);
            }

            if (min_component_volume > 0)
            {
                MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume);
            }
            if (is_invalidated())
            {
                return(null);
            }

            DMesh3 offsetMesh = c.Mesh;

            MeshConnectedComponents comp = new MeshConnectedComponents(offsetMesh);

            comp.FindConnectedT();
            if (is_invalidated())
            {
                return(null);
            }
            DSubmesh3Set subMeshes = new DSubmesh3Set(offsetMesh, comp);

            if (is_invalidated())
            {
                return(null);
            }

            MeshSpatialSort sort = new MeshSpatialSort();

            foreach (var subMesh in subMeshes)
            {
                sort.AddMesh(subMesh.SubMesh, subMesh);
            }
            sort.Sort();
            if (is_invalidated())
            {
                return(null);
            }

            DMesh3 outerMesh = new DMesh3();

            foreach (var solid in sort.Solids)
            {
                DMesh3 outer = solid.Outer.Mesh;
                //if (is_outward_oriented(outer) == false)
                //    outer.ReverseOrientation();
                MeshEditor.Append(outerMesh, outer);
            }
            if (is_invalidated())
            {
                return(null);
            }

            return(compute_inset(outerMesh));
        }
Ejemplo n.º 20
0
        public bool Apply()
        {
            bool do_checks = false;

            if (do_checks)
            {
                Mesh.CheckValidity();
            }


            /*
             * Remove parts of the mesh we don't want before we bother with anything else
             * TODO: maybe we need to repair orientation first? if we want to use MWN...
             */
            do_remove_inside();
            if (Cancelled())
            {
                return(false);
            }

            int repeat_count = 0;

repeat_all:

            /*
             * make sure orientation of connected components is consistent
             * TODO: what about mobius strip problems?
             */
            repair_orientation(false);
            if (Cancelled())
            {
                return(false);
            }

            /*
             *  Do safe close-cracks to handle easy cases
             */

            repair_cracks(true, RepairTolerance);
            if (Mesh.IsClosed())
            {
                goto all_done;
            }
            if (Cancelled())
            {
                return(false);
            }

            /*
             * Collapse tiny edges and then try easy cases again, and
             * then allow for handling of ambiguous cases
             */

            collapse_all_degenerate_edges(RepairTolerance * 0.5, true);
            if (Cancelled())
            {
                return(false);
            }
            repair_cracks(true, 2 * RepairTolerance);
            if (Cancelled())
            {
                return(false);
            }
            repair_cracks(false, 2 * RepairTolerance);
            if (Cancelled())
            {
                return(false);
            }
            if (Mesh.IsClosed())
            {
                goto all_done;
            }

            /*
             * Possibly we have joined regions with different orientation (is it?), fix that
             * TODO: mobius strips again
             */
            repair_orientation(false);
            if (Cancelled())
            {
                return(false);
            }

            if (do_checks)
            {
                Mesh.CheckValidity();
            }

            // get rid of any remaining single-triangles before we start filling holes
            remove_loners();

            /*
             * Ok, fill simple holes.
             */
            int nRemainingBowties = 0;
            int nHoles; bool bSawSpans;

            fill_trivial_holes(out nHoles, out bSawSpans);
            if (Cancelled())
            {
                return(false);
            }
            if (Mesh.IsClosed())
            {
                goto all_done;
            }

            /*
             * Now fill harder holes. If we saw spans, that means boundary loops could
             * not be resolved in some cases, do we disconnect bowties and try again.
             */

            fill_any_holes(out nHoles, out bSawSpans);

            if (Cancelled())
            {
                return(false);
            }
            if (bSawSpans)
            {
                disconnect_bowties(out nRemainingBowties);
                fill_any_holes(out nHoles, out bSawSpans);
            }
            if (Cancelled())
            {
                return(false);
            }
            if (Mesh.IsClosed())
            {
                goto all_done;
            }

            /*
             * We may have a closed mesh now but it might still have bowties (eg
             * tetrahedra sharing vtx case). So disconnect those.
             */
            disconnect_bowties(out nRemainingBowties);
            if (Cancelled())
            {
                return(false);
            }

            /*
             * If the mesh is not closed, we will do one more round to try again.
             */
            if (repeat_count == 0 && Mesh.IsClosed() == false)
            {
                repeat_count++;
                goto repeat_all;
            }

            /*
             * Ok, we didn't get anywhere on our first repeat. If we are still not
             * closed, we will try deleting boundary triangles and repeating.
             * Repeat this N times.
             */
            if (repeat_count <= ErosionIterations && Mesh.IsClosed() == false)
            {
                repeat_count++;
                MeshFaceSelection bdry_faces = new MeshFaceSelection(Mesh);
                foreach (int eid in MeshIterators.BoundaryEdges(Mesh))
                {
                    bdry_faces.SelectEdgeTris(eid);
                }
                MeshEditor.RemoveTriangles(Mesh, bdry_faces, true);
                goto repeat_all;
            }

all_done:

            /*
             * Remove tiny edges
             */
            if (MinEdgeLengthTol > 0)
            {
                collapse_all_degenerate_edges(MinEdgeLengthTol, false);
            }
            if (Cancelled())
            {
                return(false);
            }

            /*
             * finally do global orientation
             */
            repair_orientation(true);
            if (Cancelled())
            {
                return(false);
            }

            if (do_checks)
            {
                Mesh.CheckValidity();
            }

            /*
             * Might as well compact output mesh...
             */
            Mesh = new DMesh3(Mesh, true);
            MeshNormals.QuickCompute(Mesh);

            return(true);
        }
Ejemplo n.º 21
0
        protected virtual void compute_hollow()
        {
            double offset_distance = -wall_thickness;

            if (cached_sdf == null ||
                wall_thickness > cached_sdf_max_offset ||
                grid_cell_size != cached_sdf.CellSize)
            {
                DMesh3 meshIn      = MeshSource.GetDMeshUnsafe();
                int    exact_cells = (int)((wall_thickness) / grid_cell_size) + 1;

                // only use spatial DS if we are computing enough cells
                DMeshAABBTree3         use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial(input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z);
                MeshSignedDistanceGrid sdf         = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial)
                {
                    ExactBandWidth = exact_cells
                };
                if (use_spatial != null)
                {
                    sdf.NarrowBandMaxDistance = wall_thickness + grid_cell_size;
                    sdf.ComputeMode           = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill;
                }

                sdf.CancelF = is_invalidated;
                sdf.Compute();
                if (is_invalidated())
                {
                    return;
                }
                cached_sdf            = sdf;
                cached_sdf_max_offset = wall_thickness;
                cached_sdf_bounds     = meshIn.CachedBounds;
            }

            var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize);
            ImplicitOffset3d shell_field = new ImplicitOffset3d()
            {
                A = iso, Offset = offset_distance
            };
            ImplicitFunction3d use_iso = shell_field;


            if (enable_infill)
            {
                GridDistanceField grid_df = new GridDistanceField()
                {
                    CellSize = infill_spacing,
                    Radius   = infill_thickness * 0.5,
                    Origin   = cached_sdf.GridOrigin
                };
                ImplicitDifference3d diff = new ImplicitDifference3d()
                {
                    A = shell_field, B = grid_df
                };
                use_iso = diff;
            }


            MarchingCubes c = new MarchingCubes();

            c.Implicit = use_iso;
            c.IsoValue = 0;
            c.Bounds   = cached_sdf_bounds;
            c.CubeSize = mesh_cell_size;
            c.Bounds.Expand(offset_distance + 3 * c.CubeSize);
            c.RootMode      = MarchingCubes.RootfindingModes.LerpSteps;
            c.RootModeSteps = 5;

            c.CancelF = is_invalidated;
            c.Generate();
            if (is_invalidated())
            {
                return;
            }

            Reducer r = new Reducer(c.Mesh);

            r.FastCollapsePass(c.CubeSize * 0.5, 3, true);
            if (is_invalidated())
            {
                return;
            }

            //r.ReduceToTriangleCount(c.Mesh.TriangleCount / 5);
            //if (is_invalidated())
            //    return;

            if (min_component_volume > 0)
            {
                MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume);
            }
            if (is_invalidated())
            {
                return;
            }

            c.Mesh.AttachMetadata("is_partial", new object());

            ResultMesh = c.Mesh;
        }