Update to Worldwind release 0.4.0
[worldwind-tracker.git] / gov / nasa / worldwind / view / FlatOrbitViewModel.java
blob849909df24fe5afcdadb1ea2ef47ce445a4454ff
1 /*
2 Copyright (C) 2001, 2006 United States Government as represented by
3 the Administrator of the National Aeronautics and Space Administration.
4 All Rights Reserved.
5 */
6 package gov.nasa.worldwind.view;
8 import gov.nasa.worldwind.geom.*;
9 import gov.nasa.worldwind.globes.Globe;
10 import gov.nasa.worldwind.render.DrawContext;
11 import gov.nasa.worldwind.util.Logging;
13 /**
14 * @author Patrick Muris from dcollins OrbitViewModel
15 * @version $Id$
17 class FlatOrbitViewModel
19 private Matrix transformMatrix = null;
21 public FlatOrbitViewModel(DrawContext dc)
23 this(dc, Angle.ZERO, Angle.ZERO, Angle.ZERO, Angle.ZERO, 0);
26 public FlatOrbitViewModel(DrawContext dc,
27 Angle lookAtLatitude, Angle lookAtLongitude,
28 Angle heading, Angle pitch,
29 double zoom)
31 this(dc, createInitTransform(
32 dc,
33 lookAtLatitude, lookAtLongitude,
34 heading, pitch,
35 zoom));
38 public FlatOrbitViewModel(DrawContext dc, Matrix transformMatrix)
40 if (dc == null)
42 String message = Logging.getMessage("nullValue.DrawContextIsNull");
43 Logging.logger().severe(message);
44 throw new IllegalArgumentException(message);
46 if (transformMatrix == null)
48 String message = Logging.getMessage("nullValue.MatrixIsNull");
49 Logging.logger().severe(message);
50 throw new IllegalArgumentException(message);
53 this.setTransform(dc, transformMatrix);
56 public Matrix getTransformMatrix()
58 return this.transformMatrix;
61 private void onTransformChange(DrawContext dc, Matrix newTransformMatrix)
65 public void setTransform(DrawContext dc, Matrix newTransformMatrix)
67 if (dc == null)
69 String message = Logging.getMessage("nullValue.DrawContextIsNull");
70 Logging.logger().severe(message);
71 throw new IllegalArgumentException(message);
73 if (newTransformMatrix == null)
75 String message = Logging.getMessage("nullValue.MatrixIsNull");
76 Logging.logger().severe(message);
77 throw new IllegalArgumentException(message);
80 this.transformMatrix = newTransformMatrix;
81 this.onTransformChange(dc, newTransformMatrix);
84 public void transform(DrawContext dc, Matrix transformMatrix)
86 if (dc == null)
88 String message = Logging.getMessage("nullValue.DrawContextIsNull");
89 Logging.logger().severe(message);
90 throw new IllegalArgumentException(message);
92 if (transformMatrix == null)
94 String message = Logging.getMessage("nullValue.MatrixIsNull");
95 Logging.logger().severe(message);
96 throw new IllegalArgumentException(message);
99 if (this.transformMatrix == null)
100 return;
102 Matrix newTransformMatrix = this.transformMatrix.multiply(transformMatrix);
103 this.setTransform(dc, newTransformMatrix);
106 public void transformLatitude(DrawContext dc, Angle amount)
108 if (dc == null)
110 String message = Logging.getMessage("nullValue.DrawContextIsNull");
111 Logging.logger().severe(message);
112 throw new IllegalArgumentException(message);
114 if (amount == null)
116 String message = Logging.getMessage("nullValue.AngleIsNull");
117 Logging.logger().severe(message);
118 throw new IllegalArgumentException(message);
121 Matrix latTransform = this.createLatitudeTransform(dc, amount);
122 if (latTransform == null)
123 return;
125 if (this.transformMatrix == null)
126 return;
128 // Test transform application.
129 Matrix newTransformMatrix = this.transformMatrix.multiply(latTransform);
130 Vec4 center = computeLookAtPoint(dc, this.transformMatrix);
131 Vec4 newCenter = computeLookAtPoint(dc, newTransformMatrix);
132 Position centerPos = dc.getGlobe().computePositionFromPoint(center);
133 Position newCenterPos = dc.getGlobe().computePositionFromPoint(newCenter);
134 // Abort the transform when it causes model errors.
135 final double EPSILON = 1;
136 if (Math.abs(newCenterPos.getLongitude().subtract(centerPos.getLongitude()).degrees) > EPSILON)
137 return;
139 this.transform(dc, latTransform);
142 public void transformLongitude(DrawContext dc, Angle amount)
144 if (dc == null)
146 String message = Logging.getMessage("nullValue.DrawContextIsNull");
147 Logging.logger().severe(message);
148 throw new IllegalArgumentException(message);
150 if (amount == null)
152 String message = Logging.getMessage("nullValue.AngleIsNull");
153 Logging.logger().severe(message);
154 throw new IllegalArgumentException(message);
157 Matrix lonTransform = this.createLongitudeTransform(dc, amount);
158 if (lonTransform == null)
159 return;
161 this.transform(dc, lonTransform);
164 public void transformAltitude(DrawContext dc, double amount)
166 if (dc == null)
168 String message = Logging.getMessage("nullValue.DrawContextIsNull");
169 Logging.logger().severe(message);
170 throw new IllegalArgumentException(message);
173 Matrix altTransform = this.createAltitudeTransform(dc, amount);
174 if (altTransform == null)
175 return;
177 this.transform(dc, altTransform);
180 public void transformHeading(DrawContext dc, Angle amount)
182 if (dc == null)
184 String message = Logging.getMessage("nullValue.DrawContextIsNull");
185 Logging.logger().severe(message);
186 throw new IllegalArgumentException(message);
188 if (amount == null)
190 String message = Logging.getMessage("nullValue.AngleIsNull");
191 Logging.logger().severe(message);
192 throw new IllegalArgumentException(message);
195 Matrix headingTransform = this.createHeadingTransform(dc, amount);
196 if (headingTransform == null)
197 return;
199 this.transform(dc, headingTransform);
202 public void transformPitch(DrawContext dc, Angle amount)
204 if (dc == null)
206 String message = Logging.getMessage("nullValue.DrawContextIsNull");
207 Logging.logger().severe(message);
208 throw new IllegalArgumentException(message);
210 if (amount == null)
212 String message = Logging.getMessage("nullValue.AngleIsNull");
213 Logging.logger().severe(message);
214 throw new IllegalArgumentException(message);
217 Matrix pitchTransform = this.createPitchTransform(dc, amount);
218 if (pitchTransform == null)
219 return;
221 if (this.transformMatrix == null)
222 return;
224 // Test transform application.
225 Matrix newTransformMatrix = this.transformMatrix.multiply(pitchTransform);
226 Vec4 centerVec = computeLookAtPoint(dc, this.transformMatrix);
227 Vec4 newHeading = computeHeadingVector(newTransformMatrix, centerVec);
228 Vec4 newForward = Vec4.UNIT_NEGATIVE_Z.transformBy3(newTransformMatrix.getInverse());
229 // Abort the transform when it causes model errors.
230 if (newHeading.dot3(newForward) < 0)
231 return;
233 this.transform(dc, pitchTransform);
236 public void transformZoom(DrawContext dc, double amount)
238 if (dc == null)
240 String message = Logging.getMessage("nullValue.DrawContextIsNull");
241 Logging.logger().severe(message);
242 throw new IllegalArgumentException(message);
245 Matrix zoomTransform = this.createZoomTransform(dc, amount);
246 if (zoomTransform == null)
247 return;
249 this.transform(dc, zoomTransform);
252 public Quaternion getRotation()
254 return Quaternion.fromMatrix(this.transformMatrix);
257 public void setRotation(DrawContext dc, Quaternion newRotation)
259 if (dc == null)
261 String message = Logging.getMessage("nullValue.DrawContextIsNull");
262 Logging.logger().severe(message);
263 throw new IllegalArgumentException(message);
265 if (newRotation == null)
267 String message = Logging.getMessage("nullValue.QuaternionIsNull");
268 Logging.logger().severe(message);
269 throw new IllegalArgumentException(message);
272 if (this.transformMatrix == null)
273 return;
275 Matrix posMatrix = Matrix.fromTranslation(
276 this.transformMatrix.m14,
277 this.transformMatrix.m24,
278 this.transformMatrix.m34);
279 Matrix rotMatrix = Matrix.fromQuaternion(newRotation);
280 Matrix newTransformMatrix = posMatrix.multiply(rotMatrix);
281 this.setTransform(dc, newTransformMatrix);
284 public void transformRotation(DrawContext dc, Quaternion rotation)
286 if (dc == null)
288 String message = Logging.getMessage("nullValue.DrawContextIsNull");
289 Logging.logger().severe(message);
290 throw new IllegalArgumentException(message);
292 if (rotation == null)
294 String message = Logging.getMessage("nullValue.QuaternionIsNull");
295 Logging.logger().severe(message);
296 throw new IllegalArgumentException(message);
299 Quaternion transformRotation = Quaternion.fromMatrix(this.transformMatrix);
300 Quaternion newTransformRotation = transformRotation.multiply(rotation);
301 this.setRotation(dc, newTransformRotation);
304 // ============== Model Transforms ======================= //
305 // ============== Model Transforms ======================= //
306 // ============== Model Transforms ======================= //
308 private static Matrix createInitTransform(
309 DrawContext dc,
310 Angle lookAtLatitude, Angle lookAtLongitude,
311 Angle heading, Angle pitch,
312 double zoom)
314 if (dc == null
315 || dc.getGlobe() == null
316 || lookAtLatitude == null
317 || lookAtLongitude == null
318 || heading == null
319 || pitch == null)
320 return null;
322 Globe globe = dc.getGlobe();
323 // Vec4 globeOrigin = globe.getCenter();
324 Matrix initTransform = Matrix.IDENTITY;
325 // Not sure why this isn't necessary, but when globeOrigin!=0 View is still centered on the Globe,
326 // without this code.
327 // initTransform = initTransform.multiply(Matrix.fromTranslation(
328 // globeOrigin.x,
329 // globeOrigin.y,
330 // globeOrigin.z));
331 // Flat sea level at zero on z, no need to move from globe center to surface
332 // initTransform = initTransform.multiply(Matrix.fromTranslation(
333 // 0.0,
334 // 0.0,
335 // 0.0 - globe.getRadiusAt(lookAtLatitude, lookAtLongitude)));
336 initTransform = initTransform.multiply(Matrix.fromRotationX(heading.multiply(-1)));
337 initTransform = initTransform.multiply(Matrix.fromRotationZ(pitch));
338 initTransform = initTransform.multiply(Matrix.fromTranslation(
339 0.0,
340 0.0,
341 0.0 - zoom));
342 // Use translation for lat/lon placement
343 Vec4 lookAtPoint = globe.computePointFromPosition(lookAtLatitude, lookAtLongitude, 0);
344 initTransform = initTransform.multiply(Matrix.fromTranslation(
345 -lookAtPoint.x, -lookAtPoint.y, -lookAtPoint.z));
347 return initTransform;
350 // TODO: use translation on y (OK)
351 public Matrix createLatitudeTransform(DrawContext dc, Angle amount)
353 if (dc == null)
355 String message = Logging.getMessage("nullValue.DrawContextIsNull");
356 Logging.logger().severe(message);
357 throw new IllegalArgumentException(message);
359 if (amount == null)
361 String message = Logging.getMessage("nullValue.AngleIsNull");
362 Logging.logger().severe(message);
363 throw new IllegalArgumentException(message);
366 Vec4 delta = dc.getGlobe().computePointFromPosition(amount, Angle.ZERO, 0);
367 return Matrix.fromTranslation(-delta.x, -delta.y, -delta.z);
370 // TODO: use translation on x (OK)
371 public Matrix createLongitudeTransform(DrawContext dc, Angle amount)
373 if (dc == null)
375 String message = Logging.getMessage("nullValue.DrawContextIsNull");
376 Logging.logger().severe(message);
377 throw new IllegalArgumentException(message);
379 if (amount == null)
381 String message = Logging.getMessage("nullValue.AngleIsNull");
382 Logging.logger().severe(message);
383 throw new IllegalArgumentException(message);
386 Vec4 delta = dc.getGlobe().computePointFromPosition(Angle.ZERO, amount, 0);
387 return Matrix.fromTranslation(-delta.x, -delta.y, -delta.z);
389 // TODO: use translation on z (OK)
390 public Matrix createAltitudeTransform(DrawContext dc, double amount)
392 if (dc == null)
394 String message = Logging.getMessage("nullValue.DrawContextIsNull");
395 Logging.logger().severe(message);
396 throw new IllegalArgumentException(message);
399 return Matrix.fromTranslation(0, 0, amount);
402 public Matrix createHeadingTransform(DrawContext dc, Angle amount)
404 if (dc == null)
406 String message = Logging.getMessage("nullValue.DrawContextIsNull");
407 Logging.logger().severe(message);
408 throw new IllegalArgumentException(message);
410 if (amount == null)
412 String message = Logging.getMessage("nullValue.AngleIsNull");
413 Logging.logger().severe(message);
414 throw new IllegalArgumentException(message);
417 Vec4 centerVec = this.getLookAtVector(dc);
418 if (centerVec == null)
419 return null;
421 Vec4 axis = Vec4.UNIT_Z; // TODO: use globe normal (OK)
422 Matrix axisAngleTransform = Matrix.fromAxisAngle(amount, axis);
423 return this.createTransformAboutPivot(axisAngleTransform, centerVec);
426 public Matrix createPitchTransform(DrawContext dc, Angle amount)
428 if (dc == null)
430 String message = Logging.getMessage("nullValue.DrawContextIsNull");
431 Logging.logger().severe(message);
432 throw new IllegalArgumentException(message);
434 if (amount == null)
436 String message = Logging.getMessage("nullValue.AngleIsNull");
437 Logging.logger().severe(message);
438 throw new IllegalArgumentException(message);
441 if (this.transformMatrix == null)
442 return null;
444 Vec4 centerVec = this.getLookAtVector(dc);
445 if (centerVec == null)
446 return null;
448 Vec4 axis = Vec4.UNIT_X.transformBy3(this.transformMatrix.getInverse());
449 Matrix axisAngleTransform = Matrix.fromAxisAngle(amount.multiply(-1), axis);
450 return this.createTransformAboutPivot(axisAngleTransform, centerVec);
453 public Matrix createZoomTransform(DrawContext dc, double amount)
455 if (dc == null)
457 String message = Logging.getMessage("nullValue.DrawContextIsNull");
458 Logging.logger().severe(message);
459 throw new IllegalArgumentException(message);
462 if (this.transformMatrix == null)
463 return null;
465 Vec4 zoomVec = Vec4.UNIT_NEGATIVE_Z.transformBy3(this.transformMatrix.getInverse());
466 zoomVec = zoomVec.normalize3();
467 zoomVec = zoomVec.multiply3(amount);
468 return Matrix.fromTranslation(zoomVec);
471 private Matrix createTransformAboutPivot(Matrix transform, Vec4 pivot)
473 if (transform == null || pivot == null)
474 return null;
476 Matrix matrix = Matrix.IDENTITY;
477 matrix = matrix.multiply(Matrix.fromTranslation(pivot.x, pivot.y, pivot.z));
478 matrix = matrix.multiply(transform);
479 matrix = matrix.multiply(Matrix.fromTranslation(-pivot.x, -pivot.y, -pivot.z));
480 return matrix;
483 // ============== Rotation Transforms ======================= //
484 // ============== Rotation Transforms ======================= //
485 // ============== Rotation Transforms ======================= //
487 // TODO: return no rotation or use globe normal (OK)
488 public Quaternion createRotationBetweenPositions(DrawContext dc, Position beginPosition, Position endPosition)
490 if (dc == null)
492 String message = Logging.getMessage("nullValue.DrawContextIsNull");
493 Logging.logger().severe(message);
494 throw new IllegalArgumentException(message);
496 if (beginPosition == null || endPosition == null)
498 String message = Logging.getMessage("nullValue.PositionIsNull");
499 Logging.logger().severe(message);
500 throw new IllegalArgumentException(message);
503 Globe globe = dc.getGlobe();
504 if (globe == null)
505 return null;
507 Vec4 beginPoint = globe.computePointFromPosition(beginPosition);
508 Vec4 endPoint = globe.computePointFromPosition(endPosition);
509 if (beginPoint == null || endPoint == null)
510 return null;
512 Angle angle = beginPoint.angleBetween3(endPoint);
513 if (angle == null)
514 return null;
516 Vec4 axis = beginPoint.cross3(endPoint);
517 return Quaternion.fromAxisAngle(angle, axis);
519 return Quaternion.IDENTITY;
522 public Quaternion createRotationForward(DrawContext dc, Angle amount)
524 if (amount == null)
526 String message = Logging.getMessage("nullValue.AngleIsNull");
527 Logging.logger().severe(message);
528 throw new IllegalArgumentException(message);
531 if (this.transformMatrix == null)
532 return null;
534 Vec4 xAxis = Vec4.UNIT_X.transformBy3(this.transformMatrix.getInverse());
535 return Quaternion.fromAxisAngle(amount, xAxis);
538 public Quaternion createRotationRight(DrawContext dc, Angle amount)
540 if (amount == null)
542 String message = Logging.getMessage("nullValue.AngleIsNull");
543 Logging.logger().severe(message);
544 throw new IllegalArgumentException(message);
547 if (this.transformMatrix == null)
548 return null;
550 Vec4 xAxis = Vec4.UNIT_X.transformBy3(this.transformMatrix.getInverse());
551 Vec4 centerVec = this.getLookAtVector(dc);
552 centerVec = centerVec.normalize3();
553 Vec4 yAxisNoTilt = centerVec.cross3(xAxis);
554 return Quaternion.fromAxisAngle(amount.multiply(-1), yAxisNoTilt);
557 // ============== Viewing Attributes ======================= //
558 // ============== Viewing Attributes ======================= //
559 // ============== Viewing Attributes ======================= //
561 public Vec4 getEyeVector()
563 if (this.transformMatrix == null)
564 return null;
566 return Vec4.UNIT_W.transformBy4(this.transformMatrix.getInverse());
569 public Position getEyePosition(DrawContext dc)
571 if (dc == null)
573 String message = Logging.getMessage("nullValue.DrawContextIsNull");
574 Logging.logger().severe(message);
575 throw new IllegalArgumentException(message);
578 Vec4 eyeVec = this.getEyeVector();
579 if (eyeVec == null)
580 return null;
582 if (dc.getGlobe() == null)
583 return null;
585 return dc.getGlobe().computePositionFromPoint(eyeVec);
588 public Vec4 getLookAtVector(DrawContext dc)
590 if (dc == null)
592 String message = Logging.getMessage("nullValue.DrawContextIsNull");
593 Logging.logger().severe(message);
594 throw new IllegalArgumentException(message);
597 if (this.transformMatrix == null)
598 return null;
600 return computeLookAtPoint(dc, this.transformMatrix);
603 public Position getLookAtPosition(DrawContext dc)
605 if (dc == null)
607 String message = Logging.getMessage("nullValue.DrawContextIsNull");
608 Logging.logger().severe(message);
609 throw new IllegalArgumentException(message);
612 Vec4 centerVec = this.getLookAtVector(dc);
613 if (centerVec == null)
614 return null;
616 if (dc.getGlobe() == null)
617 return null;
619 return dc.getGlobe().computePositionFromPoint(centerVec);
622 public Angle getHeading(DrawContext dc)
624 if (dc == null)
626 String message = Logging.getMessage("nullValue.DrawContextIsNull");
627 Logging.logger().severe(message);
628 throw new IllegalArgumentException(message);
631 if (this.transformMatrix == null)
632 return null;
634 Vec4 centerVec = this.getLookAtVector(dc);
635 if (centerVec == null)
636 return null;
638 HeadingCoordinates headingCoordinates = computeHeadingCoordinates(centerVec);
639 if (headingCoordinates == null)
640 return null;
642 return computeHeading(headingCoordinates, this.transformMatrix, centerVec);
645 public Angle getPitch(DrawContext dc)
647 if (dc == null)
649 String message = Logging.getMessage("nullValue.DrawContextIsNull");
650 Logging.logger().severe(message);
651 throw new IllegalArgumentException(message);
654 if (this.transformMatrix == null)
655 return null;
657 Vec4 centerVec = this.getLookAtVector(dc);
658 if (centerVec == null)
659 return null;
661 return computePitch(this.transformMatrix, centerVec);
664 public Double getZoom(DrawContext dc)
666 if (dc == null)
668 String message = Logging.getMessage("nullValue.DrawContextIsNull");
669 Logging.logger().severe(message);
670 throw new IllegalArgumentException(message);
673 if (this.transformMatrix == null)
674 return null;
676 Vec4 centerVec = this.getLookAtVector(dc);
677 if (centerVec == null)
678 return null;
680 return computeZoom(this.transformMatrix, centerVec);
683 // ============== Attribute Computation Support ======================= //
684 // ============== Attribute Computation Support ======================= //
685 // ============== Attribute Computation Support ======================= //
687 private static Vec4 computeLookAtPoint(DrawContext dc, Matrix transformMatrix)
689 if (dc == null
690 || dc.getGlobe() == null
691 || transformMatrix == null)
692 return null;
694 Globe globe = dc.getGlobe();
695 Vec4 eyeVec = Vec4.UNIT_W.transformBy4(transformMatrix.getInverse());
696 Vec4 forwardVec = Vec4.UNIT_NEGATIVE_Z.transformBy3(transformMatrix.getInverse());
697 forwardVec = forwardVec.normalize3();
699 Position centerPos = globe.getIntersectionPosition(new Line(eyeVec, forwardVec));
700 if (centerPos != null)
702 Angle centerLat = centerPos.getLatitude();
703 Angle centerLon = centerPos.getLongitude();
704 double centerElevation = dc.getVerticalExaggeration() * globe.getElevation(centerLat, centerLon);
705 return globe.computePointFromPosition(centerLat, centerLon, centerElevation);
708 return computeHorizonPoint(globe, transformMatrix);
711 // TODO: adapt to flat globe
712 private static Vec4 computeHorizonPoint(Globe globe, Matrix transformMatrix)
714 if (globe == null || transformMatrix == null)
715 return null;
717 Vec4 globeOrigin = globe.getCenter();
718 Vec4 eyeVec = Vec4.UNIT_W.transformBy4(transformMatrix.getInverse());
719 Vec4 forward = Vec4.UNIT_NEGATIVE_Z.transformBy3(transformMatrix.getInverse());
720 Vec4 origin_sub_eye = globeOrigin.subtract3(eyeVec);
722 double r = globe.getRadius();
723 double dSquared = origin_sub_eye.getLengthSquared3() - (r * r);
724 if (dSquared < 0)
725 return null;
727 double d = Math.sqrt(dSquared);
728 return forward.normalize3().multiply3(d).add3(eyeVec);
731 private static Angle computeHeading(HeadingCoordinates headingCoords, Matrix transformMatrix, Vec4 lookAtPoint)
733 if (headingCoords == null
734 || transformMatrix == null
735 || lookAtPoint == null)
736 return null;
738 Vec4 headingVec = computeHeadingVector(transformMatrix, lookAtPoint);
739 if (headingVec == null)
740 return null;
742 double dot = headingCoords.northVec.dot3(headingVec);
743 // Compute the sum of magnitudes.
744 double length = headingCoords.northVec.getLength3() * headingVec.getLength3();
745 // Normalize the dot product, if necessary.
746 if ((length != 0) && (length != 1.0))
747 dot /= length;
749 if (dot < -1) // Angle is positive 180.
751 return Angle.POS180;
753 else if (dot > 1) // Angle is zero.
755 return Angle.ZERO;
758 double degrees = Math.toDegrees(Math.acos(dot));
759 if (Double.isNaN(degrees))
760 return null;
762 if (headingCoords.eastVec.dot3(headingVec) < 0)
763 degrees = 360 - degrees;
765 // Collapses duplicate values for North heading.
766 if (degrees == 360)
767 degrees = 0;
769 return Angle.fromDegrees(degrees);
772 private static class HeadingCoordinates
774 public final Vec4 northVec;
775 public final Vec4 eastVec;
777 public HeadingCoordinates(Vec4 northVec, Vec4 eastVec)
779 this.northVec = northVec;
780 this.eastVec = eastVec;
784 private static HeadingCoordinates computeHeadingCoordinates(Vec4 lookAtPoint)
786 if (lookAtPoint == null)
787 return null;
789 Vec4 surfaceNormal = Vec4.UNIT_Z; // TODO: get globe normal (OK)
790 Vec4 y_sub_normal = Vec4.UNIT_Y.subtract3(surfaceNormal);
791 y_sub_normal = y_sub_normal.normalize3();
792 Vec4 eastVec = y_sub_normal.cross3(surfaceNormal);
793 Vec4 northVec = surfaceNormal.cross3(eastVec);
794 eastVec = northVec.cross3(surfaceNormal);
796 return new HeadingCoordinates(northVec, eastVec);
799 private static Vec4 computeHeadingVector(Matrix transformMatrix, Vec4 surfacePoint)
801 if (transformMatrix == null || surfacePoint == null)
802 return null;
804 Vec4 surfaceNormal = Vec4.UNIT_Z; // TODO: get globe normal (OK)
805 Vec4 forward = Vec4.UNIT_NEGATIVE_Z.transformBy3(transformMatrix.getInverse());
806 Vec4 up = Vec4.UNIT_Y.transformBy3(transformMatrix.getInverse());
808 final double EPSILON = 0.1;
809 Vec4 heading = forward.cross3(surfaceNormal);
810 if (heading.getLength3() < EPSILON)
811 heading = up.cross3(surfaceNormal);
812 heading = surfaceNormal.cross3(heading);
813 heading = heading.normalize3();
815 return heading;
818 private static Angle computePitch(Matrix transformMatrix, Vec4 lookAtPoint)
820 if (transformMatrix == null || lookAtPoint == null)
821 return null;
823 Vec4 surfaceNormal = Vec4.UNIT_Z; // TODO: get globe normal
824 Vec4 forward = Vec4.UNIT_Z.transformBy3(transformMatrix.getInverse());
825 forward = forward.normalize3();
827 double dot = surfaceNormal.dot3(forward);
828 // Compute the sum of magnitudes.
829 double length = surfaceNormal.getLength3() * forward.getLength3();
830 // Normalize the dot product, if necessary.
831 if ((length != 0) && (length != 1))
832 dot /= length;
834 if (dot <= 0) // Angle is positive 90.
836 return Angle.POS90;
838 else if (dot >= 1) // Angle is zero.
840 return Angle.ZERO;
842 else // Angle is arc-cosine of dot product.
844 double radians = Math.acos(dot);
845 if (!Double.isNaN(radians))
846 return Angle.fromRadians(radians);
849 return null;
852 private static Double computeZoom(Matrix transformMatrix, Vec4 lookAtPoint)
854 if (transformMatrix == null || lookAtPoint == null)
855 return null;
857 Vec4 eyeVec = Vec4.UNIT_W.transformBy4(transformMatrix.getInverse());
858 return lookAtPoint.subtract3(eyeVec).getLength3();
861 // private static class SurfaceAttributes
862 // {
863 // public final Vec4 center;
864 // public final Position centerPos;
865 // public final Vec4 north;
866 // public final Vec4 east;
868 // public SurfaceAttributes(Vec4 centerVec, Position centerPos, Vec4 headingUp, Vec4 headingRight)
869 // {
870 // this.center = centerVec;
871 // this.centerPos = centerPos;
872 // this.north = headingUp;
873 // this.east = headingRight;
874 // }
875 // }
877 // private static SurfaceAttributes computeSurfaceAttributes(DrawContext dc, Matrix transformMatrix)
878 // {
879 // if (dc == null || dc.getGlobe() == null)
880 // return null;
882 // if (transformMatrix == null)
883 // return null;
885 // Globe globe = dc.getGlobe();
886 // Vec4 eyeVec = Vec4.UNIT_W.transformBy4(transformMatrix.getInverse());
887 // Vec4 forwardVec = Vec4.UNIT_NEGATIVE_Z.transformBy3(transformMatrix.getInverse());
888 // forwardVec = forwardVec.normalize3();
890 // Vec4 centerVec;
891 // Position centerPos = globe.getIntersectionPosition(new Line(eyeVec, forwardVec));
892 // if (centerPos != null)
893 // {
894 // Angle centerLat = centerPos.getLatitude();
895 // Angle centerLon = centerPos.getLongitude();
896 // double centerElevation = dc.getVerticalExaggeration() * globe.getElevation(centerLat, centerLon);
897 // centerVec = globe.computePointFromPosition(centerLat, centerLon, centerElevation);
898 // }
899 // else
900 // {
901 // centerVec = computeHorizonPoint(globe, transformMatrix);
902 // centerPos = globe.computePositionFromPoint(centerVec);
903 // }
905 // if (centerVec == null)
906 // return null;
908 // Vec4 normalVec = centerVec.normalize3();
910 // Vec4 y_sub_normal = Vec4.UNIT_Y.subtract3(normalVec);
911 // y_sub_normal = y_sub_normal.normalize3();
912 // Vec4 headingRight = y_sub_normal.cross3(normalVec);
913 // Vec4 headingUp = normalVec.cross3(headingRight);
914 // headingRight = headingUp.cross3(normalVec);
916 // return new SurfaceAttributes(centerVec, centerPos, headingUp.normalize3(), headingRight.normalize3());
917 // }