36# include <simgear/constants.h>
37# include <simgear/math/simd.hxx>
38# include <simgear/math/simd4x4.hxx>
39# include <simgear/math/sg_geodesy.hxx>
48# include "simd4x4.hxx"
51#define FEET_TO_INCHES 12.0f
52#define INCHES_TO_FEET (1.0f/FEET_TO_INCHES)
54FGAISim::FGAISim(
double dt)
56 simd4x4::zeros(xCDYLT);
57 simd4x4::zeros(xClmnT);
59 for (
size_t i=0;
i<AISIM_MAX; ++
i)
61 contact_pos[
i] = 0.0f;
62 contact_spring[
i] = contact_damp[
i] = 0.0f;
67 SGPath aircraft_path(
fgGetString(
"/sim/fg-root") );
68 SGPropertyNode_ptr aero =
fgGetNode(
"sim/aero",
true);
69 aircraft_path.append(
"Aircraft-aisim");
70 aircraft_path.append(aero->getStringValue());
71 aircraft_path.concat(
".json");
73 load(aircraft_path.str());
78 set_rudder_norm(0.0f);
79 set_elevator_norm(0.0f);
80 set_aileron_norm(0.0f);
81 set_throttle_norm(0.0f);
85 set_velocity_fps(0.0f);
98 xCadot[LIFT] = -CLadot;
101 xCadot[PITCH] = Cmadot;
103 xCDYLT.ptr()[MIN][LIFT] = -CLmin;
104 xCDYLT.ptr()[MIN][DRAG] = -CDmin;
107 inv_mass = aiVec3(1.0f)/mass;
110 float cg_agl = -cg[
Z];
113 for (
size_t i=0;
i<no_contacts; ++
i) {
114 cg_agl += contact_pos[
i][
Z];
116 cg_agl /=
static_cast<float>(no_contacts);
118 set_altitude_agl_ft(cg_agl);
121 contact_pos[no_contacts] = 0.0f;
122 contact_spring[no_contacts] = -20000.0f;
123 contact_damp[no_contacts] = -2000.0f;
128 simd4x4::translate(mcg, cg);
130 mJ = aiMtx4( I[XX], 0.0f, -I[XZ], 0.0f,
131 0.0f, I[YY], 0.0f, 0.0f,
132 -I[XZ], 0.0f, I[ZZ], 0.0f,
133 0.0f, 0.0f, 0.0f, 0.0f);
134 mJinv = invert_inertia(mJ);
136 mJinv *= matrix_inverse(mcg);
154 SG_LOG( SG_FLIGHT, SG_INFO,
"Starting initializing AISim" );
157 set_Altitude( get_Altitude() + cg_agl );
158 set_location_geod( get_Latitude(), get_Longitude(), get_Altitude() );
159 set_euler_angles_rad( get_Phi(), get_Theta(), get_Psi() );
160 set_velocity_fps(
fgGetFloat(
"sim/presets/uBody-fps"),
167FGAISim::update(
double ddt)
170 if (is_suspended() || ddt == 0)
182 printf(
"pitch: % 7.5f, roll: % 7.5f, heading: % 7.5f\n", euler[THETA], euler[PHI], euler[PSI]);
183 printf(
"wind north: % 7.5f, east: % 7.5f, down: % 7.5f\n", wind_ned[0], wind_ned[1], wind_ned[2]);
188 aiVec3 vector = euler;
189 float len = simd4::normalize(vector);
190 aiMtx4 mNed2Body = simd4x4::rotation_matrix(len, vector);
191 aiMtx4 mBody2Ned = simd4x4::transpose(mNed2Body);
192 aiVec3 wind = mNed2Body*wind_ned;
195 vUVWaero = vUVW + wind;
196 update_velocity( simd4::magnitude( vUVWaero ) );
199 aiVec3 prevAOA = AOA;
200 alpha = (vUVWaero[U] == 0.0f) ? 0.0f : std::atan2(vUVWaero[
W], vUVWaero[U]);
201 set_alpha_rad( alpha );
203 beta = (velocity == 0.0f) ? 0.0f : std::asin(vUVWaero[V]/velocity);
204 set_beta_rad( beta );
207 AOAdot = (AOA - prevAOA)/dt;
210 printf(
"velocity: %f, vUVWaero: %3.2f, %3.2f, %3.2f, mach: %3.2f\n", velocity, vUVWaero[U], vUVWaero[V], vUVWaero[
W], mach);
211 printf(
"cg_agl: %5.4f, alpha: %5.4f, beta: %5.4f, adot: %5.4f, bdot: %5.4f\n", cg_agl, AOA[ALPHA], AOA[BETA], AOAdot[ALPHA], AOAdot[BETA]);
219 float adot = AOAdot[ALPHA];
229 aiVec4 Ccbar2U = (xCq*q + xCadot*adot)*cbar_2U;
230 aiVec4 Cb2U = (xCp*
p + xCr*r)*b_2U;
234 aiVec4 CDYL(0.0f, Cb2U[SIDE], Ccbar2U[LIFT]);
235 aiVec4 Clmn(Cb2U[ROLL], Ccbar2U[PITCH], Cb2U[YAW]);
238 CDYL +=
static_cast<aiVec4
>(xCDYLT.m4x4()[
i]);
239 Clmn +=
static_cast<aiVec4
>(xClmnT.m4x4()[
i]);
243 float CL = CDYL[LIFT];
244 CDYL += aiVec3(CDi*CL*CL, 0.0f, 0.0f);
246 printf(
" p: %6.3f, q: %6.3f, r: %6.3f, adot: %6.3f\n",
p, q, r, adot);
247 printf(
" CLa: %6.3f, CLadot: %6.3f, CLq: %6.3f\n", xCDYLT.ptr()[ALPHA][LIFT],CLadot*adot,CLq*q);
248 printf(
" CDa: %6.3f, CDb: %6.3f, CDi: %6.3f\n", xCDYLT.ptr()[ALPHA][DRAG],xCDYLT.ptr()[BETA][DRAG],CDi*CL*CL);
249 printf(
" CYb: %6.3f, CYp: %6.3f, CYr: %6.3f\n", xCDYLT.ptr()[BETA][SIDE],CYp*
p,CYr*r);
250 printf(
" Cma: %6.3f, Cmadot: %6.3f, Cmq: %6.3f\n", xClmnT.ptr()[ALPHA][PITCH],Cmadot*adot,Cmq*q);
251 printf(
" Clb: %6.3f, Clp: %6.3f, Clr: %6.3f\n", xClmnT.ptr()[BETA][ROLL],Clp*
p,Clr*r);
252 printf(
" Cnb: %6.3f, Cnp: %6.3f, Cnr: %6.3f\n", xClmnT.ptr()[BETA][YAW],Cnp*
p,Cnr*r);
254 printf(
" Cmde: %6.3f\n", xClmnT.ptr()[ELEVATOR][PITCH]);
255 printf(
" CYdr: %6.3f, Cldr: %6.3f, Cndr: %6.3f\n", xCDYLT.ptr()[RUDDER][SIDE], xClmnT.ptr()[RUDDER][ROLL], xClmnT.ptr()[RUDDER][YAW]);
256 printf(
" Clda: %6.3f, CYda: %6.3f\n", xClmnT.ptr()[AILERON][ROLL], xClmnT.ptr()[AILERON][YAW]);
257 printf(
" Cldf: %6.3f, CDdf: %6.3f, Cmdf: %6.3f\n", xCDYLT.ptr()[FLAPS][LIFT], xCDYLT.ptr()[FLAPS][DRAG], xClmnT.ptr()[FLAPS][PITCH]);
262 aiVec3 FDYL = CDYL*Coef2Force;
263 aiVec3 Mlmn = Clmn*Coef2Moment;
267 len = simd4::normalize(vector);
268 aiMtx4 mWind2Body = simd4x4::rotation_matrix(len, vector);
269 aiVec3 FXYZ_body = mWind2Body*FDYL;
271 aiVec3 gravity_body = mNed2Body*gravity_ned;
272 FXYZ_body += gravity_body*mass;
279 aiVec3 FEngine = FT[
i]*(Cth*n2[
i]);
280 aiVec3 MEngine = MT[
i]*Cth;
282 FXYZ_body += FEngine;
285 printf(
"FT[%lu]: %5.4f, %5.4f, %5.4f\n",
i, FEngine[X], FEngine[
Y], FEngine[
Z]);
286 printf(
"MT[%lu]: %5.4f, % 7.5f, %5.4f\n",
i, MEngine[ROLL], MEngine[PITCH], MEngine[YAW]);
291 printf(
"FXYZ: %5.4f, %5.4f, %5.4f\n", FXYZ_body[X], FXYZ_body[
Y], FXYZ_body[
Z]);
292 printf(
"Mlmn: %5.4f, % 7.5f, %5.4f\n", Mlmn[ROLL], Mlmn[PITCH], Mlmn[YAW]);
297 if (no_contacts && cg_agl < 10.0f)
303 aiVec3 lg_ground_ned = mBody2Ned*contact_pos[
i];
304 if (lg_ground_ned[
Z] > cg_agl)
306 aiVec3 lg_vrot = simd4::cross(vPQR, contact_pos[
i]);
307 aiVec3 lg_cg_vned = mBody2Ned*lg_vrot;
308 aiVec3 lg_vned = vNED + lg_cg_vned;
309 float Fn = std::min((contact_spring[
i]*lg_ground_ned[
Z] +
310 contact_damp[
i]*lg_vned[
Z]), 0.0f);
312 aiVec3 Fgear(0.0f, 0.0f, Fn);
313 aiVec3 Fbody = mNed2Body*Fgear;
314 aiVec3 Fbrake = mu_body*Fbody;
316 aiVec3 FLGear = Fbody + Fbrake;
322 printf(
"gear: %lu: pos: % 3.2f % 3.2f % 3.2f\n",
i,
323 lg_ground_ned[0], lg_ground_ned[1], lg_ground_ned[2]);
324 printf(
" Fbody: % 7.2f % 7.2f % 7.2f\n", Fbody[0], Fbody[1], Fbody[2]);
325 printf(
" Fbrake: % 7.2f % 7.2f % 7.2f\n", Fbrake[0], Fbrake[1], Fbrake[2]);
326 printf(
" Fgear: % 7.2f % 7.2f % 7.2f\n", lg_ground_ned[0], lg_ground_ned[1], lg_ground_ned[2]);
327 printf(
" Mgear: % 7.2f % 7.2f % 7.2f\n", MLGear[0], MLGear[1], MLGear[2]);
331 WoW = (WoW_main == 3);
333 while(++
i < no_contacts);
337 XYZdot = FXYZ_body*inv_mass;
339printf(
"AOAdot: %5.4f, AOA: %5.4f, up: XYZdot: % 7.5f, XYZ: % 7.5f, gravity: % 7.5f\n", AOAdot[ALPHA], AOA[ALPHA], XYZdot[
Z], FXYZ_body[
Z]/mass, gravity_body[DOWN]);
343 printf(
"XYZdot % 7.5f, % 7.5f, % 7.5f\n", XYZdot[X], XYZdot[
Y], XYZdot[
Z]);
344 printf(
"Mlmn: % 7.5f, % 7.5f, % 7.5f\n", Mlmn[ROLL], Mlmn[PITCH], Mlmn[YAW]);
350 vUVWdot = XYZdot - simd4::cross(vPQR, vUVW);
354 vPQRdot = mJinv*(Mlmn - vPQR*(mJ*vPQR));
357 printf(
"PQRdot: % 7.5f, % 7.5f, % 7.5f\n", vPQRdot[P], vPQRdot[Q], vPQRdot[
R]);
358 printf(
"PQR: % 7.5f, % 7.5f, % 7.5f\n", vPQR[P], vPQR[Q], vPQR[
R]);
359 printf(
"UVWdot: % 7.5f, % 7.5f, % 7.5f\n", vUVWdot[U], vUVWdot[V], vUVWdot[
W]);
360 printf(
"UVW: % 7.5f, % 7.5f, %1.7f\n", vUVW[U], vUVW[V], vUVW[
W]);
364 vNED = mBody2Ned*vUVW;
365 aiVec3 NEDdist = vNED*dt;
367 printf(
"vNED: % 7.5f, % 7.5f, % 7.5f\n", vNED[NORTH], vNED[EAST], vNED[DOWN]);
368 printf(
"NEDdist: % 7.5f, % 7.5f, % 7.5f\n", NEDdist[NORTH], NEDdist[EAST], NEDdist[DOWN]);
372 double dist = simd4::magnitude( aiVec2(NEDdist) );
374 double lat2 = 0.0, lon2 = 0.0, az2 = 0.0;
375 geo_direct_wgs_84( 0.0, location_geod[LATITUDE] * SGD_RADIANS_TO_DEGREES,
376 location_geod[LONGITUDE] * SGD_RADIANS_TO_DEGREES,
377 euler[PSI] * SGD_RADIANS_TO_DEGREES,
378 dist * SG_FEET_TO_METER, &lat2, &lon2, &az2 );
379 set_location_geod( lat2 * SGD_DEGREES_TO_RADIANS,
380 lon2 * SGD_DEGREES_TO_RADIANS,
381 location_geod[ALTITUDE] - NEDdist[DOWN] );
384 location_geod[X] += NEDdist[X];
385 location_geod[
Y] += NEDdist[
Y];
386 location_geod[
Z] -= NEDdist[
Z];
387 set_altitude_cg_agl_ft(location_geod[DOWN]);
390 printf(
"GEOD: % 7.5f, % 7.5f, % 7.5f\n", location_geod[0], location_geod[1], location_geod[2]);
395 vector = simd4::normalize(euler);
396 float len = simd4::normalize(vector);
397 aiMtx4 mWind2Body = simd4x4::rotation_matrix(len, vector);
398 euler_dot = mWind2Body*vPQR;
399 euler += euler_dot*dt;
403 float sin_p = std::sin(euler[PHI]);
404 float cos_p = std::cos(euler[PHI]);
405 float sin_t = std::sin(euler[THETA]);
406 float cos_t = std::cos(euler[THETA]);
407 if (std::abs(cos_t) < 0.00001f) cos_t = std::copysign(0.00001f,cos_t);
410 euler_dot[PSI] = 0.0f;
412 euler_dot[PSI] = (q*sin_p + r*cos_p)/cos_t;
414 euler_dot[THETA] = q*cos_p - r*sin_p;
416 euler_dot[PHI] =
p + euler_dot[PSI]*sin_t;
417 euler += euler_dot*dt;
419 printf(
"euler: % 7.5f, % 7.5f, % 7.5f\n", euler[PHI], euler[THETA], euler[PSI]);
430FGAISim::copy_to_AISim()
432 set_rudder_norm(
globals->get_controls()->get_rudder());
433 set_elevator_norm(
globals->get_controls()->get_elevator());
434 set_aileron_norm(
globals->get_controls()->get_aileron());
435 set_flaps_norm(
globals->get_controls()->get_flaps());
436 set_throttle_norm(
globals->get_controls()->get_throttle(0));
437 set_brake_norm(0.5f*(
globals->get_controls()->get_brake_left()
438 +
globals->get_controls()->get_brake_right()));
441 set_altitude_asl_ft(get_Altitude());
442 set_altitude_agl_ft(get_Altitude_AGL());
451FGAISim::copy_from_AISim()
455 _set_CG_Position( cg[X], cg[
Y], cg[
Z]);
458 _set_Accels_Body( vUVWdot[U], vUVWdot[V], vUVWdot[
W] );
461 _set_V_equiv_kts( velocity*std::sqrt(sigma) * SG_FPS_TO_KT );
462 _set_V_calibrated_kts( std::sqrt( 2.0f*qbar*sigma/rho) * SG_FPS_TO_KT );
463 _set_V_ground_speed( simd4::magnitude(aiVec2(vNED)) * SG_FPS_TO_KT );
464 _set_Mach_number( mach );
466 _set_Velocities_Local( vNED[NORTH], vNED[EAST], vNED[DOWN] );
468 _set_Velocities_Body( vUVW[U], vUVW[V], vUVW[
W] );
469 _set_Omega_Body( vPQR[P], vPQR[Q], vPQR[
R] );
470 _set_Euler_Rates( euler_dot[PHI], euler_dot[THETA], euler_dot[PSI] );
473 double lon = location_geod[LONGITUDE];
474 double lat_geod = location_geod[LATITUDE];
475 double altitude = location_geod[ALTITUDE];
481 _set_Geodetic_Position( lat_geod, lon,
altitude );
483 _set_Euler_Angles( euler[PHI], euler[THETA],
484 SGMiscd::normalizePeriodic(0, SGD_2PI, euler[PSI]) );
486 set_altitude_agl_ft(
altitude - get_Runway_altitude() );
487 _set_Altitude_AGL( cg_agl );
500 _set_Sea_level_radius( sl_radius * SG_METER_TO_FEET );
505 _set_Climb_Rate( -vNED[DOWN] );
507 _update_ground_elev_at_pos();
515#define OMEGA_EARTH 0.00007272205217f
519float FGAISim::density[
MAX_ALT] = {
520 0.0023771699, 0.0023083901, 0.0022411400, 0.0021753900, 0.0021111399,
521 0.0020483399, 0.0019869800, 0.0019270401, 0.0018685000, 0.0018113200,
522 0.0017554900, 0.0017009900, 0.0016477900, 0.0015958800, 0.0015452200,
523 0.0014958100, 0.0014476100, 0.0014006100, 0.0013547899, 0.0013101200,
524 0.0012665900, 0.0012241700, 0.0011828500, 0.0011426000, 0.0011034100,
525 0.0010652600, 0.0010281201, 0.0009919840, 0.0009568270, 0.0009226310,
526 0.0008893780, 0.0008570500, 0.0008256280, 0.0007950960, 0.0007654340,
527 0.0007366270, 0.0007086570, 0.0006759540, 0.0006442340, 0.0006140020,
528 0.0005851890, 0.0005577280, 0.0005315560, 0.0005066120, 0.0004828380,
529 0.0004601800, 0.0004385860, 0.0004180040, 0.0003983890, 0.0003796940,
530 0.0003618760, 0.0003448940, 0.0003287090, 0.0003132840, 0.0002985830,
531 0.0002845710, 0.0002712170, 0.0002584900, 0.0002463600, 0.0002347990,
532 0.0002237810, 0.0002132790, 0.0002032710, 0.0001937320, 0.0001846410,
533 0.0001759760, 0.0001676290, 0.0001595480, 0.0001518670, 0.0001445660,
534 0.0001376250, 0.0001310260, 0.0001247530, 0.0001187880, 0.0001131160,
535 0.0001077220, 0.0001025920, 0.0000977131, 0.0000930725, 0.0000886582,
536 0.0000844590, 0.0000804641, 0.0000766632, 0.0000730467, 0.0000696054,
537 0.0000663307, 0.0000632142, 0.0000602481, 0.0000574249, 0.0000547376,
538 0.0000521794, 0.0000497441, 0.0000474254, 0.0000452178, 0.0000431158,
539 0.0000411140, 0.0000392078, 0.0000373923, 0.0000356632, 0.0000340162,
544float FGAISim::vsound[
MAX_ALT] = {
545 1116.450, 1112.610, 1108.750, 1104.880, 1100.990, 1097.090, 1093.180,
546 1089.250, 1085.310, 1081.360, 1077.390, 1073.400, 1069.400, 1065.390,
547 1061.360, 1057.310, 1053.250, 1049.180, 1045.080, 1040.970, 1036.850,
548 1032.710, 1028.550, 1024.380, 1020.190, 1015.980, 1011.750, 1007.510,
549 1003.240, 998.963, 994.664, 990.347, 986.010, 981.655, 977.280,
550 972.885, 968.471, 968.076, 968.076, 968.076, 968.076, 968.076,
551 968.076, 968.076, 968.076, 968.076, 968.076, 968.076, 968.076,
552 968.076, 968.076, 968.076, 968.076, 968.076, 968.076, 968.076,
553 968.076, 968.076, 968.076, 968.076, 968.076, 968.076, 968.076,
554 968.076, 968.076, 968.076, 968.337, 969.017, 969.698, 970.377,
555 971.056, 971.735, 972.413, 973.091, 973.768, 974.445, 975.121,
556 975.797, 976.472, 977.147, 977.822, 978.496, 979.169, 979.842,
557 980.515, 981.187, 981.858, 982.530, 983.200, 983.871, 984.541,
558 985.210, 985.879, 986.547, 987.215, 987.883, 988.550, 989.217,
559 989.883, 990.549, 991.214
563FGAISim::update_velocity(
float v)
568 float alt_kft = _MINMAX(location_geod[ALTITUDE]/1000.0f, 0,
MAX_ALT);
569 float alt_idx = std::floor(alt_kft);
570 size_t idx =
static_cast<size_t>(alt_idx);
571 float fract = alt_kft - alt_idx;
572 float ifract = 1.0f - fract;
575 rho = ifract*density[idx] + fract*density[idx+1];
577 sigma = rho/density[0];
579 float Sqbar = Sw*qbar;
580 float Sbqbar = Sqbar*span;
581 float Sqbarcbar = Sqbar*cbar;
583 Coef2Force = aiVec3(Sqbar);
584 Coef2Moment = aiVec3(Sbqbar);
585 Coef2Moment[PITCH] = Sqbarcbar;
588 float vs = ifract*vsound[idx] + fract*vsound[idx+1];
593 cbar_2U = b_2U = 0.0f;
598 cbar_2U = 0.5f*cbar/v;
605FGAISim::struct_to_body(aiVec3 &pos)
613FGAISim::matrix_inverse(aiMtx4 mtx)
618 dst = simd4x4::transpose(mtx);
620 v1 =
static_cast<aiVec4
>(mtx.m4x4()[3]);
621 v2 =
static_cast<aiVec4
>(mtx.m4x4()[0]);
622 dst.ptr()[3][0] = -simd4::dot(v1, v2);
624 v2 =
static_cast<aiVec4
>(mtx.m4x4()[1]);
625 dst.ptr()[3][1] = -simd4::dot(v1, v2);
627 v2 =
static_cast<aiVec4
>(mtx.m4x4()[2]);
628 dst.ptr()[3][2] = -simd4::dot(v1, v2);
634FGAISim::invert_inertia(aiMtx4 mtx)
636 float Ixx, Iyy, Izz, Ixz;
637 float k1, k3, k4, k6;
640 Ixx = mtx.ptr()[0][0];
641 Iyy = mtx.ptr()[1][1];
642 Izz = mtx.ptr()[2][2];
643 Ixz = -mtx.ptr()[0][2];
647 denom = 1.0f/(Ixx*k1 - Ixz*k3);
651 k4 = (Izz*Ixx - Ixz*Ixz)*denom;
654 return aiMtx4( k1, 0.0f, k3, 0.0f,
655 0.0f, k4, 0.0f, 0.0f,
657 0.0f, 0.0f, 0.0f, 0.0f );
661std::map<std::string,float>
662FGAISim::jsonParse(
const char *str)
664 cJSON *json = ::cJSON_Parse(str);
668 for (
int i=0;
i<::cJSON_GetArraySize(json); ++
i)
670 cJSON* cj = ::cJSON_GetArrayItem(json,
i);
673 if (cj->valuedouble) {
674 rv.emplace(cj->string, cj->valuedouble);
676 else if (cj->type == cJSON_Array)
678 cJSON* child = cj->child;
679 for (
int j=0; child; child = child->next, ++j)
681 std::string str = cj->string;
683 str += std::to_string(j);
685 if (child->type == cJSON_Object)
687 cJSON* subchild = child->child;
688 for (
int k=0; subchild; subchild = subchild->next, ++k)
690 std::string substr = str;
692 substr += subchild->string;
694 if (subchild->type == cJSON_Array)
696 cJSON* array = subchild->child;
697 for (
int l=0; array; array = array->next, ++l)
699 std::string arraystr = substr;
701 arraystr += std::to_string(l);
703 rv.emplace(arraystr, array->valuedouble);
707 rv.emplace(substr, subchild->valuedouble);
712 rv.emplace(str, child->valuedouble);
718 ::cJSON_Delete(json);
722 std::string err = ::cJSON_GetErrorPtr();
723 err = err.substr(0, 16);
724 err =
"AISim: Can't parse Aircraft data around: "+err;
725 SG_LOG(SG_FLIGHT, SG_ALERT, err );
731FGAISim::load(std::string path)
733 std::ifstream file(path);
734 std::string jsonString;
736 file.seekg(0, std::ios::end);
737 jsonString.reserve(file.tellg());
738 file.seekg(0, std::ios::beg);
740 jsonString.assign((std::istreambuf_iterator<char>(file)),
741 std::istreambuf_iterator<char>());
743 jsonMap data = jsonParse(jsonString.c_str());
749 mass = data[
"mass"]/AISIM_G;
763 cg[X] = data[
"cg[0]"];
764 cg[
Y] = data[
"cg[1]"];
765 cg[
Z] = data[
"cg[2]"];
772 size_t i = no_contacts;
773 std::string gearstr =
"gear[" + std::to_string(
i) +
"]";
775 float spring = data[gearstr +
"/spring"];
778 contact_pos[
i][X] = data[gearstr +
"/pos[0]"];
779 contact_pos[
i][
Y] = data[gearstr +
"/pos[1]"];
780 contact_pos[
i][
Z] = data[gearstr +
"/pos[2]"];
781 struct_to_body(contact_pos[
i]);
783 contact_spring[
i] = -data[gearstr +
"/spring"];
784 contact_damp[
i] = -data[gearstr +
"/damp"];
786 printf(
"%lu: pos: % 3.2f, % 3.2f, % 3.2f, spring: % 7.1f, damp: % 7.1f\n",
i, contact_pos[
i][X], contact_pos[
i][
Y], contact_pos[
i][
Z], contact_spring[
i], contact_damp[
i]);
789 while (++no_contacts < AISIM_MAX);
795 size_t i = no_engines;
796 std::string engstr =
"engine[" + std::to_string(
i) +
"]";
798 float FTmax = data[engstr +
"/FT_max"];
802 pos[0] = data[engstr +
"/pos[0]"];
803 pos[1] = data[engstr +
"/pos[1]"];
804 pos[2] = data[engstr +
"/pos[2]"];
808 aiVec3 orientation(data[engstr +
"/dir[1]"],
809 data[engstr +
"/dir[0]"],
810 data[engstr +
"/dir[2]"]);
811 orientation *= SG_DEGREES_TO_RADIANS;
813 float len = simd4::normalize(orientation);
814 aiMtx4 mWind2Body = simd4x4::rotation_matrix(len, orientation);
815 aiVec3 dir = mWind2Body*aiVec3(1.0f, 0.0f, 0.0f);
816 aiVec3 rot = simd4::cross(pos, dir);
818 float rho = 0.002379f;
821 float max_rpm = data[engstr +
"/rpm_max"];
822 if (max_rpm == 0.0f) {
827 n2[
i] = max_rpm/60.0f;
831 FTmax /= (rho*n2[
i]);
837 while(++no_engines < AISIM_MAX);
839 float de_max = data[
"de_max"]*SG_DEGREES_TO_RADIANS;
840 float dr_max = data[
"dr_max"]*SG_DEGREES_TO_RADIANS;
841 float da_max = data[
"da_max"]*SG_DEGREES_TO_RADIANS;
842 float df_max = data[
"df_max"]*SG_DEGREES_TO_RADIANS;
845 CLmin = data[
"CLmin"];
847 CLadot = data[
"CLadot"];
849 CLdf_n = data[
"CLdf"]*df_max;
851 CDmin = data[
"CDmin"];
855 CDdf_n = data[
"CDdf"]*df_max;
860 CYdr_n = data[
"CYdr"]*dr_max;
865 Clda_n = data[
"Clda"]*da_max;
866 Cldr_n = data[
"Cldr"]*dr_max;
869 Cmadot = data[
"Cmadot"];
871 Cmde_n = data[
"Cmde"]*de_max;
872 Cmdf_n = data[
"Cmdf"]*df_max;
877 Cnda_n = data[
"Cnda"]*da_max;
878 Cndr_n = data[
"Cndr"]*dr_max;
886SGSubsystemMgr::Registrant<FGAISim> registrantFGAISim;
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
float fgGetFloat(const char *name, float defaultValue)
Get a float value for a property.