19 package org.sleuthkit.autopsy.geolocation;
 
   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.Paint;
 
   27 import java.awt.Point;
 
   28 import java.awt.Rectangle;
 
   29 import java.awt.RenderingHints;
 
   30 import java.awt.event.ActionEvent;
 
   31 import java.awt.event.ActionListener;
 
   32 import java.awt.event.ComponentAdapter;
 
   33 import java.awt.event.ComponentEvent;
 
   34 import java.awt.geom.GeneralPath;
 
   35 import java.awt.geom.Point2D;
 
   36 import java.awt.image.BufferedImage;
 
   37 import java.beans.PropertyChangeEvent;
 
   38 import java.beans.PropertyChangeListener;
 
   40 import java.io.IOException;
 
   41 import java.util.ArrayList;
 
   42 import java.util.Collection;
 
   43 import java.util.HashMap;
 
   44 import java.util.HashSet;
 
   45 import java.util.Iterator;
 
   46 import java.util.List;
 
   49 import java.util.logging.Level;
 
   50 import java.util.prefs.PreferenceChangeEvent;
 
   51 import java.util.prefs.PreferenceChangeListener;
 
   52 import javax.swing.JMenuItem;
 
   53 import javax.swing.JOptionPane;
 
   54 import javax.swing.JPopupMenu;
 
   55 import javax.swing.JSeparator;
 
   56 import javax.swing.Popup;
 
   57 import javax.swing.PopupFactory;
 
   58 import javax.swing.Timer;
 
   59 import javax.swing.event.MouseInputListener;
 
   60 import org.jxmapviewer.JXMapViewer;
 
   61 import org.jxmapviewer.OSMTileFactoryInfo;
 
   62 import org.jxmapviewer.VirtualEarthTileFactoryInfo;
 
   63 import org.jxmapviewer.input.CenterMapListener;
 
   64 import org.jxmapviewer.input.ZoomMouseWheelListenerCursor;
 
   65 import org.jxmapviewer.viewer.DefaultTileFactory;
 
   66 import org.jxmapviewer.viewer.GeoPosition;
 
   67 import org.jxmapviewer.viewer.TileFactory;
 
   68 import org.jxmapviewer.viewer.TileFactoryInfo;
 
   69 import org.jxmapviewer.viewer.WaypointPainter;
 
   70 import org.jxmapviewer.viewer.WaypointRenderer;
 
   71 import org.openide.util.NbBundle.Messages;
 
   77 import javax.imageio.ImageIO;
 
   78 import javax.swing.SwingUtilities;
 
   79 import org.jxmapviewer.painter.CompoundPainter;
 
   80 import org.jxmapviewer.painter.Painter;
 
   86 @SuppressWarnings(
"deprecation")
 
   87 final public class 
MapPanel extends javax.swing.JPanel {
 
   89     static final String CURRENT_MOUSE_GEOPOSITION = 
"CURRENT_MOUSE_GEOPOSITION";
 
   93     private static final long serialVersionUID = 1L;
 
   94     private static final Set<Integer> DOT_WAYPOINT_TYPES = 
new HashSet<>();
 
   95     private static final int DOT_SIZE = 12;
 
   96     private static final Set<Integer> VERY_SMALL_DOT_WAYPOINT_TYPES = 
new HashSet<>();
 
   97     private static final int VERY_SMALL_DOT_SIZE = 6;
 
  102     private List<Set<MapWaypoint>> tracks = 
new ArrayList<>();
 
  103     private List<Set<MapWaypoint>> areas = 
new ArrayList<>();
 
  108     private static final int POPUP_WIDTH = 300;
 
  109     private static final int POPUP_HEIGHT = 200;
 
  110     private static final int POPUP_MARGIN = 10;
 
  129         "MapPanel_connection_failure_message=Failed to connect to new geolocation map tile source.",
 
  130         "MapPanel_connection_failure_message_title=Connection Failure" 
  135         zoomChanging = 
false;
 
  137         popupFactory = 
new PopupFactory();
 
  140             whiteWaypointImage = ImageIO.read(getClass().getResource(
"/org/sleuthkit/autopsy/images/waypoint_white.png"));
 
  141             transparentWaypointImage = ImageIO.read(getClass().getResource(
"/org/sleuthkit/autopsy/images/waypoint_transparent.png"));
 
  142         } 
