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); }