├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images ├── cursor │ └── modifier │ │ ├── magic-wand-add.svg │ │ ├── magic-wand-sam.svg │ │ ├── magic-wand-subs.svg │ │ └── magic-wand.svg ├── dialogs │ ├── auto-sam.svg │ ├── magic-wand-encode.svg │ ├── magicwand-info.svg │ └── magicwand.svg └── mapmode │ ├── magic-wand-add.svg │ ├── magic-wand-merge.svg │ ├── magic-wand-sam.svg │ ├── magic-wand-simplify.svg │ ├── magic-wand-subs.svg │ └── magic-wand.svg ├── settings.gradle.kts └── src └── org └── openstreetmap └── josm └── plugins └── devseed └── JosmMagicWand ├── Actions ├── MagicWandAction.java ├── MergeSelectAction.java ├── SamDecodeAction.java └── SimplifySelectAction.java ├── MainJosmMagicWandPlugin.java ├── ToolSettings.java ├── Ui ├── ButtonActions │ ├── AutoAddTagAction.java │ ├── AutoSam.java │ └── SamEncondeAction.java ├── MagicWandDialog.java └── TagsDialog.java └── utils ├── CommonUtils.java ├── Constants.java ├── CustomPolygon.java ├── FloodFillFacade.java ├── ImagePanel.java ├── ImagePanelListener.java ├── ImageSamPanelListener.java ├── LayerImageValues.java ├── NumericField.java ├── SamImage.java ├── SamImageGrid.java └── samDto ├── DecodeRequestBody.java ├── EncodeResponse.java └── EncondeRequestBody.java /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/ 9 | *.iws 10 | *.iml 11 | *.ipr 12 | out/ 13 | !**/src/main/**/out/ 14 | !**/src/test/**/out/ 15 | 16 | ### Eclipse ### 17 | .apt_generated 18 | .classpath 19 | .factorypath 20 | .project 21 | .settings 22 | .springBeans 23 | .sts4-cache 24 | bin/ 25 | !**/src/main/**/bin/ 26 | !**/src/test/**/bin/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /nbbuild/ 31 | /dist/ 32 | /nbdist/ 33 | /.nb-gradle/ 34 | 35 | ### VS Code ### 36 | .vscode/ 37 | 38 | ### Mac OS ### 39 | .DS_Store 40 | .classname 41 | 42 | ### Other ### 43 | osmjar/ 44 | 45 | *.env 46 | ### constants 47 | ./src/**/utils/Constants.java -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Development Seed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DS-annotate plugin for Java OpenStreetMap Editor 2 | 3 | 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. 4 | 5 | ![Peek 2022-11-09 16-53](https://user-images.githubusercontent.com/12978932/200950045-179c72d5-600c-4012-b2a4-3ceb1345ea25.gif) 6 | 7 | ## Installation 8 | 9 | 1. Search the magic wand plugin. 10 | 11 | ![image](https://user-images.githubusercontent.com/12978932/200428835-a652ef65-f895-4acd-a19a-bef3e7a8175a.png) 12 | 13 | 2. Wait to download the plugin, sometimes it takes a few minutes, because the plugin is 100 MB in size. 14 | 15 | ![image](https://user-images.githubusercontent.com/12978932/200429273-ce2e2d4d-8839-46ce-ba47-a620e3984b17.png) 16 | 17 | 3. Confirmation window. 18 | 19 | ![image](https://user-images.githubusercontent.com/12978932/200429366-c8566cb9-d842-4efe-b810-151b68f86fc3.png) 20 | ![image](https://user-images.githubusercontent.com/12978932/200431510-a414f03f-c285-4217-adf0-d9d91d41d47f.png) 21 | 22 | ## Usage 23 | 24 | The JOSM Magic Wand plugin offers three functionalities: 25 | 26 | - Generate Geometries 27 | - Merge Geometries 28 | - Simplify Geometries 29 | 30 | ### Generate geometries. 31 | 32 | To generate geometries, you must have a base map activated and a data layer. 33 | 34 | - You can press the shortcut `Ctrl + 1` or select directly in the mode bar (upper 35 | left) ![image](https://user-images.githubusercontent.com/12978932/191857775-71da462d-66fd-401f-b03a-fbf444c07b04.png), 36 | you will enter Magic Wand mode and you will see a wand on the 37 | cursor ![image](https://user-images.githubusercontent.com/12978932/191858042-942aa381-3c4b-42bf-b9df-b23782d1dce5.png) 38 | . 39 | - Click on the area. 40 | - `ctrl + 2` to generate the geometry. 41 | 42 | - To add or enhance the selection, you can press the `ctrl` button and `click` on new area. 43 | - To subtract the selection, you can press the `switch` button and `click` on area. 44 | 45 | ### Merge geometries 46 | 47 | This functionality allows you to merge several geometries into one, the geometries must intersects. 48 | 49 | ![Peek 2022-09-22 22-44](https://user-images.githubusercontent.com/12978932/191888528-ea2105bc-7994-40e0-95bd-9d6c87c97631.gif) 50 | 51 | - Select one or more geometries. 52 | - Press `ctrl + 3`. 53 | 54 | ### Simplify geometries. 55 | 56 | This functionality allows you to simplify and smooth a geometry. 57 | 58 | - Select one or more geometries. 59 | - Press `ctrl + 4`. 60 | 61 | 62 | ## Requirements 63 | 64 | - Java JDK 11+. 65 | - JOSM 18193 or higher. 66 | 67 | ## Extra options 68 | 69 | ![image](https://user-images.githubusercontent.com/12978932/200949130-5c4bdea3-cccb-4865-987a-5d15013089d7.png) 70 | 71 | ![image](https://github.com/developmentseed/JosmMagicWand/assets/12978932/3261b754-e1f2-495b-9255-d0cc83b6009c) 72 | 1. Select mode. 73 | 2. Open window. 74 | 3. In the window, you will find the following options: 75 | 76 | - **Tolerance**: This option allows you to configure the color tolerance of the Magic Wand tool. 77 | 78 | ``` 79 | Higher values expand the tolerance to more colors. 80 | Lower values make the tool more specific to colors. 81 | ``` 82 | - **Exterior contour**: This algorithm is specifically designed to simplify polygons while maintaining the shape and outer contour (hull) of the original polygon. 83 | 84 | ``` 85 | Higher values result in less simplification. 86 | Lower values result in more simplification. 87 | ``` 88 | - **Vertices**: This algorithm focuses on the general simplification of polygons. Its goal is to reduce the number of vertices in a geometry while preserving its overall shape. 89 | 90 | ``` 91 | Higher values result in more simplification. 92 | Lower values result in less simplification. 93 | ``` 94 | - **Topology**: This algorithm is used to simplify geometries while preserving their topology. Topology refers to the spatial relationship and connectivity between geometric elements. 95 | 96 | ``` 97 | Higher values result in more simplification. 98 | Lower values result in less simplification. 99 | ``` 100 | - **Smooth Angle**: This option allows you to smooth very sharp angles. The value entered represents the minimum angle to be simplified. 101 | - **add tag**: a pop-up window will appear, allowing you to enter the tag that will be added when generating or simplifying the geometry, the format its `key=value`. 102 | 103 | 104 | To disable the algorithms, set the value to 0. 105 | 106 | ## Use cases 107 | ### Cases where it works well 108 | 109 | | Image | Description | 110 | |------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------| 111 | | ![image](https://user-images.githubusercontent.com/12978932/200626354-cfe0ab0b-5490-4abf-9e0d-0e30bf57abf7.png) | The edge of the lake has borders marked with the path. | 112 | | ![image](https://user-images.githubusercontent.com/12978932/200627390-ddd26531-cfe7-47c8-bf16-8e7a64ce3f60.png) | The edge of the lake and the farm have marked borders. | 113 | | ![image](https://user-images.githubusercontent.com/12978932/200627737-04ec310a-2499-4a2d-8b33-c112e6926cdf.png) | Uniform color and sharp edges (contrast). | 114 | | ![image](https://user-images.githubusercontent.com/12978932/200628149-7e536725-369b-42aa-8309-d7cd37a73baa.png) | Uniform color and sharp edges (contrast). | 115 | | ![image](https://user-images.githubusercontent.com/12978932/200628412-756285de-581f-4369-8e81-f94c8f2f6da5.png) | Uniform color and sharp edges (contrast). | 116 | | ![image](https://user-images.githubusercontent.com/12978932/200628944-2c2143ec-a7e0-4b87-a507-41ad069e4d39.png) | Uniform color and sharp edges (contrast). | 117 | 118 | 119 | 120 | ### Cases where it doesn't work well 121 | 122 | | Image | Description | 123 | |------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------| 124 | | ![image](https://user-images.githubusercontent.com/12978932/200629118-48fa92ef-60a3-4d8a-b807-917c9dd95b8c.png) | The two farms are separated by a very thin path of similar color. | 125 | | ![image](https://user-images.githubusercontent.com/12978932/200629404-9b9a48f5-4c9d-483e-9f8d-1a7499f51659.png) | Parts of the farm and the border have similar colors with the rest. | 126 | | ![image](https://user-images.githubusercontent.com/12978932/200644356-09bbca8e-833c-49f8-9427-cb2c4de7a223.png) | The borders of the farm with the road and the other farm have similar colors. | 127 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.net.URL 2 | 3 | plugins { 4 | id("com.github.ben-manes.versions") version "0.39.0" 5 | id("org.openstreetmap.josm") version "0.8.0" 6 | id("java") 7 | id("java-library") 8 | } 9 | 10 | group = "org.openstreetmap.josm.plugins.devseed.JosmMagicWand" 11 | version = "3.0.0" 12 | 13 | java { 14 | toolchain { 15 | languageVersion.set(JavaLanguageVersion.of(17)) 16 | } 17 | } 18 | 19 | tasks.jar { 20 | duplicatesStrategy = DuplicatesStrategy.INCLUDE 21 | } 22 | // Repositories Configuration 23 | repositories { 24 | mavenLocal() 25 | mavenCentral() 26 | } 27 | 28 | // Source Sets Configuration 29 | sourceSets { 30 | main { 31 | java { 32 | srcDir("src") 33 | include("org/openstreetmap/**") 34 | } 35 | resources { 36 | srcDir(project.projectDir).include("images/**") 37 | } 38 | } 39 | } 40 | 41 | configurations { 42 | create("externalLibs") 43 | } 44 | 45 | dependencies { 46 | // Libraries to be packed into the JAR 47 | packIntoJar("org.locationtech.jts:jts-core:1.19.0") 48 | packIntoJar("org.locationtech.jts.io:jts-io-common:1.19.0") 49 | packIntoJar("org.openpnp:opencv:4.7.0-0") 50 | packIntoJar("com.fasterxml.jackson.core:jackson-databind:2.15.2") 51 | packIntoJar("com.squareup.okhttp3:okhttp:4.10.0") 52 | } 53 | 54 | josm { 55 | pluginName = "josm_magic_wand" 56 | debugPort = 1729 57 | josmCompileVersion = "19230" 58 | manifest { 59 | description = "JOSM plugin for select areas by color range." 60 | mainClass = "org.openstreetmap.josm.plugins.devseed.JosmMagicWand.MainJosmMagicWandPlugin" 61 | minJosmVersion = "19067" 62 | author = "yunica" 63 | canLoadAtRuntime = true 64 | iconPath = "images/dialogs/magicwand.svg" 65 | website = URL("https://github.com/developmentseed/JosmMagicWand") 66 | minJavaVersion = 17 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developmentseed/JosmMagicWand/0ecfd62f5cc9c06c1246cfd696a4271cb44ccc3e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /images/cursor/modifier/magic-wand-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 93 | -------------------------------------------------------------------------------- /images/cursor/modifier/magic-wand-sam.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 100 | -------------------------------------------------------------------------------- /images/cursor/modifier/magic-wand-subs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 86 | -------------------------------------------------------------------------------- /images/cursor/modifier/magic-wand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 77 | -------------------------------------------------------------------------------- /images/dialogs/auto-sam.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /images/dialogs/magic-wand-encode.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /images/dialogs/magicwand-info.svg: -------------------------------------------------------------------------------- 1 | 2 | 114 | -------------------------------------------------------------------------------- /images/dialogs/magicwand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /images/mapmode/magic-wand-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 93 | -------------------------------------------------------------------------------- /images/mapmode/magic-wand-merge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 94 | -------------------------------------------------------------------------------- /images/mapmode/magic-wand-sam.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 100 | -------------------------------------------------------------------------------- /images/mapmode/magic-wand-simplify.svg: -------------------------------------------------------------------------------- 1 | 2 | 163 | -------------------------------------------------------------------------------- /images/mapmode/magic-wand-subs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 86 | -------------------------------------------------------------------------------- /images/mapmode/magic-wand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 77 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "JosmMagicWand" 2 | 3 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/MagicWandAction.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions; 2 | 3 | import org.locationtech.jts.geom.Geometry; 4 | import org.opencv.core.Mat; 5 | import org.opencv.core.MatOfPoint; 6 | import org.openstreetmap.josm.actions.mapmode.MapMode; 7 | import org.openstreetmap.josm.command.Command; 8 | import org.openstreetmap.josm.command.SequenceCommand; 9 | import org.openstreetmap.josm.data.Bounds; 10 | import org.openstreetmap.josm.data.UndoRedoHandler; 11 | import org.openstreetmap.josm.data.osm.DataSet; 12 | import org.openstreetmap.josm.data.preferences.NamedColorProperty; 13 | import org.openstreetmap.josm.gui.MainApplication; 14 | import org.openstreetmap.josm.gui.MapFrame; 15 | import org.openstreetmap.josm.gui.MapView; 16 | import org.openstreetmap.josm.gui.Notification; 17 | import org.openstreetmap.josm.gui.layer.Layer; 18 | import org.openstreetmap.josm.gui.layer.MapViewPaintable; 19 | import org.openstreetmap.josm.gui.util.KeyPressReleaseListener; 20 | import org.openstreetmap.josm.gui.util.ModifierExListener; 21 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings; 22 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils; 23 | import org.openstreetmap.josm.spi.preferences.Config; 24 | import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener; 25 | import org.openstreetmap.josm.tools.ImageProvider; 26 | import org.openstreetmap.josm.tools.Logging; 27 | import org.openstreetmap.josm.tools.Shortcut; 28 | 29 | import javax.swing.*; 30 | import java.awt.*; 31 | import java.awt.event.KeyEvent; 32 | import java.awt.event.MouseEvent; 33 | import java.awt.event.MouseWheelEvent; 34 | import java.awt.event.MouseWheelListener; 35 | import java.awt.image.BufferedImage; 36 | import java.util.Arrays; 37 | import java.util.Collection; 38 | import java.util.List; 39 | import java.util.stream.Collectors; 40 | 41 | import static org.openstreetmap.josm.tools.I18n.marktr; 42 | import static org.openstreetmap.josm.tools.I18n.tr; 43 | 44 | public class MagicWandAction extends MapMode implements MapViewPaintable, KeyPressReleaseListener, ModifierExListener, MouseWheelListener { 45 | 46 | private static final Cursor CURSOR_CUSTOM = ImageProvider.getCursor("crosshair", "magic-wand"); 47 | private static final Cursor CURSOR_ADD = ImageProvider.getCursor("crosshair", "magic-wand-add"); 48 | private static final Cursor CURSOR_SUBS = ImageProvider.getCursor("crosshair", "magic-wand-subs"); 49 | // OPEN CV 50 | private static Mat mat_mask; 51 | private static Mat mat_image; 52 | private final PreferenceChangedListener shapeChangeListener = event -> updCursor(); 53 | private Mode mode = Mode.None; 54 | private Mode nextMode = Mode.None; 55 | private Color selectedColor = Color.red; 56 | private Point drawStartPos; 57 | private Point mousePos; 58 | 59 | public MagicWandAction() { 60 | 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)); 61 | 62 | } 63 | 64 | private Cursor getCursor() { 65 | try { 66 | if (ctrl) { 67 | return CURSOR_ADD; 68 | } 69 | if (shift) { 70 | return CURSOR_SUBS; 71 | } 72 | return CURSOR_CUSTOM; 73 | } catch (Exception e) { 74 | Logging.error(e); 75 | } 76 | return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); 77 | } 78 | 79 | private void setCursor(final Cursor c) { 80 | MainApplication.getMap().mapView.setNewCursor(c, this); 81 | } 82 | 83 | @Override 84 | public void enterMode() { 85 | super.enterMode(); 86 | 87 | MapFrame map = MainApplication.getMap(); 88 | selectedColor = new NamedColorProperty(marktr("selected"), selectedColor).get(); 89 | map.mapView.addMouseListener(this); 90 | map.mapView.addMouseMotionListener(this); 91 | map.mapView.addTemporaryLayer(this); 92 | map.mapView.addMouseWheelListener(this); 93 | map.keyDetector.addKeyListener(this); 94 | map.keyDetector.addModifierExListener(this); 95 | Config.getPref().addKeyPreferenceChangeListener("magic_wand_tool.shape", shapeChangeListener); 96 | 97 | updCursor(); 98 | 99 | } 100 | 101 | @Override 102 | public void exitMode() { 103 | super.exitMode(); 104 | MapFrame map = MainApplication.getMap(); 105 | map.mapView.removeMouseListener(this); 106 | map.mapView.removeMouseMotionListener(this); 107 | map.mapView.removeTemporaryLayer(this); 108 | map.mapView.removeMouseWheelListener(this); 109 | map.keyDetector.removeKeyListener(this); 110 | map.keyDetector.removeModifierExListener(this); 111 | Config.getPref().removeKeyPreferenceChangeListener("magic_wand_tool.shape", shapeChangeListener); 112 | cleanMasks(); 113 | if (mode != Mode.None) map.mapView.repaint(); 114 | mode = Mode.None; 115 | } 116 | 117 | public final void cancelDrawing() { 118 | mode = Mode.None; 119 | MapFrame map = MainApplication.getMap(); 120 | if (map == null || map.mapView == null) return; 121 | map.statusLine.setHeading(-1); 122 | map.statusLine.setAngle(-1); 123 | map.mapView.repaint(); 124 | updateStatusLine(); 125 | } 126 | 127 | @Override 128 | public void modifiersExChanged(int modifiers) { 129 | boolean oldCtrl = ctrl; 130 | boolean oldShift = shift; 131 | updateKeyModifiersEx(modifiers); 132 | if (ctrl != oldCtrl || shift != oldShift) { 133 | processMouseEvent(null); 134 | updCursor(); 135 | if (mode != Mode.None) MainApplication.getMap().mapView.repaint(); 136 | } 137 | } 138 | 139 | @Override 140 | public void doKeyPressed(KeyEvent e) { 141 | if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 142 | if (mode != Mode.None) e.consume(); 143 | cancelDrawing(); 144 | } 145 | if ((e.getKeyCode() == KeyEvent.VK_2) && ctrl) { 146 | try { 147 | drawContours(); 148 | new Notification(tr("Mapping completed successfully.")).setIcon(JOptionPane.INFORMATION_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 149 | } catch (Exception ex) { 150 | Logging.error(ex); 151 | cleanMasks(); 152 | new Notification(tr("Error create ways.")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 153 | } 154 | } 155 | } 156 | 157 | @Override 158 | public void doKeyReleased(KeyEvent e) { 159 | } 160 | 161 | private void processMouseEvent(MouseEvent e) { 162 | if (e != null) { 163 | mousePos = e.getPoint(); 164 | updateKeyModifiers(e); 165 | 166 | } 167 | if (mode == Mode.None) { 168 | nextMode = Mode.None; 169 | return; 170 | } 171 | if (mode != Mode.Drawing) { 172 | new Notification(tr("Invalid drawing mode.")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 173 | } else { 174 | nextMode = Mode.Drawing; 175 | } 176 | } 177 | 178 | @Override 179 | public void mouseWheelMoved(MouseWheelEvent e) { 180 | cleanMasks(); 181 | } 182 | 183 | @Override 184 | public void paint(Graphics2D g, MapView mv, Bounds bbox) { 185 | if (mat_mask != null && mat_image != null) { 186 | try { 187 | Mat new_mask = CommonUtils.maskInsideImage(mat_image, mat_mask, 0.45); 188 | BufferedImage bi_mask = CommonUtils.toBufferedImage(new_mask); 189 | g.drawImage(bi_mask, 0, 0, null); 190 | } catch (Exception e) { 191 | Logging.error(e); 192 | } 193 | } 194 | if (mode == Mode.None) { 195 | return; 196 | } 197 | 198 | g.setColor(selectedColor); 199 | g.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 200 | g.setStroke(new BasicStroke(1)); 201 | } 202 | 203 | private void drawingStart(MouseEvent e) { 204 | mousePos = e.getPoint(); 205 | drawStartPos = mousePos; 206 | mode = Mode.Drawing; 207 | updateStatusLine(); 208 | } 209 | 210 | @Override 211 | public void mousePressed(MouseEvent e) { 212 | Logging.info("-------- mousePressed -----------"); 213 | if (e.getButton() != MouseEvent.BUTTON1) return; 214 | if (!MainApplication.getMap().mapView.isActiveLayerDrawable()) return; 215 | requestFocusInMapView(); 216 | if (mode == Mode.None) drawingStart(e); 217 | } 218 | 219 | @Override 220 | public void mouseDragged(MouseEvent e) { 221 | Logging.info("-------- mouseDragged -----------"); 222 | if (e.getButton() == MouseEvent.BUTTON1) return; 223 | 224 | processMouseEvent(e); 225 | updCursor(); 226 | cleanMasks(); 227 | MainApplication.getMap().mapView.repaint(); 228 | } 229 | 230 | @Override 231 | public void mouseReleased(MouseEvent e) { 232 | Logging.info("-------- mouseReleased -----------"); 233 | if (e.getButton() != MouseEvent.BUTTON1) return; 234 | if (!MainApplication.getMap().mapView.isActiveLayerDrawable()) return; 235 | try { 236 | drawingFinish(e); 237 | } catch (Exception ex) { 238 | Logging.error(ex); 239 | } 240 | } 241 | 242 | private void drawingFinish(MouseEvent e) throws Exception { 243 | 244 | if (mat_image == null) { 245 | mat_image = CommonUtils.bufferedImage2Mat(getLayeredImage()); 246 | } 247 | 248 | Logging.info("-------- drawingFinish -----------"); 249 | mat_mask = CommonUtils.processImage(mat_image, mat_mask, ctrl, shift, e.getX(), e.getY()); 250 | MainApplication.getMap().repaint(); 251 | } 252 | 253 | private void updCursor() { 254 | if (!MainApplication.isDisplayingMapView()) return; 255 | setCursor(getCursor()); 256 | } 257 | 258 | @Override 259 | public boolean layerIsSupported(Layer l) { 260 | return isEditableDataLayer(l); 261 | } 262 | 263 | private BufferedImage getLayeredImage() { 264 | MapView mapView = MainApplication.getMap().mapView; 265 | 266 | BufferedImage bufImage = new BufferedImage(mapView.getWidth(), mapView.getHeight(), BufferedImage.TYPE_3BYTE_BGR); 267 | Graphics2D imgGraphics = bufImage.createGraphics(); 268 | imgGraphics.setClip(0, 0, mapView.getWidth(), mapView.getHeight()); 269 | 270 | for (Layer layer : mapView.getLayerManager().getVisibleLayersInZOrder()) { 271 | if (layer.isVisible() && layer.isBackgroundLayer()) { 272 | Composite translucent = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) layer.getOpacity()); 273 | imgGraphics.setComposite(translucent); 274 | mapView.paintLayer(layer, imgGraphics); 275 | } 276 | } 277 | 278 | return bufImage; 279 | } 280 | 281 | private void drawContours() throws Exception { 282 | if (mat_mask == null) { 283 | new Notification(tr("No have mask ")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 284 | return; 285 | } 286 | if (mat_mask.empty()) { 287 | new Notification(tr("Mask empty, select again")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 288 | return; 289 | } 290 | MapView mapview = MainApplication.getMap().mapView; 291 | List contourns = CommonUtils.obtainContour(mat_mask); 292 | List geometries = CommonUtils.contourn2Geometry(contourns, mapview); 293 | if (geometries.isEmpty()) return; 294 | DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 295 | // simplify 296 | List geometriesSimplify = geometries.stream().map(CommonUtils::simplifySmoothGeometry).collect(Collectors.toList()); 297 | if (geometriesSimplify.isEmpty()) return; 298 | String tagKey = ""; 299 | String tagValue = ""; 300 | if (ToolSettings.getAutoTags() != null && !ToolSettings.getAutoTags().isEmpty()) { 301 | List strings = Arrays.asList(ToolSettings.getAutoTags().split("=")); 302 | if (strings.size() > 1) { 303 | tagKey = strings.get(0); 304 | tagValue = strings.get(1); 305 | } 306 | } 307 | 308 | Collection cmds = CommonUtils.geometry2WayCommands(ds, geometriesSimplify, tagKey, tagValue); 309 | UndoRedoHandler.getInstance().add(new SequenceCommand(tr("draw merge way"), cmds)); 310 | cleanMasks(); 311 | mapview.repaint(); 312 | } 313 | 314 | private void cleanMasks() { 315 | mat_mask = null; 316 | mat_image = null; 317 | } 318 | 319 | private enum Mode { 320 | None, Drawing 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/MergeSelectAction.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions; 2 | 3 | import org.locationtech.jts.geom.Geometry; 4 | import org.openstreetmap.josm.actions.JosmAction; 5 | import org.openstreetmap.josm.command.Command; 6 | import org.openstreetmap.josm.command.SequenceCommand; 7 | import org.openstreetmap.josm.data.UndoRedoHandler; 8 | import org.openstreetmap.josm.data.osm.DataSelectionListener; 9 | import org.openstreetmap.josm.data.osm.DataSet; 10 | import org.openstreetmap.josm.data.osm.OsmPrimitive; 11 | import org.openstreetmap.josm.data.osm.Way; 12 | import org.openstreetmap.josm.gui.MainApplication; 13 | import org.openstreetmap.josm.gui.MapFrame; 14 | import org.openstreetmap.josm.gui.Notification; 15 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings; 16 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils; 17 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CustomPolygon; 18 | import org.openstreetmap.josm.tools.Logging; 19 | import org.openstreetmap.josm.tools.Shortcut; 20 | 21 | import javax.swing.*; 22 | import java.awt.event.ActionEvent; 23 | import java.awt.event.KeyEvent; 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | import java.util.Collection; 27 | import java.util.List; 28 | 29 | import static org.openstreetmap.josm.tools.I18n.tr; 30 | 31 | public class MergeSelectAction extends JosmAction implements DataSelectionListener { 32 | 33 | 34 | public MergeSelectAction(String text) { 35 | super(tr(text), "mapmode/magic-wand-merge", tr("merge multiple geometries into one"), Shortcut.registerShortcut("data:magicwandmerge", tr("Data: {0}", tr("merge multiple geometries into one")), KeyEvent.VK_3, Shortcut.CTRL), true); 36 | } 37 | 38 | @Override 39 | public void actionPerformed(ActionEvent actionEvent) { 40 | if (!isEnabled()) return; 41 | Collection selWays = getSelectedWays(); 42 | if (selWays.isEmpty()) { 43 | new Notification(tr("No ways selected.")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 44 | return; 45 | } 46 | 47 | List geometryMerge; 48 | try { 49 | geometryMerge = mergeWays(selWays); 50 | } catch (Exception e) { 51 | new Notification(tr("Incorrect geometry.")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 52 | return; 53 | } 54 | if (geometryMerge.isEmpty()) { 55 | new Notification(tr("Does not have merged ways.")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 56 | return; 57 | } 58 | boolean hasDraw = drawWays(geometryMerge); 59 | if (hasDraw) { 60 | removeSelected(actionEvent); 61 | } 62 | 63 | } 64 | 65 | @Override 66 | public void selectionChanged(SelectionChangeEvent event) { 67 | updateEnabledStateOnCurrentSelection(); 68 | } 69 | 70 | @Override 71 | protected void updateEnabledState(Collection selection) { 72 | updateEnabledStateOnModifiableSelection(selection); 73 | } 74 | 75 | private Collection getSelectedWays() { 76 | return getLayerManager().getEditDataSet().getSelectedWays(); 77 | } 78 | 79 | private List mergeWays(Collection ways) throws Exception { 80 | List polygons = new ArrayList<>(); 81 | for (Way w : ways) { 82 | CustomPolygon cp = new CustomPolygon(); 83 | cp.fromWay(w); 84 | polygons.add(cp); 85 | } 86 | return CommonUtils.mergeGeometry(polygons); 87 | } 88 | 89 | private boolean drawWays(List geometries) { 90 | if (geometries.isEmpty()) return false; 91 | DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 92 | 93 | try { 94 | String tagKey = ""; 95 | String tagValue = ""; 96 | if (ToolSettings.getAutoTags() != null && !ToolSettings.getAutoTags().isEmpty()) { 97 | List strings = Arrays.asList(ToolSettings.getAutoTags().split("=")); 98 | if (strings.size() > 1) { 99 | tagKey = strings.get(0); 100 | tagValue = strings.get(1); 101 | } 102 | } 103 | Collection cmds = CommonUtils.geometry2WayCommands(ds, geometries, tagKey, tagValue); 104 | UndoRedoHandler.getInstance().add(new SequenceCommand(tr("draw merge way"), cmds)); 105 | return !cmds.isEmpty(); 106 | } catch (Exception e) { 107 | Logging.error(e); 108 | return false; 109 | } 110 | } 111 | 112 | private void removeSelected(ActionEvent e) { 113 | MapFrame map = MainApplication.getMap(); 114 | if (!isEnabled() || !map.mapView.isActiveLayerVisible()) { 115 | return; 116 | } 117 | map.mapModeDelete.doActionPerformed(e); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/SamDecodeAction.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions; 2 | 3 | import org.openstreetmap.josm.actions.mapmode.MapMode; 4 | import org.openstreetmap.josm.data.coor.EastNorth; 5 | import org.openstreetmap.josm.data.coor.LatLon; 6 | import org.openstreetmap.josm.data.osm.DataSet; 7 | import org.openstreetmap.josm.data.projection.Projection; 8 | import org.openstreetmap.josm.data.projection.Projections; 9 | import org.openstreetmap.josm.gui.MainApplication; 10 | import org.openstreetmap.josm.gui.MapFrame; 11 | import org.openstreetmap.josm.gui.MapView; 12 | import org.openstreetmap.josm.gui.Notification; 13 | import org.openstreetmap.josm.gui.layer.OsmDataLayer; 14 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings; 15 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils; 16 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.ImageSamPanelListener; 17 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImage; 18 | import org.openstreetmap.josm.tools.ImageProvider; 19 | import org.openstreetmap.josm.tools.Logging; 20 | 21 | import javax.swing.*; 22 | import java.awt.*; 23 | import java.awt.event.MouseEvent; 24 | import java.awt.event.MouseListener; 25 | 26 | import static org.openstreetmap.josm.tools.I18n.tr; 27 | 28 | public class SamDecodeAction extends MapMode implements MouseListener { 29 | private static final Cursor CURSOR_CUSTOM = ImageProvider.getCursor("crosshair", "magic-wand-sam"); 30 | private Mode mode = Mode.None; 31 | private final Mode nextMode = Mode.None; 32 | private Point drawStartPos; 33 | private Point mousePos; 34 | private final ImageSamPanelListener listener; 35 | 36 | public SamDecodeAction(ImageSamPanelListener listener) { 37 | super(tr("Magic Wand SAM"), "magic-wand-sam", tr("Magic Wand SAM action"), null, ImageProvider.getCursor("crosshair", null)); 38 | this.listener = listener; 39 | } 40 | 41 | private Cursor getCursor() { 42 | return CURSOR_CUSTOM; 43 | } 44 | 45 | private void setCursor(final Cursor c) { 46 | MainApplication.getMap().mapView.setNewCursor(c, this); 47 | } 48 | 49 | private void updCursor() { 50 | if (!MainApplication.isDisplayingMapView()) return; 51 | setCursor(getCursor()); 52 | } 53 | 54 | @Override 55 | public void enterMode() { 56 | super.enterMode(); 57 | 58 | MapFrame map = MainApplication.getMap(); 59 | map.mapView.addMouseListener(this); 60 | map.mapView.addMouseMotionListener(this); 61 | 62 | updCursor(); 63 | 64 | } 65 | 66 | @Override 67 | public void exitMode() { 68 | super.exitMode(); 69 | MapFrame map = MainApplication.getMap(); 70 | map.mapView.removeMouseListener(this); 71 | map.mapView.removeMouseMotionListener(this); 72 | if (mode != Mode.None) map.mapView.repaint(); 73 | mode = Mode.None; 74 | } 75 | 76 | public final void cancelDrawing() { 77 | mode = Mode.None; 78 | MapFrame map = MainApplication.getMap(); 79 | if (map == null || map.mapView == null) return; 80 | map.statusLine.setHeading(-1); 81 | map.statusLine.setAngle(-1); 82 | map.mapView.repaint(); 83 | updateStatusLine(); 84 | } 85 | 86 | private void drawingStart(MouseEvent e) { 87 | mousePos = e.getPoint(); 88 | drawStartPos = mousePos; 89 | mode = Mode.Drawing; 90 | updateStatusLine(); 91 | } 92 | 93 | @Override 94 | public void mouseReleased(MouseEvent event) { 95 | Logging.info("-------- mouseReleased -----------"); 96 | if (event.getButton() != MouseEvent.BUTTON1) return; 97 | if (!MainApplication.getMap().mapView.isActiveLayerDrawable()) return; 98 | 99 | checkApi(event.getX(), event.getY()); 100 | } 101 | 102 | private void checkApi(int x, int y) { 103 | Thread apiThread = new Thread(() -> { 104 | String device = CommonUtils.serverSamLive(); 105 | SwingUtilities.invokeLater(() -> { 106 | if (!device.isEmpty()) { 107 | Logging.info("Server is online: " + device); 108 | apiThreadDecode(x, y); 109 | } else { 110 | Logging.error("Server is down"); 111 | new Notification(tr("SAM server not reachable.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 112 | } 113 | }); 114 | }); 115 | apiThread.start(); 116 | } 117 | 118 | private void apiThreadDecode(int x, int y) { 119 | Thread aoiThread = new Thread(() -> { 120 | drawWays(x, y); 121 | SwingUtilities.invokeLater(() -> { 122 | Logging.error("later"); 123 | }); 124 | }); 125 | aoiThread.start(); 126 | } 127 | 128 | 129 | private void drawWays(int x, int y) { 130 | try { 131 | 132 | OsmDataLayer dataActiveLayer = CommonUtils.getActiveDataLayerNameOrCreate("Data Layer new"); 133 | 134 | MapView mapView = MainApplication.getMap().mapView; 135 | DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 136 | 137 | String tagKey = ""; 138 | String tagValue = ""; 139 | 140 | LatLon latLon = mapView.getLatLon(x, y); 141 | Projection currentProjection = mapView.getProjection(); 142 | EastNorth eastNorth = latLon.getEastNorth(currentProjection); 143 | 144 | SamImage samImage = listener.getSamImageIncludepoint(eastNorth.getX(), eastNorth.getY()); 145 | if (samImage == null) { 146 | new Notification(tr("Click inside of active AOI to enable Segment Anything Model.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 147 | return; 148 | } 149 | Projection epsg4326 = Projections.getProjectionByCode("EPSG:4326"); 150 | EastNorth eastNort4326 = epsg4326.latlon2eastNorth(latLon); 151 | 152 | 153 | OsmDataLayer newLayerSam = samImage.fetchDecodePoint(eastNort4326.getX(), eastNort4326.getY()); 154 | if (newLayerSam == null) { 155 | new Notification(tr("Error fetch data.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 156 | return; 157 | } 158 | CommonUtils.pasteDataFromLayerByName(dataActiveLayer, newLayerSam); 159 | } catch (Exception e) { 160 | Logging.error(e); 161 | new Notification(tr("Error data generation.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 162 | } 163 | } 164 | 165 | private enum Mode { 166 | None, Drawing 167 | } 168 | 169 | 170 | } 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Actions/SimplifySelectAction.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions; 2 | 3 | import org.locationtech.jts.geom.Coordinate; 4 | import org.locationtech.jts.geom.Geometry; 5 | import org.openstreetmap.josm.actions.JosmAction; 6 | import org.openstreetmap.josm.command.Command; 7 | import org.openstreetmap.josm.command.SequenceCommand; 8 | import org.openstreetmap.josm.data.UndoRedoHandler; 9 | import org.openstreetmap.josm.data.osm.DataSelectionListener; 10 | import org.openstreetmap.josm.data.osm.DataSet; 11 | import org.openstreetmap.josm.data.osm.OsmPrimitive; 12 | import org.openstreetmap.josm.data.osm.Way; 13 | import org.openstreetmap.josm.gui.MainApplication; 14 | import org.openstreetmap.josm.gui.MapFrame; 15 | import org.openstreetmap.josm.gui.Notification; 16 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings; 17 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils; 18 | import org.openstreetmap.josm.tools.Logging; 19 | import org.openstreetmap.josm.tools.Shortcut; 20 | 21 | import javax.swing.*; 22 | import java.awt.event.ActionEvent; 23 | import java.awt.event.KeyEvent; 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | import java.util.Collection; 27 | import java.util.List; 28 | 29 | import static org.openstreetmap.josm.tools.I18n.tr; 30 | 31 | public class SimplifySelectAction extends JosmAction implements DataSelectionListener { 32 | 33 | 34 | public SimplifySelectAction(String text) { 35 | super(tr(text), "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); 36 | } 37 | 38 | @Override 39 | public void actionPerformed(ActionEvent actionEvent) { 40 | if (!isEnabled()) return; 41 | Collection selWays = getSelectedWays(); 42 | if (selWays.isEmpty()) { 43 | new Notification(tr("No ways selected.")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 44 | return; 45 | } 46 | 47 | try { 48 | List geometrySimplify = simplifyWays(selWays); 49 | boolean hasDraw = drawWays(geometrySimplify); 50 | if (hasDraw) { 51 | removeSelected(actionEvent); 52 | } 53 | } catch (Exception e) { 54 | Logging.error(e); 55 | } 56 | 57 | } 58 | 59 | @Override 60 | public void selectionChanged(SelectionChangeEvent event) { 61 | updateEnabledStateOnCurrentSelection(); 62 | } 63 | 64 | @Override 65 | protected void updateEnabledState(Collection selection) { 66 | updateEnabledStateOnModifiableSelection(selection); 67 | } 68 | 69 | private Collection getSelectedWays() { 70 | return getLayerManager().getEditDataSet().getSelectedWays(); 71 | } 72 | 73 | private List simplifyWays(Collection ways) throws Exception { 74 | List geometries = new ArrayList<>(); 75 | for (Way w : ways) { 76 | List coordsMercator = CommonUtils.nodes2Coordinates(w.getNodes()); 77 | Geometry geometryMercator = CommonUtils.coordinates2Polygon(coordsMercator); 78 | Geometry geometrySimplify = CommonUtils.simplifySmoothGeometry(geometryMercator); 79 | geometries.add(geometrySimplify); 80 | } 81 | return geometries; 82 | } 83 | 84 | private boolean drawWays(List geometrySimplify) { 85 | if (geometrySimplify.isEmpty()) return false; 86 | DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 87 | try { 88 | String tagKey = ""; 89 | String tagValue = ""; 90 | if (ToolSettings.getAutoTags() != null && !ToolSettings.getAutoTags().isEmpty()) { 91 | List strings = Arrays.asList(ToolSettings.getAutoTags().split("=")); 92 | if (strings.size() > 1) { 93 | tagKey = strings.get(0); 94 | tagValue = strings.get(1); 95 | } 96 | } 97 | Collection cmds = CommonUtils.geometry2WayCommands(ds, geometrySimplify, tagKey, tagValue); 98 | UndoRedoHandler.getInstance().add(new SequenceCommand(tr("simplify way"), cmds)); 99 | return !cmds.isEmpty(); 100 | } catch (Exception e) { 101 | Logging.error(e); 102 | return false; 103 | } 104 | } 105 | 106 | private void removeSelected(ActionEvent e) { 107 | MapFrame map = MainApplication.getMap(); 108 | if (!isEnabled() || !map.mapView.isActiveLayerVisible()) return; 109 | map.mapModeDelete.doActionPerformed(e); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/MainJosmMagicWandPlugin.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand; 2 | 3 | 4 | import org.openstreetmap.josm.gui.IconToggleButton; 5 | import org.openstreetmap.josm.gui.MainApplication; 6 | import org.openstreetmap.josm.gui.MainMenu; 7 | import org.openstreetmap.josm.gui.MapFrame; 8 | import org.openstreetmap.josm.plugins.Plugin; 9 | import org.openstreetmap.josm.plugins.PluginInformation; 10 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.MagicWandAction; 11 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.MergeSelectAction; 12 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.SamDecodeAction; 13 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.SimplifySelectAction; 14 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions.AutoAddTagAction; 15 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.MagicWandDialog; 16 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils; 17 | import org.openstreetmap.josm.tools.Logging; 18 | 19 | import javax.swing.*; 20 | 21 | public class MainJosmMagicWandPlugin extends Plugin { 22 | 23 | public MainJosmMagicWandPlugin(PluginInformation info) { 24 | super(info); 25 | try { 26 | if (Double.parseDouble(System.getProperty("java.specification.version")) >= 12) { 27 | nu.pattern.OpenCV.loadLocally(); 28 | } else { 29 | nu.pattern.OpenCV.loadShared(); 30 | } 31 | } catch (Exception e) { 32 | Logging.error(e.getMessage()); 33 | throw new RuntimeException(e); 34 | } 35 | 36 | JMenu jToolmenu = MainApplication.getMenu().toolsMenu; 37 | jToolmenu.addSeparator(); 38 | MainMenu.add(jToolmenu, new MergeSelectAction("Merge way")); 39 | MainMenu.add(jToolmenu, new SimplifySelectAction("Simplify way")); 40 | MainMenu.add(jToolmenu, new AutoAddTagAction("Add default tag")); 41 | 42 | // create a folder 43 | CommonUtils.createCacheDir(); 44 | CommonUtils.createCacheSamDir(); 45 | 46 | } 47 | 48 | @Override 49 | public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) { 50 | if (oldFrame == null && newFrame != null) { 51 | MagicWandDialog magicWandDialog = new MagicWandDialog(); 52 | newFrame.addToggleDialog(magicWandDialog); 53 | MainApplication.getMap().addMapMode(new IconToggleButton(new MagicWandAction())); 54 | MainApplication.getMap().addMapMode(new IconToggleButton(new SamDecodeAction(magicWandDialog))); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/ToolSettings.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand; 2 | 3 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImage; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public final class ToolSettings { 9 | private static int tolerance; 10 | private static int maskClose; 11 | private static int maskMedian; 12 | private static int maskOpen; 13 | // simplify 14 | private static double simplDouglasP; 15 | private static double simplPolygonHull; 16 | private static double simplTopologyPreserving; 17 | //smooth 18 | private static double chaikinSmooDistance; 19 | private static double chaikinSmooAngle; 20 | // tags 21 | private static String autoTags; 22 | // sam images 23 | private static int simplAreaSam; 24 | private static double simplDistanceSam; 25 | 26 | private static List samImagesList = new ArrayList<>(); 27 | private ToolSettings() { 28 | } 29 | 30 | public static List getSamImagesList() { 31 | return samImagesList; 32 | } 33 | 34 | public static void setSamImagesList(List samImagesList) { 35 | ToolSettings.samImagesList = samImagesList; 36 | } 37 | 38 | public static void setSamImage(SamImage samImage) { 39 | ToolSettings.samImagesList.add(samImage); 40 | } 41 | 42 | public static void clearSamImagesList() { 43 | ToolSettings.samImagesList.clear(); 44 | } 45 | 46 | public static int getMaskOpen() { 47 | return maskOpen; 48 | } 49 | 50 | public static void setMaskOpen(int maskOpen) { 51 | ToolSettings.maskOpen = maskOpen; 52 | } 53 | 54 | 55 | public static int getTolerance() { 56 | return tolerance; 57 | } 58 | 59 | public static void setTolerance(int tolerance) { 60 | ToolSettings.tolerance = tolerance; 61 | } 62 | 63 | public static int getMaskClose() { 64 | return maskClose; 65 | } 66 | 67 | public static void setMaskClose(int maskClose) { 68 | ToolSettings.maskClose = maskClose; 69 | } 70 | 71 | public static int getMaskMedian() { 72 | return maskMedian; 73 | } 74 | 75 | public static void setMaskMedian(int maskMedian) { 76 | ToolSettings.maskMedian = maskMedian; 77 | } 78 | 79 | public static double getSimplPolygonHull() { 80 | return simplPolygonHull; 81 | } 82 | 83 | public static void setSimplPolygonHull(double simplPolygonHull) { 84 | ToolSettings.simplPolygonHull = simplPolygonHull; 85 | } 86 | 87 | public static double getSimplTopologyPreserving() { 88 | return simplTopologyPreserving; 89 | } 90 | 91 | public static void setSimplTopologyPreserving(double simplTopologyPreserving) { 92 | ToolSettings.simplTopologyPreserving = simplTopologyPreserving; 93 | } 94 | 95 | public static double getSimplDouglasP() { 96 | return simplDouglasP; 97 | } 98 | 99 | public static void setSimplDouglasP(double simplDouglasP) { 100 | ToolSettings.simplDouglasP = simplDouglasP; 101 | } 102 | 103 | public static double getChaikinSmooAngle() { 104 | return chaikinSmooAngle; 105 | } 106 | 107 | public static void setChaikinSmooAngle(double chaikinSmooAngle) { 108 | ToolSettings.chaikinSmooAngle = chaikinSmooAngle; 109 | } 110 | 111 | public static double getChaikinSmooDistance() { 112 | return chaikinSmooDistance; 113 | } 114 | 115 | public static void setChaikinSmooDistance(double chaikinSmooDistance) { 116 | ToolSettings.chaikinSmooDistance = chaikinSmooDistance; 117 | } 118 | 119 | public static String getAutoTags() { 120 | return ToolSettings.autoTags; 121 | } 122 | 123 | public static void setAutoTags(String autoTags) { 124 | ToolSettings.autoTags = autoTags; 125 | } 126 | 127 | public static int getSimplAreaSam() { 128 | return simplAreaSam; 129 | } 130 | 131 | public static void setSimplAreaSam(int simplAreaSam) { 132 | ToolSettings.simplAreaSam = simplAreaSam; 133 | } 134 | 135 | public static double getSimplDistanceSam() { 136 | return simplDistanceSam; 137 | } 138 | 139 | public static void setSimplDistanceSam(double simplDistanceSam) { 140 | ToolSettings.simplDistanceSam = simplDistanceSam; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/AutoAddTagAction.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions; 2 | 3 | import org.openstreetmap.josm.actions.JosmAction; 4 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.TagsDialog; 5 | 6 | import java.awt.event.ActionEvent; 7 | import java.util.concurrent.atomic.AtomicBoolean; 8 | 9 | import static org.openstreetmap.josm.tools.I18n.tr; 10 | 11 | public class AutoAddTagAction extends JosmAction { 12 | AtomicBoolean isPerforming = new AtomicBoolean(false); 13 | 14 | public AutoAddTagAction(String text) { 15 | super(tr(text), "dialogs/add", tr("Add a new key/value tag to geometries"), null, false); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | if (!/*successful*/isPerforming.compareAndSet(false, true)) { 21 | return; 22 | } 23 | try { 24 | TagsDialog tagsDialog = new TagsDialog(); 25 | if (tagsDialog.getValue() != 1) return; 26 | tagsDialog.saveSettings(); 27 | } finally { 28 | isPerforming.set(false); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/AutoSam.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions; 2 | 3 | import org.openstreetmap.josm.actions.JosmAction; 4 | import org.openstreetmap.josm.gui.MainApplication; 5 | import org.openstreetmap.josm.gui.MapView; 6 | import org.openstreetmap.josm.gui.Notification; 7 | import org.openstreetmap.josm.gui.layer.ImageryLayer; 8 | import org.openstreetmap.josm.gui.layer.Layer; 9 | import org.openstreetmap.josm.gui.layer.OsmDataLayer; 10 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils; 11 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.ImageSamPanelListener; 12 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.LayerImageValues; 13 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImage; 14 | import org.openstreetmap.josm.tools.Logging; 15 | 16 | import javax.swing.*; 17 | import java.awt.*; 18 | import java.awt.event.ActionEvent; 19 | import java.awt.image.BufferedImage; 20 | import java.util.List; 21 | 22 | import static org.openstreetmap.josm.tools.I18n.tr; 23 | 24 | public class AutoSam extends JosmAction { 25 | private final ImageSamPanelListener listener; 26 | 27 | public AutoSam(ImageSamPanelListener listener) { 28 | super(tr("AUTO SAM"), "dialogs/auto-sam", tr("Automatic sam"), 29 | null, false); 30 | this.listener = listener; 31 | } 32 | 33 | @Override 34 | public void actionPerformed(ActionEvent e) { 35 | MapView mapView = MainApplication.getMap().mapView; 36 | // check layers 37 | List targetLayer = MainApplication.getLayerManager().getLayers(); 38 | boolean hasMapLayer = false; 39 | for (Layer layer : targetLayer) { 40 | if (layer instanceof ImageryLayer && layer.isVisible()) { 41 | hasMapLayer = true; 42 | break; 43 | } 44 | } 45 | 46 | if (hasMapLayer) { 47 | LayerImageValues layerImageValues = getLayeredImage(mapView); 48 | SamImage samImage = new SamImage(mapView.getProjectionBounds(), mapView.getProjection(), mapView.getScale(), layerImageValues.getBufferedImage(), layerImageValues.getLayerName()); 49 | // effect 50 | checkApi(samImage); 51 | 52 | } else { 53 | new Notification(tr("An Map active layer is needed.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 54 | } 55 | } 56 | 57 | private void checkApi(SamImage samImage) { 58 | Thread apiThread = new Thread(() -> { 59 | String device = CommonUtils.serverSamLive(); 60 | SwingUtilities.invokeLater(() -> { 61 | if (!device.isEmpty()) { 62 | Logging.info("Server is online: " + device); 63 | apiThreadCreateAoi(samImage); 64 | } else { 65 | Logging.error("Server is down"); 66 | new Notification(tr("SAM server not reachable.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 67 | } 68 | }); 69 | }); 70 | apiThread.start(); 71 | } 72 | 73 | private void apiThreadCreateAoi(SamImage samImage) { 74 | OsmDataLayer dataActiveLayer = CommonUtils.getActiveDataLayerNameOrCreate("Data Layer new"); 75 | // if (dataActiveLayer.getAssociatedFile() == null || dataActiveLayer.requiresSaveToFile()) { 76 | // new Notification(tr("Save changes to the current Data Layer or associate it with a file.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 77 | // setEnabled(true); 78 | // return; 79 | // } 80 | setEnabled(false); 81 | Thread aoiThread = new Thread(() -> { 82 | try { 83 | new Notification(tr("Creating Aoi...")).setIcon(JOptionPane.INFORMATION_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 84 | samImage.setEncodeImage(); 85 | new Notification(tr("Automatically segmenting ..")).setIcon(JOptionPane.INFORMATION_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 86 | setEnabled(false); 87 | OsmDataLayer newLayerSam = samImage.autoAnnotateSam(); 88 | setEnabled(false); 89 | SwingUtilities.invokeLater(() -> { 90 | if (newLayerSam != null) { 91 | addSamImage(samImage); 92 | CommonUtils.pasteDataFromLayerByName(dataActiveLayer, newLayerSam); 93 | samImage.updateCacheImage(); 94 | } 95 | setEnabled(true); 96 | }); 97 | } catch (Exception e) { 98 | Logging.error(e); 99 | setEnabled(true); 100 | } 101 | }); 102 | aoiThread.start(); 103 | } 104 | 105 | 106 | private void addSamImage(SamImage samImage) { 107 | if (samImage.getEncode() && !samImage.getImageUrl().isEmpty()) { 108 | listener.addLayer(); 109 | listener.addBboxLayer(samImage.getBboxWay()); 110 | listener.onAddSamImage(samImage); 111 | new Notification(tr("Added a sam image.")).setIcon(JOptionPane.INFORMATION_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 112 | } else { 113 | new Notification(tr("Error adding sam image.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 114 | } 115 | } 116 | 117 | private LayerImageValues getLayeredImage(MapView mapView) { 118 | LayerImageValues layerImageValues = new LayerImageValues(); 119 | BufferedImage bufImage = new BufferedImage(mapView.getWidth(), mapView.getHeight(), BufferedImage.TYPE_3BYTE_BGR); 120 | Graphics2D imgGraphics = bufImage.createGraphics(); 121 | imgGraphics.setClip(0, 0, mapView.getWidth(), mapView.getHeight()); 122 | 123 | for (Layer layer : mapView.getLayerManager().getVisibleLayersInZOrder()) { 124 | if (layer.isVisible() && layer.isBackgroundLayer()) { 125 | Composite translucent = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) layer.getOpacity()); 126 | imgGraphics.setComposite(translucent); 127 | mapView.paintLayer(layer, imgGraphics); 128 | layerImageValues.setBufferedImage(bufImage); 129 | layerImageValues.setLayerName(layer.getName()); 130 | } 131 | 132 | } 133 | 134 | return layerImageValues; 135 | } 136 | 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/ButtonActions/SamEncondeAction.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions; 2 | 3 | import org.openstreetmap.josm.actions.JosmAction; 4 | import org.openstreetmap.josm.gui.MainApplication; 5 | import org.openstreetmap.josm.gui.MapView; 6 | import org.openstreetmap.josm.gui.Notification; 7 | import org.openstreetmap.josm.gui.layer.ImageryLayer; 8 | import org.openstreetmap.josm.gui.layer.Layer; 9 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.CommonUtils; 10 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.ImageSamPanelListener; 11 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.LayerImageValues; 12 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.SamImage; 13 | import org.openstreetmap.josm.tools.Logging; 14 | 15 | import javax.swing.*; 16 | import java.awt.*; 17 | import java.awt.event.ActionEvent; 18 | import java.awt.image.BufferedImage; 19 | import java.util.List; 20 | 21 | import static org.openstreetmap.josm.tools.I18n.tr; 22 | 23 | public class SamEncondeAction extends JosmAction { 24 | private final ImageSamPanelListener listener; 25 | 26 | public SamEncondeAction(ImageSamPanelListener listener) { 27 | super(tr("SAM AOI"), "dialogs/magic-wand-encode", tr("Add a new SAM AOI"), null, false); 28 | this.listener = listener; 29 | } 30 | 31 | @Override 32 | public void actionPerformed(ActionEvent e) { 33 | MapView mapView = MainApplication.getMap().mapView; 34 | // check layers 35 | List targetLayer = MainApplication.getLayerManager().getLayers(); 36 | boolean hasMapLayer = false; 37 | for (Layer layer : targetLayer) { 38 | if (layer instanceof ImageryLayer && layer.isVisible()) { 39 | hasMapLayer = true; 40 | break; 41 | } 42 | } 43 | 44 | if (hasMapLayer) { 45 | LayerImageValues layerImageValues = getLayeredImage(mapView); 46 | SamImage samImage = new SamImage(mapView.getProjectionBounds(), mapView.getProjection(), mapView.getScale(), layerImageValues.getBufferedImage(), layerImageValues.getLayerName()); 47 | 48 | // effect 49 | setEnabled(false); 50 | checkApi(samImage); 51 | 52 | } else { 53 | new Notification(tr("An active layer is needed.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 54 | } 55 | } 56 | 57 | private void checkApi(SamImage samImage) { 58 | Thread apiThread = new Thread(() -> { 59 | String device = CommonUtils.serverSamLive(); 60 | SwingUtilities.invokeLater(() -> { 61 | if (!device.isEmpty()) { 62 | Logging.info("Server is online: " + device); 63 | apiThreadCreateAoi(samImage); 64 | } else { 65 | Logging.error("Server is down"); 66 | new Notification(tr("SAM server not reachable.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 67 | } 68 | }); 69 | }); 70 | apiThread.start(); 71 | } 72 | 73 | private void apiThreadCreateAoi(SamImage samImage) { 74 | setEnabled(false); 75 | Thread aoiThread = new Thread(() -> { 76 | samImage.setEncodeImage(); 77 | SwingUtilities.invokeLater(() -> { 78 | addSamImage(samImage); 79 | samImage.updateCacheImage(); 80 | setEnabled(true); 81 | }); 82 | }); 83 | aoiThread.start(); 84 | } 85 | 86 | private void addSamImage(SamImage samImage) { 87 | if (samImage.getEncode()) { 88 | listener.addLayer(); 89 | listener.addBboxLayer(samImage.getBboxWay()); 90 | listener.onAddSamImage(samImage); 91 | new Notification(tr("Added a sam image.")).setIcon(JOptionPane.INFORMATION_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 92 | } else { 93 | new Notification(tr("Error adding sam image.")).setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 94 | } 95 | } 96 | 97 | private LayerImageValues getLayeredImage(MapView mapView) { 98 | LayerImageValues layerImageValues = new LayerImageValues(); 99 | BufferedImage bufImage = new BufferedImage(mapView.getWidth(), mapView.getHeight(), BufferedImage.TYPE_3BYTE_BGR); 100 | Graphics2D imgGraphics = bufImage.createGraphics(); 101 | imgGraphics.setClip(0, 0, mapView.getWidth(), mapView.getHeight()); 102 | 103 | for (Layer layer : mapView.getLayerManager().getVisibleLayersInZOrder()) { 104 | if (layer.isVisible() && layer.isBackgroundLayer()) { 105 | Composite translucent = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) layer.getOpacity()); 106 | imgGraphics.setComposite(translucent); 107 | mapView.paintLayer(layer, imgGraphics); 108 | layerImageValues.setBufferedImage(bufImage); 109 | layerImageValues.setLayerName(layer.getName()); 110 | } 111 | 112 | } 113 | 114 | return layerImageValues; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/MagicWandDialog.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui; 2 | 3 | import org.locationtech.jts.geom.Coordinate; 4 | import org.locationtech.jts.geom.GeometryFactory; 5 | import org.locationtech.jts.geom.Point; 6 | import org.openstreetmap.josm.data.osm.DataSet; 7 | import org.openstreetmap.josm.data.osm.Node; 8 | import org.openstreetmap.josm.data.osm.Way; 9 | import org.openstreetmap.josm.gui.MainApplication; 10 | import org.openstreetmap.josm.gui.SideButton; 11 | import org.openstreetmap.josm.gui.dialogs.ToggleDialog; 12 | import org.openstreetmap.josm.gui.layer.Layer; 13 | import org.openstreetmap.josm.gui.layer.OsmDataLayer; 14 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.MergeSelectAction; 15 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Actions.SimplifySelectAction; 16 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings; 17 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions.AutoAddTagAction; 18 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions.AutoSam; 19 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui.ButtonActions.SamEncondeAction; 20 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.*; 21 | import org.openstreetmap.josm.tools.Logging; 22 | 23 | import javax.swing.*; 24 | import javax.swing.border.Border; 25 | import javax.swing.border.TitledBorder; 26 | import java.awt.*; 27 | import java.awt.event.ActionEvent; 28 | import java.awt.event.ActionListener; 29 | import java.util.ArrayList; 30 | import java.util.Arrays; 31 | import java.util.EventListener; 32 | 33 | import static org.openstreetmap.josm.tools.I18n.tr; 34 | 35 | public class MagicWandDialog extends ToggleDialog implements ImageSamPanelListener { 36 | // variables 37 | private SamImageGrid samImageGrid; 38 | private final JPanel mainJpanel; 39 | private OsmDataLayer uneditableLayer = null; 40 | private final boolean canSamAoi = false; 41 | 42 | public MagicWandDialog() { 43 | super(tr("Magic Wand"), "magicwand-info.svg", tr("Open MagicWand windows"), null, 200, false); 44 | 45 | mainJpanel = new JPanel(); 46 | mainJpanel.setLayout(new BoxLayout(mainJpanel, BoxLayout.Y_AXIS)); 47 | 48 | JPanel optionPanel = new JPanel(); 49 | optionPanel.setLayout(new GridLayout(6, 1, 3, 3)); 50 | // tolerance 51 | optionPanel.add(buildTolerancePanel()); 52 | // simplify 53 | optionPanel.add(buildPolygonHullPanel()); 54 | optionPanel.add(buildDouglaspPanel()); 55 | optionPanel.add(buildTopologyPreservingPanel()); 56 | optionPanel.add(buildChaikinAnglePanel()); 57 | optionPanel.add(buildSamParams()); 58 | // add mainJpanel 59 | mainJpanel.add(optionPanel); 60 | // sam image 61 | mainJpanel.add(buildSamImagesPanel()); 62 | // layer 63 | initLayer(); 64 | // buttons 65 | // mege 66 | SideButton mergeGeometry = new SideButton(new MergeSelectAction("")); 67 | // simplify 68 | SideButton simplifyGeometry = new SideButton(new SimplifySelectAction("")); 69 | // sam 70 | SideButton autoSamButton = new SideButton(new AutoSam(this)); 71 | // sam 72 | SideButton samButton = new SideButton(new SamEncondeAction(this)); 73 | 74 | createLayout(mainJpanel, true, Arrays.asList(mergeGeometry, simplifyGeometry, autoSamButton, samButton)); 75 | } 76 | 77 | private JPanel buildTolerancePanel() { 78 | JPanel jpanel = new JPanel(); 79 | jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS)); 80 | jpanel.setPreferredSize(new Dimension(0, 25)); 81 | int initValue = 9; 82 | TitledBorder titledBorder = BorderFactory.createTitledBorder("Tolerance: " + initValue); 83 | jpanel.setBorder(titledBorder); 84 | ToolSettings.setTolerance(initValue); 85 | // 86 | JSlider jSlider = new JSlider(1, 30, initValue); 87 | jSlider.setPaintTrack(true); 88 | jSlider.setPaintTicks(true); 89 | jSlider.setPaintLabels(true); 90 | 91 | jpanel.add(jSlider); 92 | jSlider.addChangeListener(changeEvent -> { 93 | JSlider source = (JSlider) changeEvent.getSource(); 94 | int value = source.getValue(); 95 | titledBorder.setTitle(tr("Tolerance: " + value)); 96 | ToolSettings.setTolerance(value); 97 | jpanel.repaint(); 98 | }); 99 | 100 | return jpanel; 101 | } 102 | 103 | private JPanel buildPolygonHullPanel() { 104 | JPanel jpanel = new JPanel(); 105 | jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS)); 106 | jpanel.setPreferredSize(new Dimension(0, 25)); 107 | // 108 | double decimalPlaces = Math.pow(10, 3); 109 | double min = 0.5; 110 | int initValue = (int) (0.95 * decimalPlaces); 111 | // 112 | TitledBorder titledBorder = BorderFactory.createTitledBorder("Exterior contour: " + initValue / decimalPlaces); 113 | jpanel.setBorder(titledBorder); 114 | 115 | ToolSettings.setSimplPolygonHull(initValue / decimalPlaces); 116 | // 117 | JSlider jSlider = new JSlider((int) (min * decimalPlaces), (int) decimalPlaces, initValue); 118 | jSlider.setPaintTrack(true); 119 | jSlider.setPaintTicks(true); 120 | jSlider.setPaintLabels(true); 121 | 122 | jpanel.add(jSlider); 123 | jSlider.addChangeListener(changeEvent -> { 124 | JSlider source = (JSlider) changeEvent.getSource(); 125 | double value = source.getValue(); 126 | if (value <= (min * decimalPlaces)) { 127 | value = 0.0; 128 | } else { 129 | value /= decimalPlaces; 130 | } 131 | 132 | titledBorder.setTitle(tr("Exterior contour: " + value)); 133 | ToolSettings.setSimplPolygonHull(value); 134 | jpanel.repaint(); 135 | }); 136 | 137 | 138 | return jpanel; 139 | } 140 | 141 | private JPanel buildDouglaspPanel() { 142 | JPanel jpanel = new JPanel(); 143 | jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS)); 144 | // 145 | double decimalPlaces = Math.pow(10, 3); 146 | int initValue = 1000; 147 | // 148 | TitledBorder titledBorder = BorderFactory.createTitledBorder("Vertices: " + initValue / decimalPlaces); 149 | jpanel.setBorder(titledBorder); 150 | ToolSettings.setSimplDouglasP(initValue / decimalPlaces); 151 | // 152 | JSlider jSlider = new JSlider(0, (int) (5 * decimalPlaces), initValue); 153 | jSlider.setPaintTrack(true); 154 | jSlider.setPaintTicks(true); 155 | jSlider.setPaintLabels(true); 156 | 157 | jpanel.add(jSlider); 158 | jSlider.addChangeListener(changeEvent -> { 159 | JSlider source = (JSlider) changeEvent.getSource(); 160 | double value = source.getValue() / decimalPlaces; 161 | titledBorder.setTitle(tr("Vertices: " + value)); 162 | ToolSettings.setSimplDouglasP(value); 163 | jpanel.repaint(); 164 | }); 165 | 166 | 167 | return jpanel; 168 | } 169 | 170 | private JPanel buildTopologyPreservingPanel() { 171 | JPanel jpanel = new JPanel(); 172 | jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS)); 173 | // 174 | double decimalPlaces = Math.pow(10, 3); 175 | int initValue = 1000; 176 | // 177 | TitledBorder titledBorder = BorderFactory.createTitledBorder("Topology: " + initValue / decimalPlaces); 178 | jpanel.setBorder(titledBorder); 179 | ToolSettings.setSimplTopologyPreserving(initValue / decimalPlaces); 180 | // 181 | JSlider jSlider = new JSlider(0, (int) (5 * decimalPlaces), initValue); 182 | jSlider.setPaintTrack(true); 183 | jSlider.setPaintTicks(true); 184 | jSlider.setPaintLabels(true); 185 | 186 | jpanel.add(jSlider); 187 | jSlider.addChangeListener(changeEvent -> { 188 | JSlider source = (JSlider) changeEvent.getSource(); 189 | double value = source.getValue() / decimalPlaces; 190 | titledBorder.setTitle(tr("Topology: " + value)); 191 | ToolSettings.setSimplTopologyPreserving(value); 192 | jpanel.repaint(); 193 | }); 194 | 195 | return jpanel; 196 | } 197 | 198 | private JPanel buildChaikinAnglePanel() { 199 | JPanel jpanel = new JPanel(); 200 | jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.Y_AXIS)); 201 | // 202 | int initValue = 110; 203 | double minValue = 20.0; 204 | // 205 | TitledBorder titledBorder = BorderFactory.createTitledBorder("Smooth Angle: " + initValue); 206 | jpanel.setBorder(titledBorder); 207 | ToolSettings.setChaikinSmooAngle(initValue); 208 | // 209 | JSlider jSlider = new JSlider((int) minValue, 170, initValue); 210 | jSlider.setPaintTrack(true); 211 | jSlider.setPaintTicks(true); 212 | jSlider.setPaintLabels(true); 213 | 214 | jpanel.add(jSlider); 215 | jSlider.addChangeListener(changeEvent -> { 216 | JSlider source = (JSlider) changeEvent.getSource(); 217 | double value = source.getValue(); 218 | if (value <= minValue) { 219 | value = 0.0; 220 | } 221 | titledBorder.setTitle(tr("Smooth Angle: " + value)); 222 | ToolSettings.setChaikinSmooAngle(value); 223 | jpanel.repaint(); 224 | }); 225 | 226 | 227 | return jpanel; 228 | } 229 | 230 | private JPanel buildSamParams() { 231 | JPanel jpanel = new JPanel(); 232 | jpanel.setLayout(new GridLayout(1, 2, 3, 3)); 233 | // 234 | int initArea = 10; 235 | double initThreshold = 0.000002; 236 | // 237 | ToolSettings.setSimplAreaSam(initArea); 238 | ToolSettings.setSimplDistanceSam(initThreshold); 239 | 240 | // 241 | NumericField jTextInputArea = new NumericField(false); 242 | NumericField jTextInputThreshold = new NumericField(true); 243 | // colors 244 | jTextInputArea.setBorder(new TitledBorder("Min area simplify")); 245 | jTextInputThreshold.setBorder(new TitledBorder("Min distance simplify")); 246 | // 247 | jTextInputArea.setText(String.format("%d", initArea)); 248 | jTextInputThreshold.setText(String.format("%.8f", initThreshold)); 249 | // 250 | 251 | jTextInputArea.addPropertyChangeListener("text", e -> { 252 | try { 253 | double doubleValue = Double.parseDouble((String) e.getNewValue()); 254 | ToolSettings.setSimplAreaSam((int) doubleValue); 255 | } catch (Exception ex) { 256 | Logging.error(ex.getMessage()); 257 | } 258 | }); 259 | jTextInputThreshold.addPropertyChangeListener("text", e -> { 260 | try { 261 | double doubleValue = Double.parseDouble((String) e.getNewValue()); 262 | ToolSettings.setSimplDistanceSam(doubleValue); 263 | } catch (Exception ex) { 264 | Logging.error(ex.getMessage()); 265 | } 266 | }); 267 | 268 | // add 269 | jpanel.add(jTextInputArea); 270 | jpanel.add(jTextInputThreshold); 271 | 272 | return jpanel; 273 | } 274 | 275 | private JPanel buildSamImagesPanel() { 276 | samImageGrid = new SamImageGrid(150); 277 | samImageGrid.setLayout(new GridLayout(0, 2, 2, 3)); 278 | 279 | return samImageGrid; 280 | } 281 | 282 | private void initLayer() { 283 | if (uneditableLayer == null || !MainApplication.getLayerManager().containsLayer(uneditableLayer)) { 284 | DataSet bboxDataset = new DataSet(); 285 | uneditableLayer = new OsmDataLayer(bboxDataset, "Magic Wand Uneditable Layer", null); 286 | uneditableLayer.setUploadDiscouraged(false); 287 | } 288 | } 289 | 290 | @Override 291 | public void onAddSamImage(SamImage samImage) { 292 | samImageGrid.addSamImage(samImage); 293 | } 294 | 295 | @Override 296 | public void onRemoveAll() { 297 | samImageGrid.removeAllSamImage(); 298 | } 299 | 300 | @Override 301 | public ArrayList getSamImageList() { 302 | return samImageGrid.getSamImageList(); 303 | } 304 | 305 | @Override 306 | public SamImage getSamImageIncludepoint(double x, double y) { 307 | GeometryFactory geometryFactory = new GeometryFactory(); 308 | Coordinate coordinate = new Coordinate(x, y); 309 | Point point = geometryFactory.createPoint(coordinate); 310 | 311 | return samImageGrid.getSamImageIncludepoint(point); 312 | } 313 | 314 | @Override 315 | public void addLayer() { 316 | try { 317 | initLayer(); 318 | 319 | Layer activeLayer = MainApplication.getLayerManager().getActiveDataLayer(); 320 | if (activeLayer == null) { 321 | activeLayer = new OsmDataLayer(new DataSet(), "Data Layer ", null); 322 | MainApplication.getLayerManager().addLayer(activeLayer); 323 | } 324 | int indexActiveLayer = MainApplication.getLayerManager().getLayers().indexOf(activeLayer); 325 | 326 | if (!MainApplication.getLayerManager().containsLayer(uneditableLayer)) { 327 | MainApplication.getLayerManager().addLayer(uneditableLayer); 328 | MainApplication.getLayerManager().setActiveLayer(activeLayer); 329 | } 330 | int indexUneditableLayer = MainApplication.getLayerManager().getLayers().indexOf(uneditableLayer); 331 | 332 | if (indexActiveLayer >= indexUneditableLayer) { 333 | MainApplication.getLayerManager().moveLayer(uneditableLayer, indexActiveLayer); 334 | } 335 | } catch (Exception e) { 336 | Logging.error(e); 337 | } 338 | } 339 | 340 | @Override 341 | public void addBboxLayer(Way way) { 342 | for (Node node : way.getNodes()) { 343 | if (!uneditableLayer.getDataSet().containsNode(node)) { 344 | uneditableLayer.getDataSet().addPrimitive(node); 345 | } 346 | } 347 | uneditableLayer.getDataSet().addPrimitive(way); 348 | } 349 | 350 | } 351 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/Ui/TagsDialog.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.Ui; 2 | 3 | import org.openstreetmap.josm.gui.ExtendedDialog; 4 | import org.openstreetmap.josm.gui.MainApplication; 5 | import org.openstreetmap.josm.gui.Notification; 6 | import org.openstreetmap.josm.gui.widgets.HistoryComboBox; 7 | import org.openstreetmap.josm.plugins.devseed.JosmMagicWand.ToolSettings; 8 | import org.openstreetmap.josm.tools.GBC; 9 | 10 | import javax.swing.*; 11 | import java.awt.*; 12 | 13 | import static org.openstreetmap.josm.tools.I18n.tr; 14 | 15 | public class TagsDialog extends ExtendedDialog { 16 | 17 | private final HistoryComboBox addTags = new HistoryComboBox(); 18 | private final JPanel mainPanel; 19 | 20 | public TagsDialog() { 21 | super(MainApplication.getMainFrame(), tr("Magic Wand Auto tags"), tr("Ok"), tr("Cancel")); 22 | setButtonIcons("ok", "cancel"); 23 | setCancelButton(2); 24 | mainPanel = new JPanel(new GridBagLayout()); 25 | 26 | mainPanel.add(new JLabel(" Auto add tags" 27 | + "