catch (IOException ex) {
 
  143             logger.log(Level.WARNING, 
"Unable to load geolocation waypoint images", ex);
 
  152             public void resizeTimedOut() {
 
  153                 if(currentPopup != null) {
 
  161             public void preferenceChange(PreferenceChangeEvent evt) {
 
  164                     mapViewer.getTileFactory().dispose();
 
  166                     mapViewer.setTileFactory(getTileFactory());
 
  167                     initializeZoomSlider();
 
  169                     logger.log(Level.SEVERE, 
"Failed to connect to new geolocation tile server.", ex); 
 
  170                     JOptionPane.showMessageDialog(
MapPanel.this,
 
  171                             Bundle.MapPanel_connection_failure_message(),
 
  172                             Bundle.MapPanel_connection_failure_message_title(),
 
  173                             JOptionPane.ERROR_MESSAGE);
 
  175                             Bundle.MapPanel_connection_failure_message_title(),
 
  176                             Bundle.MapPanel_connection_failure_message());
 
  187     List<MapWaypoint> getVisibleWaypoints() {
 
  189         Rectangle viewport = mapViewer.getViewportBounds();
 
  190         List<MapWaypoint> waypoints = 
new ArrayList<>();
 
  192         Iterator<MapWaypoint> iterator = waypointTree.
iterator();
 
  193         while (iterator.hasNext()) {
 
  195             if (viewport.contains(mapViewer.getTileFactory().geoToPixel(waypoint.
getPosition(), mapViewer.getZoom()))) {
 
  196                 waypoints.add(waypoint);
 
  206     void initMap() throws GeoLocationDataException {
 
  208         TileFactory tileFactory = getTileFactory();
 
  209         mapViewer.setTileFactory(tileFactory);
 
  212         MouseInputListener mia = 
new MapPanMouseInputListener(mapViewer);
 
  213         mapViewer.addMouseListener(mia);
 
  214         mapViewer.addMouseMotionListener(mia);
 
  216         mapViewer.addMouseListener(
new CenterMapListener(mapViewer));
 
  217         mapViewer.addMouseWheelListener(
new ZoomMouseWheelListenerCursor(mapViewer));
 
  220         mapViewer.addPropertyChangeListener(
"zoom", 
new PropertyChangeListener() {
 
  222             public void propertyChange(PropertyChangeEvent evt) {
 
  223                 zoomSlider.setValue(mapViewer.getZoom());
 
  227         zoomSlider.setMinimum(tileFactory.getInfo().getMinimumZoomLevel());
 
  228         zoomSlider.setMaximum(tileFactory.getInfo().getMaximumZoomLevel());
 
  230         setZoom(tileFactory.getInfo().getMaximumZoomLevel() - 1);
 
  232         mapViewer.setCenterPosition(
new GeoPosition(0, 0));
 
  237     void initializePainter() {
 
  239         WaypointPainter<MapWaypoint> waypointPainter = 
new WaypointPainter<MapWaypoint>() {
 
  241             public Set<MapWaypoint> getWaypoints() {
 
  242                 if (currentlySelectedWaypoint != null) {
 
  243                     waypointSet.remove(currentlySelectedWaypoint);
 
  244                     waypointSet.add(currentlySelectedWaypoint);
 
  249         waypointPainter.setRenderer(
new MapWaypointRenderer());
 
  251         ArrayList<Painter<JXMapViewer>> painters = 
new ArrayList<>();
 
  252         painters.add(
new MapAreaRenderer(areas));
 
  253         painters.add(
new MapTrackRenderer(tracks));
 
  254         painters.add(waypointPainter);
 
  256         CompoundPainter<JXMapViewer> compoundPainter = 
new CompoundPainter<>(painters);
 
  257         mapViewer.setOverlayPainter(compoundPainter);
 
  263     void initializeZoomSlider() {
 
  264         TileFactory tileFactory = mapViewer.getTileFactory();
 
  265         zoomSlider.setMinimum(tileFactory.getInfo().getMinimumZoomLevel());
 
  266         zoomSlider.setMaximum(tileFactory.getInfo().getMaximumZoomLevel());
 
  268         zoomSlider.repaint();
 
  269         zoomSlider.revalidate();
 
  279             case ONLINE_USER_DEFINED_OSM_SERVER:
 
  281             case OFFLINE_OSM_ZIP:
 
  283             case OFFILE_MBTILES_FILE:
 
  286                 return new DefaultTileFactory(
new VirtualEarthTileFactoryInfo(VirtualEarthTileFactoryInfo.MAP));
 
  300         if (address.isEmpty()) {
 
  301             throw new GeoLocationDataException(
"Invalid user preference for OSM user define tile server. Address is an empty string.");
 
  303             TileFactoryInfo info = 
new OSMTileFactoryInfo(
"User Defined Server", address);
 
  318         if (path.isEmpty()) {
 
  319             throw new GeoLocationDataException(
"Invalid OSM tile Zip file. User preference value is empty string.");
 
  321             File file = 
new File(path);
 
  322             if (!file.exists() || !file.canRead()) {
 
  323                 throw new GeoLocationDataException(
"Invalid OSM tile zip file.  Unable to read file: " + path);
 
  326             String zipPath = path.replaceAll(
"\\\\", 
"/");
 
  328             return new OSMTileFactoryInfo(
"ZIP archive", 
"jar:file:/" + zipPath + 
"!");  
 
  337     void setWaypoints(Set<MapWaypoint> waypoints) {
 
  339         this.waypointSet = waypoints;
 
  341             waypointTree.
add(waypoint);
 
  351     void setTracks(List<Set<MapWaypoint>> tracks) {
 
  352         this.tracks = tracks;
 
  360     void setAreas(List<Set<MapWaypoint>> areas) {
 
  369     void setZoom(
int zoom) {
 
  371         mapViewer.setZoom(zoom);
 
  372         zoomSlider.setValue(zoom);
 
  373         zoomChanging = 
false;
 
  379     void clearWaypoints() {
 
  381         currentlySelectedWaypoint = null;
 
  382         currentlySelectedSet = null;
 
  383         if (currentPopup != null) {
 
  397             List<MapWaypoint> waypoints = findClosestWaypoint(point);
 
  399             if (waypoints.size() > 0) {
 
  400                 waypoint = waypoints.get(0);
 
  402             showPopupMenu(waypoint, point);
 
  405             if (waypoint != null && !waypoint.
equals(currentlySelectedWaypoint)) {
 
  406                 currentlySelectedWaypoint = waypoint;
 
  407                 if (currentPopup != null) {
 
  413             logger.log(Level.WARNING, 
"Failed to show popup for waypoint", ex);
 
  424         if (waypoint == null) {
 
  428         JMenuItem[] items = waypoint.getMenuItems();
 
  429         JPopupMenu popupMenu = 
new JPopupMenu();
 
  430         for (JMenuItem menu : items) {
 
  435                 popupMenu.add(
new JSeparator());
 
  438         popupMenu.show(mapViewer, point.x, point.y);
 
  445         if (currentlySelectedWaypoint != null) {
 
  446             if (currentPopup != null) {
 
  450             WaypointDetailPanel detailPane = 
new WaypointDetailPanel();
 
  451             detailPane.setWaypoint(currentlySelectedWaypoint);
 
  452             detailPane.setPreferredSize(
new Dimension(POPUP_WIDTH, POPUP_HEIGHT));
 
  453             detailPane.addActionListener(
new ActionListener() {
 
  455                 public void actionPerformed(ActionEvent e) {
 
  456                     if (currentPopup != null) {
 
  464             Point popupLocation = getLocationForDetailsPopup();
 
  466             currentPopup = popupFactory.getPopup(
this, detailPane, popupLocation.x, popupLocation.y);
 
  470             if (currentPopup != null) {
 
  475         mapViewer.revalidate();
 
  485         Point panelCorner = this.getLocationOnScreen();
 
  486         int width = this.getWidth();
 
  488         int popupX = panelCorner.x + width - POPUP_WIDTH - POPUP_MARGIN;
 
  489         int popupY = panelCorner.y + POPUP_MARGIN;
 
  491         return new Point(popupX, popupY);
 
  503         if (waypointTree == null) {
 
  504             return new ArrayList<>();
 
  508         GeoPosition geopos = mapViewer.convertPointToGeoPosition(clickPoint);
 
  513         if (waypoints == null || waypoints.isEmpty()) {
 
  517         Iterator<MapWaypoint> iterator = waypoints.iterator();
 
  521         List<MapWaypoint> closestPoints = 
new ArrayList<>();
 
  522         while (iterator.hasNext()) {
 
  524             Point2D point = mapViewer.convertGeoPositionToPoint(nextWaypoint.
getPosition());
 
  525             int pointX = (int) point.
getX();
 
  526             int pointY = (int) point.getY();
 
  528             if (DOT_WAYPOINT_TYPES.contains(nextWaypoint.getArtifactTypeID())) {
 
  529                 rect = 
new Rectangle(
 
  530                         pointX - (DOT_SIZE / 2),
 
  531                         pointY - (DOT_SIZE / 2),
 
  535             } 
else if (VERY_SMALL_DOT_WAYPOINT_TYPES.contains(nextWaypoint.getArtifactTypeID())) {
 
  536                 rect = 
new Rectangle(
 
  537                         pointX - (VERY_SMALL_DOT_SIZE / 2),
 
  538                         pointY - (VERY_SMALL_DOT_SIZE / 2),
 
  543                 rect = 
new Rectangle(
 
  544                         pointX - (whiteWaypointImage.getWidth() / 2),
 
  545                         pointY - whiteWaypointImage.getHeight(),
 
  546                         whiteWaypointImage.getWidth(),
 
  547                         whiteWaypointImage.getHeight()
 
  551             if (rect.contains(clickPoint)) {
 
  552                 closestPoints.add(nextWaypoint);
 
  556         return closestPoints;
 
  569             extends ComponentAdapter
 
  570             implements ActionListener {
 
  573         private static final int DEFAULT_TIMEOUT = 200;
 
  580             this(DEFAULT_TIMEOUT);
 
  589             timer = 
new Timer(delayMS, 
this);
 
  590             timer.setRepeats(
false);
 
  591             timer.setCoalesce(
false);
 
  607         public abstract void resizeTimedOut();
 
  615     @SuppressWarnings(
"unchecked")
 
  617     private 
void initComponents() {
 
  618         java.awt.GridBagConstraints gridBagConstraints;
 
  620         mapViewer = 
new org.jxmapviewer.JXMapViewer();
 
  621         zoomPanel = 
new javax.swing.JPanel();
 
  622         zoomSlider = 
new javax.swing.JSlider();
 
  623         javax.swing.JButton zoomInBtn = 
new javax.swing.JButton();
 
  624         javax.swing.JButton zoomOutBtn = 
new javax.swing.JButton();
 
  627         setLayout(
new java.awt.BorderLayout());
 
  629         mapViewer.addMouseMotionListener(
new java.awt.event.MouseMotionAdapter() {
 
  630             public void mouseMoved(java.awt.event.MouseEvent evt) {
 
  631                 mapViewerMouseMoved(evt);
 
  634         mapViewer.addMouseListener(
new java.awt.event.MouseAdapter() {
 
  635             public void mouseClicked(java.awt.event.MouseEvent evt) {
 
  636                 mapViewerMouseClicked(evt);
 
  638             public void mousePressed(java.awt.event.MouseEvent evt) {
 
  639                 mapViewerMousePressed(evt);
 
  641             public void mouseReleased(java.awt.event.MouseEvent evt) {
 
  642                 mapViewerMouseReleased(evt);
 
  645         mapViewer.setLayout(
new java.awt.GridBagLayout());
 
  647         zoomPanel.setFocusable(
false);
 
  648         zoomPanel.setOpaque(
false);
 
  649         zoomPanel.setRequestFocusEnabled(
false);
 
  650         zoomPanel.setLayout(
new java.awt.GridBagLayout());
 
  652         zoomSlider.setMaximum(15);
 
  653         zoomSlider.setMinimum(10);
 
  654         zoomSlider.setMinorTickSpacing(1);
 
  655         zoomSlider.setOrientation(javax.swing.JSlider.VERTICAL);
 
  656         zoomSlider.setPaintTicks(
true);
 
  657         zoomSlider.setSnapToTicks(
true);
 
  658         zoomSlider.setInverted(
true);
 
  659         zoomSlider.setMinimumSize(
new java.awt.Dimension(35, 100));
 
  660         zoomSlider.setOpaque(
false);
 
  661         zoomSlider.setPreferredSize(
new java.awt.Dimension(35, 190));
 
  662         zoomSlider.addChangeListener(
new javax.swing.event.ChangeListener() {
 
  663             public void stateChanged(javax.swing.event.ChangeEvent evt) {
 
  664                 zoomSliderStateChanged(evt);
 
  667         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  668         gridBagConstraints.gridx = 0;
 
  669         gridBagConstraints.gridy = 1;
 
  670         zoomPanel.add(zoomSlider, gridBagConstraints);
 
  672         zoomInBtn.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/plus-grey.png"))); 
 
  673         org.openide.awt.Mnemonics.setLocalizedText(zoomInBtn, 
org.openide.util.NbBundle.getMessage(
MapPanel.class, 
"MapPanel.zoomInBtn.text")); 
 
  674         zoomInBtn.setBorder(null);
 
  675         zoomInBtn.setBorderPainted(
false);
 
  676         zoomInBtn.setFocusPainted(
false);
 
  677         zoomInBtn.setRequestFocusEnabled(
false);
 
  678         zoomInBtn.setRolloverEnabled(
false);
 
  679         zoomInBtn.addActionListener(
new java.awt.event.ActionListener() {
 
  680             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  681                 zoomInBtnActionPerformed(evt);
 
  684         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  685         gridBagConstraints.gridx = 0;
 
  686         gridBagConstraints.gridy = 0;
 
  687         zoomPanel.add(zoomInBtn, gridBagConstraints);
 
  689         zoomOutBtn.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/minus-grey.png"))); 
 
  690         org.openide.awt.Mnemonics.setLocalizedText(zoomOutBtn, 
org.openide.util.NbBundle.getMessage(
MapPanel.class, 
"MapPanel.zoomOutBtn.text")); 
 
  691         zoomOutBtn.setBorder(null);
 
  692         zoomOutBtn.setBorderPainted(
false);
 
  693         zoomOutBtn.setFocusPainted(
false);
 
  694         zoomOutBtn.setRequestFocusEnabled(
false);
 
  695         zoomOutBtn.setRolloverEnabled(
false);
 
  696         zoomOutBtn.addActionListener(
new java.awt.event.ActionListener() {
 
  697             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  698                 zoomOutBtnActionPerformed(evt);
 
  701         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  702         gridBagConstraints.gridx = 0;
 
  703         gridBagConstraints.gridy = 2;
 
  704         zoomPanel.add(zoomOutBtn, gridBagConstraints);
 
  706         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  707         gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHWEST;
 
  708         gridBagConstraints.weightx = 1.0;
 
  709         gridBagConstraints.weighty = 1.0;
 
  710         gridBagConstraints.insets = 
new java.awt.Insets(4, 4, 4, 4);
 
  711         mapViewer.add(zoomPanel, gridBagConstraints);
 
  713         add(mapViewer, java.awt.BorderLayout.CENTER);
 
  718             setZoom(zoomSlider.getValue());
 
  723         if (evt.isPopupTrigger()) {
 
  724             showPopupMenu(evt.getPoint());
 
  729         if (evt.isPopupTrigger()) {
 
  730             showPopupMenu(evt.getPoint());
 
  735         GeoPosition geopos = mapViewer.convertPointToGeoPosition(evt.getPoint());
 
  736         firePropertyChange(CURRENT_MOUSE_GEOPOSITION, null, geopos);
 
  740         if (!evt.isPopupTrigger() && SwingUtilities.isLeftMouseButton(evt)) {
 
  741             List<MapWaypoint> waypoints = findClosestWaypoint(evt.getPoint());
 
  742             if (waypoints.size() > 0) {
 
  744                 currentlySelectedWaypoint = selection;
 
  745                 currentlySelectedSet = null;
 
  746                 for (Set<MapWaypoint> track : tracks) {
 
  747                     if (track.contains(selection)) {
 
  748                         currentlySelectedSet = track;
 
  752                 if (currentlySelectedSet == null) {
 
  753                     for (Set<MapWaypoint> area : areas) {
 
  754                         if (area.contains(selection)) {
 
  755                             currentlySelectedSet = area;
 
  761                 currentlySelectedWaypoint = null;
 
  762                 currentlySelectedSet = null;
 
  769         int currentValue = mapViewer.getZoom();
 
  770         setZoom(currentValue - 1);
 
  774         int currentValue = mapViewer.getZoom();
 
  775         setZoom(currentValue + 1);
 
  790         private final Map<Color, BufferedImage> dotImageCache = 
new HashMap<>();
 
  791         private final Map<Color, BufferedImage> verySmallDotImageCache = 
new HashMap<>();
 
  792         private final Map<Color, BufferedImage> waypointImageCache = 
new HashMap<>();
 
  801             Color baseColor = waypoint.getColor();
 
  802             if (waypoint.
equals(currentlySelectedWaypoint)
 
  803                     || (currentlySelectedSet != null && currentlySelectedSet.contains(waypoint))) {
 
  821             BufferedImage ret = 
new BufferedImage(s, s, BufferedImage.TYPE_INT_ARGB);
 
  822             Graphics2D g = ret.createGraphics();
 
  823             g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 
  825             g.fillOval(1, 1, s - 2, s - 2);
 
  826             g.setColor(Color.BLACK);
 
  827             g.setStroke(
new BasicStroke(1));
 
  828             g.drawOval(1, 1, s - 2, s - 2);
 
  841             int w = whiteWaypointImage.getWidth();
 
  842             int h = whiteWaypointImage.getHeight();
 
  844             BufferedImage ret = 
new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
 
  846             Graphics2D g = ret.createGraphics();
 
  847             g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 
  848             g.drawImage(whiteWaypointImage, 0, 0, null);
 
  849             g.setComposite(AlphaComposite.SrcIn);
 
  851             g.fillRect(0, 0, w, h);
 
  852             g.setComposite(AlphaComposite.SrcAtop);
 
  853             g.drawImage(transparentWaypointImage, 0, 0, null);
 
  860             Color color = getColor(waypoint);
 
  862             Point2D point = map.getTileFactory().geoToPixel(waypoint.
getPosition(), map.getZoom());
 
  863             int x = (int) point.getX();
 
  864             int y = (int) point.getY();
 
  866             if (DOT_WAYPOINT_TYPES.contains(waypoint.getArtifactTypeID())) {
 
  867                 image = dotImageCache.computeIfAbsent(color, k -> {
 
  868                     return createTrackDotImage(color, DOT_SIZE);
 
  871                 y -= image.getHeight() / 2;
 
  872             } 
else if (VERY_SMALL_DOT_WAYPOINT_TYPES.contains(waypoint.getArtifactTypeID())) {
 
  873                 image = verySmallDotImageCache.computeIfAbsent(color, k -> {
 
  874                     return createTrackDotImage(color, VERY_SMALL_DOT_SIZE);
 
  877                 y -= image.getHeight() / 2;
 
  879                 image = waypointImageCache.computeIfAbsent(color, k -> {
 
  880                     return createWaypointImage(color);
 
  883                 y -= image.getHeight();
 
  886             x -= image.getWidth() / 2;
 
  888             Graphics2D g2d = (Graphics2D) g.create();
 
  889             g2d.drawImage(image, x, y, null);
 
  899         private final List<Set<MapWaypoint>> 
tracks;
 
  902             this.tracks = tracks;
 
  905         private void drawRoute(Set<MapWaypoint> track, Graphics2D g, JXMapViewer map) {
 
  909             boolean first = 
true;
 
  912                 Point2D p = map.getTileFactory().geoToPixel(wp.getPosition(), map.getZoom());
 
  913                 int thisX = (int) p.getX();
 
  914                 int thisY = (int) p.getY();
 
  919                     g.drawLine(lastX, lastY, thisX, thisY);
 
  928         public void paint(Graphics2D g, JXMapViewer map, 
int w, 
int h) {
 
  929             Graphics2D g2d = (Graphics2D) g.create();
 
  931             Rectangle bounds = map.getViewportBounds();
 
  932             g2d.translate(-bounds.x, -bounds.y);
 
  934             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 
  936             g2d.setColor(Color.BLACK);
 
  937             g2d.setStroke(
new BasicStroke(2));
 
  939             for (Set<MapWaypoint> track : tracks) {
 
  940                 drawRoute(track, g2d, map);
 
  952         private final List<Set<MapWaypoint>> 
areas;
 
  965         private void drawArea(Set<MapWaypoint> area, Graphics2D g, JXMapViewer map) {
 
  966             if (area.isEmpty()) {
 
  969             boolean first = 
true;
 
  971             GeneralPath polygon = 
new GeneralPath(GeneralPath.WIND_EVEN_ODD, area.size());
 
  974                 Point2D p = map.getTileFactory().geoToPixel(wp.getPosition(), map.getZoom());
 
  975                 int thisX = (int) p.getX();
 
  976                 int thisY = (int) p.getY();
 
  979                     polygon.moveTo(thisX, thisY);
 
  982                     polygon.lineTo(thisX, thisY);
 
  987             Color areaColor = area.iterator().next().getColor();
 
  988             final double maxColorValue = 255.0;
 
  989             g.setPaint(
new Color((
float)(areaColor.getRed() / maxColorValue), 
 
  990                     (
float)(areaColor.getGreen() / maxColorValue), 
 
  991                     (
float)(areaColor.getBlue() / maxColorValue),
 
  998         public void paint(Graphics2D g, JXMapViewer map, 
int w, 
int h) {
 
  999             Graphics2D g2d = (Graphics2D) g.create();
 
 1001             Rectangle bounds = map.getViewportBounds();
 
 1002             g2d.translate(-bounds.x, -bounds.y);
 
 1004             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 
 1006             g2d.setColor(Color.BLACK);
 
 1007             g2d.setStroke(
new BasicStroke(2));
 
 1009             for (Set<MapWaypoint> area : areas) {
 
 1010                 drawArea(area, g2d, map);
 
void paint(Graphics2D g, JXMapViewer map, int w, int h)
final List< Set< MapWaypoint > > tracks
void zoomInBtnActionPerformed(java.awt.event.ActionEvent evt)
static String getGeolocationOsmZipPath()
final PopupFactory popupFactory
void showPopupMenu(MapWaypoint waypoint, Point point)
boolean equals(Object obj)
BufferedImage createWaypointImage(Color color)
void zoomSliderStateChanged(javax.swing.event.ChangeEvent evt)
void componentResized(ComponentEvent e)
void mapViewerMouseReleased(java.awt.event.MouseEvent evt)
Collection< T > nearestNeighbourSearch(int numNeighbors, T value)
ComponentResizeEndListener()
javax.swing.JPanel zoomPanel
KdTree< MapWaypoint > waypointTree
static String getGeolocationMBTilesFilePath()
TileFactoryInfo createOnlineOSMFactory(String address)
BufferedImage whiteWaypointImage
javax.swing.JSlider zoomSlider
void mapViewerMouseClicked(java.awt.event.MouseEvent evt)
void mapViewerMousePressed(java.awt.event.MouseEvent evt)
void mapViewerMouseMoved(java.awt.event.MouseEvent evt)
void drawRoute(Set< MapWaypoint > track, Graphics2D g, JXMapViewer map)
Set< MapWaypoint > currentlySelectedSet
Color getColor(MapWaypoint waypoint)
List< MapWaypoint > findClosestWaypoint(Point clickPoint)
void drawArea(Set< MapWaypoint > area, Graphics2D g, JXMapViewer map)
static int getGeolocationtTileOption()
Point getLocationForDetailsPopup()
void actionPerformed(ActionEvent e)
final List< Set< MapWaypoint > > areas
TileFactoryInfo createOSMZipFactory(String path)
BufferedImage createTrackDotImage(Color color, int s)
static String getGeolocationOsmServerAddress()
void paintWaypoint(Graphics2D g, JXMapViewer map, MapWaypoint waypoint)
static void error(String title, String message)
TileFactory getTileFactory()
synchronized static Logger getLogger(String name)
void zoomOutBtnActionPerformed(java.awt.event.ActionEvent evt)
static void addChangeListener(PreferenceChangeListener listener)
ComponentResizeEndListener(int delayMS)
void paint(Graphics2D g, JXMapViewer map, int w, int h)
BufferedImage transparentWaypointImage
GeoPosition getPosition()
Set< MapWaypoint > waypointSet
org.jxmapviewer.JXMapViewer mapViewer
void showPopupMenu(Point point)
MapWaypoint currentlySelectedWaypoint