+ // The geodetic position of our base view position
+ SGGeod geodPos = SGGeod::fromDegFt(lon, lat, alt);
+ // The rotation rotating from the earth centerd frame to
+ // the horizontal local OpenGL frame
+ SGQuatd hlOr = SGQuatd::viewHL(geodPos);
+
+ // the rotation from the horizontal local frame to the basic view orientation
+ SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
+ hlToBody = SGQuatd::simToView(hlToBody);
+
+ // The cartesian position of the basic view coordinate
+ SGVec3d position = SGVec3d::fromGeod(geodPos);
+ // the rotation offset, don't know why heading is negative here ...
+ SGQuatd viewOffsetOr = SGQuatd::simToView(
+ SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
+ _roll_offset_deg));
+
+ // Compute the eyepoints orientation and position
+ // wrt the earth centered frame - that is global coorinates
+ SGQuatd ec2body = hlOr*hlToBody;
+ _absolute_view_pos = position + ec2body.backTransform(_offset_m);
+ mViewOrientation = ec2body*viewOffsetOr;
+}
+
+void
+FGViewer::recalcLookAt ()
+{
+ // The geodetic position of our target to look at
+ SGGeod geodTargetPos;
+ SGQuatd geodTargetOr;
+ if ( _at_model ) {
+ geodTargetPos = SGGeod::fromDegFt(_target_location->getLongitude_deg(),
+ _target_location->getLatitude_deg(),
+ _target_location->getAltitudeASL_ft());
+ double head = _target_location->getHeading_deg();
+ double pitch = _target_location->getPitch_deg();
+ double roll = _target_location->getRoll_deg();
+ geodTargetOr = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
+ } else {
+ dampEyeData(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+ _target_location->setPosition( _target_lon_deg, _target_lat_deg, _target_alt_ft );
+ _target_location->setOrientation( _target_roll_deg, _target_pitch_deg, _target_heading_deg );
+ _target_location->getTransformMatrix();
+
+ // if not model then calculate our own target position...
+ geodTargetPos = SGGeod::fromDegFt(_target_lon_deg,
+ _target_lat_deg,
+ _target_alt_ft);
+ geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
+ _target_pitch_deg,
+ _target_roll_deg);
+ }
+ SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(geodTargetPos);
+
+
+ SGGeod geodEyePos;
+ SGQuatd geodEyeOr;
+ if ( _from_model ) {
+ geodEyePos = SGGeod::fromDegFt(_location->getLongitude_deg(),
+ _location->getLatitude_deg(),
+ _location->getAltitudeASL_ft());
+ double head = _location->getHeading_deg();
+ double pitch = _location->getPitch_deg();
+ double roll = _location->getRoll_deg();
+ geodEyeOr = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
+ } else {
+ dampEyeData(_roll_deg, _pitch_deg, _heading_deg);
+ _location->setPosition( _lon_deg, _lat_deg, _alt_ft );
+ _location->setOrientation( _roll_deg, _pitch_deg, _heading_deg );
+ _location->getTransformMatrix();
+
+ // update from our own data, just the rotation here...
+ geodEyePos = SGGeod::fromDegFt(_lon_deg, _lat_deg, _alt_ft);
+ geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg,
+ _pitch_deg,
+ _roll_deg);
+ }
+ SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(geodEyePos);
+
+ // the rotation offset, don't know why heading is negative here ...
+ SGQuatd eyeOffsetOr =
+ SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
+ _roll_offset_deg);
+
+ // Offsets to the eye position
+ SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
+ SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
+ SGVec3d eyeCart = SGVec3d::fromGeod(geodEyePos);
+ eyeCart += (ec2eye*eyeOffsetOr).backTransform(eyeOff);
+
+ SGVec3d atCart = SGVec3d::fromGeod(geodTargetPos);
+
+ // add target offsets to at_position...
+ SGVec3d target_pos_off(-_target_offset_m.z(), _target_offset_m.x(),
+ -_target_offset_m.y());
+ target_pos_off = (geodTargetHlOr*geodTargetOr).backTransform(target_pos_off);
+ atCart += target_pos_off;
+ eyeCart += target_pos_off;
+
+ // Compute the eyepoints orientation and position
+ // wrt the earth centered frame - that is global coorinates
+ _absolute_view_pos = eyeCart;
+
+ // the view direction
+ SGVec3d dir = normalize(atCart - eyeCart);
+ // the up directon
+ SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
+ // rotate dir to the 0-th unit vector
+ // rotate up to 2-th unit vector
+ mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
+}
+
+void
+FGViewer::dampEyeData(double &roll_deg, double &pitch_deg, double &heading_deg)
+{
+ const double interval = 0.01;
+
+ static FGViewer *last_view = 0;
+ if (last_view != this) {
+ _damp_sync = 0.0;
+ _damped_roll_deg = roll_deg;
+ _damped_pitch_deg = pitch_deg;
+ _damped_heading_deg = heading_deg;
+ last_view = this;
+ return;
+ }