/src/worldwind/kml/KMLViewer.java

http://wwj-kml.googlecode.com/ · Java · 320 lines · 237 code · 61 blank · 22 comment · 22 complexity · 8e3acef95b3f209bf6aa2300716d7219 MD5 · raw file

  1. package worldwind.kml;
  2. import gov.nasa.worldwind.BasicModel;
  3. import gov.nasa.worldwind.Model;
  4. import gov.nasa.worldwind.awt.WorldWindowGLJPanel;
  5. import gov.nasa.worldwind.event.SelectEvent;
  6. import gov.nasa.worldwind.event.SelectListener;
  7. import gov.nasa.worldwind.geom.Angle;
  8. import gov.nasa.worldwind.geom.LatLon;
  9. import gov.nasa.worldwind.geom.Position;
  10. import gov.nasa.worldwind.geom.Sector;
  11. import gov.nasa.worldwind.layers.CompassLayer;
  12. import gov.nasa.worldwind.layers.WorldMapLayer;
  13. import gov.nasa.worldwind.layers.Earth.BMNGSurfaceLayer;
  14. import gov.nasa.worldwind.layers.Earth.LandsatI3;
  15. import gov.nasa.worldwind.render.WWIcon;
  16. import gov.nasa.worldwind.util.BasicDragger;
  17. import gov.nasa.worldwind.util.StatusBar;
  18. import gov.nasa.worldwind.view.orbit.BasicOrbitView;
  19. import java.awt.BorderLayout;
  20. import java.awt.Dimension;
  21. import java.awt.HeadlessException;
  22. import java.awt.event.ActionEvent;
  23. import java.awt.event.MouseAdapter;
  24. import java.awt.event.MouseEvent;
  25. import java.io.File;
  26. import java.net.MalformedURLException;
  27. import java.net.URL;
  28. import javax.swing.AbstractAction;
  29. import javax.swing.JFileChooser;
  30. import javax.swing.JFrame;
  31. import javax.swing.JLabel;
  32. import javax.swing.JMenu;
  33. import javax.swing.JMenuBar;
  34. import javax.swing.JMenuItem;
  35. import javax.swing.JOptionPane;
  36. import javax.swing.JScrollPane;
  37. import javax.swing.JSplitPane;
  38. import javax.swing.tree.DefaultTreeModel;
  39. import javax.swing.tree.TreePath;
  40. import worldwind.kml.model.KMLFile;
  41. import worldwind.kml.model.KMLPlacemark;
  42. import worldwind.kml.tree.DocListTreeNode;
  43. import worldwind.kml.tree.KMLDocTreeNode;
  44. import worldwind.kml.tree.KMLTreeView;
  45. import worldwind.kml.tree.Sectored;
  46. import worldwind.kml.ui.InfoDialog;
  47. /**
  48. * Created by IntelliJ IDEA.
  49. * User: tgleason
  50. * Date: Oct 17, 2008
  51. * Time: 11:53:05 PM
  52. * To change this template use File | Settings | File Templates.
  53. */
  54. public class KMLViewer extends JFrame {
  55. StatusBar statusBar;
  56. JLabel cursorPositionDisplay;
  57. WorldWindowGLJPanel wwd;
  58. DocListTreeNode docList = new DocListTreeNode();
  59. KMLTreeView tree;
  60. JSplitPane splitPane;
  61. DefaultTreeModel treeModel;
  62. URL iconURL;
  63. public KMLViewer() throws HeadlessException {
  64. super("KML Viewer");
  65. setLayout(new BorderLayout());
  66. //-- Worldwind
  67. wwd = new WorldWindowGLJPanel();
  68. wwd.setPreferredSize(new Dimension(1000, 600));
  69. //-- KLUDGE: for some reason the GLJPanel doesn't get focus when clicked
  70. wwd.addMouseListener(new MouseAdapter() {
  71. public void mouseClicked(MouseEvent e) {
  72. wwd.grabFocus();
  73. }
  74. public void mouseEntered(MouseEvent e) {
  75. wwd.grabFocus();
  76. }
  77. });
  78. //-- Create a JTree
  79. treeModel = new DefaultTreeModel(docList);
  80. tree = new KMLTreeView(wwd, treeModel);
  81. tree.setRootVisible(false);
  82. tree.setShowsRootHandles(true);
  83. //-- Double-click on a node in the tree and we'll try to zoom to it.
  84. //-- This doesn't work too well yet (and doesn't work on folder nodes)
  85. tree.addMouseListener(new MouseAdapter() {
  86. public void mouseClicked(MouseEvent e) {
  87. if (e.getClickCount() == 2) {
  88. TreePath path = tree.getPathForLocation(e.getX(), e.getY());
  89. if (path == null)
  90. return;
  91. Object obj = path.getLastPathComponent();
  92. if (obj instanceof Sectored) {
  93. zoomToSector (((Sectored)obj).getSector());
  94. }
  95. }
  96. }
  97. });
  98. //-- Set up a split view and put the tree on the left
  99. JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
  100. new JScrollPane(tree), wwd);
  101. splitter.setContinuousLayout(true);
  102. splitter.setDividerSize(3);
  103. splitter.setDividerLocation(300);
  104. this.getContentPane().add(splitter, java.awt.BorderLayout.CENTER);
  105. this.statusBar = new StatusBar();
  106. this.getContentPane().add(statusBar, BorderLayout.PAGE_END);
  107. this.statusBar.setEventSource(wwd);
  108. this.pack();
  109. //-- Set up some layers
  110. Model m = new BasicModel();
  111. m.getLayers().clear();
  112. m.getLayers().add(new BMNGSurfaceLayer());
  113. LandsatI3 lsi3 = new LandsatI3();
  114. lsi3.setDrawBoundingVolumes(false);
  115. lsi3.setOpacity(1);
  116. m.getLayers().add(lsi3);
  117. m.getLayers().add(new CompassLayer());
  118. m.getLayers().add(new WorldMapLayer());
  119. m.setShowWireframeExterior(false);
  120. m.setShowWireframeInterior(false);
  121. wwd.setModel(m);
  122. wwd.grabFocus();
  123. //-- Set up the menu bar
  124. JMenuBar menuBar = new JMenuBar();
  125. JMenu menu = new JMenu("File");
  126. menu.add(new JMenuItem(new AbstractAction("Open File...") {
  127. public void actionPerformed(ActionEvent ae) {
  128. openFile();
  129. }
  130. }));
  131. menu.add(new JMenuItem(new AbstractAction("Open URL...") {
  132. public void actionPerformed(ActionEvent ae) {
  133. openURL();
  134. }
  135. }));
  136. menu.addSeparator();
  137. JMenu samplesMenu = new JMenu("Samples");
  138. samplesMenu.add(new SampleFileAction("KML Samples", "http://code.google.com/apis/kml/documentation/KML_Samples.kml"));
  139. //http://bbs.keyhole.com/ubb/placemarks/521519-Vancouver.kmz
  140. samplesMenu.add(new SampleFileAction("Vancouver 3D", "http://bbs.keyhole.com/ubb/placemarks/521519-Vancouver.kmz"));
  141. samplesMenu.add(new SampleFileAction("Appalachian Trail", "http://bbs.keyhole.com/ubb/download.php?Number=1114687"));
  142. samplesMenu.add(new SampleFileAction("World Heritage Sites", "http://whc.unesco.org/p_dynamic/sites/whc-en.kmz"));
  143. samplesMenu.add(new SampleFileAction("Inca Trail", "http://www.jqjacobs.net/archaeo/sites/machu_picchu.kmz"));
  144. //TODO: Support: http://wikiloc.com/wikiloc/geoServer.do?format=kml&id=190160
  145. menu.add(samplesMenu);
  146. menuBar.add(menu);
  147. setJMenuBar(menuBar);
  148. //-- Listen for Point selections:
  149. wwd.addSelectListener(new SelectListener()
  150. {
  151. private WWIcon lastToolTipIcon = null;
  152. private BasicDragger dragger = new BasicDragger(wwd);
  153. public void selected(SelectEvent event)
  154. {
  155. if (event.getEventAction().equals(SelectEvent.LEFT_CLICK))
  156. {
  157. Object obj = event.getTopObject();
  158. if (obj != null && obj instanceof KMLPlacemark) {
  159. displayInfoPane((KMLPlacemark) obj);
  160. }
  161. }
  162. }
  163. });
  164. }
  165. private void displayInfoPane(KMLPlacemark kmlPlacemark) {
  166. if (kmlPlacemark.getDescription() != null) {
  167. new InfoDialog(this, "<html>" + kmlPlacemark.getDescription() + "</html>");
  168. }
  169. }
  170. class SampleFileAction extends AbstractAction {
  171. String urlStr;
  172. String name;
  173. SampleFileAction(String name, String url) {
  174. super(name);
  175. this.urlStr = url;
  176. this.name = name;
  177. }
  178. public void actionPerformed(ActionEvent ae) {
  179. URL url = null;
  180. try {
  181. url = new URL(urlStr);
  182. } catch (MalformedURLException e) {
  183. JOptionPane.showMessageDialog(KMLViewer.this, "Not a valid URL: " + e.getMessage());
  184. }
  185. if (url != null) {
  186. try {
  187. KMLFile kml = KMLParser.parseURL(url);
  188. addKMLLayer(kml, name);
  189. zoomToSector(kml.getSector());
  190. } catch (Exception e) {
  191. JOptionPane.showMessageDialog(KMLViewer.this, "Error: " + e.getMessage());
  192. }
  193. }
  194. }
  195. }
  196. private void openURL() {
  197. String urlStr = JOptionPane.showInputDialog("KML/KMZ URL:");
  198. if (urlStr == null)
  199. return;
  200. URL url = null;
  201. try {
  202. url = new URL(urlStr);
  203. } catch (MalformedURLException e) {
  204. JOptionPane.showMessageDialog(this, "Not a valid URL: " + e.getMessage());
  205. }
  206. if (url != null) {
  207. try {
  208. KMLFile kml = KMLParser.parseURL(url);
  209. addKMLLayer(kml, url.toString());
  210. zoomToSector(kml.getSector());
  211. } catch (Exception e) {
  212. JOptionPane.showMessageDialog(this, "Error: " + e.getMessage());
  213. }
  214. }
  215. }
  216. private void openFile () {
  217. JFileChooser chooser = new JFileChooser();
  218. if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
  219. File f = chooser.getSelectedFile();
  220. try {
  221. KMLFile kml = KMLParser.parseFile(f.getAbsolutePath());
  222. addKMLLayer(kml, f.getName());
  223. zoomToSector(kml.getSector());
  224. } catch (Exception e) {
  225. JOptionPane.showMessageDialog(this, "Error: " + e.getMessage());
  226. }
  227. }
  228. }
  229. private void addKMLLayer (KMLFile kml, String name) {
  230. KMLLayer kmlLayer = new KMLLayer(kml);
  231. wwd.getModel().getLayers().add(kmlLayer);
  232. docList.add(new KMLDocTreeNode(kml, name, kmlLayer));
  233. treeModel.nodeStructureChanged(docList);
  234. }
  235. //-- TODO: This /rotates/ to the sector, but just zooms to a fixed level. Need to
  236. //-- calculate the zoom factor from the sector size (somehow)
  237. private void zoomToSector(Sector s) {
  238. if (s == null){
  239. //System.out.println("Null sector");
  240. return;
  241. }
  242. BasicOrbitView view = (BasicOrbitView)wwd.getView();
  243. LatLon latLon = new LatLon(Angle.average(s.getMinLatitude(), s.getMaxLatitude()), Angle.average(s.getMinLongitude(), s.getMaxLongitude()));
  244. // Stop all animations on the view, and start a 'pan to' animation.
  245. view.stopAnimations();
  246. view.addPanToAnimator(new Position(latLon, 0), view.getHeading(), view.getPitch(), 100000);
  247. }
  248. public static void main(String[] args) {
  249. if (gov.nasa.worldwind.Configuration.isMacOS())
  250. {
  251. System.setProperty("apple.laf.useScreenMenuBar", "true");
  252. System.setProperty("com.apple.mrj.application.apple.menu.about.name", "World Wind AWT Canvas App");
  253. System.setProperty("com.apple.mrj.application.growbox.intrudes", "false");
  254. }
  255. KMLViewer viewer = new KMLViewer();
  256. viewer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  257. viewer.setVisible(true);
  258. }
  259. }