void S013010C_Aaron_Smith_Tank::MoveInHeadingDirection(float deltaTime) { mSteeringForce = mSteering->Calculate(deltaTime); //Acceleration = Force/Mass //mSteeringForce.Truncate(GetMaxForce()); Vector2D acceleration = mSteeringForce / GetMass(); //Update velocity. mVelocity += acceleration * deltaTime; //Don't allow the tank does not go faster than max speed. mVelocity.Truncate(GetMaxSpeed()); //cout << "mVelocity " << mVelocity.x << ":" << mVelocity.y << endl; //cout << "VELOCITY " << mVelocity.Length() << endl; if (mVelocity.Length() > 0.0001) { if (mVelocity.x != mVelocity.x || mVelocity.y != mVelocity.y) return; Vector2D newPosition = GetPosition(); newPosition.x += mVelocity.x*deltaTime; newPosition.y += (mVelocity.y)*deltaTime; //Y flipped as adding to Y moves down screen. SetPosition(newPosition); Vector2D ahead = Vec2DNormalize(mVelocity); if (ahead.Length() == 0) ahead = mHeading; Vector2D cenPos = GetCentrePosition(); Vector2D aheadDistance = cenPos + ahead * 10 ; RotateHeadingToTarget(aheadDistance); // double dynamicLength = mVelocity.Length() / GetMaxSpeed(); Vector2D left = (mHeading - mSide) * 0.5; Vector2D right = (mHeading + mSide) * 0.5; mTopLeftCorner.x = left.x; mTopLeftCorner.y = left.y; mTopLeftCorner = Vec2DNormalize(mTopLeftCorner) * -10; mTopLeftCorner += GetCentralPosition(); mTopRightCorner.x = right.x; mTopRightCorner.y = right.y; mTopRightCorner = Vec2DNormalize(mTopRightCorner) * -10; mTopRightCorner += GetCentralPosition(); /*double angle = 70; int ahead2Amount = 40; int ahead1Amount = ahead2Amount / 2; int side2Amount = 30; int side1Amount = side2Amount / 2; Vector2D fannedLeftAhead; fannedLeftAhead.x = ahead.x * cos(DegsToRads(-angle)) - ahead.y * sin(DegsToRads(-angle)); fannedLeftAhead.y = ahead.x * sin(DegsToRads(-angle)) + ahead.y * cos(DegsToRads(-angle)); Vector2D fannedRightAhead; fannedRightAhead.x = ahead.x * cos(DegsToRads(angle)) - ahead.y * sin(DegsToRads(angle)); fannedRightAhead.y = ahead.x * sin(DegsToRads(angle)) + ahead.y * cos(DegsToRads(angle)); mLeftAhead2Distance = (mTopLeftCorner) + (fannedLeftAhead * dynamicLength * side2Amount); mLeftAhead1Distance = (mTopLeftCorner) + (fannedLeftAhead * dynamicLength * side1Amount); mRightAhead2Distance = (mTopRightCorner)+(fannedRightAhead * dynamicLength * side2Amount); mRightAhead1Distance = (mTopRightCorner)+(fannedRightAhead * dynamicLength * side1Amount); mAhead1Distance = GetCentrePosition() + (ahead * dynamicLength * ahead1Amount ); mAhead2Distance = GetCentrePosition() + (ahead * dynamicLength * (ahead2Amount + 50));*/ //cout << "AHEAD " << mLeftAhead2Distance.x << ":" << mLeftAhead2Distance.y << endl; //mAhead1Distance = mAhead2Distance * 0.5; } CreateFeelers(mRightSideFeelers, 90, 30, GetCentralPosition()); CreateFeelers(mLeftSideFeelers, -90, 30, GetCentralPosition()); CreateFeelers(mLeftFeelers, -40, 30, mTopLeftCorner); CreateFeelers(mRightFeelers, 40, 30, mTopRightCorner); // 70 CreateFeelers(mStraightFeelers, 0, 40, mTopLeftCorner); }
void S013010C_Aaron_Smith_Tank::Update(float deltaTime, SDL_Event e) { //TODO: Adjust mHeading. switch (e.type) { case SDL_MOUSEMOTION: mMouseX = e.motion.x; mMouseY = e.motion.y; if (demoPursuit) { Vector2D prevPosition; prevPosition = mTargetPos; mTargetPos = Vector2D(e.motion.x , e.motion.y); Vector2D enemySteering = (Vec2DNormalize(mTargetPos - prevPosition )* 75) - mEnemyVelocity ; //mEnemyVelocity = mEnemyHeading; //Acceleration = Force/Mass //mSteeringForce.Truncate(GetMaxForce()); Vector2D acceleration = enemySteering / GetMass(); //Update velocity. mEnemyVelocity += acceleration * deltaTime; mEnemySpeed = mEnemyVelocity.Length(); //Don't allow the tank does not go faster than max speed. mEnemyVelocity.Truncate(GetMaxSpeed()); mEnemyHeading = Vec2DNormalize(mEnemyVelocity); cout << "enemySteering " << enemySteering.x << ":" << enemySteering.y << endl; } //cout << mMouseX << ":" << mMouseY << endl; break; case SDL_MOUSEBUTTONDOWN: if (e.button.button == SDL_BUTTON_LEFT) { mTargetPos = Vector2D(e.motion.x, e.motion.y); //SetHasTarget(true); } else { cout << "Mouse Down: " << e.motion.x << ":" << e.motion.y << endl; } break; case SDL_KEYDOWN: if (e.key.keysym.sym == SDLK_SPACE) { mDrawTarget = !mDrawTarget; } else if (e.key.keysym.sym == SDLK_RETURN) { mShowingDebug = !mShowingDebug; } else if (e.key.keysym.sym == SDLK_1) { demoPursuit = false; cout << "Arrive is on" << endl; mSteering->TurnArriveOn(); mSteering->TurnSeekOff(); mSteering->TurnFleeOff(); mSteering->TurnPursueOff(); } else if (e.key.keysym.sym == SDLK_2) { demoPursuit = false; cout << "Seek is on" << endl; mSteering->TurnSeekOn(); mSteering->TurnArriveOff(); mSteering->TurnFleeOff(); mSteering->TurnPursueOff(); } else if (e.key.keysym.sym == SDLK_3) { demoPursuit = false; cout << "Flee is on" << endl; mSteering->TurnFleeOn(); mSteering->TurnArriveOff(); mSteering->TurnSeekOff(); mSteering->TurnPursueOff(); } else if (e.key.keysym.sym == SDLK_4) { cout << "Pursuit is on" << endl; demoPursuit = true; mSteering->TurnPursueOn(); mSteering->TurnArriveOff(); mSteering->TurnFleeOff(); mSteering->TurnSeekOff(); } break; } if (mTanksICanSee.size() >= 1) { bool isSafe = true; for (BaseTank* enemy : mTanksICanSee) { Vector2D targetDir = enemy->GetPosition() - GetPosition(); float distance = targetDir.Length(); if (distance < 100) { cout << "START FLEEING!!!!!" << endl; mTargetPos = enemy->GetCentrePosition(); mEnemyHeading = enemy->GetHeading(); mEnemySpeed = enemy->GetCurrentSpeed(); mEnemyVelocity = enemy->GetVelocity(); mSteering->TurnEvadeOn(); isSafe = false; } if (!mIsTestTank) { mTargetPos = enemy->GetCentrePosition(); mEnemyHeading = enemy->GetHeading(); mEnemySpeed = enemy->GetCurrentSpeed(); mEnemyVelocity = enemy->GetVelocity(); mSteering->TurnPursueOn(); } } /*if (isSafe) mSteering->TurnArriveOn();*/ } else { //cout << "NO LONGER IN PURSUIT" << endl; //if(mSteering->mIsPursuing)mSteering->TurnEvadeOff(); } //Call parent update. BaseTank::Update(deltaTime, e); }
bool csBulletRigidBody::AddBulletObject () { // TODO: don't recompute everything if the internal scale hasn't changed if (insideWorld) RemoveBulletObject (); btVector3 localInertia (0.0f, 0.0f, 0.0f); float mass = GetMass (); btCollisionShape* shape; btTransform principalAxis; principalAxis.setIdentity (); btVector3 principalInertia(0,0,0); //Create btRigidBody if (compoundShape) { int shapeCount = compoundShape->getNumChildShapes (); CS_ALLOC_STACK_ARRAY(btScalar, masses, shapeCount); for (int i = 0; i < shapeCount; i++) masses[i] = density * colliders[i]->GetVolume (); if (shapeChanged) { compoundShape->calculatePrincipalAxisTransform (masses, principalAxis, principalInertia); // apply principal axis // creation is faster using a new compound to store the shifted children btCompoundShape* newCompoundShape = new btCompoundShape(); for (int i = 0; i < shapeCount; i++) { btTransform newChildTransform = principalAxis.inverse() * compoundShape->getChildTransform (i); newCompoundShape->addChildShape(newChildTransform, compoundShape->getChildShape (i)); shapeChanged = false; } delete compoundShape; compoundShape = newCompoundShape; } shape = compoundShape; } else { shape = colliders[0]->shape; principalAxis = CSToBullet (relaTransforms[0], system->getInternalScale ()); } // create new motion state btTransform trans; motionState->getWorldTransform (trans); trans = trans * motionState->inversePrincipalAxis; delete motionState; motionState = new csBulletMotionState (this, trans * principalAxis, principalAxis); //shape->calculateLocalInertia (mass, localInertia); btRigidBody::btRigidBodyConstructionInfo infos (mass, motionState, shape, localInertia); infos.m_friction = friction; infos.m_restitution = elasticity; infos.m_linearDamping = linearDampening; infos.m_angularDamping = angularDampening; // create new rigid body btBody = new btRigidBody (infos); btObject = btBody; if (haveStaticColliders > 0) physicalState = CS::Physics::STATE_STATIC; SetState (physicalState); sector->bulletWorld->addRigidBody (btBody, collGroup.value, collGroup.mask); btBody->setUserPointer (dynamic_cast<CS::Collisions::iCollisionObject*> ( dynamic_cast<csBulletCollisionObject*>(this))); insideWorld = true; return true; }
bool csBulletRigidBody::SetState (CS::Physics::RigidBodyState state) { if (physicalState != state || !insideWorld) { CS::Physics::RigidBodyState previousState = physicalState; physicalState = state; if (!btBody) return false; if (haveStaticColliders > 0 && state != CS::Physics::STATE_STATIC) return false; if (insideWorld) sector->bulletWorld->removeRigidBody (btBody); btVector3 linearVelo = CSToBullet (linearVelocity, system->getInternalScale ()); btVector3 angularVelo = btVector3 (angularVelocity.x, angularVelocity.y, angularVelocity.z); if (previousState == CS::Physics::STATE_KINEMATIC && insideWorld) { btBody->setCollisionFlags (btBody->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT); linearVelo = btBody->getInterpolationLinearVelocity (); angularVelo = btBody->getInterpolationAngularVelocity (); // create new motion state btTransform principalAxis = motionState->inversePrincipalAxis.inverse (); btTransform trans; motionState->getWorldTransform (trans); trans = trans * motionState->inversePrincipalAxis; delete motionState; motionState = new csBulletMotionState (this, trans * principalAxis, principalAxis); btBody->setMotionState (motionState); } if (state == CS::Physics::STATE_DYNAMIC) { btBody->setCollisionFlags (btBody->getCollisionFlags() & ~btCollisionObject::CF_STATIC_OBJECT); float mass = GetMass (); btVector3 localInertia (0.0f, 0.0f, 0.0f); if (compoundShape) compoundShape->calculateLocalInertia (mass, localInertia); else colliders[0]->shape->calculateLocalInertia (mass, localInertia); btBody->setMassProps (mass, localInertia); btBody->forceActivationState (ACTIVE_TAG); btBody->setLinearVelocity (linearVelo); btBody->setAngularVelocity (angularVelo); btBody->updateInertiaTensor (); } else if (state == CS::Physics::STATE_KINEMATIC) { if (!kinematicCb) kinematicCb.AttachNew (new csBulletDefaultKinematicCallback ()); // create new motion state btTransform principalAxis = motionState->inversePrincipalAxis.inverse (); btTransform trans; motionState->getWorldTransform (trans); delete motionState; motionState = new csBulletKinematicMotionState (this, trans, principalAxis); btBody->setMotionState (motionState); // set body kinematic btBody->setMassProps (0.0f, btVector3 (0.0f, 0.0f, 0.0f)); btBody->setCollisionFlags (btBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT & ~btCollisionObject::CF_STATIC_OBJECT); btBody->setActivationState (DISABLE_DEACTIVATION); btBody->updateInertiaTensor (); btBody->setInterpolationWorldTransform (btBody->getWorldTransform ()); btBody->setInterpolationLinearVelocity (btVector3(0.0f, 0.0f, 0.0f)); btBody->setInterpolationAngularVelocity (btVector3(0.0f, 0.0f, 0.0f)); } else if (state == CS::Physics::STATE_STATIC) { btBody->setCollisionFlags (btBody->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT & ~btCollisionObject::CF_KINEMATIC_OBJECT); btBody->setActivationState (ISLAND_SLEEPING); btBody->setMassProps (0.0f, btVector3 (0.0f, 0.0f, 0.0f)); btBody->updateInertiaTensor (); } if (insideWorld) sector->bulletWorld->addRigidBody (btBody); return true; } else return false; }
void h_volume::ThermalComps(double dt) { //1. averaging temperature, based on Q //2. computing vapor pressure based on new temp, for each subst present //3. boil / condense if needed, affecting Q //4. redo this every second or so.. int i; //1. compute average temp double AvgC = 0; double vap_press; for (i = 0; i < MAX_SUB; i++) AvgC += composition[i].mass * SPECIFICC[composition[i].subst_type]; if (GetMass()) { AvgC = AvgC / total_mass; //weighted average heat capacity.. gives us averaged temp (ideal case) Temp = Q / AvgC / total_mass; //average Temp of substances for (i = 0; i < MAX_SUB; i++) composition[i].SetTemp(Temp); //redistribute the temps,re-computing the Qs... mathwise we are OK } else Temp = 0; //2. Compute average Press double m_i=0; double NV=0; double PNV=0; double tNV; //some sums we need for (i = 0; i < MAX_SUB; i++) { m_i += composition[i].vapor_mass / MMASS[composition[i].subst_type]; // temperature dependency of the density is assumed 1 to 2 g/l double density = L_DENSITY[composition[i].subst_type]; if (composition[i].subst_type == SUBSTANCE_O2) { // Liquid density is temperature dependend because of cryo tank pressurization with a heater // Correction term is 0 at O2 initial tank temperature (75K), the other factors are "empirical" density += 0.56 * Temp * Temp - 134.0 * Temp + 6900.0; } else if (composition[i].subst_type == SUBSTANCE_H2) { // Liquid density is temperature dependend because of cryo tank pressurization with a heater // Correction term is 0 at H2 boiling point (20K), the other factors are "empirical" density += 0.03333 * Temp * Temp - 4.3333 * Temp + 73.3333; } tNV = (composition[i].mass - composition[i].vapor_mass) / density; NV += tNV; PNV += tNV / BULK_MOD[composition[i].subst_type];; } m_i = -m_i * R_CONST * Temp; NV = Volume - NV; double delta = NV * NV - 4.0 * m_i * PNV; //delta of quadric eq. P^2*PNV+ P*NV + m_i = 0 if (PNV) Press = (-NV + sqrt(delta)) / 2.0 / PNV; //only first solution is always valid. why is there a second? else Press = 0; NV = Volume - NV; double air_volume = Volume - NV + Press * PNV; for (i = 0; i < MAX_SUB; i++) { //recompute the vapor press vap_press = VAPPRESS[composition[i].subst_type] - (273.0 - Temp) * VAPGRAD[composition[i].subst_type];//this is vapor pressure of current substance if (vap_press > Press) //need to boil material if any Q += composition[i].Boil(dt); else Q += composition[i].Condense(dt); composition[i].p_press = R_CONST * Temp * composition[i].vapor_mass / MMASS[composition[i].subst_type] / air_volume; } }
//----------------------------------------------------------------------------- // Purpose: Give the buster a slight attraction to striders. // Ported back from the magnade. //----------------------------------------------------------------------------- void CWeaponStriderBuster::BusterFlyThink() { if (IsAttachedToStrider()) return; // early out. Think no more. // If we're nosediving, forget about magnetism. if ( m_bNoseDiving ) { if ( VPhysicsGetObject() ) VPhysicsGetObject()->ApplyForceCenter( Vector( 0, 0, striderbuster_dive_force.GetFloat() ) ); SetNextThink(gpGlobals->curtime + 0.01f); return; } // seek? const float magradius = 38.0 * sk_striderbuster_magnet_multiplier.GetFloat(); // radius of strider hull times multiplier if (magradius > 0 && GetMoveType() == MOVETYPE_VPHYSICS && VPhysicsGetObject() ) { // find the nearest enemy. CBaseEntity *pList[16]; Vector origin = GetAbsOrigin(); // do a find in box ( a little faster than sphere ) int count; { Vector mins,maxs; mins = origin; mins -= magradius; maxs = origin; maxs += magradius; count = UTIL_EntitiesInBox(pList, 16, mins, maxs, FL_NPC); } float magradiusSq = Square( magradius ); float nearestDistSq = magradiusSq + 1; int bestFit = -1; Vector toTarget; // will be garbage unless something good is found CNPC_Strider *pBestStrider = NULL; for ( int ii = 0 ; ii < count ; ++ii ) { CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(pList[ii]); if ( pStrider && !pStrider->CarriedByDropship() ) // ShouldStickToEntity() doesn't work because the strider NPC isn't what we glue to { // get distance squared VectorSubtract( pStrider->GetAdjustedOrigin(), GetAbsOrigin(), toTarget ); //NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + toTarget, 128, 0, 128, false, 0.1 ); float dSq = toTarget.LengthSqr(); if (dSq < nearestDistSq) { bestFit = ii; nearestDistSq = dSq; pBestStrider = pStrider; } } } if (bestFit >= 0) // we found something and should attract towards it. (hysterisis later?) { if ( striderbuster_debugseek.GetBool() ) { NDebugOverlay::Circle( GetAbsOrigin() + toTarget, magradius, 255, 255, 255, 255, true, .1 ); NDebugOverlay::Cross3D( GetAbsOrigin() + toTarget, magradius, 255, 255, 255, true, .1 ); } // force magnitude. float magnitude = GetMass() * striderbuster_magnetic_force_strider.GetFloat(); int falloff = striderbuster_falloff_power.GetInt(); switch (falloff) { case 1: VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / nearestDistSq) ); // dividing through by distance squared normalizes toTarget and gives a linear falloff break; case 2: VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / (nearestDistSq * sqrtf(nearestDistSq))) ); // dividing through by distance cubed normalizes toTarget and gives a quadratic falloff break; case 3: VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / (nearestDistSq * nearestDistSq)) ); // dividing through by distance fourth normalizes toTarget and gives a cubic falloff break; case 4: { Vector toTarget; pBestStrider->GetAttachment( "buster_target", toTarget ); if ( striderbuster_debugseek.GetBool() ) { NDebugOverlay::Cross3D( toTarget, magradius, 255, 0, 255, true, .1 ); NDebugOverlay::Cross3D( toTarget, magradius, 255, 0, 255, true, .1 ); } toTarget -= GetAbsOrigin(); toTarget.NormalizeInPlace(); VPhysicsGetObject()->ApplyForceCenter( toTarget * magnitude ); } break; default: // arbitrary powers VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude * powf(nearestDistSq,(falloff+1.0f)/2)) ); // square root for distance instead of squared, add one to normalize toTarget break; } } SetNextThink(gpGlobals->curtime + 0.01f); } }
// returns speed that can be reached using fuel minus reserve according to the Tsiolkovsky equation double Ship::GetSpeedReachedWithFuel() const { const double fuelmass = 1000*GetShipType().fuelTankMass * (m_thrusterFuel - m_reserveFuel); if (fuelmass < 0) return 0.0; return GetShipType().effectiveExhaustVelocity * log(GetMass()/(GetMass()-fuelmass)); }
float CPhysicsObject::GetEnergy() const { // (1/2) * mass * velocity^2 float e = 0.5f * GetMass() * m_pObject->getLinearVelocity().dot(m_pObject->getLinearVelocity()); e += 0.5f * GetMass() * m_pObject->getAngularVelocity().dot(m_pObject->getAngularVelocity()); return ConvertEnergyToHL(e); }
float CPhysicsObject::GetEnergy() const { float e = 0.5 * GetMass() * m_pObject->getLinearVelocity().dot(m_pObject->getLinearVelocity()); e =+ 0.5 * GetMass() * m_pObject->getAngularVelocity().dot(m_pObject->getAngularVelocity()); return ConvertEnergyToHL(e); }
void FGBallonet::Calculate(double dt) { const double ParentPressure = Parent->GetPressure(); // [lbs/ft^2] const double AirPressure = in.Pressure; // [lbs/ft^2] const double OldTemperature = Temperature; const double OldPressure = Pressure; unsigned int i; //-- Gas temperature -- // The model is based on the ideal gas law. // However, it does look a bit fishy. Please verify. // dT/dt = dU / (Cv n R) dU = 0.0; for (i = 0; i < HeatTransferCoeff.size(); i++) { dU += HeatTransferCoeff[i]->GetValue(); } // dt is already accounted for in dVolumeIdeal. if (Contents > 0) { Temperature += (dU * dt - Pressure * dVolumeIdeal) / (Cv_air * Contents * R); } else { Temperature = Parent->GetTemperature(); } //-- Pressure -- const double IdealPressure = Contents * R * Temperature / MaxVolume; // The pressure is at least that of the parent gas cell. Pressure = max(IdealPressure, ParentPressure); //-- Blower input -- if (BlowerInput) { const double AddedVolume = BlowerInput->GetValue() * dt; if (AddedVolume > 0.0) { Contents += Pressure * AddedVolume / (R * Temperature); } } //-- Pressure relief and manual valving -- // FIXME: Presently the effect of valving is computed using // an ad hoc formula which might not be a good representation // of reality. if ((ValveCoefficient > 0.0) && ((ValveOpen > 0.0) || (Pressure > AirPressure + MaxOverpressure))) { const double DeltaPressure = Pressure - AirPressure; const double VolumeValved = ((Pressure > AirPressure + MaxOverpressure) ? 1.0 : ValveOpen) * ValveCoefficient * DeltaPressure * dt; // FIXME: Too small values of Contents sometimes leads to NaN. // Currently the minimum is restricted to a safe value. Contents = max(1.0, Contents - Pressure * VolumeValved / (R * Temperature)); } //-- Volume -- Volume = Contents * R * Temperature / Pressure; dVolumeIdeal = Contents * R * (Temperature / Pressure - OldTemperature / OldPressure); // Compute the inertia of the ballonet. // Consider the ballonet as a shape of uniform density. // FIXME: If the ballonet isn't ellipsoid or cylindrical the inertia will // be wrong. ballonetJ = FGMatrix33(); const double mass = Contents * M_air; double Ixx, Iyy, Izz; if ((Xradius != 0.0) && (Yradius != 0.0) && (Zradius != 0.0) && (Xwidth == 0.0) && (Ywidth == 0.0) && (Zwidth == 0.0)) { // Ellipsoid volume. Ixx = (1.0 / 5.0) * mass * (Yradius*Yradius + Zradius*Zradius); Iyy = (1.0 / 5.0) * mass * (Xradius*Xradius + Zradius*Zradius); Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius); } else if ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) && (Xwidth != 0.0) && (Ywidth == 0.0) && (Zwidth == 0.0)) { // Cylindrical volume (might not be valid with an elliptical cross-section). Ixx = (1.0 / 2.0) * mass * Yradius * Zradius; Iyy = (1.0 / 4.0) * mass * Yradius * Zradius + (1.0 / 12.0) * mass * Xwidth * Xwidth; Izz = (1.0 / 4.0) * mass * Yradius * Zradius + (1.0 / 12.0) * mass * Xwidth * Xwidth; } else { // Not supported. Revert to pointmass model. Ixx = Iyy = Izz = 0.0; } // The volume is symmetric, so Ixy = Ixz = Iyz = 0. ballonetJ(1,1) = Ixx; ballonetJ(2,2) = Iyy; ballonetJ(3,3) = Izz; // Transform the moments of inertia to the body frame. ballonetJ += MassBalance->GetPointmassInertia(GetMass(), GetXYZ()); }
// ----------------------------------------------------------------------------- // Get the current COM location of the steering subsystem. // ----------------------------------------------------------------------------- ChVector<> ChPitmanArm::GetCOMPos() const { ChVector<> com = getSteeringLinkMass() * m_link->GetPos() + getPitmanArmMass() * m_arm->GetPos(); return com / GetMass(); }