" + tr("Please add in the format: key=value")), GBC.eol().fill(GBC.HORIZONTAL)); 28 | 29 | addTags.setEditable(true); 30 | addTags.getModel().prefs().load("magicwand.tags-history"); 31 | addTags.setAutocompleteEnabled(true); 32 | mainPanel.add(addTags, GBC.eop().fill(GBC.HORIZONTAL)); 33 | 34 | if (ToolSettings.getAutoTags() != null && !ToolSettings.getAutoTags().isEmpty()) { 35 | addTags.setText(ToolSettings.getAutoTags()); 36 | 37 | } 38 | 39 | setContent(mainPanel, false); 40 | setupDialog(); 41 | setVisible(true); 42 | } 43 | 44 | public void saveSettings() { 45 | if (addTags.getText().isEmpty()) { 46 | ToolSettings.setAutoTags(""); 47 | return; 48 | } 49 | String regex = "^[a-zA-Z0-9]+=[a-zA-Z0-9]+$"; 50 | if (addTags.getText().matches(regex)) { 51 | ToolSettings.setAutoTags(addTags.getText()); 52 | addTags.addItem(addTags.getText()); 53 | addTags.getModel().prefs().save("magicwand.tags-history"); 54 | } else { 55 | new Notification(tr("Label is in the wrong format")).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_SHORT).show(); 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/Constants.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | public class Constants { 4 | public static final String SAM_API = "https://samgeo-api.geocompas.ai"; 5 | public static final String ENCODE = buildEndpoint("aoi"); 6 | public static final String DECODE = buildEndpoint("segment_predictor"); 7 | public static final String AUTOMATIC = buildEndpoint("segment_automatic"); 8 | 9 | private static String buildEndpoint(String path) { 10 | return SAM_API +"/"+ path; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/CustomPolygon.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | import org.locationtech.jts.geom.Polygon; 4 | import org.openstreetmap.josm.data.osm.Way; 5 | import org.openstreetmap.josm.tools.Logging; 6 | 7 | import java.util.UUID; 8 | 9 | public class CustomPolygon { 10 | private final String id; 11 | private Polygon pol; 12 | private boolean isUse; 13 | private Way way; 14 | 15 | public CustomPolygon() { 16 | this.id = UUID.randomUUID().toString(); 17 | this.isUse = false; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "CustomPolygon [id=" + id + ", isUse=" + isUse + "]"; 23 | } 24 | 25 | public void fromWay(Way w) { 26 | this.way = w; 27 | try { 28 | this.pol = CommonUtils.coordinates2Polygon(CommonUtils.nodes2Coordinates(w.getNodes())); 29 | } catch (Exception ex) { 30 | Logging.error(ex); 31 | } 32 | } 33 | 34 | public String id() { 35 | return id; 36 | } 37 | 38 | public Polygon polygon() { 39 | return pol; 40 | } 41 | 42 | public boolean isEmpty() { 43 | return pol.isEmpty(); 44 | } 45 | 46 | public Way way() { 47 | return way; 48 | } 49 | 50 | public boolean isUse() { 51 | return isUse; 52 | } 53 | 54 | public void usePolygon() { 55 | this.isUse = true; 56 | } 57 | 58 | public void setPol(Polygon pol) { 59 | this.pol = pol; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/FloodFillFacade.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | import org.opencv.core.Mat; 4 | import org.opencv.core.Point; 5 | import org.opencv.core.Rect; 6 | import org.opencv.core.Scalar; 7 | import org.opencv.imgproc.Imgproc; 8 | import org.openstreetmap.josm.tools.Logging; 9 | 10 | import java.util.Random; 11 | 12 | public class FloodFillFacade { 13 | 14 | public static final int FIXED_RANGE = 1; 15 | private final Random random = new Random(); 16 | private final int newMaskVal = 255; 17 | private boolean colored = true; 18 | private boolean masked = true; 19 | private int range = FIXED_RANGE; 20 | private int connectivity = 8; 21 | private int lowerDiff = 7; 22 | private int upperDiff = 9; 23 | 24 | 25 | @Override 26 | public String toString() { 27 | return "FloodFillFacade [colored=" + colored + ", masked=" + masked + ", range=" + range + ", random=" + random + ", connectivity=" + connectivity + ", newMaskVal=" + newMaskVal + ", lowerDiff=" + lowerDiff + ", upperDiff=" + upperDiff + "]"; 28 | } 29 | 30 | 31 | public void fill(Mat image, Mat mask, int x, int y) { 32 | Point seedPoint = new Point(x, y); 33 | 34 | int b = random.nextInt(256); 35 | int g = random.nextInt(256); 36 | int r = random.nextInt(256); 37 | Rect rect = new Rect(); 38 | 39 | Scalar newVal = isColored() ? new Scalar(b, g, r) : new Scalar(r * 0.299 + g * 0.587 + b * 0.114); 40 | 41 | Scalar lowerDifference = new Scalar(lowerDiff, lowerDiff, lowerDiff); 42 | Scalar upperDifference = new Scalar(upperDiff, upperDiff, upperDiff); 43 | Logging.info("lowerDiff " + lowerDiff + " upperDiff " + upperDiff + " connectivity " + connectivity); 44 | int flags = connectivity + (newMaskVal << 8) + (range == FIXED_RANGE ? Imgproc.FLOODFILL_FIXED_RANGE : 0); 45 | //Imgproc.FLOODFILL_MASK_ONLY); 46 | Imgproc.floodFill(image, mask, seedPoint, newVal, rect, lowerDifference, upperDifference, flags); 47 | } 48 | 49 | 50 | public int getConnectivity() { 51 | return connectivity; 52 | } 53 | 54 | public void setConnectivity(int connectivity) { 55 | this.connectivity = connectivity; 56 | } 57 | 58 | public boolean isColored() { 59 | return colored; 60 | } 61 | 62 | public void setColored(boolean colored) { 63 | this.colored = colored; 64 | } 65 | 66 | public boolean isMasked() { 67 | return masked; 68 | } 69 | 70 | public void setMasked(boolean masked) { 71 | this.masked = masked; 72 | } 73 | 74 | public int getRange() { 75 | return range; 76 | } 77 | 78 | public void setRange(int range) { 79 | this.range = range; 80 | } 81 | 82 | 83 | public int getLowerDiff() { 84 | return lowerDiff; 85 | } 86 | 87 | public void setLowerDiff(int lowerDiff) { 88 | this.lowerDiff = lowerDiff; 89 | } 90 | 91 | public int getUpperDiff() { 92 | return upperDiff; 93 | } 94 | 95 | public void setUpperDiff(int upperDiff) { 96 | this.upperDiff = upperDiff; 97 | } 98 | 99 | public void setTolerance(int tolerance) { 100 | this.lowerDiff = tolerance; 101 | this.upperDiff = tolerance + 2; 102 | } 103 | } -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImagePanel.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | import org.openstreetmap.josm.data.ProjectionBounds; 4 | import org.openstreetmap.josm.data.imagery.ImageryInfo; 5 | import org.openstreetmap.josm.data.imagery.ImageryLayerInfo; 6 | import org.openstreetmap.josm.gui.MapView; 7 | import org.openstreetmap.josm.gui.layer.ImageryLayer; 8 | import org.openstreetmap.josm.gui.layer.Layer; 9 | import org.openstreetmap.josm.tools.ImageProvider; 10 | import org.openstreetmap.josm.tools.Logging; 11 | 12 | import javax.swing.*; 13 | import java.awt.*; 14 | import java.awt.image.BufferedImage; 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | 18 | import static org.openstreetmap.josm.gui.MainApplication.getMap; 19 | 20 | 21 | public class ImagePanel extends JPanel { 22 | 23 | private final BufferedImage image; 24 | private JButton zoomJButton; 25 | private JButton deleteJButton; 26 | private final int maxHeight; 27 | private final int maxWidth; 28 | 29 | private final SamImage samImage; 30 | 31 | private final JLabel imageLabel; 32 | private final ImagePanelListener listener; 33 | 34 | public ImagePanel(SamImage samImage, int maxWidth, ImagePanelListener listener) { 35 | setLayout(null); 36 | this.samImage = samImage; 37 | this.image = samImage.getLayerImage(); 38 | this.maxWidth = maxWidth; 39 | 40 | this.maxHeight = getMaxHeight(samImage.getLayerImage(), maxWidth); 41 | this.listener = listener; 42 | setupButtons(); 43 | // image 44 | Graphics2D g2d = this.image.createGraphics(); 45 | g2d.dispose(); 46 | ImageIcon icono = new ImageIcon(getScaledImage(this.image, maxWidth, this.maxHeight)); 47 | imageLabel = new JLabel(icono); 48 | add(imageLabel); 49 | imageLabel.setBounds(0, 0, this.maxWidth, this.maxHeight); 50 | setPreferredSize(new Dimension(this.maxWidth, this.maxHeight)); 51 | // setup actions 52 | 53 | } 54 | 55 | private Image getScaledImage(BufferedImage originalImage, int maxWidth, int maxHeight) { 56 | int width = originalImage.getWidth(); 57 | 58 | if (width <= maxWidth) { 59 | return originalImage; 60 | } 61 | 62 | return originalImage.getScaledInstance(maxWidth, maxHeight, Image.SCALE_SMOOTH); 63 | } 64 | 65 | private int getMaxHeight(BufferedImage originalImage, int maxWidth) { 66 | int width = originalImage.getWidth(); 67 | int height = originalImage.getHeight(); 68 | 69 | double radio = (double) width / height; 70 | 71 | if (width <= maxWidth) { 72 | return height; 73 | } 74 | return (int) (maxWidth / radio); 75 | 76 | } 77 | 78 | private void setupButtons() { 79 | // 80 | ImageIcon zoomIco = new ImageProvider("dialogs", "zoom-best-fit").get(); 81 | ImageIcon deleteIco = new ImageProvider("dialogs", "delete").get(); 82 | 83 | zoomJButton = new JButton(zoomIco); 84 | 85 | zoomJButton.setBounds(20, this.maxHeight - 32, zoomIco.getIconWidth(), zoomIco.getIconHeight()); 86 | zoomJButton.setContentAreaFilled(false); 87 | zoomJButton.addActionListener(e -> zoomAction()); 88 | add(zoomJButton); 89 | 90 | deleteJButton = new JButton(deleteIco); 91 | deleteJButton.setBounds(70, this.maxHeight - 32, deleteIco.getIconWidth(), deleteIco.getIconHeight()); 92 | deleteJButton.setContentAreaFilled(false); 93 | deleteJButton.addActionListener(e -> deleteAction()); 94 | 95 | add(deleteJButton); 96 | 97 | } 98 | 99 | private void zoomAction() { 100 | MapView mapView = getMap().mapView; 101 | 102 | try { 103 | // add layer 104 | List activeLayers = mapView.getLayerManager() 105 | .getVisibleLayersInZOrder() 106 | .stream() 107 | .filter(layer -> (layer instanceof ImageryLayer && layer.isVisible() && layer.getName().equals(samImage.getLayerName()))) 108 | .collect(Collectors.toList()); 109 | 110 | if (activeLayers.isEmpty()) { 111 | List imagerySources = ImageryLayerInfo 112 | .instance 113 | .getLayers() 114 | .stream() 115 | .filter(layer -> (layer.getName().equals(samImage.getLayerName()))) 116 | .collect(Collectors.toList()); 117 | 118 | if (!imagerySources.isEmpty()) { 119 | ImageryInfo imageryInfo = imagerySources.get(0); 120 | mapView.getLayerManager().addLayer(ImageryLayer.create(imageryInfo)); 121 | } 122 | } 123 | } catch (Exception e) { 124 | Logging.error(e); 125 | } 126 | 127 | ProjectionBounds projectionBounds = samImage.getProjectionBounds(); 128 | mapView.zoomTo(projectionBounds); 129 | mapView.zoomIn(); 130 | mapView.repaint(); 131 | } 132 | 133 | private void deleteAction() { 134 | try { 135 | samImage.removeCacheImge(); 136 | listener.removeSamImage(samImage); 137 | } catch (Exception e) { 138 | Logging.error(e); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImagePanelListener.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | public interface ImagePanelListener { 4 | void removeSamImage(SamImage samImage); 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/ImageSamPanelListener.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | 4 | import org.openstreetmap.josm.data.osm.Way; 5 | 6 | import java.util.ArrayList; 7 | 8 | public interface ImageSamPanelListener { 9 | void onAddSamImage(SamImage samImage); 10 | 11 | void onRemoveAll(); 12 | 13 | ArrayList getSamImageList(); 14 | 15 | SamImage getSamImageIncludepoint(double x, double y); 16 | 17 | void addLayer(); 18 | 19 | void addBboxLayer(Way way); 20 | 21 | } -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/LayerImageValues.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | import java.awt.image.BufferedImage; 4 | 5 | public class LayerImageValues { 6 | BufferedImage bufferedImage; 7 | String layerName; 8 | 9 | public LayerImageValues() { 10 | } 11 | 12 | public BufferedImage getBufferedImage() { 13 | return bufferedImage; 14 | } 15 | 16 | public void setBufferedImage(BufferedImage bufferedImage) { 17 | this.bufferedImage = bufferedImage; 18 | } 19 | 20 | public String getLayerName() { 21 | return layerName; 22 | } 23 | 24 | public void setLayerName(String layerName) { 25 | this.layerName = layerName; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/NumericField.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | import javax.swing.*; 4 | import javax.swing.text.DocumentFilter; 5 | import javax.swing.text.AttributeSet; 6 | import javax.swing.text.BadLocationException; 7 | import javax.swing.text.PlainDocument; 8 | 9 | public class NumericField extends JTextField { 10 | public NumericField(boolean allowDecimal) { 11 | super(); 12 | ((PlainDocument) this.getDocument()).setDocumentFilter(new DocumentFilter() { 13 | @Override 14 | public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { 15 | if (validateInput(string, allowDecimal)) { 16 | super.insertString(fb, offset, string, attr); 17 | firePropertyChange("text", "", getText()); 18 | } 19 | } 20 | 21 | @Override 22 | public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { 23 | if (validateInput(text, allowDecimal)) { 24 | super.replace(fb, offset, length, text, attrs); 25 | firePropertyChange("text", "", getText()); 26 | } 27 | } 28 | 29 | private boolean validateInput(String text, boolean allowDecimal) { 30 | if (allowDecimal) { 31 | return text.matches("^\\d+(\\.\\d+)?$"); 32 | } else { 33 | return text.matches("\\d*"); 34 | } 35 | } 36 | }); 37 | } 38 | } -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/SamImageGrid.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import org.locationtech.jts.geom.Point; 5 | import org.openstreetmap.josm.tools.Logging; 6 | 7 | import javax.swing.*; 8 | import java.awt.*; 9 | import java.io.File; 10 | import java.time.LocalDateTime; 11 | import java.time.format.DateTimeFormatter; 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.Comparator; 15 | 16 | public class SamImageGrid extends JPanel implements ImagePanelListener { 17 | ObjectMapper objectMapper = new ObjectMapper(); 18 | private final ArrayList samImageList; 19 | private final int maxWidth; 20 | 21 | public SamImageGrid(int maxWidth) { 22 | this.maxWidth = maxWidth; 23 | samImageList = new ArrayList<>(); 24 | setLayout(new GridLayout(0, 2, 1, 1)); 25 | 26 | // 27 | File cacheDir = new File(CommonUtils.magicWandCacheDirPath()); 28 | File[] cacheFiles = cacheDir.listFiles((dir, fileName) -> fileName.endsWith(".json")); 29 | if (cacheFiles != null) { 30 | Arrays.sort(cacheFiles, new Comparator() { 31 | @Override 32 | public int compare(File file1, File file2) { 33 | LocalDateTime dateTime1 = extractDateTimeFromFileName(file1.getName()); 34 | LocalDateTime dateTime2 = extractDateTimeFromFileName(file2.getName()); 35 | return dateTime1.compareTo(dateTime2); 36 | } 37 | }); 38 | } 39 | 40 | 41 | for (File jsonFile : cacheFiles) { 42 | try { 43 | SamImage samImage = objectMapper.readValue(jsonFile, SamImage.class); 44 | addSamImage(samImage); 45 | } catch (Exception e) { 46 | Logging.error(e); 47 | } 48 | } 49 | } 50 | 51 | public void addSamImage(SamImage samImage) { 52 | if (samImage.getEncode() && !samImage.getImageUrl().isEmpty()) { 53 | samImageList.add(0, samImage); 54 | } 55 | updateJpanel(); 56 | } 57 | 58 | public void removeAllSamImage() { 59 | samImageList.clear(); 60 | updateJpanel(); 61 | } 62 | 63 | public ArrayList getSamImageList() { 64 | return samImageList; 65 | } 66 | 67 | public SamImage getSamImageIncludepoint(Point p) { 68 | for (SamImage s : samImageList) { 69 | if (s.containsPoint(p)) { 70 | return s; 71 | } 72 | } 73 | return null; 74 | } 75 | 76 | private void updateJpanel() { 77 | removeAll(); 78 | for (SamImage samImage : samImageList) { 79 | add(new ImagePanel(samImage, this.maxWidth, this)); 80 | } 81 | revalidate(); 82 | repaint(); 83 | } 84 | 85 | private LocalDateTime extractDateTimeFromFileName(String fileName) { 86 | try { 87 | // '2024_10_07__12_17_22__farm.json' 88 | String[] parts = fileName.split("__"); 89 | String datePart = parts[0]; // '2024_10_07' 90 | String timePart = parts[1]; // '12_17_22' 91 | 92 | String dateTimeString = datePart + " " + timePart; 93 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd HH_mm_ss"); 94 | 95 | return LocalDateTime.parse(dateTimeString, formatter); 96 | } catch (Exception e) { 97 | Logging.error("Error parsing date from file name: " + fileName); 98 | return LocalDateTime.MIN; 99 | } 100 | } 101 | 102 | @Override 103 | public void removeSamImage(SamImage samImage) { 104 | try { 105 | samImageList.remove(samImage); 106 | updateJpanel(); 107 | } catch (Exception e) { 108 | Logging.error(e); 109 | 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/samDto/DecodeRequestBody.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.samDto; 2 | 3 | import java.util.List; 4 | 5 | public class DecodeRequestBody { 6 | private String action_type; 7 | private List bbox; 8 | private String crs; 9 | private String id; 10 | private List> point_coords; 11 | private List point_labels; 12 | private String project; 13 | private Integer zoom; 14 | private String return_format; 15 | private double simplify_tolerance; 16 | private int area_val; 17 | 18 | public DecodeRequestBody(String action_type, List bbox, String id, List> point_coords, List point_labels, String project, Integer zoom) { 19 | this.action_type = action_type; 20 | this.bbox = bbox; 21 | this.crs = "EPSG:4326"; 22 | this.id = id; 23 | this.point_coords = point_coords; 24 | this.point_labels = point_labels; 25 | this.project = project; 26 | this.zoom = zoom; 27 | this.return_format = "geojson"; 28 | this.simplify_tolerance = 0.000002; 29 | this.area_val = 15; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "DecodeRequestBody{" + 35 | "action_type='" + action_type + '\'' + 36 | ", bbox=" + bbox + 37 | ", crs='" + crs + '\'' + 38 | ", id='" + id + '\'' + 39 | ", point_coords=" + point_coords + 40 | ", point_labels=" + point_labels + 41 | ", project='" + project + '\'' + 42 | ", zoom=" + zoom + 43 | '}'; 44 | } 45 | 46 | public String getAction_type() { 47 | return action_type; 48 | } 49 | 50 | public void setAction_type(String action_type) { 51 | this.action_type = action_type; 52 | } 53 | 54 | public List getBbox() { 55 | return bbox; 56 | } 57 | 58 | public void setBbox(List bbox) { 59 | this.bbox = bbox; 60 | } 61 | 62 | public String getCrs() { 63 | return crs; 64 | } 65 | 66 | public void setCrs(String crs) { 67 | this.crs = crs; 68 | } 69 | 70 | public String getId() { 71 | return id; 72 | } 73 | 74 | public void setId(String id) { 75 | this.id = id; 76 | } 77 | 78 | public List> getPoint_coords() { 79 | return point_coords; 80 | } 81 | 82 | public void setPoint_coords(List> point_coords) { 83 | this.point_coords = point_coords; 84 | } 85 | 86 | public List getPoint_labels() { 87 | return point_labels; 88 | } 89 | 90 | public void setPoint_labels(List point_labels) { 91 | this.point_labels = point_labels; 92 | } 93 | 94 | public String getProject() { 95 | return project; 96 | } 97 | 98 | public void setProject(String project) { 99 | this.project = project; 100 | } 101 | 102 | public Integer getZoom() { 103 | return zoom; 104 | } 105 | 106 | public void setZoom(Integer zoom) { 107 | this.zoom = zoom; 108 | } 109 | 110 | public String getReturn_format() { 111 | return return_format; 112 | } 113 | 114 | public void setReturn_format(String return_format) { 115 | this.return_format = return_format; 116 | } 117 | 118 | public int getArea_val() { 119 | return area_val; 120 | } 121 | 122 | public void setArea_val(int area_val) { 123 | this.area_val = area_val; 124 | } 125 | 126 | public double getSimplify_tolerance() { 127 | return simplify_tolerance; 128 | } 129 | 130 | public void setSimplify_tolerance(double simplify_tolerance) { 131 | this.simplify_tolerance = simplify_tolerance; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/samDto/EncodeResponse.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.samDto; 2 | 3 | public class EncodeResponse { 4 | private String project; 5 | private String id; 6 | private double[] bbox; 7 | private int zoom; 8 | private String imageUrl; 9 | private String tifUrl; 10 | private String return_format; 11 | 12 | public EncodeResponse() { 13 | } 14 | 15 | public EncodeResponse(String project, String id, double[] bbox, int zoom, String imageUrl, String tifUrl, String return_format) { 16 | this.project = project; 17 | this.id = id; 18 | this.bbox = bbox; 19 | this.zoom = zoom; 20 | this.imageUrl = imageUrl; 21 | this.tifUrl = tifUrl; 22 | this.return_format = return_format; 23 | } 24 | 25 | // Getters y Setters 26 | public String getProject() { 27 | return project; 28 | } 29 | 30 | public void setProject(String project) { 31 | this.project = project; 32 | } 33 | 34 | public String getId() { 35 | return id; 36 | } 37 | 38 | public void setId(String id) { 39 | this.id = id; 40 | } 41 | 42 | public double[] getBbox() { 43 | return bbox; 44 | } 45 | 46 | public void setBbox(double[] bbox) { 47 | this.bbox = bbox; 48 | } 49 | 50 | public int getZoom() { 51 | return zoom; 52 | } 53 | 54 | public void setZoom(int zoom) { 55 | this.zoom = zoom; 56 | } 57 | 58 | public String getImageUrl() { 59 | return imageUrl; 60 | } 61 | 62 | public void setImageUrl(String imageUrl) { 63 | this.imageUrl = imageUrl; 64 | } 65 | 66 | public String getTifUrl() { 67 | return tifUrl; 68 | } 69 | 70 | public void setTifUrl(String tifUrl) { 71 | this.tifUrl = tifUrl; 72 | } 73 | 74 | public String getReturn_format() { 75 | return return_format; 76 | } 77 | 78 | public void setReturn_format(String return_format) { 79 | this.return_format = return_format; 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/org/openstreetmap/josm/plugins/devseed/JosmMagicWand/utils/samDto/EncondeRequestBody.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.josm.plugins.devseed.JosmMagicWand.utils.samDto; 2 | 3 | import java.util.List; 4 | 5 | public class EncondeRequestBody { 6 | private String canvas_image; 7 | private String crs; 8 | private String id; 9 | private String project; 10 | private Integer zoom; 11 | private List bbox; 12 | private String return_format; 13 | private double simplify_tolerance; 14 | private int area_val; 15 | 16 | public EncondeRequestBody(String canvas_image, String project, Integer zoom, List bbox, String id, int area_val, double simplify_tolerance) { 17 | this.canvas_image = canvas_image; 18 | this.crs = "EPSG:4326"; 19 | this.id = id; 20 | this.project = project; 21 | this.zoom = zoom; 22 | this.bbox = bbox; 23 | this.return_format = "geojson"; 24 | this.area_val = area_val; 25 | this.simplify_tolerance = simplify_tolerance; 26 | 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "EncondeRequestBody{" + 32 | "bbox=" + bbox + 33 | ", canvas_image='" + canvas_image + '\'' + 34 | ", crs='" + crs + '\'' + 35 | ", id='" + id + '\'' + 36 | ", project='" + project + '\'' + 37 | ", zoom=" + zoom + 38 | '}'; 39 | } 40 | 41 | public Integer getZoom() { 42 | return zoom; 43 | } 44 | 45 | public void setZoom(Integer zoom) { 46 | this.zoom = zoom; 47 | } 48 | 49 | public String getProject() { 50 | return project; 51 | } 52 | 53 | public void setProject(String project) { 54 | this.project = project; 55 | } 56 | 57 | public String getId() { 58 | return id; 59 | } 60 | 61 | public void setId(String id) { 62 | this.id = id; 63 | } 64 | 65 | public String getCrs() { 66 | return crs; 67 | } 68 | 69 | public void setCrs(String crs) { 70 | this.crs = crs; 71 | } 72 | 73 | public String getCanvas_image() { 74 | return canvas_image; 75 | } 76 | 77 | public void setCanvas_image(String canvas_image) { 78 | this.canvas_image = canvas_image; 79 | } 80 | 81 | public List getBbox() { 82 | return bbox; 83 | } 84 | 85 | public void setBbox(List bbox) { 86 | this.bbox = bbox; 87 | } 88 | 89 | public String getReturn_format() { 90 | return return_format; 91 | } 92 | 93 | public void setReturn_format(String return_format) { 94 | this.return_format = return_format; 95 | } 96 | 97 | public int getArea_val() { 98 | return area_val; 99 | } 100 | 101 | public void setArea_val(int area_val) { 102 | this.area_val = area_val; 103 | } 104 | 105 | public double getSimplify_tolerance() { 106 | return simplify_tolerance; 107 | } 108 | 109 | public void setSimplify_tolerance(double simplify_tolerance) { 110 | this.simplify_tolerance = simplify_tolerance; 111 | } 112 | } 113 | --------------------------------------------------------------------------------