VOID Bound::Merge( const Bound& Other ) { Sphere OtherSphere; OtherSphere.Center = Other.GetCenter(); OtherSphere.Radius = Other.GetMaxRadius(); if( m_Type == Bound::No_Bound ) { SetSphere( OtherSphere ); return; } Sphere ThisSphere; if( m_Type != Bound::Sphere_Bound ) { // convert this bound into a sphere ThisSphere.Center = GetCenter(); ThisSphere.Radius = GetMaxRadius(); } else { ThisSphere = GetSphere(); } XMVECTOR vThisCenter = XMLoadFloat3( &ThisSphere.Center ); XMVECTOR vOtherCenter = XMLoadFloat3( &OtherSphere.Center ); XMVECTOR vThisToOther = XMVectorSubtract( vOtherCenter, vThisCenter ); XMVECTOR vDistance = XMVector3LengthEst( vThisToOther ); FLOAT fCombinedDiameter = XMVectorGetX( vDistance ) + ThisSphere.Radius + OtherSphere.Radius; if( fCombinedDiameter <= ( ThisSphere.Radius * 2 ) ) { SetSphere( ThisSphere ); return; } if( fCombinedDiameter <= ( OtherSphere.Radius * 2 ) ) { SetSphere( OtherSphere ); return; } XMVECTOR vDirectionNorm = XMVector3Normalize( vThisToOther ); XMVECTOR vRadius = XMVectorSet( ThisSphere.Radius, OtherSphere.Radius, 0, 0 ); XMVECTOR vThisRadius = XMVectorSplatX( vRadius ); XMVECTOR vOtherRadius = XMVectorSplatY( vRadius ); XMVECTOR vCombinedDiameter = vThisRadius + vDistance + vOtherRadius; XMVECTOR vMaxDiameter = XMVectorMax( vCombinedDiameter, vThisRadius * 2 ); vMaxDiameter = XMVectorMax( vMaxDiameter, vOtherRadius * 2 ); XMVECTOR vMaxRadius = vMaxDiameter * 0.5f; ThisSphere.Radius = XMVectorGetX( vMaxRadius ); vMaxRadius -= vThisRadius; XMVECTOR vCombinedCenter = vThisCenter + vMaxRadius * vDirectionNorm; XMStoreFloat3( &ThisSphere.Center, vCombinedCenter ); SetSphere( ThisSphere ); }
//---------------------------------------------------------------------------- void Bound::GrowToContain (const Bound& bound) { if (bound.GetRadius() == 0.0f) { // The node is a dummy node and cannot affect growth. return; } if (GetRadius() == 0.0f) { mCenter = bound.GetCenter(); mRadius = bound.GetRadius(); return; } AVector centerDiff = bound.mCenter - mCenter; float lengthSqr = centerDiff.SquaredLength(); float radiusDiff = bound.mRadius - mRadius; float radiusDiffSqr = radiusDiff*radiusDiff; if (radiusDiffSqr >= lengthSqr) { if (radiusDiff >= 0.0f) { mCenter = bound.mCenter; mRadius = bound.mRadius; } return; } float length = Mathf::Sqrt(lengthSqr); if (length > Mathf::ZERO_TOLERANCE) { float coeff = (length + radiusDiff)/(2.0f*length); mCenter += coeff*centerDiff; } mRadius = 0.5f*(length + mRadius + bound.mRadius); }
bool OutStream::WriteAggregate (const Bound& datum) { APoint center = datum.GetCenter(); float radius = datum.GetRadius(); return WriteAggregate(center) && Write(radius); }
//---------------------------------------------------------------------------- void BoundCtrl::UpdateCtrl() { mCtrlsGroup->SetActiveChild(1); int numObjscts = PX2_SELECTION.GetNumObjects(); if (numObjscts > 0) { Bound bound; int firstBound = true; APoint pos; for (int i = 0; i < numObjscts; i++) { Object *obj = PX2_SELECTION.GetObjectAt(i); Actor *actor = DynamicCast<Actor>(obj); Movable *movable = DynamicCast<Movable>(obj); if (movable) { mCtrlsGroup->SetActiveChild(0); pos += movable->WorldTransform.GetTranslate(); if (0.0f != movable->WorldBound.GetRadius()) { if (firstBound) { bound = movable->WorldBound; firstBound = false; } else { bound.GrowToContain(movable->WorldBound); } } } } pos = pos / (float)numObjscts; float radius = bound.GetRadius(); if (0.0f == radius) { radius = 1.0f; mCtrlsGroup->WorldTransform.SetUniformScale(radius); mCtrlsGroup->WorldTransform.SetTranslate(pos); } else { mCtrlsGroup->WorldTransform.SetUniformScale(radius); mCtrlsGroup->WorldTransform.SetTranslate(bound.GetCenter()); } } else { mCtrlsGroup->SetActiveChild(1); } mCtrlsGroup->Update(Time::GetTimeInSeconds(), false); }