00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <celmath/mathlib.h>
00011 #include <celmath/solve.h>
00012 #include "observer.h"
00013 #include "simulation.h"
00014
00015 using namespace std;
00016
00017
00018 #define LY 9466411842000.000
00019 #define VELOCITY_CHANGE_TIME 0.25f
00020
00021
00022 static Vec3d slerp(double t, const Vec3d& v0, const Vec3d& v1)
00023 {
00024 double r0 = v0.length();
00025 double r1 = v1.length();
00026 Vec3d u = v0 / r0;
00027 Vec3d n = u ^ (v1 / r1);
00028 n.normalize();
00029 Vec3d v = n ^ u;
00030 if (v * v1 < 0.0)
00031 v = -v;
00032
00033 double cosTheta = u * (v1 / r1);
00034 double theta = acos(cosTheta);
00035
00036 return (cos(theta * t) * u + sin(theta * t) * v) * Mathd::lerp(t, r0, r1);
00037 }
00038
00039
00040 Observer::Observer() :
00041 simTime(0.0),
00042 velocity(0.0, 0.0, 0.0),
00043 angularVelocity(0.0f, 0.0f, 0.0f),
00044 realTime(0.0),
00045 targetSpeed(0.0),
00046 targetVelocity(0.0, 0.0, 0.0),
00047 initialVelocity(0.0, 0.0, 0.0),
00048 beginAccelTime(0.0),
00049 observerMode(Free),
00050 trackingOrientation(1.0f, 0.0f, 0.0f, 0.0f),
00051 fov((float) (PI / 4.0)),
00052 reverseFlag(false),
00053 locationFilter(~0)
00054 {
00055 }
00056
00057
00058 double Observer::getTime() const
00059 {
00060 return simTime;
00061 };
00062
00063 void Observer::setTime(double jd)
00064 {
00065 simTime = jd;
00066 }
00067
00068
00069 UniversalCoord Observer::getPosition() const
00070 {
00071
00072
00073 return frame.toUniversal(situation, getTime()).translation;
00074 }
00075
00076
00077 Point3d Observer::getRelativePosition(const Point3d& p) const
00078 {
00079 BigFix x(p.x);
00080 BigFix y(p.y);
00081 BigFix z(p.z);
00082
00083 UniversalCoord position = getPosition();
00084 double dx = (double) (position.x - x);
00085 double dy = (double) (position.y - y);
00086 double dz = (double) (position.z - z);
00087
00088 return Point3d(dx / LY, dy / LY, dz / LY);
00089 }
00090
00091
00092 Quatf Observer::getOrientation() const
00093 {
00094 Quatd q = frame.toUniversal(situation, getTime()).rotation;
00095 return Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z);
00096 }
00097
00098
00099 void Observer::setOrientation(const Quatf& q)
00100 {
00101 RigidTransform rt = frame.toUniversal(situation, getTime());
00102 rt.rotation = Quatd(q.w, q.x, q.y, q.z);
00103 situation = frame.fromUniversal(rt, getTime());
00104 }
00105
00106
00107 void Observer::setOrientation(const Quatd& q)
00108 {
00109 setOrientation(Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z));
00110 }
00111
00112
00113 Vec3d Observer::getVelocity() const
00114 {
00115 return velocity;
00116 }
00117
00118
00119 void Observer::setVelocity(const Vec3d& v)
00120 {
00121 velocity = v;
00122 }
00123
00124
00125 Vec3f Observer::getAngularVelocity() const
00126 {
00127 return angularVelocity;
00128 }
00129
00130
00131 void Observer::setAngularVelocity(const Vec3f& v)
00132 {
00133 angularVelocity = v;
00134 }
00135
00136
00137 void Observer::setPosition(const Point3d& p)
00138 {
00139 setPosition(UniversalCoord(p));
00140 }
00141
00142
00143 void Observer::setPosition(const UniversalCoord& p)
00144 {
00145 RigidTransform rt = frame.toUniversal(situation, getTime());
00146 rt.translation = p;
00147 situation = frame.fromUniversal(rt, getTime());
00148 }
00149
00150
00151 RigidTransform Observer::getSituation() const
00152 {
00153 return frame.toUniversal(situation, getTime());
00154 }
00155
00156
00157
00158 void Observer::setSituation(const RigidTransform& xform)
00159 {
00160 situation = frame.fromUniversal(xform, getTime());
00161 }
00162
00163
00164 Vec3d toUniversal(const Vec3d& v,
00165 const Observer& observer,
00166 const Selection& sel,
00167 double t,
00168 astro::CoordinateSystem frame)
00169 {
00170 switch (frame)
00171 {
00172 case astro::ObserverLocal:
00173 {
00174 Quatf q = observer.getOrientation();
00175 Quatd qd(q.w, q.x, q.y, q.z);
00176 return v * qd.toMatrix3();
00177 }
00178
00179
00180 case astro::Geographic:
00181 if (sel.getType() != Selection::Type_Body)
00182 return v;
00183 else
00184 return v * sel.body()->getGeographicToHeliocentric(t);
00185
00186 case astro::Equatorial:
00187 if (sel.getType() != Selection::Type_Body)
00188 return v;
00189 else
00190 return v * sel.body()->getLocalToHeliocentric(t);
00191
00192 case astro::Ecliptical:
00193
00194
00195 return v;
00196
00197 case astro::Universal:
00198 return v;
00199
00200 default:
00201
00202 return v;
00203 }
00204 }
00205
00206
00207 static Quatf lookAt(Point3f from, Point3f to, Vec3f up)
00208 {
00209 Vec3f n = to - from;
00210 n.normalize();
00211 Vec3f v = n ^ up;
00212 v.normalize();
00213 Vec3f u = v ^ n;
00214 return Quatf(Mat3f(v, u, -n));
00215 }
00216
00217
00218 double Observer::getArrivalTime() const
00219 {
00220 if (observerMode != Travelling)
00221 return realTime;
00222 else
00223 return journey.startTime + journey.duration;
00224 }
00225
00226
00227
00228 void Observer::update(double dt, double timeScale)
00229 {
00230 realTime += dt;
00231 simTime += (dt / 86400.0) * timeScale;
00232
00233 if (observerMode == Travelling)
00234 {
00235 float t = (float) clamp((realTime - journey.startTime) / journey.duration);
00236
00237 Vec3d jv = journey.to - journey.from;
00238 UniversalCoord p;
00239
00240
00241
00242
00243
00244
00245
00246 {
00247 double u = t < 0.5 ? t * 2 : (1 - t) * 2;
00248 double x;
00249 if (u < journey.accelTime)
00250 {
00251 x = exp(journey.expFactor * u) - 1.0;
00252 }
00253 else
00254 {
00255 x = exp(journey.expFactor * journey.accelTime) *
00256 (journey.expFactor * (u - journey.accelTime) + 1) - 1;
00257 }
00258
00259 if (journey.traj == Linear)
00260 {
00261 Vec3d v = jv;
00262 if (v.length() == 0.0)
00263 {
00264 p = journey.from;
00265 }
00266 else
00267 {
00268 v.normalize();
00269 if (t < 0.5)
00270 p = journey.from + v * astro::kilometersToMicroLightYears(x);
00271 else
00272 p = journey.to - v * astro::kilometersToMicroLightYears(x);
00273 }
00274 }
00275 else if (journey.traj == GreatCircle)
00276 {
00277 Selection centerObj = frame.refObject;
00278 if (centerObj.body() != NULL)
00279 {
00280 Body* body = centerObj.body();
00281 if (body->getSystem())
00282 {
00283 if (body->getSystem()->getPrimaryBody() != NULL)
00284 centerObj = Selection(body->getSystem()->getPrimaryBody());
00285 else
00286 centerObj = Selection(body->getSystem()->getStar());
00287 }
00288 }
00289
00290 UniversalCoord ufrom = frame.toUniversal(RigidTransform(journey.from, Quatf(1.0f)), simTime).translation;
00291 UniversalCoord uto = frame.toUniversal(RigidTransform(journey.to, Quatf(1.0f)), simTime).translation;
00292 UniversalCoord origin = centerObj.getPosition(simTime);
00293 Vec3d v0 = ufrom - origin;
00294 Vec3d v1 = uto - origin;
00295
00296 if (jv.length() == 0.0)
00297 {
00298 p = journey.from;
00299 }
00300 else
00301 {
00302 x = astro::kilometersToMicroLightYears(x / jv.length());
00303 Vec3d v;
00304
00305 if (t < 0.5)
00306 v = slerp(x, v0, v1);
00307 else
00308 v = slerp(x, v1, v0);
00309
00310 p = origin + v;
00311 p = frame.fromUniversal(RigidTransform(p, Quatf(1.0f)), simTime).translation;
00312 }
00313 }
00314 else if (journey.traj == CircularOrbit)
00315 {
00316 Selection centerObj = frame.refObject;
00317
00318 UniversalCoord ufrom = frame.toUniversal(RigidTransform(journey.from, Quatf(1.0f)), simTime).translation;
00319 UniversalCoord uto = frame.toUniversal(RigidTransform(journey.to, Quatf(1.0f)), simTime).translation;
00320 UniversalCoord origin = centerObj.getPosition(simTime);
00321 Vec3d v0 = ufrom - origin;
00322 Vec3d v1 = uto - origin;
00323
00324 if (jv.length() == 0.0)
00325 {
00326 p = journey.from;
00327 }
00328 else
00329 {
00330
00331 Quatd q0(1.0);
00332 Quatd q1(journey.rotation1.w, journey.rotation1.x,
00333 journey.rotation1.y, journey.rotation1.z);
00334 p = origin + v0 * Quatd::slerp(q0, q1, t).toMatrix3();
00335
00336 p = frame.fromUniversal(RigidTransform(p, Quatf(1.0f)),
00337 simTime).translation;
00338 }
00339 }
00340 }
00341
00342
00343
00344 Quatf orientation;
00345 if (t >= journey.startInterpolation && t < journey.endInterpolation )
00346 {
00347
00348
00349 double v;
00350 if (journey.traj == CircularOrbit)
00351 {
00352
00353
00354 v = t;
00355 }
00356 else
00357 {
00358 v = pow(sin((t - journey.startInterpolation) /
00359 (journey.endInterpolation - journey.startInterpolation) * PI / 2), 2);
00360 }
00361
00362
00363 if (norm(journey.initialOrientation - journey.finalOrientation) <
00364 norm(journey.initialOrientation + journey.finalOrientation))
00365 {
00366 orientation = Quatf::slerp(journey.initialOrientation,
00367 journey.finalOrientation, (float)v);
00368 }
00369 else
00370 {
00371 orientation = Quatf::slerp(journey.initialOrientation,
00372 -journey.finalOrientation,(float)v);
00373 }
00374 }
00375 else if (t < journey.startInterpolation)
00376 {
00377 orientation = journey.initialOrientation;
00378 }
00379 else
00380 {
00381 orientation = journey.finalOrientation;
00382 }
00383
00384 situation = RigidTransform(p, orientation);
00385
00386
00387 if (t == 1.0f)
00388 {
00389 if (journey.traj != CircularOrbit)
00390 situation = RigidTransform(journey.to, journey.finalOrientation);
00391 observerMode = Free;
00392 setVelocity(Vec3d(0, 0, 0));
00393
00394 }
00395 }
00396
00397 if (getVelocity() != targetVelocity)
00398 {
00399 double t = clamp((realTime - beginAccelTime) / VELOCITY_CHANGE_TIME);
00400 setVelocity(getVelocity() * (1.0 - t) + targetVelocity * t);
00401 }
00402
00403
00404 situation.translation = situation.translation + getVelocity() * dt;
00405
00406 if (observerMode == Free)
00407 {
00408
00409 Vec3f fAV = getAngularVelocity();
00410 Vec3d AV(fAV.x, fAV.y, fAV.z);
00411 Quatd dr = 0.5 * (AV * situation.rotation);
00412 situation.rotation += dt * dr;
00413 situation.rotation.normalize();
00414 }
00415
00416 if (!trackObject.empty())
00417 {
00418 Vec3f up = Vec3f(0, 1, 0) * getOrientation().toMatrix3();
00419 Vec3d vn = trackObject.getPosition(getTime()) - getPosition();
00420 Point3f to((float) vn.x, (float) vn.y, (float) vn.z);
00421 setOrientation(lookAt(Point3f(0, 0, 0), to, up));
00422 }
00423 }
00424
00425
00426 Selection Observer::getTrackedObject() const
00427 {
00428 return trackObject;
00429 }
00430
00431
00432 void Observer::setTrackedObject(const Selection& sel)
00433 {
00434 trackObject = sel;
00435 }
00436
00437
00438 const string& Observer::getDisplayedSurface() const
00439 {
00440 return displayedSurface;
00441 }
00442
00443
00444 void Observer::setDisplayedSurface(const string& surf)
00445 {
00446 displayedSurface = surf;
00447 }
00448
00449
00450 uint32 Observer::getLocationFilter() const
00451 {
00452 return locationFilter;
00453 }
00454
00455
00456 void Observer::setLocationFilter(uint32 _locationFilter)
00457 {
00458 locationFilter = _locationFilter;
00459 }
00460
00461
00462 void Observer::reverseOrientation()
00463 {
00464 Quatf q = getOrientation();
00465 q.yrotate((float) PI);
00466 setOrientation(q);
00467 reverseFlag = !reverseFlag;
00468 }
00469
00470
00471
00472 struct TravelExpFunc : public unary_function<double, double>
00473 {
00474 double dist, s;
00475
00476 TravelExpFunc(double d, double _s) : dist(d), s(_s) {};
00477
00478 double operator()(double x) const
00479 {
00480
00481 return exp(x * s) * (x * (1 - s) + 1) - 1 - dist;
00482 }
00483 };
00484
00485
00486 void Observer::computeGotoParameters(const Selection& destination,
00487 JourneyParams& jparams,
00488 double gotoTime,
00489 double startInter,
00490 double endInter,
00491 Vec3d offset,
00492 astro::CoordinateSystem offsetFrame,
00493 Vec3f up,
00494 astro::CoordinateSystem upFrame)
00495 {
00496 if (frame.coordSys == astro::PhaseLock)
00497 {
00498 setFrame(FrameOfReference(astro::Ecliptical, destination));
00499 }
00500 else
00501 {
00502 setFrame(FrameOfReference(frame.coordSys, destination));
00503 }
00504
00505 UniversalCoord targetPosition = destination.getPosition(getTime());
00506 Vec3d v = targetPosition - getPosition();
00507 v.normalize();
00508
00509 jparams.traj = Linear;
00510 jparams.duration = gotoTime;
00511 jparams.startTime = realTime;
00512
00513
00514 jparams.from = getPosition();
00515
00516 offset = toUniversal(offset, *this, destination, getTime(), offsetFrame);
00517 jparams.to = targetPosition + offset;
00518
00519 Vec3d upd(up.x, up.y, up.z);
00520 upd = toUniversal(upd, *this, destination, getTime(), upFrame);
00521 Vec3f upf = Vec3f((float) upd.x, (float) upd.y, (float) upd.z);
00522
00523 jparams.initialOrientation = getOrientation();
00524 Vec3d vn = targetPosition - jparams.to;
00525 Point3f focus((float) vn.x, (float) vn.y, (float) vn.z);
00526 jparams.finalOrientation = lookAt(Point3f(0, 0, 0), focus, upf);
00527 jparams.startInterpolation = min(startInter, endInter);
00528 jparams.endInterpolation = max(startInter, endInter);
00529
00530 jparams.accelTime = 0.5;
00531 double distance = astro::microLightYearsToKilometers(jparams.from.distanceTo(jparams.to)) / 2.0;
00532 pair<double, double> sol = solve_bisection(TravelExpFunc(distance, jparams.accelTime),
00533 0.0001, 100.0,
00534 1e-10);
00535 jparams.expFactor = sol.first;
00536
00537
00538 RigidTransform from(jparams.from, jparams.initialOrientation);
00539 from = frame.fromUniversal(from, getTime());
00540 jparams.from = from.translation;
00541 jparams.initialOrientation= Quatf((float) from.rotation.w,
00542 (float) from.rotation.x,
00543 (float) from.rotation.y,
00544 (float) from.rotation.z);
00545 RigidTransform to(jparams.to, jparams.finalOrientation);
00546 to = frame.fromUniversal(to, getTime());
00547 jparams.to = to.translation;
00548 jparams.finalOrientation= Quatf((float) to.rotation.w,
00549 (float) to.rotation.x,
00550 (float) to.rotation.y,
00551 (float) to.rotation.z);
00552 }
00553
00554
00555 void Observer::computeGotoParametersGC(const Selection& destination,
00556 JourneyParams& jparams,
00557 double gotoTime,
00558 double startInter,
00559 double endInter,
00560 Vec3d offset,
00561 astro::CoordinateSystem offsetFrame,
00562 Vec3f up,
00563 astro::CoordinateSystem upFrame,
00564 const Selection& centerObj)
00565 {
00566 setFrame(FrameOfReference(frame.coordSys, destination));
00567
00568 UniversalCoord targetPosition = destination.getPosition(getTime());
00569 Vec3d v = targetPosition - getPosition();
00570 v.normalize();
00571
00572 jparams.traj = GreatCircle;
00573 jparams.duration = gotoTime;
00574 jparams.startTime = realTime;
00575
00576 jparams.centerObject = centerObj;
00577
00578
00579 jparams.from = getPosition();
00580
00581 offset = toUniversal(offset, *this, destination, getTime(), offsetFrame);
00582 jparams.to = targetPosition + offset;
00583
00584 Vec3d upd(up.x, up.y, up.z);
00585 upd = toUniversal(upd, *this, destination, getTime(), upFrame);
00586 Vec3f upf = Vec3f((float) upd.x, (float) upd.y, (float) upd.z);
00587
00588 jparams.initialOrientation = getOrientation();
00589 Vec3d vn = targetPosition - jparams.to;
00590 Point3f focus((float) vn.x, (float) vn.y, (float) vn.z);
00591 jparams.finalOrientation = lookAt(Point3f(0, 0, 0), focus, upf);
00592 jparams.startInterpolation = min(startInter, endInter);
00593 jparams.endInterpolation = max(startInter, endInter);
00594
00595 jparams.accelTime = 0.5;
00596 double distance = astro::microLightYearsToKilometers(jparams.from.distanceTo(jparams.to)) / 2.0;
00597 pair<double, double> sol = solve_bisection(TravelExpFunc(distance, jparams.accelTime),
00598 0.0001, 100.0,
00599 1e-10);
00600 jparams.expFactor = sol.first;
00601
00602
00603 RigidTransform from(jparams.from, jparams.initialOrientation);
00604 from = frame.fromUniversal(from, getTime());
00605 jparams.from = from.translation;
00606 jparams.initialOrientation= Quatf((float) from.rotation.w,
00607 (float) from.rotation.x,
00608 (float) from.rotation.y,
00609 (float) from.rotation.z);
00610 RigidTransform to(jparams.to, jparams.finalOrientation);
00611 to = frame.fromUniversal(to, getTime());
00612 jparams.to = to.translation;
00613 jparams.finalOrientation= Quatf((float) to.rotation.w,
00614 (float) to.rotation.x,
00615 (float) to.rotation.y,
00616 (float) to.rotation.z);
00617 }
00618
00619
00620 void Observer::computeCenterParameters(const Selection& destination,
00621 JourneyParams& jparams,
00622 double centerTime)
00623 {
00624 UniversalCoord targetPosition = destination.getPosition(getTime());
00625
00626 jparams.duration = centerTime;
00627 jparams.startTime = realTime;
00628 jparams.traj = Linear;
00629
00630
00631 jparams.from = getPosition();
00632 jparams.to = jparams.from;
00633
00634 Vec3f up = Vec3f(0, 1, 0) * getOrientation().toMatrix4();
00635
00636 jparams.initialOrientation = getOrientation();
00637 Vec3d vn = targetPosition - jparams.to;
00638 Point3f focus((float) vn.x, (float) vn.y, (float) vn.z);
00639 jparams.finalOrientation = lookAt(Point3f(0, 0, 0), focus, up);
00640 jparams.startInterpolation = 0;
00641 jparams.endInterpolation = 1;
00642
00643
00644 jparams.accelTime = 0.5;
00645 jparams.expFactor = 0;
00646
00647
00648 RigidTransform from(jparams.from, jparams.initialOrientation);
00649 from = frame.fromUniversal(from, getTime());
00650 jparams.from = from.translation;
00651 jparams.initialOrientation= Quatf((float) from.rotation.w,
00652 (float) from.rotation.x,
00653 (float) from.rotation.y,
00654 (float) from.rotation.z);
00655
00656 RigidTransform to(jparams.to, jparams.finalOrientation);
00657 to = frame.fromUniversal(to, getTime());
00658 jparams.to = to.translation;
00659 jparams.finalOrientation= Quatf((float) to.rotation.w,
00660 (float) to.rotation.x,
00661 (float) to.rotation.y,
00662 (float) to.rotation.z);
00663 }
00664
00665
00666 void Observer::computeCenterCOParameters(const Selection& destination,
00667 JourneyParams& jparams,
00668 double centerTime)
00669 {
00670 jparams.duration = centerTime;
00671 jparams.startTime = realTime;
00672 jparams.traj = CircularOrbit;
00673
00674 jparams.centerObject = frame.refObject;
00675 jparams.expFactor = 0.5;
00676
00677 Vec3d v = destination.getPosition(getTime()) - getPosition();
00678 Vec3f wf = Vec3f(0.0, 0.0, -1.0) * getOrientation().toMatrix3();
00679 Vec3d w(wf.x, wf.y, wf.z);
00680 v.normalize();
00681
00682 Vec3d n = w ^ v;
00683 double nl = n.length();
00684 double angle = 0.0;
00685 if (nl > 0.0)
00686 {
00687 double cosAngle = w * v;
00688 if (cosAngle < 1.0 - 1e-8)
00689 {
00690 if (cosAngle > 1e-8 - 1.0)
00691 angle = acos(cosAngle);
00692 else
00693 angle = PI;
00694 }
00695 else
00696 {
00697 angle = 0.0;
00698 }
00699
00700 n = n / nl;
00701 }
00702 else
00703 {
00704 n = Vec3d(1.0, 0.0, 0.0);
00705 }
00706
00707 Selection centerObj = frame.refObject;
00708 UniversalCoord centerPos = centerObj.getPosition(getTime());
00709 UniversalCoord targetPosition = destination.getPosition(getTime());
00710
00711 Quatd qd;
00712 qd.setAxisAngle(n, -angle);
00713 Quatf q((float) qd.w, (float) qd.x, (float) qd.y, (float) qd.z);
00714
00715 jparams.from = getPosition();
00716 jparams.to = centerPos + ((getPosition() - centerPos) * qd.toMatrix3());
00717 jparams.initialOrientation = getOrientation();
00718 jparams.finalOrientation = getOrientation() * q;
00719
00720 jparams.startInterpolation = 0.0;
00721 jparams.endInterpolation = 1.0;
00722
00723 jparams.rotation1 = q;
00724
00725
00726 RigidTransform from(jparams.from, jparams.initialOrientation);
00727 from = frame.fromUniversal(from, getTime());
00728 jparams.from = from.translation;
00729 jparams.initialOrientation= Quatf((float) from.rotation.w,
00730 (float) from.rotation.x,
00731 (float) from.rotation.y,
00732 (float) from.rotation.z);
00733
00734 RigidTransform to(jparams.to, jparams.finalOrientation);
00735 to = frame.fromUniversal(to, getTime());
00736 jparams.to = to.translation;
00737 jparams.finalOrientation= Quatf((float) to.rotation.w,
00738 (float) to.rotation.x,
00739 (float) to.rotation.y,
00740 (float) to.rotation.z);
00741 }
00742
00743
00744 Observer::ObserverMode Observer::getMode() const
00745 {
00746 return observerMode;
00747 }
00748
00749
00750
00751
00752 void Observer::centerSelectionCO(const Selection& selection, double centerTime)
00753 {
00754 if (!selection.empty() && !frame.refObject.empty())
00755 {
00756 computeCenterCOParameters(selection, journey, centerTime);
00757 observerMode = Travelling;
00758 }
00759 }
00760
00761
00762 void Observer::setMode(Observer::ObserverMode mode)
00763 {
00764 observerMode = mode;
00765 }
00766
00767
00768 void Observer::setFrame(const FrameOfReference& _frame)
00769 {
00770 RigidTransform transform = frame.toUniversal(situation, getTime());
00771 if (observerMode == Travelling)
00772 {
00773 RigidTransform from = frame.toUniversal(RigidTransform(journey.from, journey.initialOrientation), getTime());
00774 RigidTransform to = frame.toUniversal(RigidTransform(journey.to, journey.finalOrientation), getTime());
00775
00776 frame = _frame;
00777 situation = frame.fromUniversal(transform, getTime());
00778
00779 from = frame.fromUniversal(from, getTime());
00780 journey.from = from.translation;
00781 journey.initialOrientation = Quatf((float) from.rotation.w,
00782 (float) from.rotation.x,
00783 (float) from.rotation.y,
00784 (float) from.rotation.z);
00785 to = frame.fromUniversal(to, getTime());
00786 journey.to = to.translation;
00787 journey.finalOrientation = Quatf((float) to.rotation.w,
00788 (float) to.rotation.x,
00789 (float) to.rotation.y,
00790 (float) to.rotation.z);
00791 }
00792 else
00793 {
00794 frame = _frame;
00795 situation = frame.fromUniversal(transform, getTime());
00796 }
00797 }
00798
00799
00800 FrameOfReference Observer::getFrame() const
00801 {
00802 return frame;
00803 }
00804
00805
00806
00807 void Observer::rotate(Quatf q)
00808 {
00809 Quatd qd(q.w, q.x, q.y, q.z);
00810 situation.rotation = qd * situation.rotation;
00811 }
00812
00813
00814
00815
00816 void Observer::orbit(const Selection& selection, Quatf q)
00817 {
00818 Selection center = frame.refObject;
00819 if (center.empty() && !selection.empty())
00820 {
00821 center = selection;
00822 setFrame(FrameOfReference(frame.coordSys, center));
00823 }
00824
00825 if (!center.empty())
00826 {
00827
00828
00829
00830
00831 UniversalCoord focusPosition = center.getPosition(getTime());
00832 focusPosition = frame.fromUniversal(RigidTransform(focusPosition), getTime()).translation;
00833
00834
00835 Vec3d v = situation.translation - focusPosition;
00836
00837
00838 Quatd qd(q.w, q.x, q.y, q.z);
00839
00840
00841
00842
00843
00844
00845 Quatd qd2 = ~situation.rotation * qd * situation.rotation;
00846 qd2.normalize();
00847
00848
00849
00850
00851 double distance = v.length();
00852 v = v * qd2.toMatrix3();
00853 v.normalize();
00854 v *= distance;
00855
00856 situation.rotation = situation.rotation * qd2;
00857 situation.translation = focusPosition + v;
00858 }
00859 }
00860
00861
00862
00863
00864 void Observer::changeOrbitDistance(const Selection& selection, float d)
00865 {
00866 Selection center = frame.refObject;
00867 if (center.empty() && !selection.empty())
00868 {
00869 center = selection;
00870 setFrame(FrameOfReference(frame.coordSys, center));
00871 }
00872
00873 if (!center.empty())
00874 {
00875 UniversalCoord focusPosition = center.getPosition(getTime());
00876
00877 double size = center.radius();
00878
00879
00880
00881 double minOrbitDistance = astro::kilometersToMicroLightYears(size);
00882 double naturalOrbitDistance = astro::kilometersToMicroLightYears(4.0 * size);
00883
00884
00885 Vec3d v = getPosition() - focusPosition;
00886 double currentDistance = v.length();
00887
00888
00889 if (currentDistance < minOrbitDistance)
00890 minOrbitDistance = currentDistance * 0.5;
00891
00892 if (currentDistance >= minOrbitDistance && naturalOrbitDistance != 0)
00893 {
00894 double r = (currentDistance - minOrbitDistance) / naturalOrbitDistance;
00895 double newDistance = minOrbitDistance + naturalOrbitDistance * exp(log(r) + d);
00896 v = v * (newDistance / currentDistance);
00897 RigidTransform framePos = frame.fromUniversal(RigidTransform(focusPosition + v),
00898 getTime());
00899 situation.translation = framePos.translation;
00900 }
00901 }
00902 }
00903
00904
00905 void Observer::setTargetSpeed(float s)
00906 {
00907 targetSpeed = s;
00908 Vec3f v;
00909 if (reverseFlag)
00910 s = -s;
00911 if (trackObject.empty())
00912 {
00913 trackingOrientation = getOrientation();
00914
00915
00916 v = Vec3f(0, 0, -s) * getOrientation().toMatrix4();
00917 }
00918 else
00919 {
00920
00921 v = Vec3f(0, 0, -s) * trackingOrientation.toMatrix4();
00922 }
00923
00924 targetVelocity = Vec3d(v.x, v.y, v.z);
00925 initialVelocity = getVelocity();
00926 beginAccelTime = realTime;
00927 }
00928
00929
00930 float Observer::getTargetSpeed()
00931 {
00932 return (float) targetSpeed;
00933 }
00934
00935
00936 void Observer::gotoJourney(const JourneyParams& params)
00937 {
00938 journey = params;
00939 double distance = astro::microLightYearsToKilometers(journey.from.distanceTo(journey.to)) / 2.0;
00940 pair<double, double> sol = solve_bisection(TravelExpFunc(distance, journey.accelTime),
00941 0.0001, 100.0,
00942 1e-10);
00943 journey.expFactor = sol.first;
00944 journey.startTime = realTime;
00945 observerMode = Travelling;
00946 }
00947
00948 void Observer::gotoSelection(const Selection& selection,
00949 double gotoTime,
00950 Vec3f up,
00951 astro::CoordinateSystem upFrame)
00952 {
00953 gotoSelection(selection, gotoTime, 0.0, 0.5, up, upFrame);
00954 }
00955
00956
00957
00958 static double getPreferredDistance(const Selection& selection)
00959 {
00960 switch (selection.getType())
00961 {
00962 case Selection::Type_Body:
00963 return 5.0 * selection.radius();
00964 case Selection::Type_DeepSky:
00965 return 5.0 * selection.radius();
00966 case Selection::Type_Star:
00967 if (selection.star()->getVisibility())
00968 return 100.0 * selection.radius();
00969 else
00970 return astro::AUtoKilometers(1.0);
00971 case Selection::Type_Location:
00972 {
00973 double maxDist = getPreferredDistance(selection.location()->getParentBody());
00974 return max(min(selection.location()->getSize() * 50.0, maxDist),
00975 1.0);
00976 }
00977 default:
00978 return 1.0;
00979 }
00980 }
00981
00982
00983
00984
00985 static double getOrbitDistance(const Selection& selection,
00986 double currentDistance)
00987 {
00988
00989
00990
00991 double maxDist = astro::kilometersToMicroLightYears(getPreferredDistance(selection));
00992 double minDist = astro::kilometersToMicroLightYears(1.01 * selection.radius());
00993 double dist = (currentDistance > maxDist * 10.0) ? maxDist : currentDistance * 0.1;
00994
00995 return max(dist, minDist);
00996 }
00997
00998
00999 void Observer::gotoSelection(const Selection& selection,
01000 double gotoTime,
01001 double startInter,
01002 double endInter,
01003 Vec3f up,
01004 astro::CoordinateSystem upFrame)
01005 {
01006 if (!selection.empty())
01007 {
01008 UniversalCoord pos = selection.getPosition(getTime());
01009 Vec3d v = pos - getPosition();
01010 double distance = v.length();
01011
01012 double orbitDistance = getOrbitDistance(selection, distance);
01013
01014 computeGotoParameters(selection, journey, gotoTime,
01015 startInter, endInter,
01016 v * -(orbitDistance / distance),
01017 astro::Universal,
01018 up, upFrame);
01019 observerMode = Travelling;
01020 }
01021 }
01022
01023
01024
01025
01026
01027 void Observer::gotoSelectionGC(const Selection& selection,
01028 double gotoTime,
01029 double startInter,
01030 double endInter,
01031 Vec3f up,
01032 astro::CoordinateSystem upFrame)
01033 {
01034 if (!selection.empty())
01035 {
01036 Selection centerObj = selection.parent();
01037
01038 UniversalCoord pos = selection.getPosition(getTime());
01039 Vec3d v = pos - centerObj.getPosition(getTime());
01040 double distanceToCenter = v.length();
01041 Vec3d viewVec = pos - getPosition();
01042 double orbitDistance = getOrbitDistance(selection,
01043 viewVec.length());
01044 if (selection.location() != NULL)
01045 {
01046 Selection parent = selection.parent();
01047 double maintainDist = astro::kilometersToMicroLightYears(getPreferredDistance(parent));
01048 Vec3d parentPos = parent.getPosition(getTime()) - getPosition();
01049 double parentDist = parentPos.length() -
01050 astro::kilometersToMicroLightYears(parent.radius());
01051
01052 if (parentDist <= maintainDist && parentDist > orbitDistance)
01053 {
01054 orbitDistance = parentDist;
01055 }
01056 }
01057
01058 computeGotoParametersGC(selection, journey, gotoTime,
01059
01060 0.25, 0.75,
01061 v * (orbitDistance / distanceToCenter),
01062 astro::Universal,
01063 up, upFrame,
01064 centerObj);
01065 observerMode = Travelling;
01066 }
01067 }
01068
01069
01070 void Observer::gotoSelection(const Selection& selection,
01071 double gotoTime,
01072 double distance,
01073 Vec3f up,
01074 astro::CoordinateSystem upFrame)
01075 {
01076 if (!selection.empty())
01077 {
01078 UniversalCoord pos = selection.getPosition(getTime());
01079
01080
01081 Vec3d v = pos - getPosition();
01082 v.normalize();
01083
01084 computeGotoParameters(selection, journey, gotoTime, 0.25, 0.75,
01085 v * -distance * 1e6, astro::Universal,
01086 up, upFrame);
01087 observerMode = Travelling;
01088 }
01089 }
01090
01091
01092 void Observer::gotoSelectionGC(const Selection& selection,
01093 double gotoTime,
01094 double distance,
01095 Vec3f up,
01096 astro::CoordinateSystem upFrame)
01097 {
01098 if (!selection.empty())
01099 {
01100 Selection centerObj = selection.parent();
01101
01102 UniversalCoord pos = selection.getPosition(getTime());
01103 Vec3d v = pos - centerObj.getPosition(getTime());
01104 v.normalize();
01105
01106
01107
01108 computeGotoParametersGC(selection, journey, gotoTime, 0.25, 0.75,
01109 v * -distance * 1e6, astro::Universal,
01110 up, upFrame,
01111 centerObj);
01112 observerMode = Travelling;
01113 }
01114 }
01115
01116
01117 void Observer::gotoSelectionLongLat(const Selection& selection,
01118 double gotoTime,
01119 double distance,
01120 float longitude,
01121 float latitude,
01122 Vec3f up)
01123 {
01124 if (!selection.empty())
01125 {
01126 double phi = -latitude + PI / 2;
01127 double theta = longitude - PI;
01128 double x = cos(theta) * sin(phi);
01129 double y = cos(phi);
01130 double z = -sin(theta) * sin(phi);
01131 computeGotoParameters(selection, journey, gotoTime, 0.25, 0.75,
01132 Vec3d(x, y, z) * distance * 1e6, astro::Geographic,
01133 up, astro::Geographic);
01134 observerMode = Travelling;
01135 }
01136 }
01137
01138
01139 void Observer::gotoLocation(const RigidTransform& transform,
01140 double duration)
01141 {
01142 journey.startTime = realTime;
01143 journey.duration = duration;
01144
01145 RigidTransform from(getPosition(), getOrientation());
01146 from = frame.fromUniversal(from, getTime());
01147 journey.from = from.translation;
01148 journey.initialOrientation= Quatf((float) from.rotation.w, (float) from.rotation.x,
01149 (float) from.rotation.y, (float) from.rotation.z);
01150
01151 journey.to = transform.translation;
01152 journey.finalOrientation = Quatf((float) transform.rotation.w,
01153 (float) transform.rotation.x,
01154 (float) transform.rotation.y,
01155 (float) transform.rotation.z);
01156 journey.startInterpolation = 0.25f;
01157 journey.endInterpolation = 0.75f;
01158
01159
01160 journey.accelTime = 0.5;
01161 double distance = astro::microLightYearsToKilometers(journey.from.distanceTo(journey.to)) / 2.0;
01162 pair<double, double> sol = solve_bisection(TravelExpFunc(distance, journey.accelTime),
01163 0.0001, 100.0,
01164 1e-10);
01165 journey.expFactor = sol.first;
01166
01167 observerMode = Travelling;
01168 }
01169
01170
01171 void Observer::getSelectionLongLat(const Selection& selection,
01172 double& distance,
01173 double& longitude,
01174 double& latitude)
01175 {
01176
01177
01178 if (!selection.empty())
01179 {
01180 FrameOfReference refFrame(astro::Geographic, selection);
01181 RigidTransform xform = refFrame.fromUniversal(RigidTransform(getPosition(), getOrientation()),
01182 getTime());
01183
01184 Point3d pos = (Point3d) xform.translation;
01185
01186 distance = pos.distanceFromOrigin();
01187 longitude = -radToDeg(atan2(-pos.z, -pos.x));
01188 latitude = radToDeg(PI/2 - acos(pos.y / distance));
01189
01190
01191 distance = astro::microLightYearsToKilometers(distance);
01192 }
01193 }
01194
01195
01196 void Observer::gotoSurface(const Selection& sel, double duration)
01197 {
01198 Vec3d vd = getPosition() - sel.getPosition(getTime());
01199 Vec3f vf((float) vd.x, (float) vd.y, (float) vd.z);
01200 vf.normalize();
01201 Vec3f viewDir = Vec3f(0, 0, -1) * getOrientation().toMatrix3();
01202 Vec3f up = Vec3f(0, 1, 0) * getOrientation().toMatrix3();
01203 Quatf q = getOrientation();
01204 if (vf * viewDir < 0.0f)
01205 {
01206 q = lookAt(Point3f(0, 0, 0), Point3f(0.0f, 0.0f, 0.0f) + up, vf);
01207 }
01208 else
01209 {
01210 }
01211
01212 FrameOfReference frame(astro::Geographic, sel);
01213 RigidTransform rt = frame.fromUniversal(RigidTransform(getPosition(), q),
01214 getTime());
01215
01216 double height = 1.0001 * astro::kilometersToMicroLightYears(sel.radius());
01217 Vec3d dir = rt.translation - Point3d(0.0, 0.0, 0.0);
01218 dir.normalize();
01219 dir *= height;
01220
01221 rt.translation = UniversalCoord(dir.x, dir.y, dir.z);
01222 gotoLocation(rt, duration);
01223 };
01224
01225
01226 void Observer::cancelMotion()
01227 {
01228 observerMode = Free;
01229 }
01230
01231
01232 void Observer::centerSelection(const Selection& selection, double centerTime)
01233 {
01234 if (!selection.empty())
01235 {
01236 computeCenterParameters(selection, journey, centerTime);
01237 observerMode = Travelling;
01238 }
01239 }
01240
01241
01242 void Observer::follow(const Selection& selection)
01243 {
01244 if (!selection.empty())
01245 {
01246 setFrame(FrameOfReference(astro::Ecliptical, selection));
01247 }
01248 }
01249
01250
01251 void Observer::geosynchronousFollow(const Selection& selection)
01252 {
01253 if (selection.body() != NULL ||
01254 selection.location() != NULL ||
01255 selection.star() != NULL)
01256 {
01257 setFrame(FrameOfReference(astro::Geographic, selection));
01258 }
01259 }
01260
01261
01262 void Observer::phaseLock(const Selection& selection)
01263 {
01264 if (frame.refObject.body() != NULL)
01265 {
01266 if (selection == frame.refObject)
01267 {
01268 setFrame(FrameOfReference(astro::PhaseLock, selection,
01269 Selection(selection.body()->getSystem()->getStar())));
01270 }
01271 else
01272 {
01273 setFrame(FrameOfReference(astro::PhaseLock, frame.refObject, selection));
01274 }
01275 }
01276 else if (frame.refObject.star() != NULL)
01277 {
01278 if (selection != frame.refObject)
01279 {
01280 setFrame(FrameOfReference(astro::PhaseLock, frame.refObject, selection));
01281 }
01282 }
01283 }
01284
01285 void Observer::chase(const Selection& selection)
01286 {
01287 if (selection.body() != NULL)
01288 {
01289 setFrame(FrameOfReference(astro::Chase, selection));
01290 }
01291 else if (selection.star() != NULL)
01292 {
01293 setFrame(FrameOfReference(astro::Chase, selection));
01294 }
01295 }
01296
01297
01298 float Observer::getFOV() const
01299 {
01300 return fov;
01301 }
01302
01303
01304 void Observer::setFOV(float _fov)
01305 {
01306 fov = _fov;
01307 }
01308
01309
01310 Vec3f Observer::getPickRay(float x, float y) const
01311 {
01312 float s = 2 * (float) tan(fov / 2.0);
01313
01314 Vec3f pickDirection = Vec3f(x * s, y * s, -1.0f);
01315 pickDirection.normalize();
01316
01317 return pickDirection;
01318 }