protected virtual IEnumerator CreateDistanceConstraints()
        {
            //Create distance constraints:
            List <int> edges = topology.GetEdgeList();

            distanceConstraintsData = new ObiDistanceConstraintsData();

            List <int> particleIndices   = new List <int>();
            List <int> constraintIndices = new List <int>();

            for (int i = 0; i < edges.Count; i++)
            {
                HalfEdgeMesh.HalfEdge hedge = topology.halfEdges[edges[i]];

                particleIndices.Add(topology.GetHalfEdgeStartVertex(hedge));
                particleIndices.Add(hedge.endVertex);
                constraintIndices.Add(constraintIndices.Count * 2);

                if (i % 500 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiCloth: generating structural constraints...", i / (float)edges.Count));
                }
            }
            constraintIndices.Add(constraintIndices.Count * 2);

            int[] constraintColors = GraphColoring.Colorize(particleIndices.ToArray(), constraintIndices.ToArray());
            for (int i = 0; i < constraintColors.Length; ++i)
            {
                int color  = constraintColors[i];
                int cIndex = constraintIndices[i];

                // Add a new batch if needed:
                if (color >= distanceConstraintsData.GetBatchCount())
                {
                    distanceConstraintsData.AddBatch(new ObiDistanceConstraintsBatch());
                }

                HalfEdgeMesh.HalfEdge hedge       = topology.halfEdges[edges[i]];
                HalfEdgeMesh.Vertex   startVertex = topology.vertices[topology.GetHalfEdgeStartVertex(hedge)];
                HalfEdgeMesh.Vertex   endVertex   = topology.vertices[hedge.endVertex];

                distanceConstraintsData.batches[color].AddConstraint(new Vector2Int(particleIndices[cIndex], particleIndices[cIndex + 1]),
                                                                     Vector3.Distance(Vector3.Scale(scale, startVertex.position), Vector3.Scale(scale, endVertex.position)));
            }

            // Set initial amount of active constraints:
            for (int i = 0; i < distanceConstraintsData.batches.Count; ++i)
            {
                distanceConstraintsData.batches[i].activeConstraintCount = distanceConstraintsData.batches[i].constraintCount;
            }
        }
 public IEnumerable <IObiConstraints> GetConstraints()
 {
     if (distanceConstraintsData != null && distanceConstraintsData.GetBatchCount() > 0)
     {
         yield return(distanceConstraintsData);
     }
     if (bendConstraintsData != null && bendConstraintsData.GetBatchCount() > 0)
     {
         yield return(bendConstraintsData);
     }
     if (pinConstraintsData != null && pinConstraintsData.GetBatchCount() > 0)
     {
         yield return(pinConstraintsData);
     }
     if (skinConstraintsData != null && skinConstraintsData.GetBatchCount() > 0)
     {
         yield return(skinConstraintsData);
     }
     if (tetherConstraintsData != null && tetherConstraintsData.GetBatchCount() > 0)
     {
         yield return(tetherConstraintsData);
     }
     if (stretchShearConstraintsData != null && stretchShearConstraintsData.GetBatchCount() > 0)
     {
         yield return(stretchShearConstraintsData);
     }
     if (bendTwistConstraintsData != null && bendTwistConstraintsData.GetBatchCount() > 0)
     {
         yield return(bendTwistConstraintsData);
     }
     if (shapeMatchingConstraintsData != null && shapeMatchingConstraintsData.GetBatchCount() > 0)
     {
         yield return(shapeMatchingConstraintsData);
     }
     if (aerodynamicConstraintsData != null && aerodynamicConstraintsData.GetBatchCount() > 0)
     {
         yield return(aerodynamicConstraintsData);
     }
     if (chainConstraintsData != null && chainConstraintsData.GetBatchCount() > 0)
     {
         yield return(chainConstraintsData);
     }
     if (volumeConstraintsData != null && volumeConstraintsData.GetBatchCount() > 0)
     {
         yield return(volumeConstraintsData);
     }
 }