Exemple #1
0
    private void Start()
    {
        int segmentCount = (int)(length / segmentLength) + 1;

        points = new Point[segmentCount + 1];
        for (int i = 0; i < points.Length; i++)
        {
            Vector3 position = Vector3.Lerp(transform.position, plug.transform.position, i / (float)points.Length) + Random.insideUnitSphere * 0.05f;
            points[i] = new Point(position);
            VerletPhysicsManager.AddPoint(points[i]);

            if (i == 0)
            {
                anchorA = VerletPhysicsManager.AddAnchorConstraint(points[i], transform.position + transform.forward * thickness);
            }
            else if (i == points.Length - 1)
            {
                anchorB = VerletPhysicsManager.AddAnchorConstraint(points[i], plug.transform.position + plug.transform.forward * thickness);
            }

            if (i > 0)
            {
                EdgeConstraint edgeConstraint = VerletPhysicsManager.AddEdgeConstraint(points[i], points[i - 1], segmentLength);
                if (i == points.Length - 1)
                {
                    edge = edgeConstraint;
                }
            }

            if (i > 1)
            {
                VerletPhysicsManager.AddEdgeConstraint(points[i], points[i - 2], segmentLength * 2f - 0.001f, EdgeConstraintType.MinimumDistance);
            }
        }

        tubePositions = new Vector3[points.Length + 2];
        tubeRenderer._useWorldSpace = true;
        UpdateTubePositions();
    }
        // most of this boilerplate comes from the Remesher class


        private ProcessResult ProcessEdgeFlip(int edgeID)
        {
            EdgeConstraint constraint =
                (constraints == null) ? EdgeConstraint.Unconstrained : constraints.GetEdgeConstraint(edgeID);

            if (constraint.NoModifications)
            {
                return(ProcessResult.Ignored_EdgeIsFullyConstrained);
            }
            if (PreventFlip.Contains(edgeID))
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }
            if (!constraint.CanFlip)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }


            // look up verts and tris for this edge
            int a = 0, b = 0, t0 = 0, t1 = 0;

            if (mesh.GetEdge(edgeID, ref a, ref b, ref t0, ref t1) == false)
            {
                return(ProcessResult.Failed_NotAnEdge);
            }
            bool bIsBoundaryEdge = (t1 == DMesh3.InvalidID);

            if (bIsBoundaryEdge)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }

            // avoid to flip edge if the shape of t1 and t2 is concave so that
            // external the profile of the flip stays the same
            //
            Index2i ov = mesh.GetEdgeOpposingV(edgeID);
            int     c = ov.a, d = ov.b;

            if (flip_inverts_normals(a, b, c, d, t0))
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }


            // only flip if two triangles are coplanar
            //
            var      tri0 = mesh.GetTriangle(t0);
            Vector3d n0   = MathUtil.Normal(
                mesh.GetVertex(tri0.a),
                mesh.GetVertex(tri0.b),
                mesh.GetVertex(tri0.c)
                );
            var      tri1 = mesh.GetTriangle(t1);
            Vector3d n1   = MathUtil.Normal(
                mesh.GetVertex(tri1.a),
                mesh.GetVertex(tri1.b),
                mesh.GetVertex(tri1.c)
                );

            // as long as normals are equal or opposite, triangle are coplanar
            // and we can flip
            var differDirect   = !n1.EpsilonEqual(n0, precision);
            var differInverted = !n1.EpsilonEqual(n0 * -1, precision);

            if (differDirect && differInverted)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }

            // impacted edges are the ones around the triangles that we are considering to flip
            // each edge might have another triangle that could be merged after the flip
            //
            // we will perform the flip only if this is the case
            //
            var doFlip       = false;
            var impactedTris = new int[] { t0, t1 };

            // evaluate if flip is beneficial
            foreach (var impactedTri in impactedTris)
            {
                // four points involved in an edge flip if we are evaluating one of the current triagles
                // the candidate merging vector would be the vertex not shared (either c or d, but not in impactedTri)
                var candidateMerging = new List <int>()
                {
                    c, d
                }.Except(mesh.GetTriangle(impactedTri).array).FirstOrDefault();

                // the 'other' edges on one the triangles that we are checking to flip
                var potentialMergedEdges = mesh.GetTriEdges(impactedTri).array.ToList();
                potentialMergedEdges.Remove(edgeID);
                foreach (var impactedEdge in potentialMergedEdges)
                {
                    var opposingVertices = mesh.GetEdgeOpposingV(impactedEdge).array.ToList();
                    opposingVertices.RemoveAll(x => x == a || x == b || x == -1);
                    // Debug.WriteLine(opposingVertices.Count);
                    foreach (var opposingVertex in opposingVertices)
                    {
                        // only the one vertex would be found, the list might be empty if -1 was also removed
                        // get the edge in question
                        var evaluatingEdge = mesh.GetEdge(impactedEdge);
                        var keep           = EvaluateRemoval(a, b, candidateMerging, opposingVertex);
                        if (keep.Count != 2)
                        {
                            doFlip = true;
                        }
                    }
                    if (doFlip)
                    {
                        break;
                    }
                }
                if (doFlip)
                {
                    break;
                }
            }

            if (!doFlip)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }

            DMesh3.EdgeFlipInfo flipInfo;
            MeshResult          result = mesh.FlipEdge(edgeID, out flipInfo);

            if (result == MeshResult.Ok)
            {
                var impactedEdges = new List <int>(6);
                impactedEdges.AddRange(mesh.GetTriEdges(t0).array);
                impactedEdges.AddRange(mesh.GetTriEdges(t1).array);
                impactedEdges.RemoveAll(x => x == edgeID);

                PreventFlip.AddRange(impactedEdges);

                return(ProcessResult.Ok_Flipped);
            }
            return(ProcessResult.Failed_OpNotSuccessful);
        }
        private ProcessResult ProcessEdgeDiagonalFlip(int edgeID)
        {
            EdgeConstraint constraint =
                (constraints == null) ? EdgeConstraint.Unconstrained : constraints.GetEdgeConstraint(edgeID);

            if (constraint.NoModifications)
            {
                return(ProcessResult.Ignored_EdgeIsFullyConstrained);
            }
            if (PreventFlip.Contains(edgeID))
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }
            if (!constraint.CanFlip)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }


            // look up verts and tris for this edge
            int a = 0, b = 0, t0 = 0, t1 = 0;

            if (mesh.GetEdge(edgeID, ref a, ref b, ref t0, ref t1) == false)
            {
                return(ProcessResult.Failed_NotAnEdge);
            }
            bool bIsBoundaryEdge = (t1 == DMesh3.InvalidID);

            if (bIsBoundaryEdge)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }


            Index2i ov = mesh.GetEdgeOpposingV(edgeID);
            int     c = ov.a, d = ov.b;

            // we are trying to reduce the lenght of the diagonal by flipping
            // we are ready to compute diagonals here
            //
            var currentDiag = getLen(a, b);
            var flippedDiag = getLen(c, d);

            if (currentDiag - flippedDiag < MathUtil.Epsilon)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }

            // avoid to flip edge if the shape of t1 and t2 is concave so that
            // external the profile of the flip stays the same
            //
            if (flip_inverts_normals(a, b, c, d, t0))
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }


            // only flip if two triangles are coplanar
            //
            var      tri0 = mesh.GetTriangle(t0);
            Vector3d n0   = MathUtil.Normal(
                mesh.GetVertex(tri0.a),
                mesh.GetVertex(tri0.b),
                mesh.GetVertex(tri0.c)
                );
            var      tri1 = mesh.GetTriangle(t1);
            Vector3d n1   = MathUtil.Normal(
                mesh.GetVertex(tri1.a),
                mesh.GetVertex(tri1.b),
                mesh.GetVertex(tri1.c)
                );

            // as long as normals are equal or opposite, triangle are coplanar
            // and we can flip
            var differDirect   = !n1.EpsilonEqual(n0, precision);
            var differInverted = !n1.EpsilonEqual(n0 * -1, precision);

            if (differDirect && differInverted)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }

            DMesh3.EdgeFlipInfo flipInfo;
            MeshResult          result = mesh.FlipEdge(edgeID, out flipInfo);

            if (result == MeshResult.Ok)
            {
                var impactedEdges = new List <int>(6);
                impactedEdges.AddRange(mesh.GetTriEdges(t0).array);
                impactedEdges.AddRange(mesh.GetTriEdges(t1).array);
                impactedEdges.RemoveAll(x => x == edgeID);

                PreventFlip.AddRange(impactedEdges);

                return(ProcessResult.Ok_Flipped);
            }
            return(ProcessResult.Failed_OpNotSuccessful);
        }
        private ProcessResult ProcessEdgeRemoval(int edgeID)
        {
            EdgeConstraint constraint =
                (constraints == null) ? EdgeConstraint.Unconstrained : constraints.GetEdgeConstraint(edgeID);

            if (constraint.NoModifications)
            {
                return(ProcessResult.Ignored_EdgeIsFullyConstrained);
            }

            // look up verts and tris for this edge
            int a = 0, b = 0, t0 = 0, t1 = 0;

            if (mesh.GetEdge(edgeID, ref a, ref b, ref t0, ref t1) == false)
            {
                return(ProcessResult.Failed_NotAnEdge);
            }

            bool bIsBoundaryEdge = (t1 == DMesh3.InvalidID);

            if (bIsBoundaryEdge)
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }

            Index2i    ov = mesh.GetEdgeOpposingV(edgeID);
            int        c = ov.a, d = ov.b;
            List <int> keep = EvaluateRemoval(a, b, c, d);

            if (keep.Count == 2) // need to keep both, ignore
            {
                return(ProcessResult.Ignored_EdgeIsFine);
            }

            // we can remove the two involved triangles and replace for a single one
            var rem1 = mesh.RemoveTriangle(t0, false, false);

            if (rem1 != MeshResult.Ok)
            {
                return(ProcessResult.Failed_OpNotSuccessful);
            }
            var rem2 = mesh.RemoveTriangle(t1, false, false);

            if (rem2 != MeshResult.Ok)
            {
                return(ProcessResult.Failed_OpNotSuccessful);
            }
            // we only add a trinagle if there was one to keep
            if (keep.Count == 1)
            {
                var add = mesh.AppendTriangle(c, d, keep[0]);
                if (add == DMesh3.InvalidID)
                {
                    return(ProcessResult.Failed_OpNotSuccessful);
                }
            }
            else
            {
                Debug.WriteLine("Warning: no face added.");
            }
            return(ProcessResult.Ok_Removed);
        }