diff --git a/.gitignore b/.gitignore
index b46f1df..335abcb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,7 @@ bin/
### Other ###
osmjar/
+
+*.env
+### constants
+./src/**/utils/Constants.java
\ No newline at end of file
diff --git a/README.md b/README.md
index 2bbbbcb..134cf4b 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
-# Josm Magic Wand
+# DS-annotate plugin for Java OpenStreetMap Editor
-Plugin created for the [JOSM](https://josm.openstreetmap.de/), allows you to select areas to label using a range of
-colors, it is also possible to add areas and subtract selected areas.
+The DS-annotate plugin is an extension for the Java OpenStreetMap Desktop Editor (JOSM). Built upon ds-annotate, this plugin utilizes the [Segment Anything Service](https://github.com/developmentseed/segment-anything-services), which leverages Generative AI. Additionally, it allows users to label areas using a spectrum of colors, similar to a magic wand tool, enabling faster and more accurate mapping.
![Peek 2022-11-09 16-53](https://user-images.githubusercontent.com/12978932/200950045-179c72d5-600c-4012-b2a4-3ceb1345ea25.gif)
diff --git a/build.gradle.kts b/build.gradle.kts
index f972974..394105c 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -8,7 +8,7 @@ plugins {
}
group = "org.openstreetmap.josm.plugins.devseed.JosmMagicWand"
-version = "1.2.0"
+version = "1.2.2"
java {
toolchain {
@@ -16,17 +16,18 @@ java {
}
}
+tasks.jar {
+ duplicatesStrategy = DuplicatesStrategy.INCLUDE // O DuplicatesStrategy.EXCLUDE si deseas excluir duplicados
+}
+// Repositories Configuration
allprojects {
repositories {
mavenLocal()
+ mavenCentral()
}
}
-configurations { create("externalLibs") }
-
-repositories {
- mavenCentral()
-}
+// Source Sets Configuration
sourceSets {
create("libs") {
java {
@@ -42,18 +43,20 @@ sourceSets {
}
}
}
-val libsImplementation: Configuration by configurations.getting {
- extendsFrom(configurations.implementation.get())
+
+configurations {
+ create("externalLibs")
}
dependencies {
+ // Libraries to be packed into the JAR
packIntoJar("org.locationtech.jts:jts-core:1.19.0")
+ packIntoJar("org.locationtech.jts.io:jts-io-common:1.19.0")
packIntoJar("org.openpnp:opencv:4.7.0-0")
- libsImplementation("org.locationtech.jts:jts-core:1.19.0")
- libsImplementation("org.openpnp:opencv:4.7.0-0")
+ packIntoJar("com.fasterxml.jackson.core:jackson-databind:2.15.2")
+ packIntoJar("com.squareup.okhttp3:okhttp:4.10.0")
}
-
josm {
pluginName = "josm_magic_wand"
debugPort = 1729
@@ -68,5 +71,4 @@ josm {
website = URL("https://github.com/developmentseed/JosmMagicWand")
minJavaVersion = 11
}
-
-}
\ No newline at end of file
+}
diff --git a/images/cursor/modifier/magic-wand-sam.svg b/images/cursor/modifier/magic-wand-sam.svg
new file mode 100644
index 0000000..b1f78d8
--- /dev/null
+++ b/images/cursor/modifier/magic-wand-sam.svg
@@ -0,0 +1,99 @@
+
+
+
+
diff --git a/images/dialogs/magic-wand-encode.svg b/images/dialogs/magic-wand-encode.svg
new file mode 100644
index 0000000..bbff56b
--- /dev/null
+++ b/images/dialogs/magic-wand-encode.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/images/dialogs/magicwand-info.svg b/images/dialogs/magicwand-info.svg
new file mode 100644
index 0000000..8d53d81
--- /dev/null
+++ b/images/dialogs/magicwand-info.svg
@@ -0,0 +1,113 @@
+
+
diff --git a/images/mapmode/magic-wand-sam.svg b/images/mapmode/magic-wand-sam.svg
new file mode 100644
index 0000000..b1f78d8
--- /dev/null
+++ b/images/mapmode/magic-wand-sam.svg
@@ -0,0 +1,99 @@
+
+
+
+
diff --git a/images/mapmode/magic-wand-simplify.svg b/images/mapmode/magic-wand-simplify.svg
new file mode 100644
index 0000000..70b86d0
--- /dev/null
+++ b/images/mapmode/magic-wand-simplify.svg
@@ -0,0 +1,162 @@
+
+
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MagicWandAction.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/MagicWandAction.java
similarity index 95%
rename from src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MagicWandAction.java
rename to src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/MagicWandAction.java
index 57be4be..3435a13 100644
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MagicWandAction.java
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/MagicWandAction.java
@@ -1,4 +1,4 @@
-package org.openstreetmap.josm.plugins.devseed.JosmMagicWand;
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions;
import org.locationtech.jts.geom.Geometry;
import org.opencv.core.Mat;
@@ -18,6 +18,7 @@
import org.openstreetmap.josm.gui.layer.MapViewPaintable;
import org.openstreetmap.josm.gui.util.KeyPressReleaseListener;
import org.openstreetmap.josm.gui.util.ModifierExListener;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings;
import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils;
import org.openstreetmap.josm.spi.preferences.Config;
import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener;
@@ -66,7 +67,7 @@ private enum Mode {
public MagicWandAction() {
- super(tr("MAgic Wand action "), "magic-wand", tr("Magic wand add"), Shortcut.registerShortcut("mapmode:magicwandadd", tr("Mode: {0}", tr("Magic wand add")), KeyEvent.VK_1, Shortcut.CTRL), ImageProvider.getCursor("crosshair", null));
+ super(tr("Magic Wand"), "magic-wand", tr("Magic wand"), Shortcut.registerShortcut("mapmode:magicwandadd", tr("Mode: {0}", tr("Magic wand add")), KeyEvent.VK_1, Shortcut.CTRL), ImageProvider.getCursor("crosshair", null));
}
@@ -158,7 +159,7 @@ public void doKeyPressed(KeyEvent e) {
} catch (Exception ex) {
Logging.error(ex);
cleanMasks();
- new Notification(tr(ex.getMessage())).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show();
+ new Notification(tr("Error create ways.")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show();
}
}
}
@@ -305,6 +306,7 @@ private void drawContours() throws Exception {
DataSet ds = MainApplication.getLayerManager().getEditDataSet();
// simplify
List geometriesSimplify = geometries.stream().map(CommonUtils::simplifySmoothGeometry).collect(Collectors.toList());
+ if (geometriesSimplify.isEmpty()) return;
String tagKey = "magic_wand";
String tagValue = "yes";
if (ToolSettings.getAutoTags()!= null && !ToolSettings.getAutoTags().isEmpty()){
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MergeSelectAction.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/MergeSelectAction.java
similarity index 96%
rename from src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MergeSelectAction.java
rename to src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/MergeSelectAction.java
index fe87c0c..dfad192 100644
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MergeSelectAction.java
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/MergeSelectAction.java
@@ -1,4 +1,4 @@
-package org.openstreetmap.josm.plugins.devseed.JosmMagicWand;
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions;
import org.locationtech.jts.geom.Geometry;
import org.openstreetmap.josm.actions.JosmAction;
@@ -12,6 +12,7 @@
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.MapFrame;
import org.openstreetmap.josm.gui.Notification;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings;
import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils;
import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CustomPolygon;
import org.openstreetmap.josm.tools.Logging;
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/SamDecodeAction.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/SamDecodeAction.java
new file mode 100644
index 0000000..cd1da07
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/SamDecodeAction.java
@@ -0,0 +1,173 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions;
+
+import org.locationtech.jts.geom.Geometry;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.UndoRedoHandler;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.ProjectionRegistry;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.Notification;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.ImageSamPanelListener;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImage;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Logging;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class SamDecodeAction extends MapMode implements MouseListener {
+ private static final Cursor CURSOR_CUSTOM = ImageProvider.getCursor("crosshair", "magic-wand-sam");
+
+
+ private enum Mode {
+ None, Drawing
+ }
+
+ private Mode mode = Mode.None;
+ private Mode nextMode = Mode.None;
+ private Point drawStartPos;
+ private Point mousePos;
+ private ImageSamPanelListener listener;
+
+ public SamDecodeAction(ImageSamPanelListener listener) {
+ super(tr("Magic Wand SAM"), "magic-wand-sam", tr("Magic Wand SAM action"), null, ImageProvider.getCursor("crosshair", null));
+ this.listener = listener;
+ }
+
+ private Cursor getCursor() {
+ return CURSOR_CUSTOM;
+ }
+
+ private void setCursor(final Cursor c) {
+ MainApplication.getMap().mapView.setNewCursor(c, this);
+ }
+
+ private void updCursor() {
+ if (!MainApplication.isDisplayingMapView()) return;
+ setCursor(getCursor());
+ }
+
+ @Override
+ public void enterMode() {
+ super.enterMode();
+
+ MapFrame map = MainApplication.getMap();
+ map.mapView.addMouseListener(this);
+ map.mapView.addMouseMotionListener(this);
+
+ updCursor();
+
+ }
+
+ @Override
+ public void exitMode() {
+ super.exitMode();
+ MapFrame map = MainApplication.getMap();
+ map.mapView.removeMouseListener(this);
+ map.mapView.removeMouseMotionListener(this);
+ if (mode != Mode.None) map.mapView.repaint();
+ mode = Mode.None;
+ }
+
+
+ public final void cancelDrawing() {
+ mode = Mode.None;
+ MapFrame map = MainApplication.getMap();
+ if (map == null || map.mapView == null) return;
+ map.statusLine.setHeading(-1);
+ map.statusLine.setAngle(-1);
+ map.mapView.repaint();
+ updateStatusLine();
+ }
+
+ private void drawingStart(MouseEvent e) {
+ mousePos = e.getPoint();
+ drawStartPos = mousePos;
+ mode = Mode.Drawing;
+ updateStatusLine();
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ Logging.info("-------- mouseReleased -----------");
+ if (e.getButton() != MouseEvent.BUTTON1) return;
+ if (!MainApplication.getMap().mapView.isActiveLayerDrawable()) return;
+
+ Thread apiThread = new Thread(() -> {
+ try {
+ drawWays(e);
+ } catch (Exception ex) {
+ Logging.error(ex);
+ new Notification(tr("Error data generation.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show();
+ }
+ SwingUtilities.invokeLater(() -> {
+ System.out.println("later");
+ });
+ });
+ apiThread.start();
+ }
+
+ private boolean drawWays(MouseEvent e) throws Exception {
+
+ MapView mapView = MainApplication.getMap().mapView;
+ DataSet ds = MainApplication.getLayerManager().getEditDataSet();
+
+ String tagKey = "magic_wand_sam";
+ String tagValue = "yes";
+
+ LatLon latLon = mapView.getLatLon(e.getX(), e.getY());
+ Projection projection = ProjectionRegistry.getProjection();
+ EastNorth eastNorth = latLon.getEastNorth(projection);
+
+
+ SamImage samImage = listener.getSamImageIncludepoint(eastNorth.getX(), eastNorth.getY());
+ if (samImage == null) {
+ new Notification(tr("Click inside of active AOI to enable Segment Anything Model.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show();
+ return false;
+ }
+
+ List geometrySamList = samImage.fetchDecodePoint(eastNorth.getX(), eastNorth.getY());
+ if (geometrySamList.isEmpty()) {
+ new Notification(tr("Error fetch data.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show();
+ return false;
+ }
+
+ Projection projectionSam = Projections.getProjectionByCode("EPSG:4326");
+ List geometriesMercator = new ArrayList<>();
+
+ for (Geometry samGeometry : geometrySamList) {
+ var nodesMercator = CommonUtils.coordinates2Nodes(Arrays.asList(samGeometry.getCoordinates()), projectionSam);
+ var coordMercator = CommonUtils.nodes2Coordinates(nodesMercator);
+ var geometry = CommonUtils.coordinates2Polygon(coordMercator);
+ var geometrySimPolygonHull = CommonUtils.simplifyPolygonHull(geometry.copy(), 0.95);
+ geometriesMercator.add(geometrySimPolygonHull);
+ }
+
+
+ Collection cmds = CommonUtils.geometry2WayCommands(ds, geometriesMercator, tagKey, tagValue);
+
+ UndoRedoHandler.getInstance().add(new SequenceCommand(tr("generate sam ways"), cmds));
+ return !cmds.isEmpty();
+
+ }
+}
+
+
+
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/SimplifySelectAction.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/SimplifySelectAction.java
similarity index 90%
rename from src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/SimplifySelectAction.java
rename to src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/SimplifySelectAction.java
index 9c9322d..474ec65 100644
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/SimplifySelectAction.java
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/SimplifySelectAction.java
@@ -1,4 +1,4 @@
-package org.openstreetmap.josm.plugins.devseed.JosmMagicWand;
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
@@ -13,6 +13,7 @@
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.MapFrame;
import org.openstreetmap.josm.gui.Notification;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings;
import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils;
import org.openstreetmap.josm.tools.Logging;
import org.openstreetmap.josm.tools.Shortcut;
@@ -31,7 +32,7 @@ public class SimplifySelectAction extends JosmAction implements DataSelectionLis
public SimplifySelectAction() {
- super(tr("Simplify way"), "mapmode/magic-wand-merge", tr("Simplify multiple geometries"), Shortcut.registerShortcut("data:magicwandsimplify", tr("Data: {0}", tr("Simplify multiple geometries")), KeyEvent.VK_4, Shortcut.CTRL), true);
+ super(tr("Simplify way"), "mapmode/magic-wand-simplify", tr("Simplify multiple geometries"), Shortcut.registerShortcut("data:magicwandsimplify", tr("Data: {0}", tr("Simplify multiple geometries")), KeyEvent.VK_4, Shortcut.CTRL), true);
}
@Override
@@ -73,7 +74,7 @@ private List simplifyWays(Collection ways) throws Exception {
List geometries = new ArrayList<>();
for (Way w : ways) {
List coordsMercator = CommonUtils.nodes2Coordinates(w.getNodes());
- Geometry geometryMercator = CommonUtils.coordinates2Geometry(coordsMercator, true);
+ Geometry geometryMercator = CommonUtils.coordinates2Polygon(coordsMercator);
Geometry geometrySimplify = CommonUtils.simplifySmoothGeometry(geometryMercator);
geometries.add(geometrySimplify);
}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MagicWandDialog.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MagicWandDialog.java
deleted file mode 100644
index e77cc8b..0000000
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MagicWandDialog.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package org.openstreetmap.josm.plugins.devseed.JosmMagicWand;
-
-import org.openstreetmap.josm.gui.SideButton;
-import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
-
-import javax.swing.*;
-import java.awt.*;
-import java.util.List;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-public class MagicWandDialog extends ToggleDialog {
- // variables
-
- public MagicWandDialog() {
- super(tr("Magic Wand"), "magicwand.svg", tr("Open MagicWand windows"), null, 90);
-
- JPanel panel = new JPanel();
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
- // tolerance
- panel.add(buildTolerancePanel());
- // simplify
- panel.add(buildPolygonHullPanel());
- panel.add(buildDouglaspPanel());
- panel.add(buildTopologyPreservingPanel());
- panel.add(buildChaikinAnglePanel());
- panel.add(buildAutoAddTag());
-
- createLayout(panel, true, List.of(new SideButton[]{}));
- }
-
- private JPanel buildTolerancePanel() {
- JPanel jpanel = new JPanel();
- jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
- //
- int initValue = 9;
- JLabel toleranceJLabel = new JLabel();
- toleranceJLabel.setText("Tolerance: " + initValue);
- ToolSettings.setTolerance(initValue);
- jpanel.add(toleranceJLabel);
- //
- JSlider jSlider = new JSlider(1, 30, initValue);
- jSlider.setPaintTrack(true);
- jSlider.setPaintTicks(true);
- jSlider.setPaintLabels(true);
- jSlider.setMajorTickSpacing(5);
- jSlider.setMinorTickSpacing(0);
-
- jpanel.add(jSlider);
- jSlider.addChangeListener(changeEvent -> {
- JSlider source = (JSlider) changeEvent.getSource();
- int value = source.getValue();
- toleranceJLabel.setText(tr("Tolerance: " + value));
- ToolSettings.setTolerance(value);
- });
- jpanel.add(new JSeparator());
-
- return jpanel;
- }
-
- private JPanel buildPolygonHullPanel() {
- JPanel jpanel = new JPanel();
- jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
- //
- JLabel simplPolygonHullJLabel = new JLabel();
- double decimalPlaces = Math.pow(10, 3);
- double min = 0.5;
- int initValue = (int) (0.95 * decimalPlaces);
- //
- simplPolygonHullJLabel.setText("Exterior contour: " + initValue / decimalPlaces);
- ToolSettings.setSimplPolygonHull(initValue / decimalPlaces);
- jpanel.add(simplPolygonHullJLabel);
- //
- JSlider jSlider = new JSlider((int) (min * decimalPlaces), (int) decimalPlaces, initValue);
- jSlider.setPaintTrack(true);
- jSlider.setPaintTicks(true);
- jSlider.setPaintLabels(true);
-
- jpanel.add(jSlider);
- jSlider.addChangeListener(changeEvent -> {
- JSlider source = (JSlider) changeEvent.getSource();
- double value = source.getValue();
- if (value <= (min * decimalPlaces)) {
- value = 0.0;
- } else {
- value /= decimalPlaces;
- }
-
- simplPolygonHullJLabel.setText(tr("Exterior contour: " + value));
- ToolSettings.setSimplPolygonHull(value);
- });
- jpanel.add(new JSeparator());
-
- return jpanel;
- }
-
- private JPanel buildDouglaspPanel() {
- JPanel jpanel = new JPanel();
- jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
- //
- JLabel simplDouglaspJLabel = new JLabel();
- double decimalPlaces = Math.pow(10, 3);
- int initValue = 1000;
- //
- simplDouglaspJLabel.setText("Vertices: " + initValue / decimalPlaces);
- ToolSettings.setSimplifyDouglasP(initValue / decimalPlaces);
- jpanel.add(simplDouglaspJLabel);
- //
- JSlider jSlider = new JSlider(0, (int) (5 * decimalPlaces), initValue);
- jSlider.setPaintTrack(true);
- jSlider.setPaintTicks(true);
- jSlider.setPaintLabels(true);
-
- jpanel.add(jSlider);
- jSlider.addChangeListener(changeEvent -> {
- JSlider source = (JSlider) changeEvent.getSource();
- double value = source.getValue() / decimalPlaces;
- simplDouglaspJLabel.setText(tr("Vertices: " + value));
- ToolSettings.setSimplifyDouglasP(value);
- });
- jpanel.add(new JSeparator());
-
- return jpanel;
- }
-
- private JPanel buildTopologyPreservingPanel() {
- JPanel jpanel = new JPanel();
- jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
- //
- JLabel simplTopologyPreservingJLabel = new JLabel();
- double decimalPlaces = Math.pow(10, 3);
- int initValue = 1000;
- //
- simplTopologyPreservingJLabel.setText("Topology: " + initValue / decimalPlaces);
- ToolSettings.setSimplTopologyPreserving(initValue / decimalPlaces);
- jpanel.add(simplTopologyPreservingJLabel);
- //
- JSlider jSlider = new JSlider(0, (int) (5 * decimalPlaces), initValue);
- jSlider.setPaintTrack(true);
- jSlider.setPaintTicks(true);
- jSlider.setPaintLabels(true);
-
- jpanel.add(jSlider);
- jSlider.addChangeListener(changeEvent -> {
- JSlider source = (JSlider) changeEvent.getSource();
- double value = source.getValue() / decimalPlaces;
- simplTopologyPreservingJLabel.setText(tr("Topology: " + value));
- ToolSettings.setSimplTopologyPreserving(value);
- });
- jpanel.add(new JSeparator());
-
- return jpanel;
- }
-
- private JPanel buildChaikinAnglePanel() {
- JPanel jpanel = new JPanel();
- jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
- //
- int initValue = 110;
- double minValue = 20.0;
- JLabel chaikinSmootherAngleJLabel = new JLabel();
- chaikinSmootherAngleJLabel.setText("Smooth Angle: " + initValue);
- ToolSettings.setChaikinSmooAngle(initValue);
- jpanel.add(chaikinSmootherAngleJLabel);
- //
- JSlider jSlider = new JSlider((int) minValue, 170, initValue);
- jSlider.setPaintTrack(true);
- jSlider.setPaintTicks(true);
- jSlider.setPaintLabels(true);
-
- jpanel.add(jSlider);
- jSlider.addChangeListener(changeEvent -> {
- JSlider source = (JSlider) changeEvent.getSource();
- double value = source.getValue();
- if (value <= minValue) {
- value = 0.0;
- }
- chaikinSmootherAngleJLabel.setText(tr("Smooth Angle: " + value));
- ToolSettings.setChaikinSmooAngle(value);
- });
- jpanel.add(new JSeparator());
-
- return jpanel;
- }
-
- private JPanel buildAutoAddTag() {
- JPanel jpanel = new JPanel();
- jpanel.setLayout(new FlowLayout());
- JButton button = new JButton("add Tag");
- button.addActionListener(e -> {
- TagsDialog tagsDialog = new TagsDialog();
- if (tagsDialog.getValue() != 1) return;
- tagsDialog.saveSettings();
- });
- jpanel.add(button);
- return jpanel;
- }
-
-}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MainJosmMagicWandPlugin.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MainJosmMagicWandPlugin.java
index 4515d8d..c331dda 100644
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MainJosmMagicWandPlugin.java
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MainJosmMagicWandPlugin.java
@@ -7,6 +7,12 @@
import org.openstreetmap.josm.gui.MapFrame;
import org.openstreetmap.josm.plugins.Plugin;
import org.openstreetmap.josm.plugins.PluginInformation;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.MagicWandAction;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.MergeSelectAction;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.SamDecodeAction;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.SimplifySelectAction;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.MagicWandDialog;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils;
import org.openstreetmap.josm.tools.Logging;
import javax.swing.*;
@@ -30,15 +36,17 @@ public MainJosmMagicWandPlugin(PluginInformation info) {
jToolmenu.addSeparator();
MainMenu.add(jToolmenu, new MergeSelectAction());
MainMenu.add(jToolmenu, new SimplifySelectAction());
-
+ // create a folder
+ CommonUtils.createCacheDir();
}
@Override
public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
if (oldFrame == null && newFrame != null) {
- newFrame.addToggleDialog( new MagicWandDialog());
+ MagicWandDialog magicWandDialog = new MagicWandDialog();
+ newFrame.addToggleDialog(magicWandDialog);
MainApplication.getMap().addMapMode(new IconToggleButton(new MagicWandAction()));
-
+ MainApplication.getMap().addMapMode(new IconToggleButton(new SamDecodeAction(magicWandDialog)));
}
}
}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/ToolSettings.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/ToolSettings.java
index b36e2e5..d216684 100644
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/ToolSettings.java
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/ToolSettings.java
@@ -1,5 +1,10 @@
package org.openstreetmap.josm.plugins.devseed.JosmMagicWand;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImage;
+
+import java.util.ArrayList;
+import java.util.List;
+
public final class ToolSettings {
private ToolSettings() {
}
@@ -16,8 +21,25 @@ private ToolSettings() {
//smooth
private static double chaikinSmooDistance;
private static double chaikinSmooAngle;
-// tags
+ // tags
private static String autoTags;
+ // sam images
+ private static List samImagesList = new ArrayList<>();
+
+ public static List getSamImagesList() {
+ return samImagesList;
+ }
+ public static void setSamImagesList(List samImagesList) {
+ ToolSettings.samImagesList = samImagesList;
+ }
+
+ public static void setSamImage(SamImage samImage) {
+ ToolSettings.samImagesList.add(samImage);
+ }
+ public static void clearSamImagesList() {
+ ToolSettings.samImagesList.clear();
+ }
+
public static int getMaskOpen() {
return maskOpen;
}
@@ -67,11 +89,11 @@ public static void setSimplTopologyPreserving(double simplTopologyPreserving) {
ToolSettings.simplTopologyPreserving = simplTopologyPreserving;
}
- public static double getSimplifyDouglasP() {
+ public static double getSimplDouglasP() {
return simplDouglasP;
}
- public static void setSimplifyDouglasP(double simplDouglasP) {
+ public static void setSimplDouglasP(double simplDouglasP) {
ToolSettings.simplDouglasP = simplDouglasP;
}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/AutoAddTagAction.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/AutoAddTagAction.java
new file mode 100644
index 0000000..2e755c6
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/AutoAddTagAction.java
@@ -0,0 +1,32 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions;
+
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.TagsDialog;
+
+import java.awt.event.ActionEvent;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class AutoAddTagAction extends JosmAction {
+ AtomicBoolean isPerforming = new AtomicBoolean(false);
+
+ public AutoAddTagAction() {
+ super(tr("Add tag"), "dialogs/add", tr("Add a new key/value tag to geometries"),
+ null, false);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (!/*successful*/isPerforming.compareAndSet(false, true)) {
+ return;
+ }
+ try {
+ TagsDialog tagsDialog = new TagsDialog();
+ if (tagsDialog.getValue() != 1) return;
+ tagsDialog.saveSettings();
+ } finally {
+ isPerforming.set(false);
+ }
+ }
+}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/SamEncondeAction.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/SamEncondeAction.java
new file mode 100644
index 0000000..2e31aa2
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/SamEncondeAction.java
@@ -0,0 +1,99 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions;
+
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.Notification;
+import org.openstreetmap.josm.gui.layer.ImageryLayer;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.ImageSamPanelListener;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.LayerImageValues;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImage;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class SamEncondeAction extends JosmAction {
+ private ImageSamPanelListener listener;
+
+ public SamEncondeAction(ImageSamPanelListener listener) {
+ super(tr("SAM AOI"), "dialogs/magic-wand-encode", tr("Add a new SAM AOI"),
+ null, false);
+ this.listener = listener;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ MapView mapView = MainApplication.getMap().mapView;
+ // check layers
+ List targetLayer = MainApplication.getLayerManager().getLayers();
+ boolean hasMapLayer = false;
+ for (Layer layer : targetLayer) {
+ if (layer instanceof ImageryLayer && layer.isVisible()) {
+ hasMapLayer = true;
+ break;
+ }
+ }
+
+ if (hasMapLayer) {
+ LayerImageValues layerImageValues = getLayeredImage(mapView);
+
+ SamImage samImage = new SamImage(mapView.getProjectionBounds(), layerImageValues.getBufferedImage(), layerImageValues.getLayerName());
+
+ // effect
+ setEnabled(false);
+ apiThread(samImage);
+
+ } else {
+ new Notification(tr("An active layer is needed.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show();
+ }
+ }
+
+ private void apiThread(SamImage samImage) {
+ Thread apiThread = new Thread(() -> {
+ samImage.setEncodeImage();
+ SwingUtilities.invokeLater(() -> {
+ addSamImage(samImage);
+ samImage.updateCacheImage();
+ setEnabled(true);
+ });
+ });
+ apiThread.start();
+ }
+
+ private void addSamImage(SamImage samImage) {
+ if (samImage.isEncodeImage()) {
+ listener.addLayer();
+ listener.addBboxLayer(samImage.getBboxWay());
+ listener.onAddSamImage(samImage);
+ new Notification(tr("Added a sam image.")).setIcon(JOptionPane.INFORMATION_MESSAGE).setDuration(Notification.TIME_SHORT).show();
+ } else {
+ new Notification(tr("Error adding sam image.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show();
+ }
+ }
+
+ private LayerImageValues getLayeredImage(MapView mapView) {
+ LayerImageValues layerImageValues = new LayerImageValues();
+ BufferedImage bufImage = new BufferedImage(mapView.getWidth(), mapView.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
+ Graphics2D imgGraphics = bufImage.createGraphics();
+ imgGraphics.setClip(0, 0, mapView.getWidth(), mapView.getHeight());
+
+ for (Layer layer : mapView.getLayerManager().getVisibleLayersInZOrder()) {
+ if (layer.isVisible() && layer.isBackgroundLayer()) {
+ Composite translucent = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) layer.getOpacity());
+ imgGraphics.setComposite(translucent);
+ mapView.paintLayer(layer, imgGraphics);
+ layerImageValues.setBufferedImage(bufImage);
+ layerImageValues.setLayerName(layer.getName());
+ }
+
+ }
+
+ return layerImageValues;
+ }
+}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/MagicWandDialog.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/MagicWandDialog.java
new file mode 100644
index 0000000..7a428c5
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/MagicWandDialog.java
@@ -0,0 +1,297 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui;
+
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.Point;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions.AutoAddTagAction;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions.SamEncondeAction;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.ImageSamPanelListener;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImage;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImageGrid;
+import org.openstreetmap.josm.tools.Logging;
+
+import javax.swing.*;
+import javax.swing.border.TitledBorder;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class MagicWandDialog extends ToggleDialog implements ImageSamPanelListener {
+ // variables
+ private SamImageGrid samImageGrid;
+ private JPanel mainJpanel;
+ private OsmDataLayer uneditableLayer = null;
+ private boolean canSamAoi = false;
+
+ public MagicWandDialog() {
+ super(tr("Magic Wand"), "magicwand-info.svg", tr("Open MagicWand windows"), null, 200, false);
+
+ mainJpanel = new JPanel();
+ mainJpanel.setLayout(new BoxLayout(mainJpanel, BoxLayout.Y_AXIS));
+
+ JPanel optionPanel = new JPanel();
+ optionPanel.setLayout(new GridLayout(5, 1, 3, 3));
+ // tolerance
+ optionPanel.add(buildTolerancePanel());
+ // simplify
+ optionPanel.add(buildPolygonHullPanel());
+ optionPanel.add(buildDouglaspPanel());
+ optionPanel.add(buildTopologyPreservingPanel());
+ optionPanel.add(buildChaikinAnglePanel());
+ // add mainJpanel
+ mainJpanel.add(optionPanel);
+ // sam image
+
+ mainJpanel.add(buildSamImagesPanel());
+ // layer
+ initLayer();
+ // buttons
+ // add
+ SideButton addTagButton = new SideButton(new AutoAddTagAction());
+ // sam
+ SideButton samButton = new SideButton(new SamEncondeAction(this));
+
+ createLayout(mainJpanel, true, Arrays.asList(addTagButton, samButton));
+ }
+
+ private JPanel buildTolerancePanel() {
+ JPanel jpanel = new JPanel();
+ jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
+ jpanel.setPreferredSize(new Dimension(0,25));
+ int initValue = 9;
+ TitledBorder titledBorder = BorderFactory.createTitledBorder("Tolerance: " + initValue);
+ jpanel.setBorder(titledBorder);
+ ToolSettings.setTolerance(initValue);
+ //
+ JSlider jSlider = new JSlider(1, 30, initValue);
+ jSlider.setPaintTrack(true);
+ jSlider.setPaintTicks(true);
+ jSlider.setPaintLabels(true);
+
+ jpanel.add(jSlider);
+ jSlider.addChangeListener(changeEvent -> {
+ JSlider source = (JSlider) changeEvent.getSource();
+ int value = source.getValue();
+ titledBorder.setTitle(tr("Tolerance: " + value));
+ ToolSettings.setTolerance(value);
+ jpanel.repaint();
+ });
+
+ return jpanel;
+ }
+
+ private JPanel buildPolygonHullPanel() {
+ JPanel jpanel = new JPanel();
+ jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
+ jpanel.setPreferredSize(new Dimension(0,25));
+ //
+ double decimalPlaces = Math.pow(10, 3);
+ double min = 0.5;
+ int initValue = (int) (0.95 * decimalPlaces);
+ //
+ TitledBorder titledBorder = BorderFactory.createTitledBorder("Exterior contour: " + initValue / decimalPlaces);
+ jpanel.setBorder(titledBorder);
+
+ ToolSettings.setSimplPolygonHull(initValue / decimalPlaces);
+ //
+ JSlider jSlider = new JSlider((int) (min * decimalPlaces), (int) decimalPlaces, initValue);
+ jSlider.setPaintTrack(true);
+ jSlider.setPaintTicks(true);
+ jSlider.setPaintLabels(true);
+
+ jpanel.add(jSlider);
+ jSlider.addChangeListener(changeEvent -> {
+ JSlider source = (JSlider) changeEvent.getSource();
+ double value = source.getValue();
+ if (value <= (min * decimalPlaces)) {
+ value = 0.0;
+ } else {
+ value /= decimalPlaces;
+ }
+
+ titledBorder.setTitle(tr("Exterior contour: " + value));
+ ToolSettings.setSimplPolygonHull(value);
+ jpanel.repaint();
+ });
+
+
+ return jpanel;
+ }
+
+ private JPanel buildDouglaspPanel() {
+ JPanel jpanel = new JPanel();
+ jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
+ //
+ double decimalPlaces = Math.pow(10, 3);
+ int initValue = 1000;
+ //
+ TitledBorder titledBorder = BorderFactory.createTitledBorder("Vertices: " + initValue / decimalPlaces);
+ jpanel.setBorder(titledBorder);
+ ToolSettings.setSimplDouglasP(initValue / decimalPlaces);
+ //
+ JSlider jSlider = new JSlider(0, (int) (5 * decimalPlaces), initValue);
+ jSlider.setPaintTrack(true);
+ jSlider.setPaintTicks(true);
+ jSlider.setPaintLabels(true);
+
+ jpanel.add(jSlider);
+ jSlider.addChangeListener(changeEvent -> {
+ JSlider source = (JSlider) changeEvent.getSource();
+ double value = source.getValue() / decimalPlaces;
+ titledBorder.setTitle(tr("Vertices: " + value));
+ ToolSettings.setSimplDouglasP(value);
+ jpanel.repaint();
+ });
+
+
+ return jpanel;
+ }
+
+ private JPanel buildTopologyPreservingPanel() {
+ JPanel jpanel = new JPanel();
+ jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
+ //
+ double decimalPlaces = Math.pow(10, 3);
+ int initValue = 1000;
+ //
+ TitledBorder titledBorder = BorderFactory.createTitledBorder("Topology: " + initValue / decimalPlaces);
+ jpanel.setBorder(titledBorder);
+ ToolSettings.setSimplTopologyPreserving(initValue / decimalPlaces);
+ //
+ JSlider jSlider = new JSlider(0, (int) (5 * decimalPlaces), initValue);
+ jSlider.setPaintTrack(true);
+ jSlider.setPaintTicks(true);
+ jSlider.setPaintLabels(true);
+
+ jpanel.add(jSlider);
+ jSlider.addChangeListener(changeEvent -> {
+ JSlider source = (JSlider) changeEvent.getSource();
+ double value = source.getValue() / decimalPlaces;
+ titledBorder.setTitle(tr("Topology: " + value));
+ ToolSettings.setSimplTopologyPreserving(value);
+ jpanel.repaint();
+ });
+
+
+ return jpanel;
+ }
+
+ private JPanel buildChaikinAnglePanel() {
+ JPanel jpanel = new JPanel();
+ jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS));
+ //
+ int initValue = 110;
+ double minValue = 20.0;
+ //
+ TitledBorder titledBorder = BorderFactory.createTitledBorder("Smooth Angle: " + initValue);
+ jpanel.setBorder(titledBorder);
+ ToolSettings.setChaikinSmooAngle(initValue);
+ //
+ JSlider jSlider = new JSlider((int) minValue, 170, initValue);
+ jSlider.setPaintTrack(true);
+ jSlider.setPaintTicks(true);
+ jSlider.setPaintLabels(true);
+
+ jpanel.add(jSlider);
+ jSlider.addChangeListener(changeEvent -> {
+ JSlider source = (JSlider) changeEvent.getSource();
+ double value = source.getValue();
+ if (value <= minValue) {
+ value = 0.0;
+ }
+ titledBorder.setTitle(tr("Smooth Angle: " + value));
+ ToolSettings.setChaikinSmooAngle(value);
+ jpanel.repaint();
+ });
+
+
+ return jpanel;
+ }
+
+ private JPanel buildSamImagesPanel() {
+ samImageGrid = new SamImageGrid(130);
+ samImageGrid.setLayout(new GridLayout(0, 2, 2, 3));
+
+ return samImageGrid;
+ }
+
+ private void initLayer() {
+ if (uneditableLayer == null || !MainApplication.getLayerManager().containsLayer(uneditableLayer)) {
+ DataSet bboxDataset = new DataSet();
+ uneditableLayer = new OsmDataLayer(bboxDataset, "Magic Wand Uneditable Layer", null);
+ uneditableLayer.setUploadDiscouraged(false);
+ }
+ }
+
+ @Override
+ public void onAddSamImage(SamImage samImage) {
+ samImageGrid.addSamImage(samImage);
+ }
+
+ @Override
+ public void onRemoveAll() {
+ samImageGrid.removeAllSamImage();
+ }
+
+ @Override
+ public ArrayList getSamImageList() {
+ return samImageGrid.getSamImageList();
+ }
+
+ @Override
+ public SamImage getSamImageIncludepoint(double x, double y) {
+ GeometryFactory geometryFactory = new GeometryFactory();
+ Coordinate coordinate = new Coordinate(x, y);
+ Point point = geometryFactory.createPoint(coordinate);
+
+ return samImageGrid.getSamImageIncludepoint(point);
+ }
+
+ @Override
+ public void addLayer() {
+ try {
+ initLayer();
+
+ Layer activeLayer = MainApplication.getLayerManager().getActiveDataLayer();
+ if (activeLayer == null) {
+ activeLayer = new OsmDataLayer(new DataSet(), "Data Layer ", null);
+ MainApplication.getLayerManager().addLayer(activeLayer);
+ }
+ int indexActiveLayer = MainApplication.getLayerManager().getLayers().indexOf(activeLayer);
+
+ if (!MainApplication.getLayerManager().containsLayer(uneditableLayer)) {
+ MainApplication.getLayerManager().addLayer(uneditableLayer);
+ MainApplication.getLayerManager().setActiveLayer(activeLayer);
+ }
+ int indexUneditableLayer = MainApplication.getLayerManager().getLayers().indexOf(uneditableLayer);
+
+ if (indexActiveLayer >= indexUneditableLayer) {
+ MainApplication.getLayerManager().moveLayer(uneditableLayer, indexActiveLayer);
+ }
+ } catch (Exception e) {
+ Logging.error(e);
+ }
+ }
+
+ @Override
+ public void addBboxLayer(Way way) {
+ for (Node node : way.getNodes()) {
+ if (!uneditableLayer.getDataSet().containsNode(node)) {
+ uneditableLayer.getDataSet().addPrimitive(node);
+ }
+ }
+ uneditableLayer.getDataSet().addPrimitive(way);
+ }
+
+}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/TagsDialog.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/TagsDialog.java
similarity index 93%
rename from src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/TagsDialog.java
rename to src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/TagsDialog.java
index 22c0dc4..50aeab0 100644
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/TagsDialog.java
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/TagsDialog.java
@@ -1,9 +1,10 @@
-package org.openstreetmap.josm.plugins.devseed.JosmMagicWand;
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui;
import org.openstreetmap.josm.gui.ExtendedDialog;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.Notification;
import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
+import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings;
import org.openstreetmap.josm.tools.GBC;
import javax.swing.*;
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CommonUtils.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CommonUtils.java
index 3997cc6..810b79c 100644
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CommonUtils.java
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CommonUtils.java
@@ -1,15 +1,13 @@
package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
import org.locationtech.jts.algorithm.Angle;
-import org.locationtech.jts.geom.Coordinate;
-import org.locationtech.jts.geom.Geometry;
-import org.locationtech.jts.geom.GeometryFactory;
-import org.locationtech.jts.geom.PrecisionModel;
+import org.locationtech.jts.geom.*;
import org.locationtech.jts.geom.util.GeometryFixer;
import org.locationtech.jts.precision.GeometryPrecisionReducer;
import org.locationtech.jts.simplify.DouglasPeuckerSimplifier;
import org.locationtech.jts.simplify.PolygonHullSimplifier;
import org.locationtech.jts.simplify.TopologyPreservingSimplifier;
+import org.opencv.core.Point;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.photo.Photo;
@@ -21,6 +19,7 @@
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.TagMap;
import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.preferences.JosmBaseDirectories;
import org.openstreetmap.josm.data.projection.Projection;
import org.openstreetmap.josm.data.projection.ProjectionRegistry;
import org.openstreetmap.josm.gui.MapView;
@@ -31,13 +30,15 @@
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.DataBufferByte;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
import java.util.stream.Collectors;
+import static org.openstreetmap.josm.tools.I18n.tr;
public class CommonUtils {
// IMAGE
public static Mat bufferedImage2Mat(BufferedImage bi) {
@@ -56,14 +57,18 @@ public static BufferedImage mat2BufferedImageGray(Mat mat) {
return image;
}
- public static void bufferedImageSaveFile(BufferedImage image, String filePath) throws Exception {
- File oupFile = new File(filePath);
- int index = filePath.lastIndexOf('.');
- String extension = "jpg";
- if (index > 0) {
- extension = filePath.substring(index + 1);
+ public static void bufferedImageSaveFile(BufferedImage image, String filePath) {
+ try {
+ File oupFile = new File(filePath);
+ int index = filePath.lastIndexOf('.');
+ String extension = "jpg";
+ if (index > 0) {
+ extension = filePath.substring(index + 1);
+ }
+ ImageIO.write(image, extension, oupFile);
+ } catch (Exception e) {
+ Logging.error("Exception " + e + " save image");
}
- ImageIO.write(image, extension, oupFile);
}
public static BufferedImage convertColorspace(BufferedImage image, int newType) {
@@ -221,19 +226,28 @@ public static Geometry reduceGeometry(Geometry g, int scale) {
}
// GEOMETRY UTILS
- public static Geometry coordinates2Geometry(List coordinates, boolean close) throws Exception {
+ public static Polygon coordinates2Polygon(List coordinates) throws Exception {
+ if (coordinates == null || coordinates.size() < 3) {
+ throw new Exception("The coordinate list must have at least 3 points to form a valid polygon.");
+ }
GeometryFactory gf = new GeometryFactory();
- if (close) {
- if (!coordinates.get(coordinates.size() - 1).equals(coordinates.get(0)))
- coordinates.add(coordinates.get(0));
- var tmpPolygon = gf.createPolygon(coordinates.toArray(new Coordinate[]{}));
- if (!tmpPolygon.isValid()) {
- return GeometryFixer.fix(tmpPolygon);
+ if (!coordinates.get(coordinates.size() - 1).equals(coordinates.get(0))) {
+ coordinates.add(coordinates.get(0));
+ }
+
+ Polygon tmpPolygon = gf.createPolygon(coordinates.toArray(new Coordinate[]{}));
+ if (!tmpPolygon.isValid()) {
+ Geometry fixedGeometry = GeometryFixer.fix(tmpPolygon);
+ if (fixedGeometry instanceof Polygon) {
+ return gf.createPolygon(((Polygon) fixedGeometry).getExteriorRing().getCoordinates());
+ } else if (fixedGeometry instanceof MultiPolygon) {
+ return gf.createPolygon(((Polygon) fixedGeometry.getGeometryN(0)).getExteriorRing().getCoordinates());
+ } else {
+ throw new Exception("La corrección de la geometría no produjo un polígono válido.");
}
- return tmpPolygon;
}
- return gf.createLineString(coordinates.toArray(new Coordinate[]{}));
+ return tmpPolygon;
}
public static List nodes2Coordinates(List nodes) {
@@ -255,9 +269,22 @@ public static List coordinates2Nodes(List coordinates, Project
public static Collection geometry2WayCommands(DataSet ds, List geometries, String tagMapKey, String tagMapValue) throws Exception {
Collection cmds = new LinkedList<>();
Projection projection = ProjectionRegistry.getProjection();
+ List geometriesSplit = new ArrayList<>();
for (Geometry geometry : geometries) {
+ if (geometry.getNumGeometries() > 1) {
+ for (int j = 0; j < geometry.getNumGeometries(); j++) {
+ geometriesSplit.add(geometry.union());
+ System.out.println("geom interno");
+ }
+ } else {
+ geometriesSplit.add(geometry.union());
+ System.out.println("geom externo");
+ }
+ }
+
+ for (Geometry geometry : geometriesSplit) {
Way w = new Way();
- List nodes = coordinates2Nodes(List.of(geometry.getCoordinates()), projection);
+ List nodes = coordinates2Nodes(List.of(geometry.union().getCoordinates()), projection);
int index = 0;
for (Node n : nodes) {
if (index == (nodes.size() - 1)) {
@@ -314,7 +341,7 @@ public static Geometry chaikinAlgotihm(Geometry geometry, double maxAngle) {
}
Logging.info("-- chaikinAlgotihm -- Ang: " + maxAngle + " Orig: " + coordinates.length + " new : " + tmpCoords.size());
- return simplifyPolygonHull(coordinates2Geometry(tmpCoords, true), 0.999);
+ return simplifyPolygonHull(coordinates2Polygon(tmpCoords), 0.999);
} catch (Exception e) {
Logging.error(e);
return geometry;
@@ -339,13 +366,14 @@ public static Mat processImage(Mat mat_image, Mat mat_mask, boolean ctrl_, boole
mat_flood.create(new Size(mat_image.cols() + 2, mat_image.rows() + 2), CvType.CV_8UC1);
mat_flood.setTo(new Scalar(0));
floodFillFacade.setTolerance(ToolSettings.getTolerance());
- //
+ // improve colors
Mat mat_blur = blur(mat_image, 7);
floodFillFacade.fill(mat_blur, mat_flood, x, y);
+
Mat mat_open = open(mat_flood, 5);
- Mat mat_close = close(mat_open, 9);
- Mat mat_erode = erode(mat_close, 3);
- Mat mat_dilate = dilate(mat_erode, 5);
+ Mat mat_close = close(mat_open, 5);
+// Mat mat_erode = erode(mat_close, 3);
+ Mat mat_dilate = dilate(mat_close, 1);
if (mat_mask != null) {
@@ -364,7 +392,7 @@ public static Mat processImage(Mat mat_image, Mat mat_mask, boolean ctrl_, boole
mat_tmp.create(new Size(mat_image.cols() + 2, mat_image.rows() + 2), CvType.CV_8UC1);
mat_tmp.setTo(new Scalar(0));
Core.subtract(mat_mask.clone(), mat_dilate.clone(), mat_tmp);
- Mat mat_tmp_open = open(mat_tmp, 5);
+ Mat mat_tmp_open = open(mat_tmp, 9);
return mat_tmp_open.clone();
}
}
@@ -415,7 +443,7 @@ public static List contourn2Geometry(List contours, MapVie
tmpCoords.add(c);
}
// create multi
- Geometry geometryTmp = coordinates2Geometry(tmpCoords, true);
+ Geometry geometryTmp = coordinates2Polygon(tmpCoords);
geometries.add(geometryTmp.copy());
} catch (Exception ex) {
Logging.error(ex);
@@ -426,8 +454,8 @@ public static List contourn2Geometry(List contours, MapVie
}
public static Geometry simplifySmoothGeometry(Geometry geometry) {
- if (ToolSettings.getSimplifyDouglasP() > 0) {
- geometry = CommonUtils.simplifyDouglasP(geometry.copy(), ToolSettings.getSimplifyDouglasP());
+ if (ToolSettings.getSimplDouglasP() > 0) {
+ geometry = CommonUtils.simplifyDouglasP(geometry.copy(), ToolSettings.getSimplDouglasP());
}
if (ToolSettings.getSimplPolygonHull() > 0) {
geometry = CommonUtils.simplifyPolygonHull(geometry.copy(), ToolSettings.getSimplPolygonHull());
@@ -440,4 +468,91 @@ public static Geometry simplifySmoothGeometry(Geometry geometry) {
}
return geometry.copy();
}
+
+ public static String encodeImageToBase64(BufferedImage image) {
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ImageIO.write(image, "jpg", outputStream);
+ byte[] imageBytes = outputStream.toByteArray();
+ return Base64.getEncoder().encodeToString(imageBytes);
+ } catch (Exception e) {
+ Logging.error(e);
+ return "";
+ }
+
+ }
+
+ public static BufferedImage decodeBase64ToImage(String base64Image) {
+ try {
+ byte[] imageBytes = Base64.getDecoder().decode(base64Image);
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
+ return ImageIO.read(inputStream);
+ } catch (Exception e) {
+ Logging.error(e);
+ return null;
+ }
+ }
+
+ public static String magicWandCacheDirPath() {
+ String josmCacheDataDir = JosmBaseDirectories.getInstance().getCacheDirectory(true).toString();
+
+ return josmCacheDataDir + File.separator + "magicwand";
+ }
+
+ public static boolean existCacheDir() {
+ return new File(magicWandCacheDirPath()).exists();
+ }
+
+ public static void createCacheDir() {
+ String magicWandDirPath = magicWandCacheDirPath();
+ File magicWandDir = new File(magicWandDirPath);
+ if (!magicWandDir.exists()) {
+ boolean wasDirectoryCreated = magicWandDir.mkdir();
+
+ if (wasDirectoryCreated) {
+ Logging.info(tr("magicwand " + "Folder 'magicwand' successfully created at: " + magicWandDirPath));
+ } else {
+ Logging.info(tr("magicwand " + "Failed to create the 'magicwand' folder at: " + magicWandDirPath));
+ }
+ } else {
+ Logging.info(tr("magicwand " + "The 'magicwand' folder already exists at: " + magicWandDirPath));
+ }
+
+ }
+
+ public static String getDateTime() {
+ LocalDateTime now = LocalDateTime.now();
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd__HH_mm_ss");
+ return now.format(formatter);
+ }
+
+ public static String getMapLayerName(String layerName) {
+
+ if (layerName.length() >= 50) {
+ String normalized = layerName.trim().substring(0, 50).replaceAll("[^a-zA-Z0-9\\s-]", "").replaceAll("\\s+", " ");
+ return normalized.replaceAll("\\s", "-").toLowerCase();
+ } else if (!layerName.isEmpty()) {
+ String normalized = layerName.trim().replaceAll("[^a-zA-Z0-9\\s-]", "").replaceAll("\\s+", " ");
+ return normalized.replaceAll("\\s", "-").toLowerCase();
+ } else {
+ return "no_layer_name";
+ }
+ }
+
+ public static List extractPolygons(Geometry geometry) {
+ List polygons = new ArrayList<>();
+
+ if (geometry instanceof MultiPolygon) {
+ for (int i = 0; i < geometry.getNumGeometries(); i++) {
+ Geometry subGeometry = geometry.getGeometryN(i);
+ polygons.addAll(extractPolygons(subGeometry));
+ }
+ } else if (geometry instanceof Polygon) {
+ if (geometry.getNumPoints() > 5 && geometry.isValid()) {
+ polygons.add((Polygon) geometry);
+ }
+ }
+
+ return polygons;
+ }
}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/Constants.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/Constants.java
new file mode 100644
index 0000000..3773f3f
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/Constants.java
@@ -0,0 +1,6 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+public class Constants {
+ public static final String ENCODE_URL = "";
+ public static final String DECODE_URL = "";
+}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CustomPolygon.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CustomPolygon.java
index e086fc3..540c8a9 100644
--- a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CustomPolygon.java
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CustomPolygon.java
@@ -24,7 +24,7 @@ public CustomPolygon() {
public void fromWay(Way w) {
this.way = w;
try {
- this.pol = (Polygon) CommonUtils.coordinates2Geometry(CommonUtils.nodes2Coordinates(w.getNodes()), true);
+ this.pol = CommonUtils.coordinates2Polygon(CommonUtils.nodes2Coordinates(w.getNodes()));
} catch (Exception ex) {
Logging.error(ex);
}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/DecondeRequestBody.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/DecondeRequestBody.java
new file mode 100644
index 0000000..abbe5fc
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/DecondeRequestBody.java
@@ -0,0 +1,80 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+import java.util.List;
+
+public class DecondeRequestBody {
+ private List bbox;
+ private String crs;
+ private String image_embeddings;
+ private List image_shape;
+ private int input_label;
+ private List input_point;
+ private double zoom;
+
+ public DecondeRequestBody(List bbox, String image_embeddings, List image_shape, List input_point) {
+ this.bbox = bbox;
+ this.crs="EPSG:3857";
+ this.image_embeddings = image_embeddings;
+ this.image_shape = image_shape;
+ this.input_label = 1;
+ this.input_point = input_point;
+ this.zoom = 15;
+ }
+
+
+ public List getBbox() {
+ return bbox;
+ }
+
+ public void setBbox(List bbox) {
+ this.bbox = bbox;
+ }
+
+ public String getCrs() {
+ return crs;
+ }
+
+ public void setCrs(String crs) {
+ this.crs = crs;
+ }
+
+ public String getImage_embeddings() {
+ return image_embeddings;
+ }
+
+ public void setImage_embeddings(String image_embeddings) {
+ this.image_embeddings = image_embeddings;
+ }
+
+ public List getImage_shape() {
+ return image_shape;
+ }
+
+ public void setImage_shape(List image_shape) {
+ this.image_shape = image_shape;
+ }
+
+ public int getInput_label() {
+ return input_label;
+ }
+
+ public void setInput_label(int input_label) {
+ this.input_label = input_label;
+ }
+
+ public List getInput_point() {
+ return input_point;
+ }
+
+ public void setInput_point(List input_point) {
+ this.input_point = input_point;
+ }
+
+ public double getZoom() {
+ return zoom;
+ }
+
+ public void setZoom(double zoom) {
+ this.zoom = zoom;
+ }
+}
\ No newline at end of file
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/EncondeRequestBody.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/EncondeRequestBody.java
new file mode 100644
index 0000000..8a9c9d4
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/EncondeRequestBody.java
@@ -0,0 +1,19 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+public class EncondeRequestBody {
+ private String encoded_image;
+
+ public EncondeRequestBody(String encodedImage) {
+ encoded_image = encodedImage;
+ }
+
+ public String getEncoded_image() {
+ return encoded_image;
+ }
+
+ public void setEncoded_image(String encoded_image) {
+ this.encoded_image = encoded_image;
+ }
+
+
+}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImagePanel.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImagePanel.java
new file mode 100644
index 0000000..e6b2d2b
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImagePanel.java
@@ -0,0 +1,141 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+import org.openstreetmap.josm.data.ProjectionBounds;
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.ImageryLayer;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Logging;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.openstreetmap.josm.gui.MainApplication.getMap;
+
+
+public class ImagePanel extends JPanel {
+
+ private BufferedImage image;
+ private JButton zoomJButton;
+ private JButton deleteJButton;
+ private int maxHeight;
+ private int maxWidth;
+
+ private SamImage samImage;
+
+ private JLabel imageLabel;
+ private ImagePanelListener listener;
+
+ public ImagePanel(SamImage samImage, int maxWidth, ImagePanelListener listener) {
+ setLayout(null);
+ this.samImage = samImage;
+ this.image = samImage.getLayerImage();
+ this.maxWidth = maxWidth;
+
+ this.maxHeight = getMaxHeight(samImage.getLayerImage(), maxWidth);
+ this.listener = listener;
+ setupButtons();
+ // image
+ Graphics2D g2d = this.image.createGraphics();
+ g2d.dispose();
+ ImageIcon icono = new ImageIcon(getScaledImage(this.image, maxWidth, this.maxHeight));
+ imageLabel = new JLabel(icono);
+ add(imageLabel);
+ imageLabel.setBounds(0, 0, this.maxWidth, this.maxHeight);
+ setPreferredSize(new Dimension(this.maxWidth, this.maxHeight));
+ // setup actions
+
+ }
+
+ private Image getScaledImage(BufferedImage originalImage, int maxWidth, int maxHeight) {
+ int width = originalImage.getWidth();
+
+ if (width <= maxWidth) {
+ return originalImage;
+ }
+
+ return originalImage.getScaledInstance(maxWidth, maxHeight, Image.SCALE_SMOOTH);
+ }
+
+ private int getMaxHeight(BufferedImage originalImage, int maxWidth) {
+ int width = originalImage.getWidth();
+ int height = originalImage.getHeight();
+
+ double radio = (double) width / height;
+
+ if (width <= maxWidth) {
+ return height;
+ }
+ return (int) (maxWidth / radio);
+
+ }
+
+ private void setupButtons() {
+ // Creamos los botones
+ ImageIcon zoomIco = new ImageProvider("dialogs", "zoom-best-fit").get();
+ ImageIcon deleteIco = new ImageProvider("dialogs", "delete").get();
+
+ zoomJButton = new JButton(zoomIco);
+
+ zoomJButton.setBounds(20, this.maxHeight - 32, zoomIco.getIconWidth(), zoomIco.getIconHeight());
+ zoomJButton.setContentAreaFilled(false);
+ zoomJButton.addActionListener(e -> zoomAction());
+ add(zoomJButton);
+
+ deleteJButton = new JButton(deleteIco);
+ deleteJButton.setBounds(70, this.maxHeight - 32, deleteIco.getIconWidth(), deleteIco.getIconHeight());
+ deleteJButton.setContentAreaFilled(false);
+ deleteJButton.addActionListener(e -> deleteAction());
+
+ add(deleteJButton);
+
+ }
+
+ private void zoomAction() {
+ MapView mapView = getMap().mapView;
+
+ try {
+ // add layer
+ List activeLayers = mapView.getLayerManager()
+ .getVisibleLayersInZOrder()
+ .stream()
+ .filter(layer -> (layer instanceof ImageryLayer && layer.isVisible() && layer.getName().equals(samImage.getLayerName())))
+ .collect(Collectors.toList());
+
+ if (activeLayers.isEmpty()) {
+ List imagerySources = ImageryLayerInfo
+ .instance
+ .getLayers()
+ .stream()
+ .filter(layer -> (layer.getName().equals(samImage.getLayerName())))
+ .collect(Collectors.toList());
+
+ if (!imagerySources.isEmpty()) {
+ ImageryInfo imageryInfo = imagerySources.get(0);
+ mapView.getLayerManager().addLayer(ImageryLayer.create(imageryInfo));
+ }
+ }
+ } catch (Exception e) {
+ Logging.error(e);
+ }
+
+ ProjectionBounds projectionBounds = samImage.getProjectionBounds();
+ mapView.zoomTo(projectionBounds);
+ mapView.zoomIn();
+ mapView.repaint();
+ }
+
+ private void deleteAction() {
+ try {
+ samImage.removeCacheImge();
+ listener.removeSamImage(samImage);
+ } catch (Exception e) {
+ Logging.error(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImagePanelListener.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImagePanelListener.java
new file mode 100644
index 0000000..a91f9d0
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImagePanelListener.java
@@ -0,0 +1,6 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+public interface ImagePanelListener {
+ void removeSamImage(SamImage samImage);
+
+}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImageSamPanelListener.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImageSamPanelListener.java
new file mode 100644
index 0000000..9770be4
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImageSamPanelListener.java
@@ -0,0 +1,21 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+
+import org.openstreetmap.josm.data.osm.Way;
+
+import java.util.ArrayList;
+
+public interface ImageSamPanelListener {
+ void onAddSamImage(SamImage samImage);
+
+ void onRemoveAll();
+
+ ArrayList getSamImageList();
+
+ SamImage getSamImageIncludepoint(double x, double y);
+
+ void addLayer();
+
+ void addBboxLayer(Way way);
+
+}
\ No newline at end of file
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/LayerImageValues.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/LayerImageValues.java
new file mode 100644
index 0000000..0134c70
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/LayerImageValues.java
@@ -0,0 +1,28 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+import java.awt.image.BufferedImage;
+
+public class LayerImageValues {
+ BufferedImage bufferedImage;
+ String layerName;
+
+ public BufferedImage getBufferedImage() {
+ return bufferedImage;
+ }
+
+ public void setBufferedImage(BufferedImage bufferedImage) {
+ this.bufferedImage = bufferedImage;
+ }
+
+ public String getLayerName() {
+ return layerName;
+ }
+
+ public void setLayerName(String layerName) {
+ this.layerName = layerName;
+ }
+
+ public LayerImageValues() {
+ }
+
+}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/SamImage.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/SamImage.java
new file mode 100644
index 0000000..d88a8f0
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/SamImage.java
@@ -0,0 +1,381 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import okhttp3.*;
+import org.locationtech.jts.geom.*;
+import org.locationtech.jts.io.geojson.GeoJsonReader;
+import org.openstreetmap.josm.data.ProjectionBounds;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.tools.Logging;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+@JsonRootName(value = "SamImage")
+public class SamImage {
+
+ @JsonIgnore
+ private final ObjectMapper objectMapper = new ObjectMapper();
+ // fields
+
+ @JsonIgnore
+ private BufferedImage layerImage;
+ @JsonIgnore
+ private ProjectionBounds projectionBounds;
+ // encode
+ @JsonProperty("base64Image")
+ private String base64Image;
+
+ @JsonIgnore
+ private EastNorth center;
+ // enconde fields
+
+ @JsonProperty("isEncodeImage")
+ private boolean isEncodeImage = false;
+ @JsonProperty("imageShape")
+ private List imageShape;
+ @JsonProperty("crs")
+ private String crs = "EPSG:3857";
+ @JsonProperty("bbox")
+ private List bbox;
+ @JsonProperty("imageEmbedding")
+ private String imageEmbedding;
+ @JsonIgnore
+ private Polygon bboxPolygon;
+ @JsonIgnore
+ private Way bboxWay;
+ @JsonProperty("nameObject")
+ private String nameObject;
+ @JsonProperty("layerName")
+ private String layerName;
+
+
+ public SamImage(ProjectionBounds projectionBounds, BufferedImage layerImage, String layerName) {
+ // image
+ this.setLayerImage(layerImage);
+ this.setBase64Image(CommonUtils.encodeImageToBase64(layerImage));
+ // create imageShape
+ this.setImageShape(new ArrayList<>(Arrays.asList(
+ layerImage.getHeight(), layerImage.getWidth()
+ )));
+
+ // projectionBounds
+ this.setCenter(projectionBounds.getCenter());
+ this.setProjectionBounds(projectionBounds);
+ // create bbox
+ this.setBbox(new ArrayList<>(Arrays.asList(
+ projectionBounds.getMin().getX(),
+ projectionBounds.getMin().getY(),
+ projectionBounds.getMax().getX(),
+ projectionBounds.getMax().getY())));
+ this.setBboxPolygon(createPolygonFromDoubles(this.getBbox()));
+ this.setBboxWay(createBboxWay());
+ this.setNameObject(CommonUtils.getDateTime() + "__" + CommonUtils.getMapLayerName(layerName) + ".json");
+ this.setLayerName(layerName);
+ saveCache(this.nameObject);
+ }
+
+ public SamImage(
+ @JsonProperty("nameObject") String nameObject,
+ @JsonProperty("base64Image") String base64Image,
+ @JsonProperty("isEncodeImage") boolean isEncodeImage,
+ @JsonProperty("imageShape") List imageShape,
+ @JsonProperty("crs") String crs,
+ @JsonProperty("bbox") List bbox,
+ @JsonProperty("imageEmbedding") String imageEmbedding,
+ @JsonProperty("layerName") String layerName
+
+ ) {
+ this.setNameObject(nameObject);
+ this.setBase64Image(base64Image);
+ this.setLayerImage(CommonUtils.decodeBase64ToImage(base64Image));
+ this.setEncodeImage(isEncodeImage);
+ this.setImageShape(imageShape);
+ this.setCrs(crs);
+ this.setBbox(bbox);
+ ProjectionBounds projectionBoundsTmp = new ProjectionBounds(bbox.get(0), bbox.get(1), bbox.get(2), bbox.get(3));
+ this.setProjectionBounds(projectionBoundsTmp);
+ this.setBboxPolygon(createPolygonFromDoubles(this.getBbox()));
+ this.setBboxWay(createBboxWay());
+ this.setImageEmbedding(imageEmbedding);
+ this.setLayerName(layerName);
+
+ }
+
+ private void saveCache(String fileName) {
+ if (!CommonUtils.existCacheDir()) {
+ CommonUtils.createCacheDir();
+ }
+ String magicWandDirPath = CommonUtils.magicWandCacheDirPath();
+ String filePath = magicWandDirPath + File.separator + fileName;
+ try {
+ File file = new File(filePath);
+ objectMapper.writeValue(file, this);
+
+ Logging.info("Object save in : " + filePath);
+ } catch (Exception e) {
+ Logging.error(e);
+ e.printStackTrace();
+ }
+ }
+ public void updateCacheImage(){
+ saveCache(nameObject);
+ }
+ public void removeCacheImge(){
+ try {
+ String magicWandDirPath = CommonUtils.magicWandCacheDirPath();
+ String filePath = magicWandDirPath + File.separator + nameObject;
+ File file = new File(filePath);
+ file.delete();
+ }catch (Exception e){
+ Logging.error(e);
+ }
+
+ }
+ public BufferedImage getLayerImage() {
+ return layerImage;
+ }
+
+ public EastNorth getCenter() {
+ return center;
+ }
+
+ public ProjectionBounds getProjectionBounds() {
+ return projectionBounds;
+ }
+
+ public boolean isEncodeImage() {
+ return isEncodeImage;
+ }
+
+ public void setEncodeImage() {
+ try {
+ // request body
+ EncondeRequestBody encodeRequestBody = new EncondeRequestBody(getBase64Image());
+ String requestBodyJson = objectMapper.writeValueAsString(encodeRequestBody);
+ MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+ RequestBody requestBody = RequestBody.create(JSON, requestBodyJson);
+
+ // client
+ OkHttpClient client = new OkHttpClient.Builder()
+ .connectTimeout(5, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ .build();
+
+ Request request = new Request.Builder()
+ .url(Constants.ENCODE_URL)
+ .post(requestBody)
+ .build();
+ // response
+ Response response = client.newCall(request).execute();
+
+ String responseData = response.body().string();
+ Map dataMap = objectMapper.readValue(responseData, Map.class);
+ // get fields
+ setImageEmbedding((String) dataMap.getOrDefault("image_embedding", ""));
+ setEncodeImage(true);
+ } catch (Exception e) {
+ Logging.error(e);
+ setEncodeImage(false);
+ }
+
+ }
+
+ public Polygon createPolygonFromDoubles(List coordinates) {
+ Coordinate[] vertices = {
+ new Coordinate(coordinates.get(0), coordinates.get(1)),
+ new Coordinate(coordinates.get(0), coordinates.get(3)),
+ new Coordinate(coordinates.get(2), coordinates.get(3)),
+ new Coordinate(coordinates.get(2), coordinates.get(1)),
+ new Coordinate(coordinates.get(0), coordinates.get(1))
+ };
+
+ GeometryFactory geometryFactory = new GeometryFactory();
+ return geometryFactory.createPolygon(vertices);
+ }
+
+ public List fetchDecodePoint(double x, double y) {
+ List geometryList = new ArrayList<>();
+ GeoJsonReader reader = new GeoJsonReader();
+
+ try {
+
+ // request body
+ Coordinate clickCoordinate = mouseClick2Coordinate(x, y);
+
+ DecondeRequestBody decodeRequestBody = new DecondeRequestBody(getBbox(), getImageEmbedding(), getImageShape(), Arrays.asList((int) clickCoordinate.x, (int) clickCoordinate.y));
+ String requestBodyJson = objectMapper.writeValueAsString(decodeRequestBody);
+ MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+ RequestBody requestBody = RequestBody.create(JSON, requestBodyJson);
+ // client
+
+ OkHttpClient client = new OkHttpClient.Builder()
+ .connectTimeout(3, TimeUnit.SECONDS)
+ .readTimeout(3, TimeUnit.SECONDS)
+ .build();
+
+
+ Request request = new Request.Builder()
+ .url(Constants.DECODE_URL)
+ .post(requestBody)
+ .build();
+
+ Response response = client.newCall(request).execute();
+
+ if (response.isSuccessful()) {
+ String responseData = response.body().string();
+ Map dataMap = objectMapper.readValue(responseData, Map.class);
+ if (dataMap.getOrDefault("status", "").equals("success")) {
+ List geojsonsList = (List) dataMap.get("geojsons");
+ List geojsonConfidence = (List) dataMap.get("confidence_scores");
+ Double maxVal = Collections.max(geojsonConfidence);
+ Integer maxIdx = geojsonConfidence.indexOf(maxVal);
+ Geometry geometryJson = reader.read(geojsonsList.get(maxIdx));
+ // validate geometry
+ geometryList = CommonUtils.extractPolygons(geometryJson);
+ }
+ }
+
+ } catch (Exception e) {
+ Logging.error(e);
+ }
+ return CommonUtils.filterByArea(geometryList, 0.1);
+ }
+
+ public Coordinate mouseClick2Coordinate(double x, double y) {
+ double minX = getBbox().get(0);
+ double minY = getBbox().get(1);
+ double maxX = getBbox().get(2);
+ double maxY = getBbox().get(3);
+
+ // image size
+ int bboxHeight = getImageShape().get(0);
+ int bboxWidth = getImageShape().get(1);
+
+ // factor (nx, ny)
+ double nx = (x - minX) / (maxX - minX);
+ double ny = (y - minY) / (maxY - minY);
+ // Y i invert
+ return new Coordinate(nx * bboxWidth, (1 - ny) * bboxHeight);
+ }
+
+
+ public boolean containsPoint(Point p) {
+ try {
+ return getBboxPolygon().contains(p);
+ } catch (Exception e) {
+ Logging.error(e);
+ }
+ return false;
+ }
+
+ private Way createBboxWay() {
+ Node node1 = new Node(new EastNorth(getBbox().get(0), getBbox().get(1)));
+ Node node2 = new Node(new EastNorth(getBbox().get(0), getBbox().get(3)));
+ Node node3 = new Node(new EastNorth(getBbox().get(2), getBbox().get(3)));
+ Node node4 = new Node(new EastNorth(getBbox().get(2), getBbox().get(1)));
+
+ Way way = new Way();
+ way.addNode(node1);
+ way.addNode(node2);
+ way.addNode(node3);
+ way.addNode(node4);
+ way.addNode(node1);
+ return way;
+ }
+
+ public Way getBboxWay() {
+ return bboxWay;
+ }
+
+ public void setLayerImage(BufferedImage layerImage) {
+ this.layerImage = layerImage;
+ }
+
+ public void setProjectionBounds(ProjectionBounds projectionBounds) {
+ this.projectionBounds = projectionBounds;
+ }
+
+ public String getBase64Image() {
+ return base64Image;
+ }
+
+ public void setBase64Image(String base64Image) {
+ this.base64Image = base64Image;
+ }
+
+ public void setCenter(EastNorth center) {
+ this.center = center;
+ }
+
+ public void setEncodeImage(boolean encodeImage) {
+ isEncodeImage = encodeImage;
+ }
+
+ public List getImageShape() {
+ return imageShape;
+ }
+
+ public void setImageShape(List imageShape) {
+ this.imageShape = imageShape;
+ }
+
+ public String getCrs() {
+ return crs;
+ }
+
+ public void setCrs(String crs) {
+ this.crs = crs;
+ }
+
+ public List getBbox() {
+ return bbox;
+ }
+
+ public void setBbox(List bbox) {
+ this.bbox = bbox;
+ }
+
+ public String getImageEmbedding() {
+ return imageEmbedding;
+ }
+
+ public void setImageEmbedding(String imageEmbedding) {
+ this.imageEmbedding = imageEmbedding;
+ }
+
+ public Polygon getBboxPolygon() {
+ return bboxPolygon;
+ }
+
+ public void setBboxPolygon(Polygon bboxPolygon) {
+ this.bboxPolygon = bboxPolygon;
+ }
+
+ public void setBboxWay(Way bboxWay) {
+ this.bboxWay = bboxWay;
+ }
+
+ public String getNameObject() {
+ return nameObject;
+ }
+
+ public void setNameObject(String nameObject) {
+ this.nameObject = nameObject;
+ }
+
+ public String getLayerName() {
+ return layerName;
+ }
+
+ public void setLayerName(String layerName) {
+ this.layerName = layerName;
+ }
+}
diff --git a/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/SamImageGrid.java b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/SamImageGrid.java
new file mode 100644
index 0000000..87058b0
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/SamImageGrid.java
@@ -0,0 +1,80 @@
+package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.locationtech.jts.geom.Point;
+import org.openstreetmap.josm.tools.Logging;
+
+import javax.swing.*;
+import java.awt.*;
+import java.io.File;
+import java.util.ArrayList;
+public class SamImageGrid extends JPanel implements ImagePanelListener {
+ private ArrayList samImageList;
+ private int maxWidth;
+ ObjectMapper objectMapper = new ObjectMapper();
+
+ public SamImageGrid(int maxWidth) {
+ this.maxWidth = maxWidth;
+ samImageList = new ArrayList<>();
+ setLayout(new GridLayout(0, 2, 1, 1));
+
+ //
+ File cacheDir = new File(CommonUtils.magicWandCacheDirPath());
+ File[] cacheFiles = cacheDir.listFiles((dir, fileName) -> fileName.endsWith(".json"));
+
+ for (File jsonFile : cacheFiles) {
+ try {
+ SamImage samImage = objectMapper.readValue(jsonFile, SamImage.class);
+ addSamImage(samImage);
+ } catch (Exception e) {
+ Logging.error(e);
+ }
+ }
+ }
+
+ public void addSamImage(SamImage samImage) {
+ if (samImage.isEncodeImage()) {
+ samImageList.add(samImage);
+ }
+ updateJpanel();
+ }
+
+ public void removeAllSamImage() {
+ samImageList.clear();
+ updateJpanel();
+ }
+
+ public ArrayList getSamImageList() {
+ return samImageList;
+ }
+
+ public SamImage getSamImageIncludepoint(Point p) {
+ for (SamImage s : samImageList) {
+ if (s.containsPoint(p)) {
+ return s;
+ }
+ }
+ return null;
+ }
+
+ private void updateJpanel() {
+ removeAll();
+ for (SamImage samImage : samImageList) {
+ add(new ImagePanel(samImage, this.maxWidth,this));
+ }
+ revalidate();
+ repaint();
+ }
+
+
+ @Override
+ public void removeSamImage(SamImage samImage) {
+ try {
+ samImageList.remove(samImage);
+ updateJpanel();
+ } catch (Exception e) {
+ Logging.error(e);
+
+ }
+ }
+}
\ No newline at end of file