private void AddLCPValues( ref List <int> index, ref List <double> values, int indexVal, KeyValuePair <HashSetStruct, List <DictionaryConstraintValue> > constraintCheckItem, HashSetStruct constraintValuesKey, HashSetStruct symmetricHashSet, Vector3d?linearComponentA, Vector3d angularComponentA, MassData massData, bool componentA) { double mValue = 0.0; if (!constraintCheckItem.Key.Equals(constraintValuesKey) && !constraintCheckItem.Key.Equals(symmetricHashSet)) { for (int i = 0; i < constraintCheckItem.Value.Count; i++) { int innerIndex = constraintCheckItem.Value[i].Index; JacobianConstraint contactB = constraintCheckItem.Value[i].Constraint; var lComponent = contactB.LinearComponentB; var aComponent = contactB.AngularComponentB; if (componentA) { lComponent = contactB.LinearComponentA; aComponent = contactB.AngularComponentA; } mValue = GetLCPMatrixValue( linearComponentA, lComponent, angularComponentA, aComponent, massData); AddValues(ref index, ref values, mValue, innerIndex); } } }
public LinearProblemProperties BuildLCP( JacobianConstraint[] constraints, double timeStep) { LinearProblemBaseProperties baseProperties = new LinearProblemBaseProperties(constraints.Length); Dictionary <HashSetStruct, List <DictionaryConstraintValue> > constraintsDictionary = new Dictionary <HashSetStruct, List <DictionaryConstraintValue> >(); for (int i = 0; i < constraints.Length; i++) { JacobianConstraint itemConstraint = constraints[i]; HashSetStruct hash = new HashSetStruct(itemConstraint.ObjectA.ID, itemConstraint.ObjectB.ID); if (constraintsDictionary.TryGetValue(hash, out List <DictionaryConstraintValue> jc)) { jc.Add(new DictionaryConstraintValue(itemConstraint, i)); } else { constraintsDictionary.Add(hash, new List <DictionaryConstraintValue> { new DictionaryConstraintValue(itemConstraint, i) }); } } Graph graph = new Graph(constraints.Length); var dictionaryArray = constraintsDictionary.ToArray(); var key_ID_A = constraintsDictionary.ToLookup(x => x.Key.ID_A); var key_ID_B = constraintsDictionary.ToLookup(x => x.Key.ID_B); var rangePartitioner = Partitioner.Create( 0, dictionaryArray.Length, Convert.ToInt32(dictionaryArray.Length / EngineParameters.MaxThreadNumber) + 1); double timeFreq = 1.0 / timeStep; Parallel.ForEach( rangePartitioner, new ParallelOptions { MaxDegreeOfParallelism = EngineParameters.MaxThreadNumber }, (range, loopState) => { for (int i = range.Item1; i < range.Item2; i++) { var constraintValues = dictionaryArray[i]; var constraintValueKey = constraintValues.Key; int contactA_ID_A = constraintValues.Key.ID_A; int contactA_ID_B = constraintValues.Key.ID_B; for (int w = 0; w < constraintValues.Value.Count; w++) { JacobianConstraint contactA = constraintValues.Value[w].Constraint; List <int> index = new List <int>(); List <double> values = new List <double>(); int indexVal = constraintValues.Value[w].Index; double correctionVal = contactA.CorrectionValue * timeFreq; double correctionValue = (correctionVal) < 0 ? Math.Max(correctionVal, -EngineParameters.MaxCorrectionValue) : Math.Min(correctionVal, EngineParameters.MaxCorrectionValue); baseProperties.B[indexVal] = correctionValue - contactA.JacobianVelocity - contactA.ConstraintValue; baseProperties.ConstraintsArray[indexVal] = contactA.ContactReference; baseProperties.ConstraintLimit[indexVal] = contactA.ConstraintLimit; baseProperties.ConstraintType[indexVal] = contactA.Type; //Diagonal value double mValue = GetLCPDiagonalValue(contactA) + (contactA.CFM * timeFreq) + EngineParameters.CFM + 1E-40; baseProperties.D[indexVal] = mValue; baseProperties.InvD[indexVal] = 1.0 / mValue; //contactA_ID_A == contactB_ID_A && contactA_ID_B == contactB_ID_B for (int j = 0; j < constraintValues.Value.Count; j++) { int innerIndex = constraintValues.Value[j].Index; if (innerIndex != indexVal) { JacobianConstraint contactB = constraintValues.Value[j].Constraint; mValue = GetLCPMatrixValue( contactA.LinearComponentA, contactB.LinearComponentA, contactA.AngularComponentA, contactB.AngularComponentA, contactA.ObjectA.MassInfo); mValue += GetLCPMatrixValue( contactA.LinearComponentB, contactB.LinearComponentB, contactA.AngularComponentB, contactB.AngularComponentB, contactA.ObjectB.MassInfo); AddValues(ref index, ref values, mValue, innerIndex); } } //contactA_ID_A == contactB_ID_B && contactA_ID_B == contactB_ID_A var symmetricHashSet = new HashSetStruct(contactA_ID_B, contactA_ID_A); if (constraintsDictionary.TryGetValue(symmetricHashSet, out List <DictionaryConstraintValue> symmetricList)) { foreach (var item in symmetricList) { int innerIndex = item.Index; if (innerIndex != indexVal) { JacobianConstraint contactB = item.Constraint; mValue = GetLCPMatrixValue( contactA.LinearComponentA, contactB.LinearComponentB, contactA.AngularComponentA, contactB.AngularComponentB, contactA.ObjectA.MassInfo); mValue += GetLCPMatrixValue( contactA.LinearComponentB, contactB.LinearComponentA, contactA.AngularComponentB, contactB.AngularComponentA, contactA.ObjectB.MassInfo); AddValues(ref index, ref values, mValue, innerIndex); } } } //contactA_ID_A == contactB_ID_A foreach (var constraintCheckItem in key_ID_A[contactA_ID_A]) { AddLCPValues( ref index, ref values, indexVal, constraintCheckItem, constraintValueKey, symmetricHashSet, contactA.LinearComponentA, contactA.AngularComponentA, contactA.ObjectA.MassInfo, true); } //contactA_ID_A == contactB_ID_B foreach (var constraintCheckItem in key_ID_B[contactA_ID_A]) { AddLCPValues( ref index, ref values, indexVal, constraintCheckItem, constraintValueKey, symmetricHashSet, contactA.LinearComponentA, contactA.AngularComponentA, contactA.ObjectA.MassInfo, false); } //contactA_ID_B == contactB_ID_A foreach (var constraintCheckItem in key_ID_A[contactA_ID_B]) { AddLCPValues( ref index, ref values, indexVal, constraintCheckItem, constraintValueKey, symmetricHashSet, contactA.LinearComponentB, contactA.AngularComponentB, contactA.ObjectB.MassInfo, true); } //contactA_ID_B == contactB_ID_B foreach (var constraintCheckItem in key_ID_B[contactA_ID_B]) { AddLCPValues( ref index, ref values, indexVal, constraintCheckItem, constraintValueKey, symmetricHashSet, contactA.LinearComponentB, contactA.AngularComponentB, contactA.ObjectB.MassInfo, false); } //Sparse Matrix baseProperties.M.Rows[indexVal] = new SparseVector( values.ToArray(), index.ToArray(), baseProperties.M.m); UpdateGraph(ref graph, index, indexVal); } } }); var lp = new LinearProblemProperties( baseProperties, graph, EngineParameters.FrictionDirections); return(lp); }