PageRenderTime 44ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Common/src/main/java/au/gov/ga/worldwind/common/view/orbit/BaseOrbitView.java

http://github.com/ga-m3dv/ga-worldwind-suite
Java | 528 lines | 416 code | 71 blank | 41 comment | 66 complexity | a7281c4bf00e2b003105a63c58058e2d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*******************************************************************************
  2. * Copyright 2012 Geoscience Australia
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. ******************************************************************************/
  16. package au.gov.ga.worldwind.common.view.orbit;
  17. import gov.nasa.worldwind.Configuration;
  18. import gov.nasa.worldwind.WorldWind;
  19. import gov.nasa.worldwind.avlist.AVKey;
  20. import gov.nasa.worldwind.awt.ViewInputHandler;
  21. import gov.nasa.worldwind.geom.Angle;
  22. import gov.nasa.worldwind.geom.Frustum;
  23. import gov.nasa.worldwind.geom.Matrix;
  24. import gov.nasa.worldwind.geom.Position;
  25. import gov.nasa.worldwind.geom.Vec4;
  26. import gov.nasa.worldwind.render.DrawContext;
  27. import gov.nasa.worldwind.util.Logging;
  28. import gov.nasa.worldwind.view.ViewPropertyLimits;
  29. import gov.nasa.worldwind.view.orbit.BasicOrbitViewLimits;
  30. import gov.nasa.worldwind.view.orbit.OrbitView;
  31. import gov.nasa.worldwind.view.orbit.OrbitViewLimits;
  32. import javax.media.opengl.GL;
  33. /**
  34. * Better {@link OrbitView} implementation.
  35. *
  36. * @author Michael de Hoog (michael.dehoog@ga.gov.au)
  37. */
  38. public class BaseOrbitView extends AbstractView implements OrbitView
  39. {
  40. protected final static double DEFAULT_MIN_ELEVATION = 0;
  41. protected final static double DEFAULT_MAX_ELEVATION = 4000000;
  42. protected final static Angle DEFAULT_MIN_PITCH = Angle.fromDegrees(0);
  43. protected final static Angle DEFAULT_MAX_PITCH = Angle.fromDegrees(120);
  44. protected final IViewState state;
  45. protected OrbitViewLimits viewLimits;
  46. protected boolean outOfFocus = false;
  47. protected final BaseOrbitViewCollisionSupport collisionSupport = new BaseOrbitViewCollisionSupport();
  48. protected boolean resolvingCollisions;
  49. protected Position appliedEyePosition;
  50. protected Vec4 appliedEyePoint;
  51. protected Position unsetEyePosition;
  52. public BaseOrbitView()
  53. {
  54. this.state = createViewState();
  55. this.viewInputHandler = createViewInputHandler();
  56. this.viewLimits = createOrbitViewLimits();
  57. this.collisionSupport.setCollisionThreshold(COLLISION_THRESHOLD);
  58. this.collisionSupport.setNumIterations(COLLISION_NUM_ITERATIONS);
  59. loadConfigurationValues();
  60. }
  61. protected IViewState createViewState()
  62. {
  63. return new ViewState();
  64. }
  65. protected ViewInputHandler createViewInputHandler()
  66. {
  67. return (ViewInputHandler) WorldWind.createConfigurationComponent(AVKey.VIEW_INPUT_HANDLER_CLASS_NAME);
  68. }
  69. protected OrbitViewLimits createOrbitViewLimits()
  70. {
  71. OrbitViewLimits viewLimits = new BasicOrbitViewLimits();
  72. viewLimits.setPitchLimits(DEFAULT_MIN_PITCH, DEFAULT_MAX_PITCH);
  73. viewLimits.setEyeElevationLimits(DEFAULT_MIN_ELEVATION, DEFAULT_MAX_ELEVATION);
  74. return viewLimits;
  75. }
  76. protected void loadConfigurationValues()
  77. {
  78. Position center = getCenterPosition();
  79. Double initLat = Configuration.getDoubleValue(AVKey.INITIAL_LATITUDE);
  80. Double initLon = Configuration.getDoubleValue(AVKey.INITIAL_LONGITUDE);
  81. double initElev = center.getElevation();
  82. // Set center latitude and longitude. Do not change center elevation.
  83. if (initLat != null && initLon != null)
  84. {
  85. setCenterPosition(Position.fromDegrees(initLat, initLon, initElev));
  86. }
  87. else if (initLat != null)
  88. {
  89. setCenterPosition(Position.fromDegrees(initLat, center.getLongitude().degrees, initElev));
  90. }
  91. else if (initLon != null)
  92. {
  93. setCenterPosition(Position.fromDegrees(center.getLatitude().degrees, initLon, initElev));
  94. }
  95. Double initHeading = Configuration.getDoubleValue(AVKey.INITIAL_HEADING);
  96. if (initHeading != null)
  97. {
  98. setHeading(Angle.fromDegrees(initHeading));
  99. }
  100. Double initPitch = Configuration.getDoubleValue(AVKey.INITIAL_PITCH);
  101. if (initPitch != null)
  102. {
  103. setPitch(Angle.fromDegrees(initPitch));
  104. }
  105. Double initAltitude = Configuration.getDoubleValue(AVKey.INITIAL_ALTITUDE);
  106. if (initAltitude != null)
  107. {
  108. setZoom(initAltitude);
  109. }
  110. Double initFov = Configuration.getDoubleValue(AVKey.FOV);
  111. if (initFov != null)
  112. {
  113. setFieldOfView(Angle.fromDegrees(initFov));
  114. }
  115. }
  116. public IViewState getState()
  117. {
  118. return state;
  119. }
  120. @Override
  121. public Position getEyePosition()
  122. {
  123. if (appliedEyePosition != null)
  124. {
  125. return appliedEyePosition;
  126. }
  127. return getCurrentEyePosition();
  128. }
  129. @Override
  130. public Vec4 getEyePoint()
  131. {
  132. if (appliedEyePoint != null)
  133. {
  134. return appliedEyePoint;
  135. }
  136. return getCurrentEyePoint();
  137. }
  138. @Override
  139. public Vec4 getUpVector()
  140. {
  141. if (globe == null)
  142. {
  143. return Vec4.ZERO;
  144. }
  145. return state.getUp(globe);
  146. }
  147. @Override
  148. public Vec4 getForwardVector()
  149. {
  150. if (globe == null)
  151. {
  152. return Vec4.ZERO;
  153. }
  154. return state.getForward(globe);
  155. }
  156. @Override
  157. public Vec4 getCenterPoint()
  158. {
  159. if (globe == null)
  160. {
  161. return Vec4.ZERO;
  162. }
  163. return state.getCenterPoint(globe);
  164. }
  165. @Override
  166. public Position getCenterPosition()
  167. {
  168. return state.getCenter();
  169. }
  170. @Override
  171. public void setCenterPosition(Position center)
  172. {
  173. state.setCenter(center);
  174. resolveCollisionsWithPitch();
  175. markOutOfFocus();
  176. }
  177. @Override
  178. public Vec4 getCurrentEyePoint()
  179. {
  180. if (globe == null)
  181. {
  182. return Vec4.ZERO;
  183. }
  184. return state.getEyePoint(globe);
  185. }
  186. @Override
  187. public Position getCurrentEyePosition()
  188. {
  189. if (globe == null)
  190. {
  191. if (unsetEyePosition != null)
  192. {
  193. return unsetEyePosition;
  194. }
  195. return Position.ZERO;
  196. }
  197. return state.getEye(globe);
  198. }
  199. @Override
  200. public void setOrientation(Position eyePosition, Position centerPosition)
  201. {
  202. setCenterPosition(centerPosition);
  203. setEyePosition(eyePosition);
  204. }
  205. @Override
  206. public void setEyePosition(Position eyePosition)
  207. {
  208. if (globe == null)
  209. {
  210. unsetEyePosition = eyePosition;
  211. return;
  212. }
  213. unsetEyePosition = null;
  214. state.setEye(eyePosition, globe);
  215. resolveCollisionsWithPitch();
  216. markOutOfFocus();
  217. }
  218. @Override
  219. public double getZoom()
  220. {
  221. return state.getZoom();
  222. }
  223. @Override
  224. public void setZoom(double zoom)
  225. {
  226. state.setZoom(zoom);
  227. resolveCollisionsWithPitch();
  228. markOutOfFocus();
  229. }
  230. @Override
  231. public Angle getHeading()
  232. {
  233. return state.getHeading();
  234. }
  235. @Override
  236. public void setHeading(Angle heading)
  237. {
  238. state.setHeading(heading);
  239. resolveCollisionsWithPitch();
  240. focusOnViewportCenter();
  241. }
  242. @Override
  243. public Angle getPitch()
  244. {
  245. return state.getPitch();
  246. }
  247. @Override
  248. public void setPitch(Angle pitch)
  249. {
  250. state.setPitch(pitch);
  251. resolveCollisionsWithPitch();
  252. focusOnViewportCenter();
  253. }
  254. @Override
  255. public Angle getRoll()
  256. {
  257. return state.getRoll();
  258. }
  259. @Override
  260. public void setRoll(Angle roll)
  261. {
  262. state.setRoll(roll);
  263. focusOnViewportCenter();
  264. }
  265. protected void resolveCollisionsWithPitch()
  266. {
  267. if (this.dc == null)
  268. {
  269. return;
  270. }
  271. if (!isDetectCollisions() || resolvingCollisions)
  272. {
  273. return;
  274. }
  275. resolvingCollisions = true;
  276. // Compute the near distance corresponding to the current set of values.
  277. // If there is no collision, 'newPitch' will be null. Otherwise it will contain a value
  278. // that will resolve the collision.
  279. double nearDistance = this.computeNearDistance(this.getCurrentEyePosition());
  280. Angle newPitch = this.collisionSupport.computePitchToResolveCollision(this, nearDistance, this.dc);
  281. if (newPitch != null)
  282. {
  283. setPitch(newPitch);
  284. flagHadCollisions();
  285. }
  286. resolvingCollisions = false;
  287. }
  288. protected void flagHadCollisions()
  289. {
  290. this.hadCollisions = true;
  291. }
  292. @Override
  293. public ViewPropertyLimits getViewPropertyLimits()
  294. {
  295. return viewLimits;
  296. }
  297. @Override
  298. public OrbitViewLimits getOrbitViewLimits()
  299. {
  300. return viewLimits;
  301. }
  302. @Override
  303. public void setOrbitViewLimits(OrbitViewLimits limits)
  304. {
  305. this.viewLimits = limits;
  306. }
  307. protected void markOutOfFocus()
  308. {
  309. outOfFocus = true;
  310. }
  311. @Override
  312. public boolean canFocusOnViewportCenter()
  313. {
  314. if (this.dc == null || this.globe == null)
  315. {
  316. //cannot focus on viewport center until the view has been applied at least once
  317. return false;
  318. }
  319. if (this.isAnimating())
  320. {
  321. //don't change the viewport center (rotation point) while the user is in the middle of changing the view
  322. return false;
  323. }
  324. if (Math.abs(this.getPitch().degrees) >= 90)
  325. {
  326. //don't try and focus on the viewport center if the user is pitched below the surface
  327. return false;
  328. }
  329. if (this.dc.getViewportCenterPosition() == null)
  330. {
  331. //cannot focus on a null point!
  332. return false;
  333. }
  334. return true;
  335. }
  336. @Override
  337. public void focusOnViewportCenter()
  338. {
  339. if (!canFocusOnViewportCenter())
  340. {
  341. return;
  342. }
  343. if (!outOfFocus)
  344. {
  345. return;
  346. }
  347. outOfFocus = false;
  348. //calculate the center point in cartesian space
  349. Position viewportCenter = this.dc.getViewportCenterPosition();
  350. double elevation = this.globe.getElevation(viewportCenter.latitude, viewportCenter.longitude);
  351. Position viewportExaggerated = new Position(viewportCenter, elevation * dc.getVerticalExaggeration());
  352. Vec4 viewportCenterPoint = this.globe.computePointFromPosition(viewportExaggerated);
  353. //find a point along the forward vector so the view doesn't appear to change, only the distance from the center point
  354. Vec4 eyePoint = getCurrentEyePoint();
  355. Vec4 forward = getForwardVector();
  356. double distance = eyePoint.distanceTo3(viewportCenterPoint);
  357. Vec4 newCenterPoint = Vec4.fromLine3(eyePoint, distance, forward);
  358. state.setCenter(globe.computePositionFromPoint(newCenterPoint));
  359. state.setZoom(distance);
  360. }
  361. @Override
  362. public void stopMovementOnCenter()
  363. {
  364. firePropertyChange(CENTER_STOPPED, null, null);
  365. }
  366. @Override
  367. protected void doApply(DrawContext dc)
  368. {
  369. if (dc == null)
  370. {
  371. String message = Logging.getMessage("nullValue.DrawContextIsNull"); //$NON-NLS-1$
  372. Logging.logger().severe(message);
  373. throw new IllegalArgumentException(message);
  374. }
  375. if (dc.getGL() == null)
  376. {
  377. String message = Logging.getMessage("nullValue.DrawingContextGLIsNull"); //$NON-NLS-1$
  378. Logging.logger().severe(message);
  379. throw new IllegalArgumentException(message);
  380. }
  381. if (dc.getGlobe() == null)
  382. {
  383. String message = Logging.getMessage("nullValue.DrawingContextGlobeIsNull"); //$NON-NLS-1$
  384. Logging.logger().severe(message);
  385. throw new IllegalArgumentException(message);
  386. }
  387. if (unsetEyePosition != null)
  388. {
  389. setEyePosition(unsetEyePosition);
  390. }
  391. beforeComputeMatrices();
  392. //========== modelview matrix state ==========//
  393. // Compute the current modelview matrix.
  394. this.modelview = computeModelView();
  395. if (this.modelview == null)
  396. {
  397. this.modelview = Matrix.IDENTITY;
  398. }
  399. // Compute the current inverse-modelview matrix.
  400. this.modelviewInv = this.modelview.getInverse();
  401. if (this.modelviewInv == null)
  402. {
  403. this.modelviewInv = Matrix.IDENTITY;
  404. }
  405. //========== projection matrix state ==========//
  406. // Get the current OpenGL viewport state.
  407. this.viewport = computeViewport(dc);
  408. // Compute the current clip plane distances.
  409. this.nearClipDistance = this.computeNearClipDistance();
  410. this.farClipDistance = this.computeFarClipDistance();
  411. // Compute the current projection matrix.
  412. this.projection = computeProjection(this.fieldOfView, this.nearClipDistance, this.farClipDistance);
  413. // Compute the current frustum.
  414. this.frustum = computeFrustum(this.nearClipDistance, this.farClipDistance);
  415. //========== load GL matrix state ==========//
  416. loadGLViewState(dc, this.modelview, this.projection);
  417. afterDoApply();
  418. }
  419. protected void afterDoApply()
  420. {
  421. // Establish frame-specific values.
  422. this.horizonDistance = this.computeHorizonDistance();
  423. this.appliedEyePosition = getCurrentEyePosition();
  424. this.appliedEyePoint = getCurrentEyePoint();
  425. // Clear cached computations.
  426. this.lastFrustumInModelCoords = null;
  427. }
  428. protected void beforeComputeMatrices()
  429. {
  430. }
  431. protected java.awt.Rectangle computeViewport(DrawContext dc)
  432. {
  433. int[] viewportArray = new int[4];
  434. this.dc.getGL().glGetIntegerv(GL.GL_VIEWPORT, viewportArray, 0);
  435. return new java.awt.Rectangle(viewportArray[0], viewportArray[1], viewportArray[2], viewportArray[3]);
  436. }
  437. protected Matrix computeModelView()
  438. {
  439. if (globe == null)
  440. {
  441. return Matrix.IDENTITY;
  442. }
  443. return state.getTransform(globe);
  444. }
  445. protected Matrix computeProjection(Angle horizontalFieldOfView, double nearDistance, double farDistance)
  446. {
  447. double viewportWidth = this.viewport.width <= 0.0 ? 1.0 : this.viewport.width;
  448. double viewportHeight = this.viewport.height <= 0.0 ? 1.0 : this.viewport.height;
  449. return Matrix.fromPerspective(horizontalFieldOfView, viewportWidth, viewportHeight, nearDistance, farDistance);
  450. }
  451. protected Frustum computeFrustum(double nearDistance, double farDistance)
  452. {
  453. int viewportWidth = this.viewport.width <= 0.0 ? 1 : (int) this.viewport.width;
  454. int viewportHeight = this.viewport.height <= 0.0 ? 1 : (int) this.viewport.height;
  455. return Frustum.fromPerspective(this.fieldOfView, viewportWidth, viewportHeight, nearDistance, farDistance);
  456. }
  457. }