46#include "models/FGGroundReactions.h"
47#include "models/FGInertial.h"
48#include "math/FGTable.h"
49#include "input_output/FGXMLElement.h"
50#include "input_output/FGLog.h"
66const FGMatrix33 FGLGear::Tb2s(-1./inchtoft, 0., 0., 0., 1./inchtoft, 0., 0., 0., -1./inchtoft);
67const FGMatrix33 FGLGear::Ts2b(-inchtoft, 0., 0., 0., inchtoft, 0., 0., 0., -inchtoft);
79 StaticFriction(false),
82 kSpring = bDamp = bDampRebound = dynamicFCoeff = staticFCoeff = rollingFCoeff = maxSteerAngle = 0;
83 isRetractable =
false;
85 eDampTypeRebound = dtLinear;
89 if (sContactType ==
"BOGEY") {
90 eContactType = ctBOGEY;
91 }
else if (sContactType ==
"STRUCTURE") {
92 eContactType = ctSTRUCTURE;
95 eContactType = ctSTRUCTURE;
99 if (eContactType == ctSTRUCTURE) {
100 kSpring = in.EmptyWeight;
102 bDampRebound = kSpring * 10;
113 fStrutForce =
new FGFunction(fdmex, springFunc);
121 eDampType = dtSquare;
131 eDampTypeRebound = dtSquare;
137 bDampRebound = bDamp;
138 eDampTypeRebound = eDampType;
156 if ((maxSteerAngle == 360 && !castered_el)
158 eSteerType = stCaster;
161 else if (maxSteerAngle == 0.0) {
162 eSteerType = stFixed;
165 eSteerType = stSteer;
171 while (force_table) {
173 if (force_type ==
"CORNERING_COEFF") {
174 ForceY_Table =
new FGTable(PropertyManager, force_table);
178 log <<
"Undefined force table for " << name <<
" contact point\n";
187 err <<
"\nNo location given for contact " << name <<
"\n";
190 SetTransformType(FGForce::tCustom);
193 if (element && (eContactType == ctBOGEY)) {
196 mTGear = quatFromEuler.
GetT();
206 if (sBrakeGroup ==
"LEFT" ) eBrakeGrp = bgLeft;
207 else if (sBrakeGroup ==
"RIGHT" ) eBrakeGrp = bgRight;
208 else if (sBrakeGroup ==
"CENTER") eBrakeGrp = bgCenter;
209 else if (sBrakeGroup ==
"NOSE" ) eBrakeGrp = bgCenter;
210 else if (sBrakeGroup ==
"TAIL" ) eBrakeGrp = bgCenter;
211 else if (sBrakeGroup ==
"NONE" ) eBrakeGrp = bgNone;
212 else if (sBrakeGroup.empty() ) eBrakeGrp = bgNone;
215 log <<
"Improper braking group specification in config file: "
216 << sBrakeGroup <<
" is undefined.\n";
222 useFCSGearPos =
false;
224 TakeoffReported = LandingReported =
false;
235 bind(PropertyManager.get());
251void FGLGear::ResetToIC(
void)
255 WOW = lastWOW =
false;
256 FirstContact =
false;
257 StartedGroundRun =
false;
258 LandingDistanceTraveled = TakeoffDistanceTraveled = TakeoffDistanceTraveled50ft = 0.0;
259 MaximumStrutForce = MaximumStrutTravel = 0.0;
260 SinkRate = GroundSpeed = 0.0;
263 vWhlVelVec.InitMatrix();
265 compressLength = 0.0;
272 for (
int i=0; i < 3; i++) {
273 LMultiplier[i].ForceJacobian.InitMatrix();
274 LMultiplier[i].LeverArm.InitMatrix();
275 LMultiplier[i].Min = 0.0;
276 LMultiplier[i].Max = 0.0;
277 LMultiplier[i].value = 0.0;
285 double gearPos = 1.0;
294 vLocalGear = in.Tb2l * vWhlBodyVec;
299 double height = fdmex->
GetInertial()->GetContactPoint(gearLoc, contact,
300 normal, terrainVel, dummy);
304 AGL = max(height, 0.0);
306 if (isRetractable) gearPos = GetGearUnitPos();
308 if (gearPos > 0.99) {
310 if (!fdmex->GetTrimStatus())
316 isSolid = GroundReactions->
GetSolid();
319 double LGearProj = 1.0;
323 vGroundNormal = in.Tec2b * normal;
329 double normalZ = (in.Tec2l*normal)(eZ);
330 LGearProj = -(mTGear.
Transposed() * vGroundNormal)(eZ);
334 switch(eContactType) {
337 compressLength = LGearProj > 0.0 ? height * normalZ / LGearProj : 0.0;
345 compressLength = height * normalZ /
DotProduct(normal, normal);
346 vWhlDisplVec = compressLength * vGroundNormal;
355 vActingXYZn = vXYZn + Tb2s * vWhlDisplVec;
357 vBodyWhlVel += in.UVW - in.Tec2b * terrainVel;
358 vWhlVelVec = mTGear.
Transposed() * vBodyWhlVel;
360 InitializeReporting();
361 ComputeSteeringAngle();
362 ComputeGroundFrame();
364 vGroundWhlVel = mT.
Transposed() * vBodyWhlVel;
366 if (fdmex->GetTrimStatus() || in.TotalDeltaT == 0.0)
369 compressSpeed = -vGroundWhlVel(eZ);
370 if (eContactType == ctBOGEY)
371 compressSpeed /= LGearProj;
376 double maxCompressSpeed = compressLength/in.TotalDeltaT;
377 if (fabs(compressSpeed) > maxCompressSpeed)
378 compressSpeed = sign(compressSpeed)*maxCompressSpeed;
381 ComputeVerticalStrutForce();
384 if (eContactType == ctBOGEY) {
386 ComputeBrakeForceCoefficient();
387 ComputeSideForceCoefficient();
392 ComputeJacobian(vWhlContactVec);
394 compressLength = 0.0;
398 vWhlDisplVec.InitMatrix();
400 LMultiplier[ftRoll].value = 0.0;
401 LMultiplier[ftSide].value = 0.0;
402 LMultiplier[ftDynamic].value = 0.0;
405 SteerAngle *= max(gearPos-0.8, 0.0)/0.2;
413 vWhlVelVec(eX) -= 13.0 * in.TotalDeltaT;
414 if (vWhlVelVec(eX) < 0.0) vWhlVelVec(eX) = 0.0;
417 if (!fdmex->GetTrimStatus()) {
418 ReportTakeoffOrLanding();
422 if (WOW && lastWOW) CrashDetect();
427 return FGForce::GetBodyForces();
436void FGLGear::ComputeGroundFrame(
void)
441 roll -=
DotProduct(roll, vGroundNormal) * vGroundNormal;
445 mT(eX,eX) = roll(eX);
446 mT(eY,eX) = roll(eY);
447 mT(eZ,eX) = roll(eZ);
448 mT(eX,eY) = side(eX);
449 mT(eY,eY) = side(eY);
450 mT(eZ,eY) = side(eZ);
451 mT(eX,eZ) = vGroundNormal(eX);
452 mT(eY,eZ) = vGroundNormal(eY);
453 mT(eZ,eZ) = vGroundNormal(eZ);
459void FGLGear::ComputeSlipAngle(
void)
462 if (vGroundWhlVel.
Magnitude(eX,eY) > 1E-3)
463 WheelSlip = -atan2(vGroundWhlVel(eY), fabs(vGroundWhlVel(eX)))*radtodeg;
470void FGLGear::ComputeSteeringAngle(
void)
475 SteerAngle = atan2(vWhlVelVec(eY), fabs(vWhlVelVec(eX)));
482void FGLGear::ResetReporting(
void)
484 if (in.DistanceAGL > 200.0) {
485 FirstContact =
false;
486 StartedGroundRun =
false;
487 LandingReported =
false;
488 TakeoffReported =
true;
489 LandingDistanceTraveled = 0.0;
490 MaximumStrutForce = MaximumStrutTravel = 0.0;
496void FGLGear::InitializeReporting(
void)
503 SinkRate = compressSpeed;
504 GroundSpeed = in.Vground;
505 TakeoffReported =
false;
510 if ((in.Vground > 0.1) &&
511 (in.BrakePos[bgLeft] == 0) &&
512 (in.BrakePos[bgRight] == 0) &&
513 (in.TakeoffThrottle && !StartedGroundRun))
515 TakeoffDistanceTraveled = 0;
516 TakeoffDistanceTraveled50ft = 0;
517 StartedGroundRun =
true;
524void FGLGear::ReportTakeoffOrLanding(
void)
527 LandingDistanceTraveled += in.Vground * in.TotalDeltaT;
529 if (StartedGroundRun) {
530 TakeoffDistanceTraveled50ft += in.Vground * in.TotalDeltaT;
531 if (WOW) TakeoffDistanceTraveled += in.Vground * in.TotalDeltaT;
535 && in.Vground <= 0.05
539 if (debug_lvl > 0) Report(erLand);
544 && (in.DistanceAGL - vLocalGear(eZ)) > 50.0
547 if (debug_lvl > 0) Report(erTakeoff);
553 FGLogging log(LogLevel::INFO);
554 log <<
"GEAR_CONTACT: " << fixed << fdmex->
GetSimTime() <<
" seconds: "
555 << name <<
" " << WOW <<
"\n";
563void FGLGear::CrashDetect(
void)
565 if ( (compressLength > 500.0 ||
567 GetMoments().Magnitude() > 5000000000.0 ||
571 FGLogging log(LogLevel::INFO);
572 log <<
"*CRASH DETECTED* " << fixed << fdmex->
GetSimTime() <<
" seconds: "
588void FGLGear::ComputeBrakeForceCoefficient(
void)
590 BrakeFCoeff = rollingFFactor * rollingFCoeff;
592 if (eBrakeGrp != bgNone)
593 BrakeFCoeff += in.BrakePos[eBrakeGrp] * staticFFactor * (staticFCoeff - rollingFCoeff);
606void FGLGear::ComputeSideForceCoefficient(
void)
609 FCoeff = ForceY_Table->
GetValue(WheelSlip);
611 double StiffSlip = Stiffness*WheelSlip;
612 FCoeff = Peak * sin(Shape*atan(StiffSlip - Curvature*(StiffSlip - atan(StiffSlip))));
614 FCoeff *= staticFFactor;
624void FGLGear::ComputeVerticalStrutForce()
627 StrutForce = min(fStrutForce->
GetValue(), (
double)0.0);
629 double springForce = -compressLength * kSpring;
630 double dampForce = 0;
632 if (compressSpeed >= 0.0) {
634 if (eDampType == dtLinear)
635 dampForce = -compressSpeed * bDamp;
637 dampForce = -compressSpeed * compressSpeed * bDamp;
641 if (eDampTypeRebound == dtLinear)
642 dampForce = -compressSpeed * bDampRebound;
644 dampForce = compressSpeed * compressSpeed * bDampRebound;
648 StrutForce = min(springForce + dampForce, (
double)0.0);
649 if (StrutForce > maximumForce) {
650 StrutForce = maximumForce;
651 compressLength = -StrutForce / kSpring;
656 switch (eContactType) {
659 vFn(eZ) = StrutForce / (mTGear.
Transposed()*vGroundNormal)(eZ);
662 vFn(eZ) = -StrutForce;
667 MaximumStrutForce = max(MaximumStrutForce, fabs(StrutForce));
668 MaximumStrutTravel = max(MaximumStrutTravel, fabs(compressLength));
673double FGLGear::GetGearUnitPos(
void)
const
676 if( useFCSGearPos || in.FCSGearPos != 1.0 ) {
677 useFCSGearPos =
true;
678 return in.FCSGearPos;
687void FGLGear::ComputeJacobian(
const FGColumnVector3& vWhlContactVec)
692 if ((eContactType == ctSTRUCTURE) && (vGroundWhlVel.
Magnitude(eX,eY) > 1E-3)) {
694 FGColumnVector3 velocityDirection = vGroundWhlVel;
696 StaticFriction =
false;
698 velocityDirection(eZ) = 0.;
699 velocityDirection.Normalize();
701 LMultiplier[ftDynamic].ForceJacobian = mT * velocityDirection;
702 LMultiplier[ftDynamic].Max = 0.;
703 LMultiplier[ftDynamic].Min = -fabs(staticFFactor * dynamicFCoeff * vFn(eZ));
704 LMultiplier[ftDynamic].LeverArm = vWhlContactVec;
711 LMultiplier[ftDynamic].value =
Constrain(LMultiplier[ftDynamic].Min, LMultiplier[ftDynamic].value, LMultiplier[ftDynamic].Max);
713 GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftDynamic]);
721 StaticFriction =
true;
723 LMultiplier[ftRoll].ForceJacobian = mT * FGColumnVector3(1.,0.,0.);
724 LMultiplier[ftSide].ForceJacobian = mT * FGColumnVector3(0.,1.,0.);
725 LMultiplier[ftRoll].LeverArm = vWhlContactVec;
726 LMultiplier[ftSide].LeverArm = vWhlContactVec;
728 switch(eContactType) {
730 LMultiplier[ftRoll].Max = fabs(BrakeFCoeff * vFn(eZ));
731 LMultiplier[ftSide].Max = fabs(FCoeff * vFn(eZ));
734 LMultiplier[ftRoll].Max = fabs(staticFFactor * staticFCoeff * vFn(eZ));
735 LMultiplier[ftSide].Max = LMultiplier[ftRoll].Max;
739 LMultiplier[ftRoll].Min = -LMultiplier[ftRoll].Max;
740 LMultiplier[ftSide].Min = -LMultiplier[ftSide].Max;
747 LMultiplier[ftRoll].value =
Constrain(LMultiplier[ftRoll].Min, LMultiplier[ftRoll].value, LMultiplier[ftRoll].Max);
748 LMultiplier[ftSide].value =
Constrain(LMultiplier[ftSide].Min, LMultiplier[ftSide].value, LMultiplier[ftSide].Max);
750 GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftRoll]);
751 GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftSide]);
759void FGLGear::UpdateForces(
void)
761 if (StaticFriction) {
762 vFn(eX) = LMultiplier[ftRoll].value;
763 vFn(eY) = LMultiplier[ftSide].value;
766 FGColumnVector3 forceDir = mT.
Transposed() * LMultiplier[ftDynamic].ForceJacobian;
767 vFn(eX) = LMultiplier[ftDynamic].value * forceDir(eX);
768 vFn(eY) = LMultiplier[ftDynamic].value * forceDir(eY);
774void FGLGear::SetstaticFCoeff(
double coeff)
776 staticFCoeff = coeff;
782void FGLGear::bind(FGPropertyManager* PropertyManager)
784 string property_name;
785 string base_property_name;
787 switch(eContactType) {
789 base_property_name = CreateIndexedPropertyName(
"gear/unit", GearNumber);
792 base_property_name = CreateIndexedPropertyName(
"contact/unit", GearNumber);
798 property_name = base_property_name +
"/AGL-ft";
799 PropertyManager->Tie(property_name.c_str(), &AGL);
800 property_name = base_property_name +
"/WOW";
801 PropertyManager->Tie( property_name.c_str(), &WOW );
802 property_name = base_property_name +
"/x-position";
803 PropertyManager->Tie( property_name.c_str(), (FGForce*)
this,
804 &FGForce::GetLocationX, &FGForce::SetLocationX);
805 property_name = base_property_name +
"/y-position";
806 PropertyManager->Tie( property_name.c_str(), (FGForce*)
this,
807 &FGForce::GetLocationY, &FGForce::SetLocationY);
808 property_name = base_property_name +
"/z-position";
809 PropertyManager->Tie( property_name.c_str(), (FGForce*)
this,
810 &FGForce::GetLocationZ, &FGForce::SetLocationZ);
811 property_name = base_property_name +
"/compression-ft";
812 PropertyManager->Tie( property_name.c_str(), &compressLength );
813 property_name = base_property_name +
"/compression-velocity-fps";
814 PropertyManager->Tie( property_name.c_str(), &compressSpeed );
815 property_name = base_property_name +
"/static_friction_coeff";
816 PropertyManager->Tie( property_name.c_str(), (FGLGear*)
this,
817 &FGLGear::GetstaticFCoeff, &FGLGear::SetstaticFCoeff);
818 property_name = base_property_name +
"/dynamic_friction_coeff";
819 PropertyManager->Tie( property_name.c_str(), &dynamicFCoeff );
821 if (eContactType == ctBOGEY) {
822 property_name = base_property_name +
"/slip-angle-deg";
823 PropertyManager->Tie( property_name.c_str(), &WheelSlip );
824 property_name = base_property_name +
"/wheel-speed-fps";
825 PropertyManager->Tie( property_name.c_str(), (FGLGear*)
this,
826 &FGLGear::GetWheelRollVel);
827 property_name = base_property_name +
"/side_friction_coeff";
828 PropertyManager->Tie( property_name.c_str(), &FCoeff );
829 property_name = base_property_name +
"/rolling_friction_coeff";
830 PropertyManager->Tie( property_name.c_str(), &rollingFCoeff );
832 if (eSteerType == stCaster) {
833 property_name = base_property_name +
"/steering-angle-deg";
834 PropertyManager->Tie( property_name.c_str(),
this, &FGLGear::GetSteerAngleDeg );
835 property_name = base_property_name +
"/castered";
836 PropertyManager->Tie( property_name.c_str(), &Castered);
840 if( isRetractable ) {
841 property_name = base_property_name +
"/pos-norm";
842 PropertyManager->Tie( property_name.c_str(), &GearPos );
845 if (eSteerType != stFixed) {
849 string tmp = CreateIndexedPropertyName(
"fcs/steer-pos-deg", GearNumber);
850 PropertyManager->Tie(tmp.c_str(),
this, &FGLGear::GetSteerAngleDeg, &FGLGear::SetSteerAngleDeg);
853 property_name = base_property_name +
"/solid";
854 PropertyManager->Tie( property_name.c_str(), &isSolid);
855 property_name = base_property_name +
"/bumpiness";
856 PropertyManager->Tie( property_name.c_str(), &bumpiness);
857 property_name = base_property_name +
"/maximum-force-lbs";
858 PropertyManager->Tie( property_name.c_str(), &maximumForce);
859 property_name = base_property_name +
"/rolling_friction-factor";
860 PropertyManager->Tie( property_name.c_str(), &rollingFFactor);
861 property_name = base_property_name +
"/static-friction-factor";
862 PropertyManager->Tie( property_name.c_str(), &staticFFactor);
867void FGLGear::Report(ReportType repType)
869 if (fabs(TakeoffDistanceTraveled) < 0.001)
return;
871 FGLogging log(LogLevel::INFO);
875 log <<
"\nTouchdown report for " << name <<
" (WOW at time: " << fixed
877 log <<
" Sink rate at contact: " << SinkRate <<
" fps, "
878 << SinkRate*0.3048 <<
" mps\n";
879 log <<
" Contact ground speed: " << GroundSpeed*.5925 <<
" knots, "
880 << GroundSpeed*0.3048 <<
" mps\n";
881 log <<
" Maximum contact force: " << MaximumStrutForce <<
" lbs, "
882 << MaximumStrutForce*4.448 <<
" Newtons\n";
883 log <<
" Maximum strut travel: " << MaximumStrutTravel*12.0 <<
" inches, "
884 << MaximumStrutTravel*30.48 <<
" cm\n";
885 log <<
" Distance traveled: " << LandingDistanceTraveled <<
" ft, "
886 << LandingDistanceTraveled*0.3048 <<
" meters\n";
887 LandingReported =
true;
890 log <<
"\nTakeoff report for " << name <<
" (Liftoff at time: " << fixed
892 log <<
" Distance traveled: " << TakeoffDistanceTraveled
893 <<
" ft, " << TakeoffDistanceTraveled*0.3048 <<
" meters\n";
894 log <<
" Distance traveled (over 50'): " << TakeoffDistanceTraveled50ft
895 <<
" ft, " << TakeoffDistanceTraveled50ft*0.3048 <<
" meters\n";
896 log <<
" [Altitude (ASL): " << in.DistanceASL <<
" ft. / "
897 << in.DistanceASL*FGJSBBase::fttom <<
" m | Temperature: "
898 << in.Temperature - 459.67 <<
" F / "
900 log <<
" [Velocity (KCAS): " << in.VcalibratedKts <<
"]\n";
901 TakeoffReported =
true;
927void FGLGear::Debug(
int from)
929 static const char* sSteerType[] = {
"STEERABLE",
"FIXED",
"CASTERED" };
930 static const char* sBrakeGroup[] = {
"NONE",
"LEFT",
"RIGHT",
"CENTER",
"NOSE",
"TAIL"};
931 static const char* sContactType[] = {
"BOGEY",
"STRUCTURE" };
933 if (debug_lvl <= 0)
return;
936 FGLogging log(LogLevel::DEBUG);
938 log <<
" " << sContactType[eContactType] <<
" " << name <<
"\n" << fixed;
939 log <<
" Location: " << vXYZn <<
"\n";
940 log <<
" Spring Constant: " << kSpring <<
"\n";
942 if (eDampType == dtLinear)
943 log <<
" Damping Constant: " << bDamp <<
" (linear)\n";
945 log <<
" Damping Constant: " << bDamp <<
" (square law)\n";
947 if (eDampTypeRebound == dtLinear)
948 log <<
" Rebound Damping Constant: " << bDampRebound <<
" (linear)\n";
950 log <<
" Rebound Damping Constant: " << bDampRebound <<
" (square law)\n";
952 log <<
" Dynamic Friction: " << dynamicFCoeff <<
"\n";
953 log <<
" Static Friction: " << staticFCoeff <<
"\n";
954 if (eContactType == ctBOGEY) {
955 log <<
" Rolling Friction: " << rollingFCoeff <<
"\n";
956 log <<
" Steering Type: " << sSteerType[eSteerType] <<
"\n";
957 log <<
" Grouping: " << sBrakeGroup[eBrakeGrp] <<
"\n";
958 log <<
" Max Steer Angle: " << maxSteerAngle <<
"\n";
959 log <<
" Retractable: " << isRetractable <<
"\n";
963 if (debug_lvl & 2 ) {
964 FGLogging log(LogLevel::DEBUG);
965 if (from == 0) log <<
"Instantiated: FGLGear\n";
966 if (from == 1) log <<
"Destroyed: FGLGear\n";
968 if (debug_lvl & 4 ) {
970 if (debug_lvl & 8 ) {
972 if (debug_lvl & 16) {
974 if (debug_lvl & 64) {
Element * FindElement(const std::string &el="")
Searches for a specified element.
FGColumnVector3 FindElementTripletConvertTo(const std::string &target_units)
Composes a 3-element column vector for the supplied location or orientation.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
std::string FindElementValue(const std::string &el="")
Searches for the named element and returns the string data belonging to it.
double FindElementValueAsNumberConvertTo(const std::string &el, const std::string &target_units)
Searches for the named element and converts and returns the data belonging to it.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
double GetDataAsNumber(void)
Converts the element data to a number.
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
This class implements a 3 element column vector.
double Magnitude(void) const
Length of the vector.
FGColumnVector3 & Normalize(void)
Normalize.
Encapsulates the JSBSim simulation executive.
std::shared_ptr< FGGroundReactions > GetGroundReactions(void) const
Returns the FGGroundReactions pointer.
bool IntegrationSuspended(void) const
Returns the simulation suspension state.
double GetSimTime(void) const
Returns the cumulative simulation time in seconds.
std::shared_ptr< FGInertial > GetInertial(void) const
Returns the FGInertial pointer.
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
Utility class that aids in the conversion of forces between coordinate systems and calculation of mom...
Represents a mathematical function.
double GetValue(void) const override
Retrieves the value of the function object.
static constexpr double Constrain(double min, double value, double max)
Constrain a value between a minimum and a maximum value.
static constexpr double RankineToCelsius(double rankine)
Converts from degrees Rankine to degrees Celsius.
const FGColumnVector3 & GetBodyForces(void) override
The Force vector for this gear.
FGLGear(Element *el, FGFDMExec *Executive, int number, const struct Inputs &input)
Constructor.
FGLocation holds an arbitrary location in the Earth centered Earth fixed reference frame (ECEF).
FGLocation LocalToLocation(const FGColumnVector3 &lvec) const
Conversion from Local frame coordinates to a location in the earth centered and fixed frame.
FGMatrix33 Transposed(void) const
Transposed matrix.
Models the Quaternion representation of rotations.
const FGMatrix33 & GetT(void) const
Transformation matrix.
bool GetSolid(void)
Gets the surface is a solid flag value.
double GetBumpiness(void)
Gets the normalized bumpiness factor associated with the surface.
double GetRollingFFactor(void)
Gets the rolling friction factor of the surface area.
double GetMaximumForce(void)
Gets the maximum force of the surface area.
double GetBumpHeight()
Returns the height of the bump at the provided offset.
double GetStaticFFactor(void)
Gets the static friction factor of the surface area.
double GetValue(void) const
Get the current table value.
Main namespace for the JSBSim Flight Dynamics Model.
double DotProduct(const FGColumnVector3 &v1, const FGColumnVector3 &v2)
Dot product of two vectors Compute and return the euclidean dot (or scalar) product of two vectors v1...