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;
}
Exemple #5
0
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);
	}
}
Exemple #7
0
// 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);
}
Exemple #10
0
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());
}
Exemple #11
0
// -----------------------------------------------------------------------------
// 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();
}