更新obi到7.1

This commit is contained in:
Bob.Song
2025-11-03 11:53:45 +08:00
parent d12e1bc495
commit 7cf7f545bc
1161 changed files with 158924 additions and 37802 deletions

View File

@@ -76,8 +76,8 @@ namespace Obi
{
particleIndices[m_ActiveConstraintCount + i] = actor.solverIndices[batch.particleIndices[i]];
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3] = batch.aerodynamicCoeffs[i*3];
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3 + 1] = user.drag;
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3 + 2] = user.lift;
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3 + 1] = user.GetDrag(batch, i);
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3 + 2] = user.GetLift(batch, i);
}
base.Merge(actor, other);
@@ -96,6 +96,10 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
aerodynamicCoeffs.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -115,6 +115,12 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
restBends.Dispose();
bendingStiffnesses.Dispose();
plasticity.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -116,6 +116,12 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
restDarbouxVectors.Dispose();
plasticity.Dispose();
stiffnesses.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -120,6 +120,12 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
firstParticle.Dispose();
numParticles.Dispose();
lengths.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -42,6 +42,7 @@ namespace Obi
bool DeactivateConstraint(int constraintIndex);
bool ActivateConstraint(int constraintIndex);
void DeactivateAllConstraints();
void ActivateAllConstraints();
void Clear();
@@ -100,8 +101,12 @@ namespace Obi
protected abstract void SwapConstraints(int sourceIndex, int destIndex);
public abstract void GetParticlesInvolved(int index, List<int> particles);
public abstract void AddToSolver(ObiSolver solver);
public abstract void RemoveFromSolver(ObiSolver solver);
public virtual void AddToSolver(ObiSolver solver) { }
public virtual void RemoveFromSolver(ObiSolver solver) {
particleIndices.Dispose();
lambdas.Dispose();
}
protected virtual void CopyConstraint(ObiConstraintsBatch batch, int constraintIndex) { }
@@ -176,6 +181,11 @@ namespace Obi
m_ActiveConstraintCount = 0;
}
public void ActivateAllConstraints()
{
m_ActiveConstraintCount = m_ConstraintCount;
}
// Swaps the constraint with the last one and reduces the amount of constraints by one.
public void RemoveConstraint(int constraintIndex)
{

View File

@@ -30,7 +30,7 @@ namespace Obi
get { return m_BatchImpl; }
}
public ObiDistanceConstraintsBatch(int a = 0)
public ObiDistanceConstraintsBatch(ObiDistanceConstraintsData constraints = null) : base()
{
}
@@ -135,6 +135,11 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
restLengths.Dispose();
stiffnesses.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -8,12 +8,12 @@ namespace Obi
[Serializable]
public class ObiPinConstraintsBatch : ObiConstraintsBatch
{
protected IPinConstraintsBatchImpl m_BatchImpl;
protected IPinConstraintsBatchImpl m_BatchImpl;
/// <summary>
/// for each constraint, handle of the pinned collider.
/// </summary>
[HideInInspector] public List<ObiColliderHandle> pinBodies = new List<ObiColliderHandle>();
[HideInInspector] public List<ObiColliderHandle> pinBodies = new List<ObiColliderHandle>();
/// <summary>
/// index of the pinned collider in the collider world.
@@ -23,22 +23,17 @@ namespace Obi
/// <summary>
/// Pin position expressed in the attachment's local space.
/// </summary>
[HideInInspector] public ObiNativeVector4List offsets = new ObiNativeVector4List();
[HideInInspector] public ObiNativeVector4List offsets = new ObiNativeVector4List();
/// <summary>
/// Rest Darboux vector for each constraint.
/// </summary>
[HideInInspector] public ObiNativeQuaternionList restDarbouxVectors = new ObiNativeQuaternionList();
[HideInInspector] public ObiNativeQuaternionList restDarbouxVectors = new ObiNativeQuaternionList();
/// <summary>
/// Compliances of pin constraits. 2 float per constraint (positional and rotational compliance).
/// </summary>
[HideInInspector] public ObiNativeFloatList stiffnesses = new ObiNativeFloatList();
/// <summary>
/// One float per constraint: break threshold.
/// </summary>
[HideInInspector] public ObiNativeFloatList breakThresholds = new ObiNativeFloatList();
[HideInInspector] public ObiNativeFloatList stiffnesses = new ObiNativeFloatList();
public override Oni.ConstraintType constraintType
{
@@ -54,18 +49,17 @@ namespace Obi
{
}
public void AddConstraint(int solverIndex, ObiColliderBase body, Vector3 offset, Quaternion restDarboux, float linearCompliance, float rotationalCompliance, float breakThreshold)
public void AddConstraint(int solverIndex, ObiColliderBase body, Vector3 offset, Quaternion restDarboux, float linearCompliance, float rotationalCompliance, bool projectRenderable = false)
{
RegisterConstraint();
particleIndices.Add(solverIndex);
pinBodies.Add(body != null ? body.Handle : new ObiColliderHandle());
colliderIndices.Add(body != null ? body.Handle.index : -1);
offsets.Add(offset);
offsets.Add(new Vector4(offset.x, offset.y, offset.z, projectRenderable ? 1:0));
restDarbouxVectors.Add(restDarboux);
stiffnesses.Add(linearCompliance);
stiffnesses.Add(rotationalCompliance);
breakThresholds.Add(breakThreshold);
}
public override void Clear()
@@ -108,13 +102,11 @@ namespace Obi
offsets.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
restDarbouxVectors.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
stiffnesses.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 2);
breakThresholds.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
lambdas.ResizeInitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 4);
offsets.CopyFrom(batch.offsets, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
restDarbouxVectors.CopyFrom(batch.restDarbouxVectors, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
stiffnesses.CopyFrom(batch.stiffnesses, 0, m_ActiveConstraintCount * 2, batch.activeConstraintCount * 2);
breakThresholds.CopyFrom(batch.breakThresholds, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
for (int i = 0; i < batch.activeConstraintCount; ++i)
{
@@ -139,6 +131,13 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
restDarbouxVectors.Dispose();
colliderIndices.Dispose();
offsets.Dispose();
stiffnesses.Dispose();
if (solver != null && solver.implementation != null)
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -0,0 +1,220 @@
using UnityEngine;
using System;
using System.Collections.Generic;
namespace Obi
{
[Serializable]
public class ObiPinholeConstraintsBatch : ObiConstraintsBatch
{
[Serializable]
public struct PinholeEdge
{
public int edgeIndex;
public float coordinate;
public PinholeEdge(int edgeIndex, float coordinate)
{
this.edgeIndex = edgeIndex;
this.coordinate = coordinate;
}
public float GetRopeCoordinate(ObiActor actor)
{
int edgeCount = actor.GetDeformableEdgeCount();
return edgeCount > 0 ? Mathf.Clamp01((edgeIndex + coordinate) / edgeCount) : 0;
}
}
protected IPinholeConstraintsBatchImpl m_BatchImpl;
/// <summary>
/// for each constraint, handle of the pinned collider.
/// </summary>
[HideInInspector] public List<ObiColliderHandle> pinBodies = new List<ObiColliderHandle>();
/// <summary>
/// for each constraint, reference to the actor pinned.
/// </summary>
[HideInInspector] public List<ObiActor> pinActors = new List<ObiActor>();
/// <summary>
/// index of the pinned collider in the collider world.
/// </summary>
[HideInInspector] public ObiNativeIntList colliderIndices = new ObiNativeIntList();
/// <summary>
/// Pinhole position expressed in the attachment's local space.
/// </summary>
[HideInInspector] public ObiNativeVector4List offsets = new ObiNativeVector4List();
/// <summary>
// Normalized coordinate along current edge.
/// </summary>
[HideInInspector] public ObiNativeFloatList edgeMus = new ObiNativeFloatList();
/// <summary>
/// Edge range as 2 ints (first edge, last edge) for each constraint.
/// </summary>
[HideInInspector] public ObiNativeIntList edgeRanges = new ObiNativeIntList();
/// <summary>
/// Min/max cooridnate in each of the first and last edges as 2 floats for each constraint.
/// </summary>
[HideInInspector] public ObiNativeFloatList edgeRangeMus = new ObiNativeFloatList();
/// <summary>
/// Parameters of pinhole constraints. 5 floats per constraint (compliance, friction, motor speed, motor force and normalized coordinate along edge).
/// </summary>
[HideInInspector] public ObiNativeFloatList parameters = new ObiNativeFloatList();
/// <summary>
/// Relative velocities between rope and pinhole.
/// </summary>
[HideInInspector] public ObiNativeFloatList relativeVelocities = new ObiNativeFloatList();
public override Oni.ConstraintType constraintType
{
get { return Oni.ConstraintType.Pinhole; }
}
public override IConstraintsBatchImpl implementation
{
get { return m_BatchImpl; }
}
public ObiPinholeConstraintsBatch(ObiPinholeConstraintsData constraints = null) : base()
{
}
public void AddConstraint(PinholeEdge edge, PinholeEdge firstEdge, PinholeEdge lastEdge, ObiActor actor, ObiColliderBase body, Vector3 offset, float compliance, float friction, float motorSpeed, float motorForce, bool clampAtEnds)
{
RegisterConstraint();
particleIndices.Add(edge.edgeIndex);
edgeMus.Add(edge.coordinate);
edgeRanges.Add(firstEdge.edgeIndex);
edgeRanges.Add(lastEdge.edgeIndex);
edgeRangeMus.Add(firstEdge.coordinate);
edgeRangeMus.Add(lastEdge.coordinate);
pinBodies.Add(body != null ? body.Handle : new ObiColliderHandle());
pinActors.Add(actor);
colliderIndices.Add(body != null ? body.Handle.index : -1);
offsets.Add(offset);
parameters.Add(compliance);
parameters.Add(friction);
parameters.Add(motorSpeed);
parameters.Add(motorForce);
parameters.Add(clampAtEnds ? 1 : 0);
relativeVelocities.Add(0);
}
public override void Clear()
{
base.Clear();
particleIndices.Clear();
pinBodies.Clear();
colliderIndices.Clear();
offsets.Clear();
edgeMus.Clear();
edgeRanges.Clear();
edgeRangeMus.Clear();
parameters.Clear();
relativeVelocities.Clear();
}
public override void GetParticlesInvolved(int index, List<int> particles)
{
particles.Add(particleIndices[index]);
}
protected override void SwapConstraints(int sourceIndex, int destIndex)
{
particleIndices.Swap(sourceIndex, destIndex);
pinBodies.Swap(sourceIndex, destIndex);
colliderIndices.Swap(sourceIndex, destIndex);
offsets.Swap(sourceIndex, destIndex);
edgeMus.Swap(sourceIndex, destIndex);
edgeRanges.Swap(sourceIndex * 2, destIndex * 2);
edgeRanges.Swap(sourceIndex * 2 + 1, destIndex * 2 + 1);
edgeRangeMus.Swap(sourceIndex * 2, destIndex * 2);
edgeRangeMus.Swap(sourceIndex * 2 + 1, destIndex * 2 + 1);
for (int i = 0; i < 5; ++i)
parameters.Swap(sourceIndex * 5 + i, destIndex * 5 + i);
relativeVelocities.Swap(sourceIndex, destIndex);
}
public override void Merge(ObiActor actor, IObiConstraintsBatch other)
{
var batch = other as ObiPinholeConstraintsBatch;
if (batch != null)
{
particleIndices.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
colliderIndices.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
offsets.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
edgeRanges.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 2);
edgeRangeMus.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 2);
edgeMus.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
parameters.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 5);
relativeVelocities.ResizeInitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
lambdas.ResizeInitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
edgeMus.CopyFrom(batch.edgeMus, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
edgeRangeMus.CopyFrom(batch.edgeRangeMus, 0, m_ActiveConstraintCount * 2, batch.activeConstraintCount * 2);
offsets.CopyFrom(batch.offsets, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
relativeVelocities.CopyFrom(batch.relativeVelocities, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
parameters.CopyFrom(batch.parameters, 0, m_ActiveConstraintCount * 5, batch.activeConstraintCount * 5);
for (int i = 0; i < batch.activeConstraintCount; ++i)
{
int currentEdge = -1, firstEdge = -1, lastEdge = -1;
if (batch.pinActors[i] != null)
{
currentEdge = batch.pinActors[i].deformableEdgesOffset + batch.particleIndices[i];
firstEdge = batch.pinActors[i].deformableEdgesOffset + batch.edgeRanges[i * 2];
lastEdge = batch.pinActors[i].deformableEdgesOffset + batch.edgeRanges[i * 2 + 1];
}
edgeRanges[(m_ActiveConstraintCount + i) * 2] = firstEdge;
edgeRanges[(m_ActiveConstraintCount + i) * 2 + 1] = lastEdge;
particleIndices[m_ActiveConstraintCount + i] = Mathf.Clamp(currentEdge, firstEdge, lastEdge);
colliderIndices[m_ActiveConstraintCount + i] = batch.pinBodies[i] != null ? batch.pinBodies[i].index : -1;
}
base.Merge(actor, other);
}
}
public override void AddToSolver(ObiSolver solver)
{
if (solver != null && solver.implementation != null)
{
m_BatchImpl = solver.implementation.CreateConstraintsBatch(constraintType) as IPinholeConstraintsBatchImpl;
if (m_BatchImpl != null)
m_BatchImpl.SetPinholeConstraints(particleIndices, colliderIndices, offsets, edgeMus, edgeRanges, edgeRangeMus, parameters, relativeVelocities, lambdas, m_ActiveConstraintCount);
}
}
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
edgeRanges.Dispose();
colliderIndices.Dispose();
offsets.Dispose();
parameters.Dispose();
if (solver != null && solver.implementation != null)
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d642dbf4a869c4761b38ce3f65e22f05
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -8,38 +8,38 @@ namespace Obi
[Serializable]
public class ObiShapeMatchingConstraintsBatch : ObiConstraintsBatch
{
protected IShapeMatchingConstraintsBatchImpl m_BatchImpl;
protected IShapeMatchingConstraintsBatchImpl m_BatchImpl;
/// <summary>
/// index of the first particle in each constraint.
/// </summary>
public ObiNativeIntList firstIndex = new ObiNativeIntList();
public ObiNativeIntList firstIndex = new ObiNativeIntList();
/// <summary>
/// amount of particles in each constraint.
/// </summary>
public ObiNativeIntList numIndices = new ObiNativeIntList();
public ObiNativeIntList numIndices = new ObiNativeIntList();
/// <summary>
/// whether the constraint is implicit (0) or explicit (>0).
/// </summary>
public ObiNativeIntList explicitGroup = new ObiNativeIntList();
public ObiNativeIntList explicitGroup = new ObiNativeIntList();
/// <summary>
/// 5 floats per constraint: stiffness, plastic yield, creep, recovery and max deformation.
/// </summary>
public ObiNativeFloatList materialParameters = new ObiNativeFloatList();
public ObiNativeFloatList materialParameters = new ObiNativeFloatList();
/// <summary>
/// rest center of mass for each constraint.
/// </summary>
public ObiNativeVector4List restComs = new ObiNativeVector4List();
public ObiNativeVector4List restComs = new ObiNativeVector4List();
/// <summary>
/// current center of mass for each constraint.
/// </summary>
public ObiNativeVector4List coms = new ObiNativeVector4List();
public ObiNativeVector4List coms = new ObiNativeVector4List();
/// <summary>
/// current best-match orientation for each constraint.
@@ -96,7 +96,7 @@ namespace Obi
{
int first = firstIndex[index];
int num = numIndices[index];
for (int i = first; i < first + num; ++i)
for (int i = first; i < first + num; ++i)
particles.Add(particleIndices[i]);
}
@@ -154,7 +154,7 @@ namespace Obi
// shape matching constraint particle indices are not reordered when deactivating constraints,
// so instead of using batch.activeConstraintCount, batch.constraintCount. We need all of them.
int numActiveIndices = 0;
for (int i = 0; i < batch.constraintCount; ++i)
for (int i = 0; i < batch.constraintCount; ++i)
numActiveIndices += batch.numIndices[i];
particleIndices.ResizeUninitialized(initialIndexCount + numActiveIndices);
@@ -209,6 +209,19 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
firstIndex.Dispose();
numIndices.Dispose();
explicitGroup.Dispose();
materialParameters.Dispose();
restComs.Dispose();
coms.Dispose();
orientations.Dispose();
linearTransforms.Dispose();
plasticDeformations.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -131,6 +131,13 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
skinPoints.Dispose();
skinNormals.Dispose();
skinRadiiBackstop.Dispose();
skinCompliance.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -141,6 +141,13 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
orientationIndices.Dispose();
restLengths.Dispose();
restOrientations.Dispose();
stiffnesses.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -104,6 +104,11 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
maxLengthsScales.Dispose();
stiffnesses.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -126,6 +126,13 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
firstTriangle.Dispose();
numTriangles.Dispose();
restVolumes.Dispose();
pressureStiffness.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -13,18 +13,8 @@ namespace Obi
set;
}
float drag
{
get;
set;
}
float lift
{
get;
set;
}
float GetDrag(ObiAerodynamicConstraintsBatch batch, int constraintIndex);
float GetLift(ObiAerodynamicConstraintsBatch batch, int constraintIndex);
}
[Serializable]

View File

@@ -0,0 +1,16 @@
using UnityEngine;
using System.Collections;
using System;
namespace Obi
{
[Serializable]
public class ObiPinholeConstraintsData : ObiConstraints<ObiPinholeConstraintsBatch>
{
public override ObiPinholeConstraintsBatch CreateBatch(ObiPinholeConstraintsBatch source = null)
{
return new ObiPinholeConstraintsBatch();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: caeaf013c17424e0884d22017414ee1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -8,8 +8,8 @@ namespace Obi
{
Oni.ConstraintType? GetConstraintType();
IObiConstraintsBatch GetBatch(int i);
int GetBatchCount();
IObiConstraintsBatch GetBatch(int i);
int batchCount { get; }
void Clear();
bool AddToSolver(ObiSolver solver);
@@ -17,6 +17,7 @@ namespace Obi
int GetConstraintCount();
int GetActiveConstraintCount();
void ActivateAllConstraints();
void DeactivateAllConstraints();
void Merge(ObiActor actor, IObiConstraints other);
@@ -28,6 +29,8 @@ namespace Obi
[NonSerialized] protected ObiSolver m_Solver;
[HideInInspector] public List<T> batches = new List<T>();
public int batchCount { get => batches == null ? 0 : batches.Count; }
// merges constraints from a given actor with this one.
public void Merge(ObiActor actor, IObiConstraints other)
{
@@ -42,11 +45,11 @@ namespace Obi
actor.solverBatchOffsets[constraintType].Clear();
// create new empty batches if needed:
int newBatches = Mathf.Max(0, others.GetBatchCount() - GetBatchCount());
int newBatches = Mathf.Max(0, others.batchCount - batchCount);
for (int i = 0; i < newBatches; ++i)
AddBatch(CreateBatch());
for (int i = 0; i < other.GetBatchCount(); ++i)
for (int i = 0; i < other.batchCount; ++i)
{
// store this batch's offset:
actor.solverBatchOffsets[constraintType].Add(batches[i].activeConstraintCount);
@@ -64,11 +67,6 @@ namespace Obi
return null;
}
public int GetBatchCount()
{
return batches == null ? 0 : batches.Count;
}
public int GetConstraintCount()
{
int count = 0;
@@ -101,6 +99,14 @@ namespace Obi
batch.DeactivateAllConstraints();
}
public void ActivateAllConstraints()
{
if (batches != null)
foreach (T batch in batches)
if (batch != null)
batch.ActivateAllConstraints();
}
public T GetFirstBatch()
{
return (batches != null && batches.Count > 0) ? batches[0] : null;