Autopsy  4.15.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
MapPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.geolocation;
20 
21 import java.awt.AlphaComposite;
22 import java.awt.BasicStroke;
23 import java.awt.Color;
24 import java.awt.Dimension;
25 import java.awt.Graphics2D;
26 import java.awt.Point;
27 import java.awt.Rectangle;
28 import java.awt.RenderingHints;
29 import java.awt.event.ActionEvent;
30 import java.awt.event.ActionListener;
31 import java.awt.event.ComponentAdapter;
32 import java.awt.event.ComponentEvent;
33 import java.awt.geom.Point2D;
34 import java.awt.image.BufferedImage;
35 import java.beans.PropertyChangeEvent;
36 import java.beans.PropertyChangeListener;
37 import java.io.File;
38 import java.io.IOException;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.Iterator;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Set;
47 import java.util.logging.Level;
48 import java.util.prefs.PreferenceChangeEvent;
49 import java.util.prefs.PreferenceChangeListener;
50 import javax.swing.JMenuItem;
51 import javax.swing.JOptionPane;
52 import javax.swing.JPopupMenu;
53 import javax.swing.JSeparator;
54 import javax.swing.Popup;
55 import javax.swing.PopupFactory;
56 import javax.swing.Timer;
57 import javax.swing.event.MouseInputListener;
58 import org.jxmapviewer.JXMapViewer;
59 import org.jxmapviewer.OSMTileFactoryInfo;
60 import org.jxmapviewer.VirtualEarthTileFactoryInfo;
61 import org.jxmapviewer.input.CenterMapListener;
62 import org.jxmapviewer.input.ZoomMouseWheelListenerCursor;
63 import org.jxmapviewer.viewer.DefaultTileFactory;
64 import org.jxmapviewer.viewer.GeoPosition;
65 import org.jxmapviewer.viewer.TileFactory;
66 import org.jxmapviewer.viewer.TileFactoryInfo;
67 import org.jxmapviewer.viewer.WaypointPainter;
68 import org.jxmapviewer.viewer.WaypointRenderer;
69 import org.openide.util.NbBundle.Messages;
74 import org.sleuthkit.datamodel.TskCoreException;
75 import javax.imageio.ImageIO;
76 import javax.swing.SwingUtilities;
77 import org.jxmapviewer.painter.CompoundPainter;
78 import org.jxmapviewer.painter.Painter;
79 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
80 
84 @SuppressWarnings("deprecation")
85 final public class MapPanel extends javax.swing.JPanel {
86 
87  static final String CURRENT_MOUSE_GEOPOSITION = "CURRENT_MOUSE_GEOPOSITION";
88 
89  private static final Logger logger = Logger.getLogger(MapPanel.class.getName());
90 
91  private static final long serialVersionUID = 1L;
92  private static final Set<Integer> DOT_WAYPOINT_TYPES = new HashSet<>();
93  private static final int DOT_SIZE = 12;
94 
95  private boolean zoomChanging;
97  private Set<MapWaypoint> waypointSet;
98  private List<Set<MapWaypoint>> tracks = new ArrayList<>();
99 
100  private Popup currentPopup;
101  private final PopupFactory popupFactory;
102 
103  private static final int POPUP_WIDTH = 300;
104  private static final int POPUP_HEIGHT = 200;
105  private static final int POPUP_MARGIN = 10;
106 
107  private BufferedImage whiteWaypointImage;
108  private BufferedImage transparentWaypointImage;
109 
110  private MapWaypoint currentlySelectedWaypoint;
111  private Set<MapWaypoint> currentlySelectedTrack;
112 
113  static {
114  DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID());
115  DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID());
116  DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID());
117  }
118 
122  @Messages({
123  "MapPanel_connection_failure_message=Failed to connect to new geolocation map tile source.",
124  "MapPanel_connection_failure_message_title=Connection Failure"
125  })
126  public MapPanel() {
127  initComponents();
128 
129  zoomChanging = false;
130  currentPopup = null;
131  popupFactory = new PopupFactory();
132 
133  try {
134  whiteWaypointImage = ImageIO.read(getClass().getResource("/org/sleuthkit/autopsy/images/waypoint_white.png"));
135  transparentWaypointImage = ImageIO.read(getClass().getResource("/org/sleuthkit/autopsy/images/waypoint_transparent.png"));
136  } catch (IOException ex) {
137  logger.log(Level.WARNING, "Unable to load geolocation waypoint images", ex);
138  }
139 
140  // ComponentListeners do not have a concept of resize event "complete"
141  // therefore if we move the popup as the window resizes there will be
142  // a weird blinking behavior. Using the CompnentResizeEndListener the
143  // popup will move to its corner one the resize is completed.
144  this.addComponentListener(new ComponentResizeEndListener() {
145  @Override
146  public void resizeTimedOut() {
147  showDetailsPopup();
148  }
149  });
150 
151  UserPreferences.addChangeListener(new PreferenceChangeListener() {
152  @Override
153  public void preferenceChange(PreferenceChangeEvent evt) {
154  try {
155  // Tell the old factory to cleanup
156  mapViewer.getTileFactory().dispose();
157 
158  mapViewer.setTileFactory(getTileFactory());
159  initializeZoomSlider();
160  } catch (GeoLocationDataException ex) {
161  logger.log(Level.SEVERE, "Failed to connect to new geolocation tile server.", ex); //NON-NLS
162  JOptionPane.showMessageDialog(MapPanel.this,
163  Bundle.MapPanel_connection_failure_message(),
164  Bundle.MapPanel_connection_failure_message_title(),
165  JOptionPane.ERROR_MESSAGE);
167  Bundle.MapPanel_connection_failure_message_title(),
168  Bundle.MapPanel_connection_failure_message());
169  }
170  }
171  });
172  }
173 
179  List<MapWaypoint> getVisibleWaypoints() {
180 
181  Rectangle viewport = mapViewer.getViewportBounds();
182  List<MapWaypoint> waypoints = new ArrayList<>();
183 
184  Iterator<MapWaypoint> iterator = waypointTree.iterator();
185  while (iterator.hasNext()) {
186  MapWaypoint waypoint = iterator.next();
187  if (viewport.contains(mapViewer.getTileFactory().geoToPixel(waypoint.getPosition(), mapViewer.getZoom()))) {
188  waypoints.add(waypoint);
189  }
190  }
191 
192  return waypoints;
193  }
194 
198  void initMap() throws GeoLocationDataException {
199 
200  TileFactory tileFactory = getTileFactory();
201  mapViewer.setTileFactory(tileFactory);
202 
203  // Add Mouse interactions
204  MouseInputListener mia = new MapPanMouseInputListener(mapViewer);
205  mapViewer.addMouseListener(mia);
206  mapViewer.addMouseMotionListener(mia);
207 
208  mapViewer.addMouseListener(new CenterMapListener(mapViewer));
209  mapViewer.addMouseWheelListener(new ZoomMouseWheelListenerCursor(mapViewer));
210 
211  // Listen to the map for a change in zoom so that we can update the slider.
212  mapViewer.addPropertyChangeListener("zoom", new PropertyChangeListener() {
213  @Override
214  public void propertyChange(PropertyChangeEvent evt) {
215  zoomSlider.setValue(mapViewer.getZoom());
216  }
217  });
218 
219  zoomSlider.setMinimum(tileFactory.getInfo().getMinimumZoomLevel());
220  zoomSlider.setMaximum(tileFactory.getInfo().getMaximumZoomLevel());
221 
222  setZoom(tileFactory.getInfo().getMaximumZoomLevel() - 1);
223 
224  mapViewer.setCenterPosition(new GeoPosition(0, 0));
225 
226  initializePainter();
227  }
228 
229  void initializePainter() {
230  // Basic painters for the way points.
231  WaypointPainter<MapWaypoint> waypointPainter = new WaypointPainter<MapWaypoint>() {
232  @Override
233  public Set<MapWaypoint> getWaypoints() {
234  if (currentlySelectedWaypoint != null) {
235  waypointSet.remove(currentlySelectedWaypoint);
236  waypointSet.add(currentlySelectedWaypoint);
237  }
238  return waypointSet;
239  }
240  };
241  waypointPainter.setRenderer(new MapWaypointRenderer());
242 
243  ArrayList<Painter<JXMapViewer>> painters = new ArrayList<>();
244  painters.add(new MapTrackRenderer(tracks));
245  painters.add(waypointPainter);
246 
247  CompoundPainter<JXMapViewer> compoundPainter = new CompoundPainter<>(painters);
248  mapViewer.setOverlayPainter(compoundPainter);
249  }
250 
254  void initializeZoomSlider() {
255  TileFactory tileFactory = mapViewer.getTileFactory();
256  zoomSlider.setMinimum(tileFactory.getInfo().getMinimumZoomLevel());
257  zoomSlider.setMaximum(tileFactory.getInfo().getMaximumZoomLevel());
258 
259  zoomSlider.repaint();
260  zoomSlider.revalidate();
261  }
262 
268  private TileFactory getTileFactory() throws GeoLocationDataException {
269  switch (GeolocationSettingsPanel.GeolocationDataSourceType.getOptionForValue(UserPreferences.getGeolocationtTileOption())) {
270  case ONLINE_USER_DEFINED_OSM_SERVER:
271  return new DefaultTileFactory(createOnlineOSMFactory(UserPreferences.getGeolocationOsmServerAddress()));
272  case OFFLINE_OSM_ZIP:
273  return new DefaultTileFactory(createOSMZipFactory(UserPreferences.getGeolocationOsmZipPath()));
274  case OFFILE_MBTILES_FILE:
275  return new MBTilesTileFactory(UserPreferences.getGeolocationMBTilesFilePath());
276  default:
277  return new DefaultTileFactory(new VirtualEarthTileFactoryInfo(VirtualEarthTileFactoryInfo.MAP));
278  }
279  }
280 
290  private TileFactoryInfo createOnlineOSMFactory(String address) throws GeoLocationDataException {
291  if (address.isEmpty()) {
292  throw new GeoLocationDataException("Invalid user preference for OSM user define tile server. Address is an empty string.");
293  } else {
294  TileFactoryInfo info = new OSMTileFactoryInfo("User Defined Server", address);
295  return info;
296  }
297  }
298 
308  private TileFactoryInfo createOSMZipFactory(String path) throws GeoLocationDataException {
309  if (path.isEmpty()) {
310  throw new GeoLocationDataException("Invalid OSM tile Zip file. User preference value is empty string.");
311  } else {
312  File file = new File(path);
313  if (!file.exists() || !file.canRead()) {
314  throw new GeoLocationDataException("Invalid OSM tile zip file. Unable to read file: " + path);
315  }
316 
317  String zipPath = path.replaceAll("\\\\", "/");
318 
319  return new OSMTileFactoryInfo("ZIP archive", "jar:file:/" + zipPath + "!"); //NON-NLS
320  }
321  }
322 
328  void setWaypoints(Set<MapWaypoint> waypoints) {
329  waypointTree = new KdTree<>();
330  this.waypointSet = waypoints;
331  for (MapWaypoint waypoint : waypoints) {
332  waypointTree.add(waypoint);
333  }
334  mapViewer.repaint();
335  }
336 
342  void setTracks(List<Set<MapWaypoint>> tracks) {
343  this.tracks = tracks;
344  }
345 
351  void setZoom(int zoom) {
352  zoomChanging = true;
353  mapViewer.setZoom(zoom);
354  zoomSlider.setValue(zoom);
355  zoomChanging = false;
356  }
357 
361  void clearWaypoints() {
362  waypointTree = null;
363  currentlySelectedWaypoint = null;
364  currentlySelectedTrack = null;
365  if (currentPopup != null) {
366  currentPopup.hide();
367  }
368  mapViewer.repaint();
369  }
370 
377  private void showPopupMenu(Point point) {
378  try {
379  List<MapWaypoint> waypoints = findClosestWaypoint(point);
380  MapWaypoint waypoint = null;
381  if (waypoints.size() > 0) {
382  waypoint = waypoints.get(0);
383  }
384  showPopupMenu(waypoint, point);
385  // Change the details popup to the currently selected point only if
386  // it the popup is currently visible
387  if (waypoint != null && !waypoint.equals(currentlySelectedWaypoint)) {
388  currentlySelectedWaypoint = waypoint;
389  if (currentPopup != null) {
390  showDetailsPopup();
391  }
392  mapViewer.repaint();
393  }
394  } catch (TskCoreException ex) {
395  logger.log(Level.WARNING, "Failed to show popup for waypoint", ex);
396  }
397  }
398 
405  private void showPopupMenu(MapWaypoint waypoint, Point point) throws TskCoreException {
406  if (waypoint == null) {
407  return;
408  }
409 
410  JMenuItem[] items = waypoint.getMenuItems();
411  JPopupMenu popupMenu = new JPopupMenu();
412  for (JMenuItem menu : items) {
413 
414  if (menu != null) {
415  popupMenu.add(menu);
416  } else {
417  popupMenu.add(new JSeparator());
418  }
419  }
420  popupMenu.show(mapViewer, point.x, point.y);
421  }
422 
426  private void showDetailsPopup() {
427  if (currentlySelectedWaypoint != null) {
428  if (currentPopup != null) {
429  currentPopup.hide();
430  }
431 
432  WaypointDetailPanel detailPane = new WaypointDetailPanel();
433  detailPane.setWaypoint(currentlySelectedWaypoint);
434  detailPane.setPreferredSize(new Dimension(POPUP_WIDTH, POPUP_HEIGHT));
435  detailPane.addActionListener(new ActionListener() {
436  @Override
437  public void actionPerformed(ActionEvent e) {
438  if (currentPopup != null) {
439  currentPopup.hide();
440  currentPopup = null;
441  }
442  }
443 
444  });
445 
446  Point popupLocation = getLocationForDetailsPopup();
447 
448  currentPopup = popupFactory.getPopup(this, detailPane, popupLocation.x, popupLocation.y);
449  currentPopup.show();
450 
451  } else {
452  if (currentPopup != null) {
453  currentPopup.hide();
454  }
455  }
456 
457  mapViewer.revalidate();
458  mapViewer.repaint();
459  }
460 
466  private Point getLocationForDetailsPopup() {
467  Point panelCorner = this.getLocationOnScreen();
468  int width = this.getWidth();
469 
470  int popupX = panelCorner.x + width - POPUP_WIDTH - POPUP_MARGIN;
471  int popupY = panelCorner.y + POPUP_MARGIN;
472 
473  return new Point(popupX, popupY);
474  }
475 
484  private List<MapWaypoint> findClosestWaypoint(Point clickPoint) {
485  if (waypointTree == null) {
486  return new ArrayList<>();
487  }
488 
489  // Convert the mouse click location to latitude & longitude
490  GeoPosition geopos = mapViewer.convertPointToGeoPosition(clickPoint);
491 
492  // Get the nearest neightbors to the point
493  Collection<MapWaypoint> waypoints = waypointTree.nearestNeighbourSearch(1, MapWaypoint.getDummyWaypoint(geopos));
494 
495  if (waypoints == null || waypoints.isEmpty()) {
496  return null;
497  }
498 
499  Iterator<MapWaypoint> iterator = waypoints.iterator();
500 
501  // These may be the points closest to the lat/lon location that was
502  // clicked, but that doesn't mean they are close in terms of pixles.
503  List<MapWaypoint> closestPoints = new ArrayList<>();
504  while (iterator.hasNext()) {
505  MapWaypoint nextWaypoint = iterator.next();
506  Point2D point = mapViewer.convertGeoPositionToPoint(nextWaypoint.getPosition());
507  int pointX = (int) point.getX();
508  int pointY = (int) point.getY();
509  Rectangle rect;
510  if (DOT_WAYPOINT_TYPES.contains(nextWaypoint.getArtifactTypeID())) {
511  rect = new Rectangle(
512  pointX - (DOT_SIZE / 2),
513  pointY - (DOT_SIZE / 2),
514  DOT_SIZE,
515  DOT_SIZE
516  );
517  } else {
518  rect = new Rectangle(
519  pointX - (whiteWaypointImage.getWidth() / 2),
520  pointY - whiteWaypointImage.getHeight(),
521  whiteWaypointImage.getWidth(),
522  whiteWaypointImage.getHeight()
523  );
524  }
525 
526  if (rect.contains(clickPoint)) {
527  closestPoints.add(nextWaypoint);
528  }
529  }
530 
531  return closestPoints;
532  }
533 
543  public abstract class ComponentResizeEndListener
544  extends ComponentAdapter
545  implements ActionListener {
546 
547  private final Timer timer;
548  private static final int DEFAULT_TIMEOUT = 200;
549 
555  this(DEFAULT_TIMEOUT);
556  }
557 
563  public ComponentResizeEndListener(int delayMS) {
564  timer = new Timer(delayMS, this);
565  timer.setRepeats(false);
566  timer.setCoalesce(false);
567  }
568 
569  @Override
570  public void componentResized(ComponentEvent e) {
571  timer.restart();
572  }
573 
574  @Override
575  public void actionPerformed(ActionEvent e) {
576  resizeTimedOut();
577  }
578 
582  public abstract void resizeTimedOut();
583  }
584 
590  @SuppressWarnings("unchecked")
591  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
592  private void initComponents() {
593  java.awt.GridBagConstraints gridBagConstraints;
594 
595  mapViewer = new org.jxmapviewer.JXMapViewer();
596  zoomPanel = new javax.swing.JPanel();
597  zoomSlider = new javax.swing.JSlider();
598  javax.swing.JButton zoomInBtn = new javax.swing.JButton();
599  javax.swing.JButton zoomOutBtn = new javax.swing.JButton();
600 
601  setFocusable(false);
602  setLayout(new java.awt.BorderLayout());
603 
604  mapViewer.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
605  public void mouseMoved(java.awt.event.MouseEvent evt) {
606  mapViewerMouseMoved(evt);
607  }
608  });
609  mapViewer.addMouseListener(new java.awt.event.MouseAdapter() {
610  public void mouseClicked(java.awt.event.MouseEvent evt) {
611  mapViewerMouseClicked(evt);
612  }
613  public void mousePressed(java.awt.event.MouseEvent evt) {
614  mapViewerMousePressed(evt);
615  }
616  public void mouseReleased(java.awt.event.MouseEvent evt) {
617  mapViewerMouseReleased(evt);
618  }
619  });
620  mapViewer.setLayout(new java.awt.GridBagLayout());
621 
622  zoomPanel.setFocusable(false);
623  zoomPanel.setOpaque(false);
624  zoomPanel.setRequestFocusEnabled(false);
625  zoomPanel.setLayout(new java.awt.GridBagLayout());
626 
627  zoomSlider.setMaximum(15);
628  zoomSlider.setMinimum(10);
629  zoomSlider.setMinorTickSpacing(1);
630  zoomSlider.setOrientation(javax.swing.JSlider.VERTICAL);
631  zoomSlider.setPaintTicks(true);
632  zoomSlider.setSnapToTicks(true);
633  zoomSlider.setInverted(true);
634  zoomSlider.setMinimumSize(new java.awt.Dimension(35, 100));
635  zoomSlider.setOpaque(false);
636  zoomSlider.setPreferredSize(new java.awt.Dimension(35, 190));
637  zoomSlider.addChangeListener(new javax.swing.event.ChangeListener() {
638  public void stateChanged(javax.swing.event.ChangeEvent evt) {
639  zoomSliderStateChanged(evt);
640  }
641  });
642  gridBagConstraints = new java.awt.GridBagConstraints();
643  gridBagConstraints.gridx = 0;
644  gridBagConstraints.gridy = 1;
645  zoomPanel.add(zoomSlider, gridBagConstraints);
646 
647  zoomInBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/plus-grey.png"))); // NOI18N
648  org.openide.awt.Mnemonics.setLocalizedText(zoomInBtn, org.openide.util.NbBundle.getMessage(MapPanel.class, "MapPanel.zoomInBtn.text")); // NOI18N
649  zoomInBtn.setBorder(null);
650  zoomInBtn.setBorderPainted(false);
651  zoomInBtn.setFocusPainted(false);
652  zoomInBtn.setRequestFocusEnabled(false);
653  zoomInBtn.setRolloverEnabled(false);
654  zoomInBtn.addActionListener(new java.awt.event.ActionListener() {
655  public void actionPerformed(java.awt.event.ActionEvent evt) {
656  zoomInBtnActionPerformed(evt);
657  }
658  });
659  gridBagConstraints = new java.awt.GridBagConstraints();
660  gridBagConstraints.gridx = 0;
661  gridBagConstraints.gridy = 0;
662  zoomPanel.add(zoomInBtn, gridBagConstraints);
663 
664  zoomOutBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/minus-grey.png"))); // NOI18N
665  org.openide.awt.Mnemonics.setLocalizedText(zoomOutBtn, org.openide.util.NbBundle.getMessage(MapPanel.class, "MapPanel.zoomOutBtn.text")); // NOI18N
666  zoomOutBtn.setBorder(null);
667  zoomOutBtn.setBorderPainted(false);
668  zoomOutBtn.setFocusPainted(false);
669  zoomOutBtn.setRequestFocusEnabled(false);
670  zoomOutBtn.setRolloverEnabled(false);
671  zoomOutBtn.addActionListener(new java.awt.event.ActionListener() {
672  public void actionPerformed(java.awt.event.ActionEvent evt) {
673  zoomOutBtnActionPerformed(evt);
674  }
675  });
676  gridBagConstraints = new java.awt.GridBagConstraints();
677  gridBagConstraints.gridx = 0;
678  gridBagConstraints.gridy = 2;
679  zoomPanel.add(zoomOutBtn, gridBagConstraints);
680 
681  gridBagConstraints = new java.awt.GridBagConstraints();
682  gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHWEST;
683  gridBagConstraints.weightx = 1.0;
684  gridBagConstraints.weighty = 1.0;
685  gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
686  mapViewer.add(zoomPanel, gridBagConstraints);
687 
688  add(mapViewer, java.awt.BorderLayout.CENTER);
689  }// </editor-fold>//GEN-END:initComponents
690 
691  private void zoomSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_zoomSliderStateChanged
692  if (!zoomChanging) {
693  setZoom(zoomSlider.getValue());
694  }
695  }//GEN-LAST:event_zoomSliderStateChanged
696 
697  private void mapViewerMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mapViewerMousePressed
698  if (evt.isPopupTrigger()) {
699  showPopupMenu(evt.getPoint());
700  }
701  }//GEN-LAST:event_mapViewerMousePressed
702 
703  private void mapViewerMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mapViewerMouseReleased
704  if (evt.isPopupTrigger()) {
705  showPopupMenu(evt.getPoint());
706  }
707  }//GEN-LAST:event_mapViewerMouseReleased
708 
709  private void mapViewerMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mapViewerMouseMoved
710  GeoPosition geopos = mapViewer.convertPointToGeoPosition(evt.getPoint());
711  firePropertyChange(CURRENT_MOUSE_GEOPOSITION, null, geopos);
712  }//GEN-LAST:event_mapViewerMouseMoved
713 
714  private void mapViewerMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mapViewerMouseClicked
715  if (!evt.isPopupTrigger() && SwingUtilities.isLeftMouseButton(evt)) {
716  List<MapWaypoint> waypoints = findClosestWaypoint(evt.getPoint());
717  if (waypoints.size() > 0) {
718  MapWaypoint selection = waypoints.get(0);
719  currentlySelectedWaypoint = selection;
720  currentlySelectedTrack = null;
721  for (Set<MapWaypoint> track : tracks) {
722  if (track.contains(selection)) {
723  currentlySelectedTrack = track;
724  break;
725  }
726  }
727  } else {
728  currentlySelectedWaypoint = null;
729  currentlySelectedTrack = null;
730  }
731  showDetailsPopup();
732  }
733  }//GEN-LAST:event_mapViewerMouseClicked
734 
735  private void zoomInBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomInBtnActionPerformed
736  int currentValue = mapViewer.getZoom();
737  setZoom(currentValue - 1);
738  }//GEN-LAST:event_zoomInBtnActionPerformed
739 
740  private void zoomOutBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutBtnActionPerformed
741  int currentValue = mapViewer.getZoom();
742  setZoom(currentValue + 1);
743  }//GEN-LAST:event_zoomOutBtnActionPerformed
744 
745 
746  // Variables declaration - do not modify//GEN-BEGIN:variables
747  private org.jxmapviewer.JXMapViewer mapViewer;
748  private javax.swing.JPanel zoomPanel;
749  private javax.swing.JSlider zoomSlider;
750  // End of variables declaration//GEN-END:variables
751 
755  private class MapWaypointRenderer implements WaypointRenderer<MapWaypoint> {
756 
757  private final Map<Color, BufferedImage> dotImageCache = new HashMap<>();
758  private final Map<Color, BufferedImage> waypointImageCache = new HashMap<>();
759 
766  private Color getColor(MapWaypoint waypoint) {
767  Color baseColor = waypoint.getColor();
768  if (waypoint.equals(currentlySelectedWaypoint)
769  || (currentlySelectedTrack != null && currentlySelectedTrack.contains(waypoint))) {
770  // Highlight this waypoint since it is selected
771  return Color.YELLOW;
772  } else {
773  return baseColor;
774  }
775  }
776 
784  private BufferedImage createTrackDotImage(Color color) {
785  int s = DOT_SIZE;
786 
787  BufferedImage ret = new BufferedImage(s, s, BufferedImage.TYPE_INT_ARGB);
788  Graphics2D g = ret.createGraphics();
789  g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
790  g.setColor(color);
791  g.fillOval(1, 1, s - 2, s - 2);
792  g.setColor(Color.BLACK);
793  g.setStroke(new BasicStroke(1));
794  g.drawOval(1, 1, s - 2, s - 2);
795  g.dispose();
796  return ret;
797  }
798 
806  private BufferedImage createWaypointImage(Color color) {
807  int w = whiteWaypointImage.getWidth();
808  int h = whiteWaypointImage.getHeight();
809 
810  BufferedImage ret = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
811 
812  Graphics2D g = ret.createGraphics();
813  g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
814  g.drawImage(whiteWaypointImage, 0, 0, null);
815  g.setComposite(AlphaComposite.SrcIn);
816  g.setColor(color);
817  g.fillRect(0, 0, w, h);
818  g.setComposite(AlphaComposite.SrcAtop);
819  g.drawImage(transparentWaypointImage, 0, 0, null);
820  g.dispose();
821  return ret;
822  }
823 
824  @Override
825  public void paintWaypoint(Graphics2D g, JXMapViewer map, MapWaypoint waypoint) {
826  Color color = getColor(waypoint);
827  BufferedImage image;
828  Point2D point = map.getTileFactory().geoToPixel(waypoint.getPosition(), map.getZoom());
829  int x = (int) point.getX();
830  int y = (int) point.getY();
831 
832  if (DOT_WAYPOINT_TYPES.contains(waypoint.getArtifactTypeID())) {
833  image = dotImageCache.computeIfAbsent(color, k -> {
834  return createTrackDotImage(color);
835  });
836  // Center the dot on the GPS coordinate
837  y -= image.getHeight() / 2;
838  } else {
839  image = waypointImageCache.computeIfAbsent(color, k -> {
840  return createWaypointImage(color);
841  });
842  // Align the bottom of the pin with the GPS coordinate
843  y -= image.getHeight();
844  }
845  // Center image horizontally on image
846  x -= image.getWidth() / 2;
847 
848  Graphics2D g2d = (Graphics2D) g.create();
849  g2d.drawImage(image, x, y, null);
850  g2d.dispose();
851  }
852  }
853 
857  private class MapTrackRenderer implements Painter<JXMapViewer> {
858 
859  private final List<Set<MapWaypoint>> tracks;
860 
861  MapTrackRenderer(List<Set<MapWaypoint>> tracks) {
862  this.tracks = tracks;
863  }
864 
865  private void drawRoute(Set<MapWaypoint> track, Graphics2D g, JXMapViewer map) {
866  int lastX = 0;
867  int lastY = 0;
868 
869  boolean first = true;
870 
871  for (MapWaypoint wp : track) {
872  Point2D p = map.getTileFactory().geoToPixel(wp.getPosition(), map.getZoom());
873  int thisX = (int) p.getX();
874  int thisY = (int) p.getY();
875 
876  if (first) {
877  first = false;
878  } else {
879  g.drawLine(lastX, lastY, thisX, thisY);
880  }
881 
882  lastX = thisX;
883  lastY = thisY;
884  }
885  }
886 
887  @Override
888  public void paint(Graphics2D g, JXMapViewer map, int w, int h) {
889  Graphics2D g2d = (Graphics2D) g.create();
890 
891  Rectangle bounds = map.getViewportBounds();
892  g2d.translate(-bounds.x, -bounds.y);
893 
894  g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
895 
896  g2d.setColor(Color.BLACK);
897  g2d.setStroke(new BasicStroke(2));
898 
899  for (Set<MapWaypoint> track : tracks) {
900  drawRoute(track, g2d, map);
901  }
902 
903  g2d.dispose();
904  }
905  }
906 }
void zoomInBtnActionPerformed(java.awt.event.ActionEvent evt)
Definition: MapPanel.java:735
void showPopupMenu(MapWaypoint waypoint, Point point)
Definition: MapPanel.java:405
void zoomSliderStateChanged(javax.swing.event.ChangeEvent evt)
Definition: MapPanel.java:691
void mapViewerMouseReleased(java.awt.event.MouseEvent evt)
Definition: MapPanel.java:703
Collection< T > nearestNeighbourSearch(int numNeighbors, T value)
Definition: KdTree.java:206
TileFactoryInfo createOnlineOSMFactory(String address)
Definition: MapPanel.java:290
void mapViewerMouseClicked(java.awt.event.MouseEvent evt)
Definition: MapPanel.java:714
void mapViewerMousePressed(java.awt.event.MouseEvent evt)
Definition: MapPanel.java:697
void mapViewerMouseMoved(java.awt.event.MouseEvent evt)
Definition: MapPanel.java:709
void drawRoute(Set< MapWaypoint > track, Graphics2D g, JXMapViewer map)
Definition: MapPanel.java:865
List< MapWaypoint > findClosestWaypoint(Point clickPoint)
Definition: MapPanel.java:484
TileFactoryInfo createOSMZipFactory(String path)
Definition: MapPanel.java:308
void paintWaypoint(Graphics2D g, JXMapViewer map, MapWaypoint waypoint)
Definition: MapPanel.java:825
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void zoomOutBtnActionPerformed(java.awt.event.ActionEvent evt)
Definition: MapPanel.java:740
static void addChangeListener(PreferenceChangeListener listener)
void paint(Graphics2D g, JXMapViewer map, int w, int h)
Definition: MapPanel.java:888
org.jxmapviewer.JXMapViewer mapViewer
Definition: MapPanel.java:747

Copyright © 2012-2020 Basis Technology. Generated on: Mon Jul 6 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.