├── .classpath ├── .eclipse-pmd ├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.yaml └── workflows │ └── ant.yml ├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── .idea └── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── .project ├── .settings ├── launchers │ ├── Build JOSM-Mapillary.launch │ ├── Launch JOSM with JOSM-Mapillary loaded.launch │ ├── Remote debug JOSM-Mapillary.launch │ └── Test JOSM-Mapillary.launch ├── org.eclipse.buildship.core.prefs ├── org.eclipse.core.resources.prefs ├── org.eclipse.core.runtime.prefs ├── org.eclipse.jdt.core.prefs └── org.eclipse.jdt.ui.prefs ├── CHANGELOG.md ├── CONTRIBUTING.md ├── INSTALL.md ├── LICENSE ├── LICENSE.md ├── LICENSE_apache ├── LICENSE_ofl-1.1 ├── README.md ├── build.xml ├── config ├── codecov │ └── codecov.yml ├── format │ └── code_format.xml └── pmd │ └── ruleset.xml ├── data ├── gh-pages ├── .nojekyll ├── fonts │ └── Roboto-Light.ttf ├── img │ ├── bg.png │ ├── josm_logo_100.png │ └── mapillary_logo_100.png ├── index.html └── style │ └── default.css ├── mapillary_structure.json ├── pom.xml ├── src └── main │ ├── java │ └── org │ │ └── openstreetmap │ │ └── josm │ │ └── plugins │ │ ├── datepicker │ │ ├── DatePicker.java │ │ ├── IDatePicker.java │ │ └── impl │ │ │ ├── DatePickerJDatePicker.java │ │ │ └── DatePickerSwing.java │ │ └── mapillary │ │ ├── MapillaryKeyListener.java │ │ ├── MapillaryLayerListener.java │ │ ├── MapillaryPlugin.java │ │ ├── actions │ │ ├── MapObjectLayerAction.java │ │ ├── MapPointObjectLayerAction.java │ │ ├── MapillaryDownloadAction.java │ │ ├── MapillaryExportAction.java │ │ ├── MapillaryZoomAction.java │ │ ├── SmartEditAddAction.java │ │ ├── SmartEditRemoveAction.java │ │ └── package-info.java │ │ ├── cache │ │ ├── CacheUtils.java │ │ ├── Caches.java │ │ ├── MapillaryCache.java │ │ └── package-info.java │ │ ├── command │ │ ├── AddMapillaryObjectCommand.java │ │ ├── DeleteCommand.java │ │ └── GenericCommand.java │ │ ├── data │ │ ├── mapillary │ │ │ ├── AdditionalInstructions.java │ │ │ ├── DataType.java │ │ │ ├── DetectionType.java │ │ │ ├── ImageMode.java │ │ │ ├── ImageNavigation.java │ │ │ ├── MapillaryDownloader.java │ │ │ ├── MapillaryFilterModel.java │ │ │ ├── MapillaryNode.java │ │ │ ├── MapillaryPrimitive.java │ │ │ ├── MapillarySequence.java │ │ │ ├── ObjectDetections.java │ │ │ ├── OrganizationRecord.java │ │ │ ├── VectorDataSelectionListener.java │ │ │ └── smartedit │ │ │ │ └── IgnoredObjects.java │ │ └── osm │ │ │ └── event │ │ │ └── FilterEventListener.java │ │ ├── gui │ │ ├── DataMouseListener.java │ │ ├── DeveloperToggleAction.java │ │ ├── ImageCheckBoxButton.java │ │ ├── ImageColorPicker.java │ │ ├── MapillaryPreferenceSetting.java │ │ ├── boilerplate │ │ │ └── MapillaryButton.java │ │ ├── dialog │ │ │ ├── ImageNavigationDialog.java │ │ │ ├── MapillaryExpertFilterDialog.java │ │ │ ├── MapillaryExportDialog.java │ │ │ ├── MapillaryFilterDialog.java │ │ │ ├── MapillaryFilterTableModel.java │ │ │ ├── OldVersionDialog.java │ │ │ ├── OrganizationListCellRenderer.java │ │ │ ├── ResetListener.java │ │ │ ├── TrafficSignFilter.java │ │ │ └── UserProfileListCellRenderer.java │ │ ├── imageinfo │ │ │ ├── AddTagToPrimitiveAction.java │ │ │ ├── ClipboardAction.java │ │ │ ├── ImageInfoPanel.java │ │ │ ├── MapillaryAction.java │ │ │ └── WebLinkAction.java │ │ ├── layer │ │ │ ├── AdditionalActionPanel.java │ │ │ ├── MapillaryCustomizeDrawingAction.java │ │ │ ├── MapillaryLayer.java │ │ │ ├── MapillaryLayerDrawTypes.java │ │ │ ├── PointObjectLayer.java │ │ │ └── geoimage │ │ │ │ └── MapillaryImageEntry.java │ │ ├── package-info.java │ │ ├── preferences │ │ │ └── display │ │ │ │ └── MapillaryGPXSettingsPanel.java │ │ ├── widget │ │ │ └── DisableShortcutsOnFocusGainedJSpinner.java │ │ └── workers │ │ │ ├── MapillaryNodeDownloader.java │ │ │ ├── MapillaryNodesDownloader.java │ │ │ ├── MapillarySequenceDownloader.java │ │ │ └── MapillaryUIDownloader.java │ │ ├── io │ │ ├── download │ │ │ ├── TileAddEventSource.java │ │ │ └── TileAddListener.java │ │ ├── export │ │ │ ├── MapillaryExportDownloadThread.java │ │ │ ├── MapillaryExportManager.java │ │ │ ├── MapillaryExportWriterThread.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ └── remotecontrol │ │ │ ├── MapillaryFilterRemoteControl.java │ │ │ └── MapillaryRemoteControl.java │ │ ├── model │ │ ├── ImageDetection.java │ │ ├── KeyIndexedObject.java │ │ ├── SpecialImageArea.java │ │ └── UserProfile.java │ │ ├── oauth │ │ ├── MapillaryLoginListener.java │ │ ├── MapillaryUser.java │ │ ├── OAuthPortListener.java │ │ ├── OAuthUtils.java │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── spi │ │ └── preferences │ │ │ ├── ApiKeyReader.java │ │ │ ├── IMapillaryUrlChange.java │ │ │ ├── IMapillaryUrls.java │ │ │ ├── MapillaryConfig.java │ │ │ └── MapillaryUrls.java │ │ └── utils │ │ ├── DetectionVerification.java │ │ ├── ImageMetaDataUtil.java │ │ ├── ImageUtil.java │ │ ├── MapillaryColorScheme.java │ │ ├── MapillaryImageUtils.java │ │ ├── MapillaryKeys.java │ │ ├── MapillaryMapFeatureUtils.java │ │ ├── MapillaryProperties.java │ │ ├── MapillarySequenceUtils.java │ │ ├── MapillaryUserUtils.java │ │ ├── MapillaryUtils.java │ │ ├── OffsetUtils.java │ │ ├── ReflectionUtils.java │ │ ├── SecurityManagerUtils.java │ │ ├── api │ │ ├── JsonDecoder.java │ │ ├── JsonImageDetailsDecoder.java │ │ ├── JsonImageDetectionDecoder.java │ │ ├── JsonMapObjectDecoder.java │ │ ├── JsonSequencesDecoder.java │ │ ├── JsonTagMapDecoder.java │ │ └── JsonUserProfileDecoder.java │ │ └── package-info.java │ ├── po │ ├── cs.po │ ├── da.po │ ├── de.po │ ├── de_DE.po │ ├── el.po │ ├── es.po │ ├── fr.po │ ├── hu.po │ ├── it.po │ ├── ja.po │ ├── ko.po │ ├── nl.po │ ├── pl.po │ ├── pt.po │ ├── ru.po │ ├── sk.po │ ├── sr-latin.po │ ├── uk.po │ ├── zh_CN.po │ └── zh_TW.po │ └── resources │ ├── data │ ├── ar.lang │ ├── ast.lang │ ├── be.lang │ ├── bg.lang │ ├── ca-valencia.lang │ ├── ca.lang │ ├── cs.lang │ ├── cy.lang │ ├── da.lang │ ├── de.lang │ ├── el.lang │ ├── en.lang │ ├── en_AU.lang │ ├── en_CA.lang │ ├── en_GB.lang │ ├── eo.lang │ ├── es.lang │ ├── et.lang │ ├── fa.lang │ ├── fi.lang │ ├── fo.lang │ ├── fr.lang │ ├── gl.lang │ ├── hu.lang │ ├── id.lang │ ├── is.lang │ ├── it.lang │ ├── ja.lang │ ├── km.lang │ ├── ko.lang │ ├── lt.lang │ ├── mr.lang │ ├── nb.lang │ ├── nl.lang │ ├── pl.lang │ ├── pt.lang │ ├── pt_BR.lang │ ├── ru.lang │ ├── sk.lang │ ├── sr-latin.lang │ ├── sv.lang │ ├── tr.lang │ ├── uk.lang │ ├── zh_CN.lang │ └── zh_TW.lang │ ├── detections │ ├── complementary.json │ ├── construction.json │ ├── detections.schema │ ├── ignorable.json │ ├── information.json │ ├── marking.json │ ├── object.json │ ├── regulatory.json │ └── warning.json │ ├── images │ ├── dialogs │ │ ├── blue.svg │ │ ├── mapillary-cancel.svg │ │ ├── mapillary-clear.svg │ │ ├── mapillary-download.svg │ │ ├── mapillary-filter-expert.svg │ │ ├── mapillary-filter.svg │ │ ├── mapillary-history.svg │ │ ├── mapillary-info.svg │ │ ├── mapillary-main.svg │ │ ├── mapillary-restart.svg │ │ ├── mapillary-upload.svg │ │ ├── mapillaryPause.png │ │ ├── mapillaryPlay.png │ │ ├── mapillaryStop.png │ │ └── red.svg │ ├── fake-avatar.png │ ├── josm-ca │ │ ├── current-ca.svg │ │ ├── default-ca-hover.svg │ │ ├── default-ca.svg │ │ ├── deleted-ca-hover.svg │ │ ├── deleted-ca.svg │ │ ├── private-ca-hover.svg │ │ ├── private-ca.svg │ │ ├── sequence-ca-hover.svg │ │ ├── sequence-ca.svg │ │ └── sign-detection.svg │ ├── link.svg │ ├── mapicon.svg │ ├── mapillary-eyedropper.svg │ ├── mapillary-logo-white.png │ ├── mapillary-logo.svg │ ├── mapmode │ │ ├── mapillary-edit.svg │ │ ├── mapillary-join.svg │ │ └── mapillary-select.svg │ ├── signs │ │ ├── crossing.png │ │ ├── intersection_danger.png │ │ ├── no_entry.png │ │ ├── no_overtaking.png │ │ ├── no_parking.png │ │ ├── no_turn.png │ │ ├── only_straight_on.png │ │ ├── roundabout_right.png │ │ ├── speed.png │ │ ├── stop.png │ │ └── uneven.png │ └── unknown-mapobject-type.svg │ └── mapcss │ └── MapillaryImagery.mapcss └── test ├── README ├── data ├── __files │ └── api │ │ └── v4 │ │ └── responses │ │ ├── README.md │ │ ├── coverageTiles │ │ └── mly1_public │ │ │ └── 2 │ │ │ └── 14 │ │ │ ├── 3251 │ │ │ ├── 6257.mvt │ │ │ └── 6258.mvt │ │ │ └── 3252 │ │ │ ├── 6257.mvt │ │ │ └── 6258.mvt │ │ └── graph │ │ ├── 104214208486349.json │ │ ├── 104214208486350.json │ │ ├── 135511895288847.json │ │ ├── 135511895288847 │ │ └── detections.json │ │ ├── 148137757289079.json │ │ ├── 148137757289079 │ │ └── detections.json │ │ ├── 308609047601518.json │ │ ├── 308609047601518 │ │ └── detections.json │ │ ├── 311681117131457.json │ │ ├── 311681117131457 │ │ └── detections.json │ │ ├── 311799370533334.json │ │ ├── 311799370533334 │ │ └── detections.json │ │ ├── 338231874314914.json │ │ ├── 4235112816526838.json │ │ ├── 4235112816526838 │ │ └── detections.json │ │ ├── 464249047982277.json │ │ ├── 464249047982277 │ │ └── detections.json │ │ ├── 496980935069177.json │ │ ├── 496980935069177 │ │ └── detections.json │ │ ├── README.md │ │ ├── application_request_limit_reached.json │ │ ├── image_ids │ │ └── 7nfcwfvjdtphz7yj6zat6a.json │ │ ├── internal_server_error.json │ │ ├── requirements.txt │ │ └── update.py ├── api │ └── v3 │ │ ├── requests │ │ ├── changeset.json │ │ ├── rotation_only_changeset.json │ │ ├── single_image_changeset.json │ │ └── translation_only_changeset.json │ │ └── responses │ │ ├── README.md │ │ ├── imageDetection.json │ │ ├── image_detections_QEVZ1tp-PmrwtqhSwdW9fQ.geojson │ │ ├── images_LwrHXqFRN_pszCopTKHF_Q.geojson │ │ ├── mapObject.json │ │ ├── searchImageDetections.json │ │ ├── searchImages.json │ │ ├── searchMapObjects.json │ │ ├── searchSequences.json │ │ ├── searchSequencesTicket20211Area1.geojson │ │ ├── sequence.json │ │ ├── userProfile.json │ │ └── userProfile2.json ├── exifTestImages │ ├── dateTimeOnly.jpg │ ├── dateTimeOnly.metadata.txt │ ├── generateExifTaggedImages.sh │ ├── gpsDirectionOnly.jpg │ ├── gpsDirectionOnly.metadata.txt │ ├── latLonOnly.jpg │ ├── latLonOnly.metadata.txt │ ├── untagged.jpg │ └── untagged.png ├── preferences │ └── preferences.xml ├── xmpTestImages │ ├── xmpProjectionOnly.jpg │ └── xmpProjectionOnly.xml └── zeroByteFile ├── resources └── unit └── org └── openstreetmap └── josm └── plugins ├── datepicker └── impl │ └── GenericDateImplementationTest.java └── mapillary ├── MapillaryKeyListenerTest.java ├── actions ├── MapObjectLayerActionTest.java └── SmartEditAddActionTest.java ├── cache ├── CachesTest.java └── MapillaryCacheTest.java ├── command └── DeleteCommandTest.java ├── data └── mapillary │ ├── AdditionalInstructionsTest.java │ ├── MapillaryFilterModelTest.java │ └── ObjectDetectionsTest.java ├── gui ├── DataMouseListenerTest.java ├── MapillaryPreferenceSettingTest.java ├── imageinfo │ └── AddTagToPrimitiveActionTest.java └── layer │ ├── MapillaryLayerTest.java │ └── PointObjectLayerTest.java ├── io ├── export │ └── MapillaryExportManagerTest.java └── remotecontrol │ └── MapillaryRemoteControlTest.java ├── model └── ImageDetectionTest.java ├── oauth ├── OAuthPortListenerTest.java └── OAuthUtilsTest.java ├── testutils └── annotations │ ├── AwaitThreadFinish.java │ ├── GuiWorkersStopper.java │ ├── IntegrationTest.java │ ├── LoggingHandler.java │ ├── MapillaryCaches.java │ ├── MapillaryLayerAnnotation.java │ ├── MapillaryURLWireMock.java │ ├── MapillaryURLWireMockErrors.java │ ├── ObjectDetectionsAnnotation.java │ └── SecurityManagerTest.java └── utils ├── ImageMetaDataUtilTest.java ├── ImageUtilTest.java ├── JsonUtil.java ├── MapillaryColorSchemeTest.java ├── MapillaryPropertiesTest.java ├── MapillaryURLTest.java ├── TestUtil.java └── api ├── JsonDecoderTest.java ├── JsonImageDetailsDecoderTest.java ├── JsonImageDetectionDecoderTest.java ├── JsonMapObjectDecoderTest.java ├── JsonSequencesDecoderTest.java └── JsonUserProfileDecoderTest.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /.eclipse-pmd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /gradlew.bat text eol=crlf 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Bug]: " 4 | labels: ["bug", "triage"] 5 | assignees: 6 | - tsmock 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thank you for taking the time to fill out this bug report! 12 | 13 | Please consider opening a ticket at [JOSM Trac](https://josm.openstreetmap.de/newticket?component=Plugin+mapillary) instead. 14 | - type: textarea 15 | id: expected-behavior 16 | attributes: 17 | label: Expected Behavior 18 | description: Please describe the behavior you expected 19 | - type: textarea 20 | id: actual-behavior 21 | attributes: 22 | label: Actual Behavior 23 | description: Please describe the behavior that you saw 24 | - type: textarea 25 | id: reproduce 26 | attributes: 27 | label: How to reproduce the issue 28 | description: Please describe if and how the issue is reproducible 29 | - type: textarea 30 | id: status-report 31 | attributes: 32 | label: JOSM Status Report 33 | description: Please copy and paste the [Status Report](https://josm.openstreetmap.de/wiki/Help/Action/ShowStatusReport) from JOSM. This will be automatically formatted, so no need for any formatting marks. 34 | render: text 35 | - type: textarea 36 | attributes: 37 | label: Additional Information 38 | description: | 39 | Anything else that may be useful for troubleshooting and/or fixing the problem, such as error messages, screenshots, or logs. 40 | 41 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 42 | validations: 43 | required: false 44 | 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | /.classpath 3 | /.project 4 | /.settings/org.sonarlint.* 5 | /bin/ 6 | 7 | # IntelliJ idea 8 | /*.iml 9 | /*.iws 10 | /*.ipr 11 | /out/ 12 | /.idea/* 13 | !/.idea/codeStyles/ 14 | /.idea/codeStyles/* 15 | !/.idea/codeStyles/codeStyleConfig.xml 16 | !/.idea/codeStyles/Project.xml 17 | 18 | # Gradle 19 | /build/ 20 | /.gradle/ 21 | 22 | /test/data/preferences/ 23 | 24 | # Netbeans 25 | /.nb-gradle/ 26 | 27 | /bin-test/ 28 | 29 | # Private key files 30 | /src/main/resources/mapillary_api_keys.json 31 | 32 | javadoc 33 | lib 34 | 35 | checkstyle-josm-Mapillary.xml -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/.gitmodules -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | JOSM-Mapillary 4 | Allows the user to work with pictures hosted at mapillary.com 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.sonarlint.eclipse.core.sonarlintBuilder 15 | 16 | 17 | 18 | 19 | ch.acanda.eclipse.pmd.builder.PMDBuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.buildship.core.gradleprojectbuilder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.jdt.core.javanature 31 | org.sonarlint.eclipse.core.sonarlintNature 32 | ch.acanda.eclipse.pmd.builder.PMDNature 33 | org.eclipse.buildship.core.gradleprojectnature 34 | org.apache.ivyde.eclipse.ivynature 35 | 36 | 37 | -------------------------------------------------------------------------------- /.settings/launchers/Build JOSM-Mapillary.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.settings/launchers/Launch JOSM with JOSM-Mapillary loaded.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.settings/launchers/Test JOSM-Mapillary.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | build.commands=org.eclipse.jdt.core.javabuilder,org.sonarlint.eclipse.core.sonarlintBuilder,ch.acanda.eclipse.pmd.builder.PMDBuilder,org.eclipse.buildship.core.gradleprojectbuilder 2 | connection.arguments= 3 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 4 | connection.gradle.user.home=null 5 | connection.java.home=null 6 | connection.jvm.arguments= 7 | connection.project.dir= 8 | derived.resources=.gradle,build 9 | eclipse.preferences.version=1 10 | natures=org.eclipse.jdt.core.javanature,org.sonarlint.eclipse.core.sonarlintNature,ch.acanda.eclipse.pmd.builder.PMDNature,org.eclipse.buildship.core.gradleprojectnature 11 | project.path=\: 12 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.runtime.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | line.separator=\n 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guidelines 2 | 3 | If you want to make a contribution to this repository, just go ahead, clone this repository (see 4 | [INSTALL.md](INSTALL.md) for instructions) and make the changes you'd like to do. 5 | 6 | When you want us to include your changes, you're welcome to open a pull request. We'll review it, give you feedback 7 | on it and if we like your changes, we'll apply them to the plugin. 8 | 9 | ## License 10 | 11 | All contributions to this repository are licensed under the GNU General Public License v2 or later. 12 | 13 | ## Code formatting 14 | 15 | The following format of source code files is preferred in this repository: 16 | * Indentation with 4 spaces per indentation level 17 | * line endings should be UNIX-style line endings (LF) 18 | * one newline (LF) at the end of the file 19 | * where possible don't make lines longer than 120 characters 20 | * avoid trailing whitespace 21 | 22 | For ease of moving code to JOSM, code should be formatted the same way JOSM formats code. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Mapillary](https://mapillary.com)-plugin for [JOSM](https://josm.openstreetmap.de) 2 | 3 | [![build status](https://gitlab.com/JOSM/plugin/Mapillary/badges/master/pipeline.svg)](https://gitlab.com/JOSM/plugin/Mapillary/pipelines) 4 | [![code coverage](https://gitlab.com/JOSM/plugin/Mapillary/badges/master/coverage.svg)](https://codecov.io/github/JOSM/Mapillary?branch=master) 5 | [![latest release](https://img.shields.io/github/release/JOSM/Mapillary.svg?style=flat-square&maxAge=7200)](https://gitlab.com/JOSM/plugin/Mapillary/releases) 6 | [![license: GPLv2 or later](https://img.shields.io/badge/license-GPLv2_or_later-blue.svg?style=flat-square&maxAge=7200)](https://gitlab.com/JOSM/plugin/Mapillary/blob/master/LICENSE.md) 7 | 8 | A plugin for showing Mapillary images inside the OpenStreetMap-Editor JOSM. 9 | 10 | You can download images from [mapillary.com](https://mapillary.com/app). 11 | 12 | For instructions on setting up your local copy of this repository, see [INSTALL.md](INSTALL.md). 13 | 14 | # Contributing 15 | Our contribution guidelines can be found in [CONTRIBUTING.md](CONTRIBUTING.md). 16 | 17 | - The **source code** locations 18 | - [GitHub](https://github.com/JOSM/mapillary) 19 | - [JOSM GitLab Group](https://gitlab.com/JOSM/plugin/Mapillary) 20 | - **Issues** are managed in [JOSM Trac](https://josm.openstreetmap.de/query?status=assigned&status=needinfo&status=new&status=reopened&component=Plugin+mapillary&group=component&max=200&col=id&col=summary&col=component&col=status&col=type&col=priority&order=priority&report=17) 21 | - Report a [New Ticket](https://josm.openstreetmap.de/newticket?component=Plugin+mapillary) 22 | - **Translations** are done on JOSM's [Launchpad](https://translations.launchpad.net/josm/trunk/+pots/josm/) and were previously done on [transifex](https://www.transifex.com/josm/josm/josm-plugin_Mapillary/). 23 | 24 | * Maintainers: 25 | * Taylor Smock (active, @smocktaylor) 26 | * nokutu (inactive) 27 | * floscher (inactive) 28 | * License: [GPL v2 or later](./LICENSE.md) 29 | * Feel free to contact me for any bug or suggestion. 30 | -------------------------------------------------------------------------------- /config/codecov/codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: on 5 | model_and_api: 6 | target: 95% 7 | flags: model_and_api 8 | flags: 9 | model_and_api: 10 | paths: 11 | - src/org/openstreetmap/josm/plugins/mapillary/utils/api/ 12 | - src/org/openstreetmap/josm/plugins/mapillary/model/ 13 | -------------------------------------------------------------------------------- /data: -------------------------------------------------------------------------------- 1 | src/main/resources/data -------------------------------------------------------------------------------- /gh-pages/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/gh-pages/.nojekyll -------------------------------------------------------------------------------- /gh-pages/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/gh-pages/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /gh-pages/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/gh-pages/img/bg.png -------------------------------------------------------------------------------- /gh-pages/img/josm_logo_100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/gh-pages/img/josm_logo_100.png -------------------------------------------------------------------------------- /gh-pages/img/mapillary_logo_100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/gh-pages/img/mapillary_logo_100.png -------------------------------------------------------------------------------- /gh-pages/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mapillary-plugin for JOSM 5 | 6 | 7 | Fork me on GitHub 12 | 13 | 14 |
15 |

Mapillary-plugin for JOSM

16 |

Developer resources

17 | 26 |
27 | -------------------------------------------------------------------------------- /gh-pages/style/default.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/Roboto-Light.ttf); 6 | } 7 | * { 8 | box-sizing: border-box; 9 | } 10 | body { 11 | font-family: Roboto, sans-serif; 12 | background-image: url('../img/bg.png'); 13 | background-color: #333; 14 | color:white; 15 | font-size: 18px; 16 | } 17 | h1,h2 { 18 | font-weight:100; 19 | } 20 | h1 { 21 | font-size:2.5em; 22 | } 23 | h2 { 24 | font-size:1.5em; 25 | } 26 | .container { 27 | text-align: center; 28 | } 29 | ul { 30 | padding:0; 31 | } 32 | ul li { 33 | list-style: none; 34 | } 35 | .container a { 36 | color:#ddd; 37 | text-decoration: none; 38 | border:1px solid white; 39 | padding:.75em; 40 | margin:.5em; 41 | display:inline-block; 42 | box-shadow: 0 0 0 #36af6d; 43 | transition:.25s ease box-shadow, .5s ease border-color, .5s ease color; 44 | } 45 | a:hover { 46 | color:#fff; 47 | border-color: #36af6d; 48 | box-shadow: 0 0 8px #36af6d; 49 | } 50 | -------------------------------------------------------------------------------- /mapillary_structure.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Mapillary JSOM plugin", 3 | "frameworks": [ 4 | "swing" 5 | ], 6 | "language": "java", 7 | "maintainers": [ 8 | "jpietri" 9 | ], 10 | "providers": [ 11 | { 12 | "dependencies": [ 13 | { 14 | "name": "api_v2" 15 | }, 16 | { 17 | "name": "api_v3" 18 | } 19 | ], 20 | "extDependencies": [ 21 | { 22 | "documentation": "https://josm.openstreetmap.de/", 23 | "name": "JOSM" 24 | } 25 | ], 26 | "description": "Mapillary JSOM plugin", 27 | "name": "josm_mapillary_plugin_provider", 28 | "services": [ 29 | { 30 | "description": "Mapillary JSOM plugin", 31 | "name": "josm_mapillary_plugin" 32 | } 33 | ], 34 | "type": "app_desktop" 35 | } 36 | ], 37 | "repo": "josm-mapillary-plugin" 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/datepicker/DatePicker.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.datepicker; 3 | 4 | import org.openstreetmap.josm.plugins.Plugin; 5 | import org.openstreetmap.josm.plugins.PluginInformation; 6 | 7 | /** 8 | * The plugin initializer for the DatePicker plugin 9 | * 10 | * @author Taylor Smock 11 | */ 12 | public final class DatePicker extends Plugin { 13 | public DatePicker(PluginInformation info) { 14 | super(info); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/datepicker/IDatePicker.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.datepicker; 3 | 4 | import java.time.Instant; 5 | import java.util.function.Consumer; 6 | 7 | import javax.swing.JComponent; 8 | 9 | import jakarta.annotation.Nonnull; 10 | import org.openstreetmap.josm.plugins.datepicker.impl.DatePickerSwing; 11 | import org.openstreetmap.josm.spi.preferences.Config; 12 | import org.openstreetmap.josm.tools.Logging; 13 | 14 | /** 15 | * This is a generic interface for date pickers. Use 16 | * {@link IDatePicker#getNewDatePicker} to get a new date picker. It uses the 17 | * {@code "datepicker.classname"} setting to determine the appropriate class. 18 | * 19 | * @author Taylor Smock 20 | * @param The component that the date picker returns for the UI 21 | */ 22 | public interface IDatePicker { 23 | /** 24 | * Set the date 25 | * 26 | * @param date The date to set 27 | */ 28 | void setInstant(@Nonnull Instant date); 29 | 30 | /** 31 | * Get the date 32 | * 33 | * @return The date 34 | */ 35 | @Nonnull 36 | Instant getInstant(); 37 | 38 | /** 39 | * Get the component 40 | * 41 | * @return The component to be added to a UI 42 | */ 43 | @Nonnull 44 | T getComponent(); 45 | 46 | /** 47 | * Reset the component 48 | */ 49 | void reset(); 50 | 51 | /** 52 | * Add an event handler for when the date changes 53 | * 54 | * @param function The function to call when the date changes 55 | */ 56 | void addEventHandler(@Nonnull Consumer> function); 57 | 58 | /** 59 | * Get a new date picker. The implementation may change. Only rely on this 60 | * interface. 61 | * 62 | * @return A new date picker 63 | */ 64 | @SuppressWarnings("unchecked") 65 | @Nonnull 66 | static IDatePicker getNewDatePicker() { 67 | String datePicker = Config.getPref().get("datepicker.classname", 68 | "org.openstreetmap.josm.plugins.datepicker.impl.DatePickerJDatePicker"); 69 | try { 70 | Class cls = Class.forName(datePicker); 71 | Object instance = cls.getConstructor().newInstance(); 72 | if (instance instanceof IDatePicker) { 73 | return (IDatePicker) instance; 74 | } 75 | } catch (ReflectiveOperationException e) { 76 | Logging.error(e); 77 | } 78 | // Fall back to basic text entry 79 | return (IDatePicker) ((IDatePicker) new DatePickerSwing()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/datepicker/impl/DatePickerSwing.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.datepicker.impl; 3 | 4 | import java.awt.event.FocusEvent; 5 | import java.awt.event.FocusListener; 6 | import java.time.Instant; 7 | import java.time.ZoneOffset; 8 | import java.time.ZonedDateTime; 9 | import java.time.format.DateTimeFormatter; 10 | import java.util.function.Consumer; 11 | 12 | import jakarta.annotation.Nonnull; 13 | import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField; 14 | import org.openstreetmap.josm.gui.widgets.JosmTextField; 15 | import org.openstreetmap.josm.plugins.datepicker.IDatePicker; 16 | 17 | /** 18 | * This is a fallback date picker. It is used when the set date picker fails to 19 | * load, for what ever reason. Do not directly use this implementation. 20 | * 21 | * @author Taylor Smock 22 | */ 23 | public class DatePickerSwing implements IDatePicker { 24 | private Instant date; 25 | private final JosmTextField component = new DisableShortcutsOnFocusGainedTextField("", 12); 26 | 27 | /** Create a new {@link DatePickerSwing} component */ 28 | public DatePickerSwing() { 29 | super(); 30 | component.setToolTipText("YYYY-MM-DD"); 31 | } 32 | 33 | @Override 34 | public void setInstant(@Nonnull Instant date) { 35 | this.date = date; 36 | if (Instant.MIN.isBefore(date)) { 37 | this.component 38 | .setText(DateTimeFormatter.ISO_DATE.format(ZonedDateTime.ofInstant(this.date, ZoneOffset.UTC))); 39 | } else { 40 | component.setText(""); 41 | } 42 | } 43 | 44 | @Nonnull 45 | @Override 46 | public Instant getInstant() { 47 | return this.date; 48 | } 49 | 50 | @Nonnull 51 | @Override 52 | public JosmTextField getComponent() { 53 | return component; 54 | } 55 | 56 | @Override 57 | public void reset() { 58 | component.setText(""); 59 | } 60 | 61 | @Override 62 | public void addEventHandler(@Nonnull Consumer> function) { 63 | component.addFocusListener(new FocusListener() { 64 | 65 | @Override 66 | public void focusGained(FocusEvent e) { 67 | // Do nothing 68 | } 69 | 70 | @Override 71 | public void focusLost(FocusEvent e) { 72 | setInstant(Instant.MIN); 73 | function.accept(DatePickerSwing.this); 74 | } 75 | }); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/MapillaryLayerListener.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary; 3 | 4 | import java.util.stream.Stream; 5 | 6 | import org.openstreetmap.josm.data.vector.VectorDataSet; 7 | import org.openstreetmap.josm.gui.layer.LayerManager; 8 | import org.openstreetmap.josm.plugins.mapillary.data.mapillary.VectorDataSelectionListener; 9 | import org.openstreetmap.josm.plugins.mapillary.gui.imageinfo.ImageInfoPanel; 10 | import org.openstreetmap.josm.plugins.mapillary.gui.layer.MapillaryLayer; 11 | import org.openstreetmap.josm.tools.Destroyable; 12 | 13 | /** 14 | * A listener that looks for new Mapillary Layers, and adds appropriate listeners 15 | * 16 | * @author Taylor Smock 17 | */ 18 | public class MapillaryLayerListener implements Destroyable, LayerManager.LayerChangeListener { 19 | private final LayerManager layerManager; 20 | 21 | public MapillaryLayerListener(LayerManager layerManager) { 22 | this.layerManager = layerManager; 23 | this.layerManager.addAndFireLayerChangeListener(this); 24 | } 25 | 26 | @Override 27 | public void layerAdded(LayerManager.LayerAddEvent e) { 28 | if (e.getAddedLayer() instanceof MapillaryLayer) { 29 | VectorDataSet dataSet = ((MapillaryLayer) e.getAddedLayer()).getData(); 30 | dataSet.addSelectionListener((VectorDataSelectionListener) ImageInfoPanel.getInstance()); 31 | Stream.of(MapillaryPlugin.getMapillaryDataListeners()).forEach(dataSet::addSelectionListener); 32 | } 33 | } 34 | 35 | @Override 36 | public void layerRemoving(LayerManager.LayerRemoveEvent e) { 37 | if (e.getRemovedLayer() instanceof MapillaryLayer) { 38 | VectorDataSet dataSet = ((MapillaryLayer) e.getRemovedLayer()).getData(); 39 | dataSet.removeSelectionListener((VectorDataSelectionListener) ImageInfoPanel.getInstance()); 40 | Stream.of(MapillaryPlugin.getMapillaryDataListeners()).forEach(dataSet::removeSelectionListener); 41 | } 42 | } 43 | 44 | @Override 45 | public void layerOrderChanged(LayerManager.LayerOrderChangeEvent e) { 46 | // Don't care 47 | } 48 | 49 | @Override 50 | public void destroy() { 51 | this.layerManager.removeAndFireLayerChangeListener(this); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/actions/MapObjectLayerAction.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.actions; 3 | 4 | import java.awt.event.ActionEvent; 5 | import java.awt.event.KeyEvent; 6 | 7 | import org.openstreetmap.josm.actions.JosmAction; 8 | import org.openstreetmap.josm.gui.MainApplication; 9 | import org.openstreetmap.josm.gui.util.GuiHelper; 10 | import org.openstreetmap.josm.plugins.mapillary.MapillaryPlugin; 11 | import org.openstreetmap.josm.plugins.mapillary.gui.layer.PointObjectLayer; 12 | import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryKeys; 13 | import org.openstreetmap.josm.tools.I18n; 14 | import org.openstreetmap.josm.tools.ImageProvider.ImageSizes; 15 | import org.openstreetmap.josm.tools.Shortcut; 16 | 17 | public class MapObjectLayerAction extends JosmAction { 18 | private static final long serialVersionUID = -8388752916891634738L; 19 | private static final String ACTION_NAME = I18n.marktr("Mapillary traffic signs layer"); 20 | private static final String DESCRIPTION = I18n 21 | .marktr("Displays the layer displaying the traffic sign objects detected by Mapillary"); 22 | 23 | public MapObjectLayerAction() { 24 | super( 25 | I18n.tr(ACTION_NAME), MapillaryPlugin.LOGO.setSize(ImageSizes.DEFAULT), I18n.tr(DESCRIPTION), 26 | Shortcut.registerShortcut("mapillary:trafficSignLayer", ACTION_NAME, KeyEvent.CHAR_UNDEFINED, Shortcut.NONE), 27 | false, "mapillary:trafficSignLayer", true); 28 | } 29 | 30 | @Override 31 | public void actionPerformed(ActionEvent e) { 32 | GuiHelper.runInEDTAndWait(() -> { 33 | // Synchronization lock must be held by EDT thread 34 | // See {@link LayerManager#addLayer(org.openstreetmap.josm.gui.layer.Layer, boolean)}. 35 | synchronized (MainApplication.getLayerManager()) { 36 | if (MainApplication.getLayerManager().getActiveDataSet() != null 37 | && MainApplication.getLayerManager().getLayersOfType(PointObjectLayer.class).parallelStream() 38 | .noneMatch(p -> MapillaryKeys.MAPILLARY_TRAFFIC_SIGNS.equals(p.getInfo()))) { 39 | MainApplication.getLayerManager() 40 | .addLayer(new PointObjectLayer(MapillaryKeys.MAPILLARY_TRAFFIC_SIGNS), false); 41 | } 42 | } 43 | }); 44 | } 45 | 46 | @Override 47 | public void updateEnabledState() { 48 | super.setEnabled(MainApplication.isDisplayingMapView()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/actions/package-info.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | /** 3 | * Actions that are normally attached to a button or a menu item and are then executed 4 | * to manipulate the {@link org.openstreetmap.josm.plugins.mapillary.gui.layer.MapillaryLayer} when 5 | * the button is clicked. 6 | */ 7 | package org.openstreetmap.josm.plugins.mapillary.actions; 8 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/cache/package-info.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | /** 3 | * This package is all about caching resources downloaded from 4 | * mapillary.com 5 | * for faster access to those resources in the future. 6 | */ 7 | package org.openstreetmap.josm.plugins.mapillary.cache; 8 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/command/AddMapillaryObjectCommand.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.command; 3 | 4 | import static org.openstreetmap.josm.tools.I18n.tr; 5 | 6 | import java.util.Collection; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import jakarta.annotation.Nullable; 10 | import org.openstreetmap.josm.command.Command; 11 | import org.openstreetmap.josm.data.osm.OsmPrimitive; 12 | import org.openstreetmap.josm.gui.MainApplication; 13 | 14 | /** 15 | * Command for adding Mapillary objects to OSM 16 | * 17 | * @author Taylor Smock 18 | */ 19 | public class AddMapillaryObjectCommand extends Command { 20 | 21 | @Nullable 22 | private final Command updateTagsCommand; 23 | @Nonnull 24 | private final GenericCommand deleteOriginal; 25 | 26 | /** 27 | * Create a new command for adding a mapillary object 28 | * 29 | * @param deleteOriginal The command to delete the original object from the Mapillary layer 30 | * @param updateTagsCommand The command to use to update tags 31 | */ 32 | public AddMapillaryObjectCommand(@Nonnull final GenericCommand deleteOriginal, 33 | @Nullable final Command updateTagsCommand) { 34 | super(updateTagsCommand != null ? updateTagsCommand.getAffectedDataSet() 35 | : MainApplication.getLayerManager().getEditDataSet()); 36 | this.updateTagsCommand = updateTagsCommand; 37 | this.deleteOriginal = deleteOriginal; 38 | } 39 | 40 | @Override 41 | public boolean executeCommand() { 42 | return super.executeCommand() && (updateTagsCommand == null || updateTagsCommand.executeCommand()) 43 | && deleteOriginal.executeCommand(); 44 | } 45 | 46 | @Override 47 | public void undoCommand() { 48 | super.undoCommand(); 49 | if (updateTagsCommand != null) { 50 | updateTagsCommand.undoCommand(); 51 | } 52 | deleteOriginal.undoCommand(); 53 | } 54 | 55 | @Override 56 | public void fillModifiedData(Collection modified, Collection deleted, 57 | Collection added) { 58 | if (updateTagsCommand != null) { 59 | updateTagsCommand.fillModifiedData(modified, deleted, added); 60 | } 61 | } 62 | 63 | @Override 64 | public String getDescriptionText() { 65 | return tr("Mapillary Smart Edit: Add objects"); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/command/GenericCommand.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.command; 3 | 4 | import java.util.Collection; 5 | 6 | import org.openstreetmap.josm.command.PseudoCommand; 7 | import org.openstreetmap.josm.data.osm.INode; 8 | import org.openstreetmap.josm.data.osm.IPrimitive; 9 | import org.openstreetmap.josm.data.osm.IRelation; 10 | import org.openstreetmap.josm.data.osm.IWay; 11 | import org.openstreetmap.josm.data.osm.OsmData; 12 | 13 | /** 14 | * A generic command class 15 | * 16 | * @param The base primitive class 17 | * @param The base node class 18 | * @param The base way class 19 | * @param The base relation class 20 | * @param The data set class 21 | */ 22 | public abstract class GenericCommand, R extends IRelation, D extends OsmData> 23 | implements PseudoCommand { 24 | 25 | private final D data; 26 | 27 | protected GenericCommand(D dataset) { 28 | this.data = dataset; 29 | } 30 | 31 | /** 32 | * Executes the command on the dataset. This implementation will remember all 33 | * primitives returned by fillModifiedData for restoring them on undo. 34 | *

35 | * The layer should be invalidated after execution so that it can be re-painted. 36 | * 37 | * @return true 38 | */ 39 | public abstract boolean executeCommand(); 40 | 41 | /** 42 | * Undoes the command. 43 | * It can be assumed that all objects are in the same state they were before. 44 | * It can also be assumed that executeCommand was called exactly once before. 45 | * This implementation undoes all objects stored by a former call to executeCommand. 46 | */ 47 | public abstract void undoCommand(); 48 | 49 | /** 50 | * Gets the data set this command affects. 51 | * 52 | * @return The data set. May be null if no layer was set and no edit layer was found. 53 | */ 54 | public D getAffectedDataSet() { 55 | return data; 56 | } 57 | 58 | /** 59 | * Return the primitives that take part in this command. 60 | * 61 | * @return primitives that take part in this command 62 | */ 63 | public abstract Collection getParticipatingIPrimitives(); 64 | 65 | /** 66 | * Fill collections with modified data 67 | * 68 | * @param modified The modified primitives 69 | * @param deleted The deleted primitives 70 | * @param added The added primitives 71 | */ 72 | public abstract void fillModifiedData(Collection modified, Collection deleted, Collection added); 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/data/mapillary/DataType.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.data.mapillary; 3 | 4 | import org.openstreetmap.josm.actions.ExpertToggleAction; 5 | import org.openstreetmap.josm.plugins.mapillary.gui.DeveloperToggleAction; 6 | 7 | /** 8 | * Use for features that should only be shown when expert/developer 9 | */ 10 | public enum DataType { 11 | /** Only visible with developer mode and expert mode */ 12 | TESTING(true, true), 13 | /** Only visible with expert mode */ 14 | PREVIEW(true, false), 15 | /** Always visible */ 16 | PRODUCTION(false, false); 17 | 18 | private final boolean expert; 19 | private final boolean developer; 20 | 21 | DataType(boolean expert, boolean developer) { 22 | this.expert = expert; 23 | this.developer = developer; 24 | } 25 | 26 | /** 27 | * Use to determine if something should be visible. Only use dynamically. 28 | * 29 | * @return {@code true} if it should be visible. 30 | */ 31 | public boolean shouldBeVisible() { 32 | boolean e = !this.expert || ExpertToggleAction.isExpert(); 33 | boolean d = !this.developer || DeveloperToggleAction.isDeveloper(); 34 | return e && d; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/data/mapillary/DetectionType.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.data.mapillary; 3 | 4 | /** 5 | * Base detection types for Mapillary object detections 6 | */ 7 | public enum DetectionType { 8 | /** Traffic sign type/class */ 9 | TRAFFIC_SIGN("signs"), 10 | /** Point object features like fire hydrants */ 11 | POINT("objects"), 12 | /** Line object features */ 13 | LINE(null), 14 | /** Segmentation features */ 15 | SEGMENTATION(null); 16 | 17 | private final String imageLocationString; 18 | 19 | /** 20 | * Create a new detection type 21 | * 22 | * @param imageLocationString {@code "mapillary_sprite_source/package_" + imageLocationString} 23 | */ 24 | DetectionType(String imageLocationString) { 25 | this.imageLocationString = imageLocationString == null ? null : "package_" + imageLocationString; 26 | } 27 | 28 | /** 29 | * The directory for the image location 30 | * 31 | * @return A path to be used as a directory when getting an image 32 | */ 33 | public String getImageLocationString() { 34 | return this.imageLocationString; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/data/mapillary/ImageMode.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.data.mapillary; 3 | 4 | import jakarta.annotation.Nonnull; 5 | 6 | /** 7 | * Possible image modes 8 | * 9 | * @author Taylor Smock 10 | */ 11 | public enum ImageMode { 12 | /** The default mode */ 13 | NORMAL, 14 | /** The mode used when walking */ 15 | WALK, 16 | /** When smart edits are being done */ 17 | SMART_EDIT; 18 | 19 | private static ImageMode currentMode = NORMAL; 20 | 21 | /** 22 | * Get the current mode 23 | * 24 | * @return The current mode 25 | */ 26 | public static ImageMode getMode() { 27 | return currentMode; 28 | } 29 | 30 | /** 31 | * Set the mode 32 | * 33 | * @param mode The new mode 34 | */ 35 | public static void setMode(@Nonnull ImageMode mode) { 36 | currentMode = mode; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/data/mapillary/VectorDataSelectionListener.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.data.mapillary; 3 | 4 | import org.openstreetmap.josm.data.osm.event.IDataSelectionListener; 5 | import org.openstreetmap.josm.data.vector.VectorDataSet; 6 | import org.openstreetmap.josm.data.vector.VectorNode; 7 | import org.openstreetmap.josm.data.vector.VectorPrimitive; 8 | import org.openstreetmap.josm.data.vector.VectorRelation; 9 | import org.openstreetmap.josm.data.vector.VectorWay; 10 | 11 | /** 12 | * A convenient listener for selection events in vector data 13 | */ 14 | public interface VectorDataSelectionListener 15 | extends IDataSelectionListener { 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/data/osm/event/FilterEventListener.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.data.osm.event; 3 | 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | import javax.swing.SwingUtilities; 9 | import javax.swing.event.TableModelEvent; 10 | import javax.swing.event.TableModelListener; 11 | 12 | import org.openstreetmap.josm.data.osm.Filter; 13 | import org.openstreetmap.josm.data.osm.FilterMatcher; 14 | import org.openstreetmap.josm.data.osm.FilterWorker; 15 | import org.openstreetmap.josm.data.osm.IFilterablePrimitive; 16 | import org.openstreetmap.josm.data.osm.OsmData; 17 | import org.openstreetmap.josm.data.osm.search.SearchParseError; 18 | import org.openstreetmap.josm.gui.MainApplication; 19 | import org.openstreetmap.josm.gui.layer.Layer; 20 | import org.openstreetmap.josm.plugins.mapillary.gui.dialog.MapillaryExpertFilterDialog; 21 | import org.openstreetmap.josm.tools.Logging; 22 | 23 | /** 24 | * This class allows layers to listen for changes to the filter dialog, and have the filters applied to an arbitrary 25 | * dataset. 26 | * 27 | * @author Taylor Smock 28 | */ 29 | public class FilterEventListener implements TableModelListener { 30 | private final Layer layer; 31 | private final OsmData data; 32 | public final FilterMatcher matcher; 33 | 34 | public FilterEventListener(Layer layer, OsmData data) { 35 | this.layer = layer; 36 | this.data = data; 37 | matcher = new FilterMatcher(); 38 | } 39 | 40 | @Override 41 | public void tableChanged(TableModelEvent e) { 42 | updateAndRunFilters(); 43 | } 44 | 45 | public synchronized void updateAndRunFilters() { 46 | matcher.reset(); 47 | if (MainApplication.getMap() != null) { 48 | for (List filters : Arrays.asList( 49 | MapillaryExpertFilterDialog.getInstance().getFilterModel().getFilters(), 50 | MainApplication.getMap().filterDialog.getFilterModel().getFilters())) { 51 | for (Filter filter : filters) { 52 | try { 53 | matcher.add(filter); 54 | } catch (SearchParseError e1) { 55 | Logging.error(e1); 56 | } 57 | } 58 | } 59 | } 60 | FilterWorker.executeFilters( 61 | data.allPrimitives().stream().filter(p -> p.getReferrers().isEmpty()).collect(Collectors.toList()), 62 | matcher); 63 | SwingUtilities.invokeLater(layer::invalidate); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/boilerplate/MapillaryButton.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.boilerplate; 3 | 4 | import java.awt.Color; 5 | import java.awt.Graphics; 6 | import java.awt.Graphics2D; 7 | import java.awt.RenderingHints; 8 | 9 | import javax.swing.Action; 10 | import javax.swing.BorderFactory; 11 | import javax.swing.JButton; 12 | 13 | import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryColorScheme; 14 | 15 | public class MapillaryButton extends JButton { 16 | private static final long serialVersionUID = 2619282066157874464L; 17 | 18 | public MapillaryButton(final Action action) { 19 | this(action, false); 20 | } 21 | 22 | public MapillaryButton(final Action action, boolean slim) { 23 | super(action); 24 | setForeground(Color.WHITE); 25 | setBorder(slim ? BorderFactory.createEmptyBorder(3, 4, 3, 4) : BorderFactory.createEmptyBorder(7, 10, 7, 10)); 26 | } 27 | 28 | @Override 29 | protected void paintComponent(final Graphics g) { 30 | if (!isEnabled()) { 31 | g.setColor(MapillaryColorScheme.TOOLBAR_DARK_GREY); 32 | } else if (getModel().isPressed()) { 33 | g.setColor(MapillaryColorScheme.MAPILLARY_GREEN.darker().darker()); 34 | } else if (getModel().isRollover()) { 35 | g.setColor(MapillaryColorScheme.MAPILLARY_GREEN.darker()); 36 | } else { 37 | g.setColor(MapillaryColorScheme.MAPILLARY_GREEN); 38 | } 39 | ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 40 | g.fillRoundRect(0, 0, getWidth(), getHeight(), 3, 3); 41 | super.paintComponent(g); 42 | } 43 | 44 | @Override 45 | public boolean isContentAreaFilled() { 46 | return false; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/dialog/OrganizationListCellRenderer.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.dialog; 3 | 4 | import java.awt.Component; 5 | import java.awt.Image; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | import javax.swing.DefaultListCellRenderer; 10 | import javax.swing.ImageIcon; 11 | import javax.swing.JLabel; 12 | import javax.swing.JList; 13 | 14 | import org.openstreetmap.josm.plugins.mapillary.data.mapillary.OrganizationRecord; 15 | import org.openstreetmap.josm.tools.ImageProvider; 16 | 17 | /** 18 | * A cell renderer for organization lists 19 | */ 20 | public class OrganizationListCellRenderer extends DefaultListCellRenderer { 21 | private static final long serialVersionUID = -1650696801628131389L; 22 | /** Scaled organization icons -- cached for performance */ 23 | private static final Map ORGANIZATION_SCALED_ICONS = new ConcurrentHashMap<>(0); 24 | 25 | @Override 26 | public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, 27 | boolean cellHasFocus) { 28 | JLabel comp = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 29 | if (value instanceof OrganizationRecord) { 30 | OrganizationRecord organization = (OrganizationRecord) value; 31 | if ((organization.niceName() != null && !organization.niceName().isEmpty()) 32 | || OrganizationRecord.NULL_RECORD.equals(organization)) { 33 | comp.setText(organization.niceName()); 34 | } else { 35 | comp.setText(Long.toString(organization.id())); 36 | } 37 | if (organization.avatar() != null) { 38 | comp.setIcon(ORGANIZATION_SCALED_ICONS.computeIfAbsent(organization, 39 | OrganizationListCellRenderer::scaleOrganizationIcon)); 40 | } 41 | } 42 | return comp; 43 | } 44 | 45 | /** 46 | * Scale organization icons 47 | * 48 | * @param organization The organization whose icon needs to be scaled 49 | * @return The scaled icon 50 | */ 51 | private static ImageIcon scaleOrganizationIcon(final OrganizationRecord organization) { 52 | final ImageProvider.ImageSizes size = ImageProvider.ImageSizes.DEFAULT; 53 | final Image scaledImage = organization.avatar().getImage().getScaledInstance(size.getAdjustedWidth(), 54 | size.getAdjustedHeight(), Image.SCALE_SMOOTH); 55 | return new ImageIcon(scaledImage); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/dialog/ResetListener.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.dialog; 3 | 4 | /** 5 | * A listener for resetting state 6 | */ 7 | public interface ResetListener { 8 | /** 9 | * Reset the implementation to a default state 10 | */ 11 | void reset(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/dialog/UserProfileListCellRenderer.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.dialog; 3 | 4 | import java.awt.Component; 5 | 6 | import javax.swing.DefaultListCellRenderer; 7 | import javax.swing.JLabel; 8 | import javax.swing.JList; 9 | 10 | import org.openstreetmap.josm.plugins.mapillary.model.UserProfile; 11 | 12 | /** 13 | * A renderer for {@link UserProfile} objects 14 | */ 15 | class UserProfileListCellRenderer extends DefaultListCellRenderer { 16 | @Override 17 | public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, 18 | boolean cellHasFocus) { 19 | JLabel comp = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 20 | if (value instanceof UserProfile userProfile) { 21 | if (userProfile.username() != null && !userProfile.username().isBlank()) { 22 | comp.setText(userProfile.username()); 23 | } else if (!UserProfile.NONE.equals(userProfile)) { 24 | comp.setText(Long.toString(userProfile.key())); 25 | } else { 26 | comp.setText(""); 27 | } 28 | } 29 | return comp; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/imageinfo/MapillaryAction.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.imageinfo; 3 | 4 | import javax.swing.Action; 5 | 6 | import org.openstreetmap.josm.actions.JosmAction; 7 | import org.openstreetmap.josm.tools.Shortcut; 8 | 9 | /** 10 | * A common class for Mapillary actions 11 | */ 12 | abstract class MapillaryAction extends JosmAction { 13 | MapillaryAction(String name, String icon, String tooltip, Shortcut shortcut, boolean registerInToolbar, 14 | String toolbarId, boolean installAdapters) { 15 | super(name, icon, tooltip, shortcut, registerInToolbar, toolbarId, installAdapters); 16 | // We don't need the large icon, and it messes with spacing in buttons 17 | this.putValue(Action.LARGE_ICON_KEY, null); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/imageinfo/WebLinkAction.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.imageinfo; 3 | 4 | import static org.openstreetmap.josm.tools.I18n.tr; 5 | 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.KeyEvent; 8 | import java.io.Serial; 9 | import java.net.URI; 10 | import java.net.URISyntaxException; 11 | 12 | import javax.swing.JOptionPane; 13 | 14 | import org.openstreetmap.josm.gui.Notification; 15 | import org.openstreetmap.josm.tools.I18n; 16 | import org.openstreetmap.josm.tools.Logging; 17 | import org.openstreetmap.josm.tools.OpenBrowser; 18 | import org.openstreetmap.josm.tools.Shortcut; 19 | 20 | /** 21 | * An action to open web links 22 | */ 23 | public class WebLinkAction extends MapillaryAction { 24 | @Serial 25 | private static final long serialVersionUID = 2397830510179013823L; 26 | 27 | private URI uri; 28 | 29 | /** 30 | * Create a new action 31 | */ 32 | public WebLinkAction() { 33 | super(tr("View in browser"), "link", tr("Open in browser"), 34 | Shortcut.registerShortcut("mapillary:open_in_browser_View_in_browser", 35 | tr("Mapillary: Open image in browser"), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE), 36 | false, "mapillary:open_in_browser_View_in_browser", false); 37 | } 38 | 39 | /** 40 | * Set the URL to be opened 41 | * 42 | * @param url the url to set 43 | */ 44 | public final void setURI(URI url) { 45 | this.uri = url; 46 | setEnabled(url != null); 47 | } 48 | 49 | /* 50 | * (non-Javadoc) 51 | * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) 52 | */ 53 | @Override 54 | public void actionPerformed(ActionEvent e) { 55 | try { 56 | if (uri != null) { 57 | OpenBrowser.displayUrl(uri); 58 | } else { 59 | throw new URISyntaxException("‹null›", "The URL is null"); 60 | } 61 | } catch (URISyntaxException e1) { 62 | String msg = I18n.tr("Could not open the URL {0} in a browser", "‹null›"); 63 | Logging.log(Logging.LEVEL_WARN, msg, e1); 64 | new Notification(msg).setIcon(JOptionPane.WARNING_MESSAGE).show(); 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/layer/AdditionalActionPanel.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.layer; 3 | 4 | import java.awt.Color; 5 | 6 | import javax.swing.BorderFactory; 7 | import javax.swing.JButton; 8 | import javax.swing.JPanel; 9 | import javax.swing.UIManager; 10 | 11 | class AdditionalActionPanel extends JPanel { 12 | private boolean hasEnabledActions; 13 | 14 | /** 15 | * Create an additional action panel 16 | * 17 | * @param actionButtons The action buttons 18 | */ 19 | public AdditionalActionPanel(JButton... actionButtons) { 20 | this.setBackground(UIManager.getColor("ToolTip.background")); 21 | this.setForeground(UIManager.getColor("ToolTip.foreground")); 22 | this.setFont(UIManager.getFont("ToolTip.font")); 23 | this.setBorder(BorderFactory.createLineBorder(Color.black)); 24 | for (JButton button : actionButtons) { 25 | this.add(button); 26 | this.hasEnabledActions = this.hasEnabledActions || button.getAction().isEnabled(); 27 | } 28 | } 29 | 30 | /** 31 | * Check if there is content in the layer 32 | * 33 | * @return {@code true} if there is content to show 34 | */ 35 | public boolean hasContent() { 36 | return this.hasEnabledActions; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/layer/MapillaryLayerDrawTypes.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.layer; 3 | 4 | /** 5 | * Supported draw types 6 | */ 7 | public enum MapillaryLayerDrawTypes { 8 | DEFAULT, VELOCITY_CAR, VELOCITY_BIKE, VELOCITY_FOOT, DIRECTION, DATE; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/package-info.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | /** 3 | * The GUI components that are special to the mapillary plugin. 4 | */ 5 | package org.openstreetmap.josm.plugins.mapillary.gui; 6 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/widget/DisableShortcutsOnFocusGainedJSpinner.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.widget; 3 | 4 | import java.util.ArrayList; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | import javax.swing.Action; 10 | import javax.swing.JSpinner; 11 | import javax.swing.SpinnerModel; 12 | 13 | import org.openstreetmap.josm.actions.JosmAction; 14 | import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedComponent; 15 | import org.openstreetmap.josm.tools.Pair; 16 | import org.openstreetmap.josm.tools.Shortcut; 17 | 18 | /** 19 | * A JSpinner that disables shortcuts when focus is gained 20 | * 21 | * @author Taylor Smock 22 | */ 23 | public class DisableShortcutsOnFocusGainedJSpinner extends JSpinner implements DisableShortcutsOnFocusGainedComponent { 24 | private final Set disabledMenuActions = new HashSet<>(); 25 | private final List> unregisteredActionShortcuts = new ArrayList<>(); 26 | 27 | public DisableShortcutsOnFocusGainedJSpinner(final SpinnerModel spinnerModel) { 28 | super(spinnerModel); 29 | } 30 | 31 | @Override 32 | public List> getUnregisteredActionShortcuts() { 33 | return this.unregisteredActionShortcuts; 34 | } 35 | 36 | @Override 37 | public Set getDisabledMenuActions() { 38 | return this.disabledMenuActions; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/workers/MapillaryNodesDownloader.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.workers; 3 | 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Objects; 7 | import java.util.concurrent.ExecutionException; 8 | import java.util.function.Consumer; 9 | import java.util.stream.Collectors; 10 | 11 | import org.openstreetmap.josm.plugins.mapillary.data.mapillary.MapillaryDownloader; 12 | import org.openstreetmap.josm.plugins.mapillary.data.mapillary.MapillaryNode; 13 | import org.openstreetmap.josm.tools.JosmRuntimeException; 14 | 15 | /** 16 | * Download nodes asynchronously 17 | */ 18 | public class MapillaryNodesDownloader extends MapillaryUIDownloader, Void> { 19 | private static final List downloadList = new ArrayList<>(); 20 | private final Consumer> onFinish; 21 | private final long[] images; 22 | 23 | public MapillaryNodesDownloader(Consumer> onFinish, long... images) { 24 | Objects.requireNonNull(onFinish); 25 | Objects.requireNonNull(images); 26 | downloadList.add(this); 27 | this.onFinish = onFinish; 28 | this.images = images.clone(); 29 | } 30 | 31 | @Override 32 | protected List doInBackground() { 33 | return MapillaryDownloader.downloadImages(images).values().stream().flatMap(List::stream) 34 | .collect(Collectors.toList()); 35 | } 36 | 37 | @Override 38 | protected void done() { 39 | try { 40 | super.done(); 41 | this.onFinish.accept(this.get()); 42 | } catch (InterruptedException e) { 43 | Thread.currentThread().interrupt(); 44 | throw new JosmRuntimeException(e); 45 | } catch (ExecutionException e) { 46 | throw new JosmRuntimeException(e); 47 | } finally { 48 | downloadList.remove(this); 49 | } 50 | } 51 | 52 | /** 53 | * Kill all download threads 54 | */ 55 | public static void killAll() { 56 | // Kill the sequence downloader first -- it may cause nodes to be downloaded 57 | MapillarySequenceDownloader.killAll(); 58 | // Kill individual node downloads 59 | MapillaryNodeDownloader.killAll(); 60 | for (MapillaryNodesDownloader downloader : downloadList) { 61 | downloader.cancel(true); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/gui/workers/MapillaryUIDownloader.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.gui.workers; 3 | 4 | import javax.swing.SwingWorker; 5 | 6 | /** 7 | * A common class for downloaders 8 | * 9 | * @param The primary return type 10 | * @param The updating type 11 | * @see SwingWorker 12 | */ 13 | abstract class MapillaryUIDownloader extends SwingWorker { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/io/download/TileAddEventSource.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.io.download; 3 | 4 | import org.openstreetmap.gui.jmapviewer.Tile; 5 | 6 | /** 7 | * The source for {@link TileAddListener} events 8 | * 9 | * @param The tile type 10 | */ 11 | public interface TileAddEventSource { 12 | /** 13 | * Add a listener 14 | * 15 | * @param listener The listener to add 16 | * @param The listener type 17 | * @return {@code true} if the listener was added 18 | */ 19 | > boolean addListener(L listener); 20 | 21 | /** 22 | * Remove a listener 23 | * 24 | * @param listener The listener to remove 25 | * @param The listener type 26 | * @return {@code true} if the listener was removed 27 | */ 28 | > boolean removeListener(L listener); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/io/download/TileAddListener.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.io.download; 3 | 4 | import org.openstreetmap.gui.jmapviewer.Tile; 5 | 6 | /** 7 | * Listen for tile add events 8 | * @param The tile type that we are listening for 9 | */ 10 | public interface TileAddListener { 11 | /** 12 | * Called when a tile is added 13 | * 14 | * @param tile The tile added 15 | */ 16 | void tileAdded(T tile); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/io/export/package-info.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | /** 3 | * Classes for exporting images that were downloaded from mapillary.com . 4 | */ 5 | package org.openstreetmap.josm.plugins.mapillary.io.export; 6 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/io/package-info.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | /** 3 | * Classes for I/O operations like downloading images and their metadata and exporting them. 4 | */ 5 | package org.openstreetmap.josm.plugins.mapillary.io; 6 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/model/KeyIndexedObject.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.model; 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * An object that is identified amongst objects of the same class by a {@link String} key. 8 | * 9 | * @param The key type 10 | */ 11 | public interface KeyIndexedObject extends Serializable { 12 | /** 13 | * Get the key for the object 14 | * 15 | * @return the unique key that identifies this object among other instances of the same class 16 | */ 17 | T key(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/model/SpecialImageArea.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.model; 3 | 4 | import java.awt.Shape; 5 | import java.util.Objects; 6 | 7 | import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryProperties; 8 | 9 | /** 10 | * Special image areas 11 | * 12 | * @param The key type 13 | * @param The shape type 14 | */ 15 | public class SpecialImageArea implements KeyIndexedObject { 16 | private final S key; 17 | private final S imageKey; 18 | private final T shape; 19 | 20 | protected SpecialImageArea(final T shape, final S imageKey, final S key) { 21 | this.key = key; 22 | this.shape = shape; 23 | this.imageKey = imageKey; 24 | } 25 | 26 | public S getImageKey() { 27 | return imageKey; 28 | } 29 | 30 | public Shape getShape() { 31 | if (Boolean.TRUE.equals(MapillaryProperties.SMART_EDIT.get())) { 32 | return shape.getBounds2D(); 33 | } 34 | return shape; 35 | } 36 | 37 | @Override 38 | public S key() { 39 | return this.key; 40 | } 41 | 42 | @Override 43 | public boolean equals(Object object) { 44 | if (super.equals(object) && this.getClass().equals(object.getClass())) { 45 | SpecialImageArea other = (SpecialImageArea) object; 46 | return Objects.equals(this.shape, other.shape) && Objects.equals(this.imageKey, other.imageKey); 47 | } 48 | return false; 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return Objects.hash(super.hashCode(), this.imageKey, this.shape); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/oauth/MapillaryLoginListener.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.oauth; 3 | 4 | /** 5 | * This interface should be implemented by components that want to get notified when the user 6 | * logs in or logs out of his Mapillary account. 7 | * Such listeners can be registered e.g. at a {@link OAuthPortListener}. 8 | */ 9 | public interface MapillaryLoginListener { 10 | /** 11 | * Should be called whenever the user logs into a mapillary account. 12 | * E.g. for updating the GUI to reflect the login status. 13 | * 14 | * @param username the username that the user is now logged in with 15 | */ 16 | void onLogin(final String username); 17 | 18 | /** 19 | * Should be called whenever the user logs out of a mapillary account. 20 | * E.g. for updating the GUI to reflect the login status. 21 | */ 22 | void onLogout(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/oauth/package-info.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | /** 3 | * Everything related to signing users in and out of Mapillary. 4 | * We are using OAuth 2.0 to authenticate the user against the Mapillary API. 5 | * See https://a.mapillary.com/#oauth for more details. 6 | */ 7 | package org.openstreetmap.josm.plugins.mapillary.oauth; 8 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/package-info.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | /** 3 | * The main package in which all core-code (so at the moment all code) resides. 4 | */ 5 | package org.openstreetmap.josm.plugins.mapillary; 6 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/spi/preferences/ApiKeyReader.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.spi.preferences; 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | import jakarta.json.Json; 8 | import jakarta.json.JsonObject; 9 | import jakarta.json.JsonReader; 10 | import org.openstreetmap.josm.spi.preferences.Config; 11 | import org.openstreetmap.josm.tools.Logging; 12 | import org.openstreetmap.josm.tools.ResourceProvider; 13 | import org.openstreetmap.josm.tools.Utils; 14 | 15 | /** 16 | * Read api keys from a system property, then JOSM preferences, and finally from an API key file in the jar. 17 | */ 18 | public final class ApiKeyReader { 19 | private ApiKeyReader() { 20 | /* Hide constructor */ } 21 | 22 | private static final String API_KEY_FILE = "mapillary_api_keys.json"; 23 | 24 | static String readValue(final String key) { 25 | // Prefer system property (this is something that can be changed fairly easily) 26 | if (System.getProperty(key) != null) { 27 | return System.getProperty(key); 28 | } 29 | // Then check if there was something stored in JOSM preferences 30 | if (Config.getPref() != null && !Utils.isStripEmpty(Config.getPref().get("mapillary.api." + key))) { 31 | return Config.getPref().get("mapillary.api." + key); 32 | } 33 | // Then check and see if the api key file has the key 34 | final InputStream fileStream = ResourceProvider.getResourceAsStream(API_KEY_FILE); 35 | if (fileStream != null) { 36 | try (JsonReader reader = Json.createReader(fileStream)) { 37 | final JsonObject object = reader.readObject(); 38 | if (object.containsKey(key)) { 39 | return object.getString(key); 40 | } 41 | } finally { 42 | try { 43 | fileStream.close(); 44 | } catch (IOException e) { 45 | Logging.error(e); 46 | } 47 | } 48 | } 49 | // Finally, return "test" no value has been found 50 | return "test"; 51 | } 52 | 53 | static long readMapillaryClientId() { 54 | try { 55 | final String stringValue = readValue("MAPILLARY_CLIENT_ID"); 56 | return Long.parseLong(stringValue); 57 | } catch (NumberFormatException numberFormatException) { 58 | Logging.error(numberFormatException); 59 | } 60 | return 4_280_585_711_960_869L; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/spi/preferences/IMapillaryUrlChange.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.spi.preferences; 3 | 4 | /** 5 | * Used to indicate that urls have changed 6 | * 7 | * @author Taylor Smock 8 | */ 9 | public interface IMapillaryUrlChange { 10 | /** 11 | * Called when {@link MapillaryConfig} changes url implementation 12 | * 13 | * @param oldUrls The old instance 14 | * @param newUrls The new instance 15 | */ 16 | void urlsChanged(final IMapillaryUrls oldUrls, final IMapillaryUrls newUrls); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/spi/preferences/MapillaryConfig.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.spi.preferences; 3 | 4 | import org.openstreetmap.josm.spi.preferences.IBaseDirectories; 5 | import org.openstreetmap.josm.tools.ListenerList; 6 | 7 | /** 8 | * A class holding configuration information 9 | * 10 | * @author Taylor Smock 11 | */ 12 | public final class MapillaryConfig { 13 | private MapillaryConfig() { 14 | // hide constructor 15 | } 16 | 17 | private static final ListenerList MAPILLARY_URL_CHANGE_LISTENER_LIST = ListenerList.create(); 18 | 19 | private static IMapillaryUrls urls; 20 | private static IBaseDirectories pluginDirs; 21 | 22 | /** 23 | * Add a listener for URL changes 24 | * 25 | * @param listener The listener to add 26 | */ 27 | public static void addUrlChangeListener(final IMapillaryUrlChange listener) { 28 | if (!MAPILLARY_URL_CHANGE_LISTENER_LIST.containsListener(listener)) { 29 | MAPILLARY_URL_CHANGE_LISTENER_LIST.addListener(listener); 30 | } 31 | } 32 | 33 | /** 34 | * Set the current URL provider 35 | * 36 | * @param urlsProvider The provider to use 37 | */ 38 | public static void setUrlsProvider(final IMapillaryUrls urlsProvider) { 39 | final IMapillaryUrls oldUrls = urls; 40 | urls = urlsProvider; 41 | MAPILLARY_URL_CHANGE_LISTENER_LIST.fireEvent(target -> target.urlsChanged(oldUrls, urls)); 42 | } 43 | 44 | /** 45 | * The current URL provider 46 | * 47 | * @return get the provider 48 | */ 49 | public static IMapillaryUrls getUrls() { 50 | return urls; 51 | } 52 | 53 | /** 54 | * Set the plugin directory provider 55 | * 56 | * @param pluginDirs The plugin directory provider 57 | */ 58 | public static void setDirectoriesProvider(IBaseDirectories pluginDirs) { 59 | MapillaryConfig.pluginDirs = pluginDirs; 60 | } 61 | 62 | /** 63 | * Get the base directories for the plugin 64 | * 65 | * @return The base directories 66 | */ 67 | public static IBaseDirectories getPluginDirs() { 68 | return pluginDirs; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/spi/preferences/MapillaryUrls.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.spi.preferences; 3 | 4 | import static org.openstreetmap.josm.plugins.mapillary.spi.preferences.ApiKeyReader.readMapillaryClientId; 5 | import static org.openstreetmap.josm.plugins.mapillary.spi.preferences.ApiKeyReader.readValue; 6 | 7 | /** 8 | * The default URL implementation 9 | * 10 | * @author Taylor Smock 11 | */ 12 | public class MapillaryUrls implements IMapillaryUrls { 13 | private static final String BASE_URL = "https://www.mapillary.com/"; 14 | /** 15 | * The API key for v4 16 | */ 17 | private static final String ACCESS_ID = readValue("MAPILLARY_CLIENT_TOKEN"); 18 | /** 19 | * This is the client id for the application, used solely for authentication 20 | */ 21 | private static final long CLIENT_ID = readMapillaryClientId(); 22 | 23 | /** 24 | * This is the client secret for the application, used solely for authentication 25 | */ 26 | private static final String CLIENT_SECRET = readValue("MAPILLARY_CLIENT_SECRET"); 27 | 28 | /** The base URL to get metadata */ 29 | private static final String BASE_META_DATA_URL = "https://graph.mapillary.com/"; 30 | /** The base URL for tiles */ 31 | private static final String BASE_TILE_URL = "https://tiles.mapillary.com/maps/vtp/"; 32 | /** The paint style url */ 33 | private static final String PAINT_STYLE_URL = "https://josm.openstreetmap.de/josmfile?page=Styles/MapillaryDetections&zip=1"; 34 | 35 | @Override 36 | public String getBaseMetaDataUrl() { 37 | return BASE_META_DATA_URL; 38 | } 39 | 40 | @Override 41 | public String getBaseTileUrl() { 42 | return BASE_TILE_URL; 43 | } 44 | 45 | @Override 46 | public String getPaintStyleUrl() { 47 | return PAINT_STYLE_URL; 48 | } 49 | 50 | @Override 51 | public String getAccessId() { 52 | return ACCESS_ID; 53 | } 54 | 55 | @Override 56 | public long getClientId() { 57 | return CLIENT_ID; 58 | } 59 | 60 | @Override 61 | public String getClientSecret() { 62 | return CLIENT_SECRET; 63 | } 64 | 65 | @Override 66 | public String getBaseUrl() { 67 | return BASE_URL; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/DetectionVerification.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | import java.util.Locale; 5 | 6 | import org.openstreetmap.josm.plugins.mapillary.model.ImageDetection; 7 | 8 | /** 9 | * Vote for/against a detection 10 | */ 11 | public final class DetectionVerification { 12 | /** The type of vote to make */ 13 | public enum TYPE { 14 | /** Approve the detection */ 15 | APPROVE, 16 | /** Reject the detection */ 17 | REJECT; 18 | 19 | @Override 20 | public String toString() { 21 | return this.name().toLowerCase(Locale.ENGLISH); 22 | } 23 | } 24 | 25 | /** 26 | * Vote for a detection 27 | * 28 | * @param detection The detection to vote for 29 | * @param type The type of vote to make 30 | * @return {@code true} if successful 31 | */ 32 | public static boolean vote(ImageDetection detection, TYPE type) { 33 | throw new UnsupportedOperationException("Mapillary: v4 API does not currently support voting"); 34 | } 35 | 36 | private DetectionVerification() { 37 | // Don't instantiate 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/ImageUtil.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | import java.awt.Graphics2D; 5 | import java.awt.Image; 6 | import java.awt.geom.AffineTransform; 7 | import java.awt.image.BufferedImage; 8 | 9 | import javax.swing.ImageIcon; 10 | 11 | import org.openstreetmap.josm.tools.Logging; 12 | 13 | public final class ImageUtil { 14 | private ImageUtil() { 15 | // Private constructor to avoid instantiation 16 | } 17 | 18 | /** 19 | * Scales an {@link ImageIcon} to the desired size 20 | * 21 | * @param icon the icon, which should be resized 22 | * @param size the desired length of the longest edge of the icon 23 | * @return the resized {@link ImageIcon}. It is the same object that you put in, 24 | * only the contained {@link Image} is exchanged. 25 | */ 26 | public static ImageIcon scaleImageIcon(final ImageIcon icon, int size) { 27 | Logging.debug("Scale icon {0} → {1}", icon.getIconWidth(), size); 28 | return new ImageIcon(icon.getImage().getScaledInstance( 29 | icon.getIconWidth() >= icon.getIconHeight() ? size 30 | : Math.max(1, Math.round(icon.getIconWidth() / (float) icon.getIconHeight() * size)), 31 | icon.getIconHeight() >= icon.getIconWidth() ? size 32 | : Math.max(1, Math.round(icon.getIconHeight() / (float) icon.getIconWidth() * size)), 33 | Image.SCALE_SMOOTH)); 34 | } 35 | 36 | public static BufferedImage scale(BufferedImage src, int width, int height) { 37 | BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 38 | Graphics2D g = dest.createGraphics(); 39 | AffineTransform at = AffineTransform.getScaleInstance((double) width / src.getWidth(), 40 | (double) height / src.getHeight()); 41 | g.drawRenderedImage(src, at); 42 | return dest; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUserUtils.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | /** 5 | * Keys and utility methods for Mapillary Users 6 | */ 7 | public class MapillaryUserUtils { 8 | public static final String KEY = "key"; 9 | public static final String ID = "id"; 10 | public static final String USER_NAME = "username"; 11 | public static final String CREATED_AT = "created_at"; 12 | 13 | private MapillaryUserUtils() { 14 | // Don't allow instantiation 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/ReflectionUtils.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | import java.lang.reflect.Field; 5 | import java.util.Optional; 6 | 7 | import jakarta.annotation.Nonnull; 8 | import jakarta.annotation.Nullable; 9 | import org.openstreetmap.josm.tools.Logging; 10 | 11 | /** 12 | * A class for getting objects from JOSM code 13 | */ 14 | public final class ReflectionUtils { 15 | private ReflectionUtils() { 16 | // Hide constructor 17 | } 18 | 19 | /** 20 | * Get a declared field 21 | * 22 | * @param parentClass The class with the declared field 23 | * @param fieldInParentClass The field to get 24 | * @param objectWithField The object with the field (may be {@code null}) 25 | * @param returnClass The return type 26 | * @param The parent class 27 | * @param The class to search 28 | * @param The return class 29 | * @return An optional with the object (may be empty) 30 | */ 31 | @Nonnull 32 | public static Optional getDeclaredField(@Nonnull Class parentClass, 33 | @Nonnull String fieldInParentClass, @Nullable C objectWithField, @Nonnull Class returnClass) { 34 | try { 35 | Field tagMenuField = parentClass.getDeclaredField(fieldInParentClass); 36 | org.openstreetmap.josm.tools.ReflectionUtils.setObjectsAccessible(tagMenuField); 37 | final Object object = tagMenuField.get(objectWithField); 38 | if (returnClass.isInstance(object)) { 39 | return Optional.of(returnClass.cast(object)); 40 | } 41 | } catch (ReflectiveOperationException e) { 42 | Logging.error(e); 43 | } 44 | return Optional.empty(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/SecurityManagerUtils.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | import org.openstreetmap.josm.plugins.mapillary.cache.Caches; 5 | import org.openstreetmap.josm.plugins.mapillary.cache.MapillaryCache; 6 | import org.openstreetmap.josm.tools.Logging; 7 | 8 | /** 9 | * This class exists to help initialize some items that fail when a security manager is installed 10 | * 11 | * @author Taylor Smock 12 | */ 13 | public class SecurityManagerUtils { 14 | private SecurityManagerUtils() { 15 | // Don't allow instantiation 16 | } 17 | 18 | /** 19 | * Do initializations that cannot occur in a ForkJoinPool (due to WebStart's security manager) 20 | */ 21 | public static void doInitializations() { 22 | if (System.getSecurityManager() != null) { 23 | // Ensure that we aren't initializing the caches in a secure context (specifically, ForkJoin pools) 24 | // -- this fails, and throws exceptions. See JOSM #20951. 25 | // Ensure that the image caches are initialized 26 | if (Caches.FULL_IMAGE_CACHE.hashCode() == 0) { 27 | Logging.trace("Mapillary: FULL_IMAGE_CACHE had a 0 hashCode. This is just a filler message."); 28 | } 29 | // Ensure that the ForkJoin pools are already initialized 30 | MapillaryUtils.getForkJoinPool(); 31 | MapillaryUtils.getForkJoinPool(MapillaryCache.class); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/api/JsonSequencesDecoder.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils.api; 3 | 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Objects; 7 | import java.util.stream.Collectors; 8 | 9 | import jakarta.json.JsonArray; 10 | import jakarta.json.JsonNumber; 11 | import jakarta.json.JsonObject; 12 | import jakarta.json.JsonString; 13 | import jakarta.json.JsonValue; 14 | import org.openstreetmap.josm.data.osm.IWay; 15 | import org.openstreetmap.josm.plugins.mapillary.spi.preferences.IMapillaryUrls; 16 | import org.openstreetmap.josm.tools.Logging; 17 | 18 | /** 19 | * Decodes the JSON returned by {@link IMapillaryUrls} into Java objects. 20 | * Takes a {@link JsonObject} and {@link #decodeSequence(JsonValue)} tries to convert it to a 21 | * {@link IWay}. 22 | */ 23 | public final class JsonSequencesDecoder { 24 | private JsonSequencesDecoder() { 25 | // Private constructor to avoid instantiation 26 | } 27 | 28 | /** 29 | * Parses a given {@link JsonObject} as an array of image identifiers into a {@link IWay}. 30 | * 31 | * @param json the {@link JsonObject} to be parsed 32 | * @return a singleton list of {@link IWay} that is parsed from the given {@link JsonObject}. If mandatory 33 | * information is missing from the JSON, or it's not meeting the expecting format in another way, 34 | * an empty list will be returned. 35 | */ 36 | public static List decodeSequence(final JsonValue json) { 37 | /* 38 | * The response looks like: 39 | * {"data":[{"id":"0"},{"id":"1"},{"id":"2"},...]} 40 | * We just have the "data" value 41 | */ 42 | if (!(json instanceof JsonArray)) { 43 | Logging.error("Mapillary: The sequence endpoint just returns an array of picture ids"); 44 | return Collections.emptyList(); 45 | } 46 | return ((JsonArray) json).getValuesAs(value -> value instanceof JsonObject ? (JsonObject) value : null).stream() 47 | .filter(Objects::nonNull).filter(image -> image.containsKey("id")).map(image -> image.get("id")) 48 | .filter(jsonObject -> jsonObject instanceof JsonString || jsonObject instanceof JsonNumber) 49 | .map(value -> value instanceof JsonString ? Long.parseLong(((JsonString) value).getString()) 50 | : ((JsonNumber) value).longValue()) 51 | .distinct().collect(Collectors.toList()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/api/JsonTagMapDecoder.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils.api; 3 | 4 | import java.util.Map; 5 | 6 | import jakarta.json.JsonObject; 7 | import jakarta.json.JsonString; 8 | import jakarta.json.JsonValue; 9 | import org.openstreetmap.josm.data.osm.TagMap; 10 | 11 | /** 12 | * Convert a properties object into a TagMap 13 | */ 14 | public final class JsonTagMapDecoder { 15 | private JsonTagMapDecoder() { 16 | // Utility class, shouldn't be instantiated 17 | } 18 | 19 | /** 20 | * Get a tag map for the values 21 | * 22 | * @param json The json to convert to a tag map (ignores sub arrays and sub objects) 23 | * @return The tagmap 24 | */ 25 | public static Map getTagMap(JsonObject json) { 26 | TagMap tags = new TagMap(); 27 | for (Map.Entry entry : json.entrySet()) { 28 | JsonValue.ValueType type = entry.getValue().getValueType(); 29 | if (type == JsonValue.ValueType.STRING) { 30 | tags.put(entry.getKey(), ((JsonString) entry.getValue()).getString()); 31 | } else if (type == JsonValue.ValueType.TRUE) { 32 | tags.put(entry.getKey(), Boolean.TRUE.toString()); 33 | } else if (type == JsonValue.ValueType.FALSE) { 34 | tags.put(entry.getKey(), Boolean.FALSE.toString()); 35 | } else { // if (type == JsonValue.ValueType.NUMBER) { 36 | tags.put(entry.getKey(), entry.getValue().toString()); 37 | } 38 | } 39 | return tags; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/api/JsonUserProfileDecoder.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils.api; 3 | 4 | import java.awt.image.BufferedImage; 5 | import java.io.IOException; 6 | import java.net.URI; 7 | 8 | import javax.imageio.ImageIO; 9 | import javax.swing.ImageIcon; 10 | 11 | import org.openstreetmap.josm.plugins.mapillary.model.UserProfile; 12 | import org.openstreetmap.josm.plugins.mapillary.spi.preferences.IMapillaryUrls; 13 | import org.openstreetmap.josm.tools.ImageProvider; 14 | import org.openstreetmap.josm.tools.Logging; 15 | 16 | import jakarta.json.JsonObject; 17 | 18 | /** 19 | * Decodes the JSON returned by {@link IMapillaryUrls} into Java objects. 20 | * Takes a {@link JsonObject} and {@link #decodeUserProfile(JsonObject)} tries to convert it to a {@link UserProfile}. 21 | */ 22 | public final class JsonUserProfileDecoder { 23 | /** The avatar for profiles without an avatar */ 24 | private static final ImageIcon FAKE_AVATAR = new ImageProvider("fake-avatar").get(); 25 | 26 | private JsonUserProfileDecoder() { 27 | // Private constructor to avoid instantiation 28 | } 29 | 30 | /** 31 | * Decode the user profile 32 | * 33 | * @param json The user profile json object 34 | * @return The decoded profile 35 | */ 36 | public static UserProfile decodeUserProfile(JsonObject json) { 37 | if (json == null) { 38 | return null; 39 | } 40 | final var username = json.getString("username", null); 41 | final var key = json.getString("id", null); 42 | if (key == null || username == null) { 43 | return null; 44 | } 45 | 46 | final var avatar = json.getString("avatar", null); 47 | ImageIcon icon = null; 48 | if (avatar != null) { 49 | try { 50 | BufferedImage img = ImageIO.read(URI.create(avatar).toURL()); 51 | if (img != null) { 52 | icon = new ImageIcon(img); 53 | } 54 | } catch (IOException e) { 55 | Logging.debug(e); 56 | } 57 | } 58 | if (icon == null) { 59 | icon = FAKE_AVATAR; 60 | } 61 | return new UserProfile(Long.parseLong(key), username, icon); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/josm/plugins/mapillary/utils/package-info.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | /** 3 | * Utility classes for simplifying recurring tasks throughout the project. 4 | * These classes are typically not instantiatable and only have static methods. 5 | */ 6 | package org.openstreetmap.josm.plugins.mapillary.utils; 7 | -------------------------------------------------------------------------------- /src/main/resources/data/ar.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/ar.lang -------------------------------------------------------------------------------- /src/main/resources/data/ast.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/ast.lang -------------------------------------------------------------------------------- /src/main/resources/data/be.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/be.lang -------------------------------------------------------------------------------- /src/main/resources/data/bg.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/bg.lang -------------------------------------------------------------------------------- /src/main/resources/data/ca-valencia.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/ca-valencia.lang -------------------------------------------------------------------------------- /src/main/resources/data/ca.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/ca.lang -------------------------------------------------------------------------------- /src/main/resources/data/cs.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/cs.lang -------------------------------------------------------------------------------- /src/main/resources/data/cy.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/cy.lang -------------------------------------------------------------------------------- /src/main/resources/data/da.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/da.lang -------------------------------------------------------------------------------- /src/main/resources/data/de.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/de.lang -------------------------------------------------------------------------------- /src/main/resources/data/el.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/el.lang -------------------------------------------------------------------------------- /src/main/resources/data/en.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/en.lang -------------------------------------------------------------------------------- /src/main/resources/data/en_AU.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/en_AU.lang -------------------------------------------------------------------------------- /src/main/resources/data/en_CA.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/en_CA.lang -------------------------------------------------------------------------------- /src/main/resources/data/en_GB.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/en_GB.lang -------------------------------------------------------------------------------- /src/main/resources/data/eo.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/eo.lang -------------------------------------------------------------------------------- /src/main/resources/data/es.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/es.lang -------------------------------------------------------------------------------- /src/main/resources/data/et.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/et.lang -------------------------------------------------------------------------------- /src/main/resources/data/fa.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/fa.lang -------------------------------------------------------------------------------- /src/main/resources/data/fi.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/fi.lang -------------------------------------------------------------------------------- /src/main/resources/data/fo.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/fo.lang -------------------------------------------------------------------------------- /src/main/resources/data/fr.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/fr.lang -------------------------------------------------------------------------------- /src/main/resources/data/gl.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/gl.lang -------------------------------------------------------------------------------- /src/main/resources/data/hu.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/hu.lang -------------------------------------------------------------------------------- /src/main/resources/data/id.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/id.lang -------------------------------------------------------------------------------- /src/main/resources/data/is.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/is.lang -------------------------------------------------------------------------------- /src/main/resources/data/it.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/it.lang -------------------------------------------------------------------------------- /src/main/resources/data/ja.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/ja.lang -------------------------------------------------------------------------------- /src/main/resources/data/km.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/km.lang -------------------------------------------------------------------------------- /src/main/resources/data/ko.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/ko.lang -------------------------------------------------------------------------------- /src/main/resources/data/lt.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/lt.lang -------------------------------------------------------------------------------- /src/main/resources/data/mr.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/mr.lang -------------------------------------------------------------------------------- /src/main/resources/data/nb.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/nb.lang -------------------------------------------------------------------------------- /src/main/resources/data/nl.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/nl.lang -------------------------------------------------------------------------------- /src/main/resources/data/pl.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/pl.lang -------------------------------------------------------------------------------- /src/main/resources/data/pt.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/pt.lang -------------------------------------------------------------------------------- /src/main/resources/data/pt_BR.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/pt_BR.lang -------------------------------------------------------------------------------- /src/main/resources/data/ru.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/ru.lang -------------------------------------------------------------------------------- /src/main/resources/data/sk.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/sk.lang -------------------------------------------------------------------------------- /src/main/resources/data/sr-latin.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/sr-latin.lang -------------------------------------------------------------------------------- /src/main/resources/data/sv.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/sv.lang -------------------------------------------------------------------------------- /src/main/resources/data/tr.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/tr.lang -------------------------------------------------------------------------------- /src/main/resources/data/uk.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/uk.lang -------------------------------------------------------------------------------- /src/main/resources/data/zh_CN.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/zh_CN.lang -------------------------------------------------------------------------------- /src/main/resources/data/zh_TW.lang: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/data/zh_TW.lang -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-cancel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-clear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-filter-expert.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 30 | 50 | 54 | 59 | E 69 | 70 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-history.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-main.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-restart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillary-upload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillaryPause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/dialogs/mapillaryPause.png -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillaryPlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/dialogs/mapillaryPlay.png -------------------------------------------------------------------------------- /src/main/resources/images/dialogs/mapillaryStop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/dialogs/mapillaryStop.png -------------------------------------------------------------------------------- /src/main/resources/images/fake-avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/fake-avatar.png -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/current-ca.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 63 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/default-ca-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 63 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/default-ca.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 63 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/deleted-ca-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/deleted-ca.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/private-ca-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 63 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/private-ca.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 63 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/sequence-ca-hover.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 63 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/sequence-ca.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 63 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/main/resources/images/josm-ca/sign-detection.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/main/resources/images/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/images/mapicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/images/mapillary-eyedropper.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/images/mapillary-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/mapillary-logo-white.png -------------------------------------------------------------------------------- /src/main/resources/images/mapillary-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/images/mapmode/mapillary-edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/images/mapmode/mapillary-join.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/images/mapmode/mapillary-select.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/images/signs/crossing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/crossing.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/intersection_danger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/intersection_danger.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/no_entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/no_entry.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/no_overtaking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/no_overtaking.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/no_parking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/no_parking.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/no_turn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/no_turn.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/only_straight_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/only_straight_on.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/roundabout_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/roundabout_right.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/speed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/speed.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/stop.png -------------------------------------------------------------------------------- /src/main/resources/images/signs/uneven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/src/main/resources/images/signs/uneven.png -------------------------------------------------------------------------------- /src/main/resources/images/unknown-mapobject-type.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory includes the test resources for the mapillary plugin. 3 | 4 | 5 | unit/ test sources (Unit tests, functional tests) 6 | 7 | config/ configuration files for running tests 8 | 9 | data/ test data 10 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/README.md: -------------------------------------------------------------------------------- 1 | This directory contains example data representative for what the APIv4 typically returns for certain queries. 2 | 3 | The data responses are organized like this: 4 | * graph (for entities) 5 | * entity\_id.json 6 | * coverageTiles (for tiles) 7 | * endpoint (minus commonalities). If there are non coordinate paths after commonalities, they are included as subdirs. 8 | * {z}/{x}/{y}.mvt 9 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/coverageTiles/mly1_public/2/14/3251/6257.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/__files/api/v4/responses/coverageTiles/mly1_public/2/14/3251/6257.mvt -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/coverageTiles/mly1_public/2/14/3251/6258.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/__files/api/v4/responses/coverageTiles/mly1_public/2/14/3251/6258.mvt -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/coverageTiles/mly1_public/2/14/3252/6257.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/__files/api/v4/responses/coverageTiles/mly1_public/2/14/3252/6257.mvt -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/coverageTiles/mly1_public/2/14/3252/6258.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/__files/api/v4/responses/coverageTiles/mly1_public/2/14/3252/6258.mvt -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/104214208486349.json: -------------------------------------------------------------------------------- 1 | {"username":"vorpalblade","id":"104214208486349"} 2 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/104214208486350.json: -------------------------------------------------------------------------------- 1 | {"username":"mapillary_userÄ2!","id":"104214208486349", "comment": "Not an actual user! Don't update!"} 2 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/135511895288847.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": 1364.617, 3 | "atomic_scale": 0.97891115347587, 4 | "camera_parameters": [ 5 | 0.85136388143343, 6 | -6.6499673206348e-05, 7 | -3.8067681992196e-05 8 | ], 9 | "camera_type": "perspective", 10 | "captured_at": 1563721072184, 11 | "compass_angle": 336.74, 12 | "computed_altitude": 1399.5043095825, 13 | "computed_compass_angle": 1.2865829255371, 14 | "computed_geometry": { 15 | "type": "Point", 16 | "coordinates": [ 17 | -108.57081597085, 18 | 39.068354912098 19 | ] 20 | }, 21 | "computed_rotation": [ 22 | 1.3642214091955, 23 | -0.0019509766093401, 24 | 0.035317244081076 25 | ], 26 | "exif_orientation": 1, 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | -108.57081597222, 31 | 39.068354972222 32 | ] 33 | }, 34 | "height": 3120, 35 | "thumb_256_url": "thumb_256_filler_url", 36 | "thumb_1024_url": "thumb_1024_filler_url", 37 | "thumb_2048_url": "thumb_2048_filler_url", 38 | "merge_cc": 4.546427159383e+18, 39 | "mesh": { 40 | "id": "903987176835273", 41 | "url": "mesh_filler_url" 42 | }, 43 | "quality_score": 0.7561310782241, 44 | "sequence": "7nfcwfvjdtphz7yj6zat6a", 45 | "sfm_cluster": { 46 | "id": "306951457725231", 47 | "url": "sfm_cluster_filler_url" 48 | }, 49 | "width": 4160, 50 | "id": "135511895288847", 51 | "thumb_original_url": "thumb_original_filler_url", 52 | "detections": { 53 | "data": [ 54 | { 55 | "id": "138291978344172" 56 | }, 57 | { 58 | "id": "138571594982877" 59 | } 60 | ] 61 | } 62 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/135511895288847/detections.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created_at": "2021-05-22T15:20:45+0000", 5 | "geometry": "GnZ4AgoGbXB5LW9yKIAgEmcIARgDImEJ5CySK9ICIgRWBE4MDAgYKAxEAn4QXgKcAQY2CBgAJgQWAJoBBQobBLkBAKsBAzUCCwEFBwMACycDIQMJA30PWwHBAQU3ByEDVwUbAwMCMQQNCgkYBzwBEgsUAAwDIgEP", 6 | "image": { 7 | "geometry": { 8 | "type": "Point", 9 | "coordinates": [ 10 | -108.57081597222, 11 | 39.068354972222 12 | ] 13 | }, 14 | "id": "135511895288847" 15 | }, 16 | "value": "object--junction-box", 17 | "id": "138291978344172" 18 | }, 19 | { 20 | "created_at": "2021-05-23T00:40:55+0000", 21 | "geometry": "GjgKBm1weS1vchIYEgIAABgDIhAJkCawDRq4BgAAhAO3BgAPGgR0eXBlIgkKB3BvbHlnb24ogCB4AQ==", 22 | "image": { 23 | "geometry": { 24 | "type": "Point", 25 | "coordinates": [ 26 | -108.57081597222, 27 | 39.068354972222 28 | ] 29 | }, 30 | "id": "135511895288847" 31 | }, 32 | "value": "information--general-directions--g1", 33 | "id": "138571594982877" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/148137757289079.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": 1365.268, 3 | "atomic_scale": 0.99647293545609, 4 | "camera_parameters": [ 5 | 0.84445215999653, 6 | 0.00013121033151786, 7 | -1.9432407137559e-06 8 | ], 9 | "camera_type": "perspective", 10 | "captured_at": 1563721048460, 11 | "compass_angle": 327.58, 12 | "computed_altitude": 1397.88957371, 13 | "computed_compass_angle": 359.18081230616, 14 | "computed_geometry": { 15 | "type": "Point", 16 | "coordinates": [ 17 | -108.57077016445, 18 | 39.065738749246 19 | ] 20 | }, 21 | "computed_rotation": [ 22 | 1.3810978714822, 23 | -0.027114611384617, 24 | -0.056708179817346 25 | ], 26 | "exif_orientation": 1, 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | -108.57076997222, 31 | 39.065739 32 | ] 33 | }, 34 | "height": 3120, 35 | "thumb_256_url": "thumb_256_filler_url", 36 | "thumb_1024_url": "thumb_1024_filler_url", 37 | "thumb_2048_url": "thumb_2048_filler_url", 38 | "merge_cc": 5.2826592657222e+17, 39 | "mesh": { 40 | "id": "1082942308776704", 41 | "url": "mesh_filler_url" 42 | }, 43 | "quality_score": 0.78643410852713, 44 | "sequence": "7nfcwfvjdtphz7yj6zat6a", 45 | "sfm_cluster": { 46 | "id": "511129849910835", 47 | "url": "sfm_cluster_filler_url" 48 | }, 49 | "width": 4160, 50 | "id": "148137757289079", 51 | "thumb_original_url": "thumb_original_filler_url", 52 | "detections": { 53 | "data": [ 54 | { 55 | "id": "149534623816059" 56 | }, 57 | { 58 | "id": "149583247144530" 59 | }, 60 | { 61 | "id": "150066420429546" 62 | }, 63 | { 64 | "id": "150499680386220" 65 | }, 66 | { 67 | "id": "150806497022205" 68 | } 69 | ] 70 | } 71 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/308609047601518.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": 1363.29, 3 | "atomic_scale": 0.97891115347587, 4 | "camera_parameters": [ 5 | 0.85136388143343, 6 | -6.6499673206348e-05, 7 | -3.8067681992196e-05 8 | ], 9 | "camera_type": "perspective", 10 | "captured_at": 1563721068212, 11 | "compass_angle": 334.28, 12 | "computed_altitude": 1399.4088478871, 13 | "computed_compass_angle": 2.8645135091551, 14 | "computed_geometry": { 15 | "type": "Point", 16 | "coordinates": [ 17 | -108.57081900996, 18 | 39.067959960774 19 | ] 20 | }, 21 | "computed_rotation": [ 22 | 1.3740205373753, 23 | -0.042444898098058, 24 | 0.032009776361988 25 | ], 26 | "exif_orientation": 1, 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | -108.570819, 31 | 39.067959972222 32 | ] 33 | }, 34 | "height": 3120, 35 | "thumb_256_url": "thumb_256_filler_url", 36 | "thumb_1024_url": "thumb_1024_filler_url", 37 | "thumb_2048_url": "thumb_2048_filler_url", 38 | "merge_cc": 4.546427159383e+18, 39 | "quality_score": 0.76024363233666, 40 | "sequence": "7nfcwfvjdtphz7yj6zat6a", 41 | "sfm_cluster": { 42 | "id": "306951457725231", 43 | "url": "sfm_cluster_filler_url" 44 | }, 45 | "width": 4160, 46 | "id": "308609047601518", 47 | "thumb_original_url": "thumb_original_filler_url", 48 | "detections": { 49 | "data": [ 50 | { 51 | "id": "310373714091718" 52 | }, 53 | { 54 | "id": "311423430653413" 55 | }, 56 | { 57 | "id": "311503437312079" 58 | }, 59 | { 60 | "id": "311542917308131" 61 | }, 62 | { 63 | "id": "311618317300591" 64 | } 65 | ] 66 | } 67 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/311681117131457.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": 1365.438, 3 | "atomic_scale": 1, 4 | "camera_parameters": [ 5 | 0.85, 6 | 0, 7 | 0 8 | ], 9 | "camera_type": "perspective", 10 | "captured_at": 1563721080184, 11 | "compass_angle": 344.66, 12 | "computed_altitude": 1399.4218842061, 13 | "computed_compass_angle": 344.94472689299, 14 | "computed_geometry": { 15 | "type": "Point", 16 | "coordinates": [ 17 | -108.57079697265, 18 | 39.069199998346 19 | ] 20 | }, 21 | "computed_rotation": [ 22 | 1.5608887723115, 23 | 0.20627902216826, 24 | -0.20625267065192 25 | ], 26 | "exif_orientation": 1, 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | -108.57079697222, 31 | 39.0692 32 | ] 33 | }, 34 | "height": 3120, 35 | "thumb_256_url": "thumb_256_filler_url", 36 | "thumb_1024_url": "thumb_1024_filler_url", 37 | "thumb_2048_url": "thumb_2048_filler_url", 38 | "merge_cc": 3.3337991113989e+18, 39 | "quality_score": 0.91282894736842, 40 | "sequence": "7nfcwfvjdtphz7yj6zat6a", 41 | "sfm_cluster": { 42 | "id": "155444533218101", 43 | "url": "sfm_cluster_filler_url" 44 | }, 45 | "width": 4160, 46 | "id": "311681117131457", 47 | "thumb_original_url": "thumb_original_filler_url", 48 | "detections": { 49 | "data": [ 50 | { 51 | "id": "313159516983617" 52 | } 53 | ] 54 | } 55 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/311681117131457/detections.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created_at": "2021-05-20T20:30:46+0000", 5 | "geometry": "GjgKBm1weS1vchIYEgIAABgDIhAJvjTKIxrIAwAAvALHAwAPGgR0eXBlIgkKB3BvbHlnb24ogCB4AQ==", 6 | "image": { 7 | "geometry": { 8 | "type": "Point", 9 | "coordinates": [ 10 | -108.57079697222, 11 | 39.0692 12 | ] 13 | }, 14 | "id": "311681117131457" 15 | }, 16 | "value": "information--general-directions--g1", 17 | "id": "313159516983617" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/311799370533334.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": 1363.049, 3 | "atomic_scale": 0.99647293545609, 4 | "camera_parameters": [ 5 | 0.84445215999653, 6 | 0.00013121033151786, 7 | -1.9432407137559e-06 8 | ], 9 | "camera_type": "perspective", 10 | "captured_at": 1563721051100, 11 | "compass_angle": 343.1, 12 | "computed_altitude": 1398.0575835621, 13 | "computed_compass_angle": 0.77063365372027, 14 | "computed_geometry": { 15 | "type": "Point", 16 | "coordinates": [ 17 | -108.57079091664, 18 | 39.065986975316 19 | ] 20 | }, 21 | "computed_rotation": [ 22 | 1.3806186802315, 23 | -0.050131317819359, 24 | -0.038180974935017 25 | ], 26 | "exif_orientation": 1, 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | -108.57079097222, 31 | 39.065986972222 32 | ] 33 | }, 34 | "height": 3120, 35 | "thumb_256_url": "thumb_256_filler_url", 36 | "thumb_1024_url": "thumb_1024_filler_url", 37 | "thumb_2048_url": "thumb_2048_filler_url", 38 | "merge_cc": 5.2826592657222e+17, 39 | "mesh": { 40 | "id": "2931656060382386", 41 | "url": "mesh_filler_url" 42 | }, 43 | "quality_score": 0.74476744186047, 44 | "sequence": "7nfcwfvjdtphz7yj6zat6a", 45 | "sfm_cluster": { 46 | "id": "511129849910835", 47 | "url": "sfm_cluster_filler_url" 48 | }, 49 | "width": 4160, 50 | "id": "311799370533334", 51 | "thumb_original_url": "thumb_original_filler_url", 52 | "detections": { 53 | "data": [ 54 | { 55 | "id": "313324430380828" 56 | }, 57 | { 58 | "id": "313366017043336" 59 | }, 60 | { 61 | "id": "313943736985564" 62 | } 63 | ] 64 | } 65 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/311799370533334/detections.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created_at": "2021-05-20T19:34:30+0000", 5 | "geometry": "GjUKBm1weS1vchIVEgIAABgDIg0Jhh2eLBpkAABiYwAPGgR0eXBlIgkKB3BvbHlnb24ogCB4AQ==", 6 | "image": { 7 | "geometry": { 8 | "type": "Point", 9 | "coordinates": [ 10 | -108.57079097222, 11 | 39.065986972222 12 | ] 13 | }, 14 | "id": "311799370533334" 15 | }, 16 | "value": "information--general-directions--g1", 17 | "id": "313324430380828" 18 | }, 19 | { 20 | "created_at": "2021-05-20T21:05:34+0000", 21 | "geometry": "GjgKBm1weS1vchIYEgIAABgDIhAJ3gbKKxqkAQAA1gGjAQAPGgR0eXBlIgkKB3BvbHlnb24ogCB4AQ==", 22 | "image": { 23 | "geometry": { 24 | "type": "Point", 25 | "coordinates": [ 26 | -108.57079097222, 27 | 39.065986972222 28 | ] 29 | }, 30 | "id": "311799370533334" 31 | }, 32 | "value": "regulatory--no-left-turn--g1", 33 | "id": "313366017043336" 34 | }, 35 | { 36 | "created_at": "2021-05-21T17:25:13+0000", 37 | "geometry": "GjcKBm1weS1vchIXEgIAABgDIg8JtBuMLRrKAQAAWMkBAA8aBHR5cGUiCQoHcG9seWdvbiiAIHgB", 38 | "image": { 39 | "geometry": { 40 | "type": "Point", 41 | "coordinates": [ 42 | -108.57079097222, 43 | 39.065986972222 44 | ] 45 | }, 46 | "id": "311799370533334" 47 | }, 48 | "value": "information--general-directions--g1", 49 | "id": "313943736985564" 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/338231874314914.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": 1364.617, 3 | "atomic_scale": 0.97891115347587, 4 | "camera_parameters": [ 5 | 0.85136388143343, 6 | -6.6499673206348e-05, 7 | -3.8067681992196e-05 8 | ], 9 | "camera_type": "perspective", 10 | "captured_at": 1563721072184, 11 | "compass_angle": 336.74, 12 | "computed_altitude": 1399.5043095825, 13 | "computed_compass_angle": 1.2865829255371, 14 | "computed_geometry": { 15 | "type": "Point", 16 | "coordinates": [ 17 | -108.57081597085, 18 | 39.068354912098 19 | ] 20 | }, 21 | "computed_rotation": [ 22 | 1.3642214091955, 23 | -0.0019509766093401, 24 | 0.035317244081076 25 | ], 26 | "exif_orientation": 1, 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | -108.57081597222, 31 | 39.068354972222 32 | ] 33 | }, 34 | "height": 3120, 35 | "thumb_256_url": "thumb_256_filler_url", 36 | "thumb_1024_url": "thumb_1024_filler_url", 37 | "thumb_2048_url": "thumb_2048_filler_url", 38 | "merge_cc": 4.546427159383e+18, 39 | "mesh": { 40 | "id": "903987176835273", 41 | "url": "mesh_filler_url" 42 | }, 43 | "quality_score": 0.7561310782241, 44 | "sequence": "7nfcwfvjdtphz7yj6zat6a", 45 | "sfm_cluster": { 46 | "id": "306951457725231", 47 | "url": "sfm_cluster_filler_url" 48 | }, 49 | "width": 4160, 50 | "id": "338231874314914", 51 | "thumb_original_url": "thumb_original_filler_url", 52 | "detections": { 53 | "data": [] 54 | }, 55 | "comment": "This file is pretty much hand written -- the image appears to be borked on Mapillary's end (as of August 17, 2021)" 56 | } 57 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/4235112816526838.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": 1362.799, 3 | "atomic_scale": 1, 4 | "camera_parameters": [ 5 | 0.85, 6 | 0, 7 | 0 8 | ], 9 | "camera_type": "perspective", 10 | "captured_at": 1563721059027, 11 | "compass_angle": 336.32, 12 | "computed_altitude": 1398.8672037208, 13 | "computed_compass_angle": 335.53765702375, 14 | "computed_geometry": { 15 | "type": "Point", 16 | "coordinates": [ 17 | -108.57081199999, 18 | 39.066878001959 19 | ] 20 | }, 21 | "computed_rotation": [ 22 | 1.5448066712781, 23 | 0.33486840325311, 24 | -0.33486442444208 25 | ], 26 | "exif_orientation": 1, 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | -108.570812, 31 | 39.066878 32 | ] 33 | }, 34 | "height": 3120, 35 | "thumb_256_url": "thumb_256_filler_url", 36 | "thumb_1024_url": "thumb_1024_filler_url", 37 | "thumb_2048_url": "thumb_2048_filler_url", 38 | "merge_cc": 7.4009176193932e+17, 39 | "quality_score": 0.80005636581413, 40 | "sequence": "7nfcwfvjdtphz7yj6zat6a", 41 | "sfm_cluster": { 42 | "id": "183557110205058", 43 | "url": "sfm_cluster_filler_url" 44 | }, 45 | "width": 4160, 46 | "id": "4235112816526838", 47 | "thumb_original_url": "thumb_original_filler_url", 48 | "detections": { 49 | "data": [ 50 | { 51 | "id": "4239760849395368" 52 | }, 53 | { 54 | "id": "4243230999048353" 55 | }, 56 | { 57 | "id": "4248247361880050" 58 | }, 59 | { 60 | "id": "4248381345199985" 61 | }, 62 | { 63 | "id": "4248765325161587" 64 | }, 65 | { 66 | "id": "4248842428487210" 67 | }, 68 | { 69 | "id": "4249042848467168" 70 | }, 71 | { 72 | "id": "4249064551798331" 73 | } 74 | ] 75 | } 76 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/464249047982277.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": 1362.421, 3 | "atomic_scale": 1, 4 | "camera_parameters": [ 5 | 0.85, 6 | 0, 7 | 0 8 | ], 9 | "camera_type": "perspective", 10 | "captured_at": 1563721062971, 11 | "compass_angle": 335.83, 12 | "computed_altitude": 1399.2187248701, 13 | "computed_compass_angle": 338.04298879857, 14 | "computed_geometry": { 15 | "type": "Point", 16 | "coordinates": [ 17 | -108.57081497264, 18 | 39.067357000697 19 | ] 20 | }, 21 | "computed_rotation": [ 22 | 1.5496206827148, 23 | 0.30062622625581, 24 | -0.30065559861764 25 | ], 26 | "exif_orientation": 1, 27 | "geometry": { 28 | "type": "Point", 29 | "coordinates": [ 30 | -108.57081497222, 31 | 39.067357 32 | ] 33 | }, 34 | "height": 3120, 35 | "thumb_256_url": "thumb_256_filler_url", 36 | "thumb_1024_url": "thumb_1024_filler_url", 37 | "thumb_2048_url": "thumb_2048_filler_url", 38 | "merge_cc": 4.0138052809816e+18, 39 | "quality_score": 0.95078612716763, 40 | "sequence": "7nfcwfvjdtphz7yj6zat6a", 41 | "sfm_cluster": { 42 | "id": "298750828608649", 43 | "url": "sfm_cluster_filler_url" 44 | }, 45 | "width": 4160, 46 | "id": "464249047982277", 47 | "thumb_original_url": "thumb_original_filler_url", 48 | "detections": { 49 | "data": [ 50 | { 51 | "id": "465612364512612" 52 | } 53 | ] 54 | } 55 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/464249047982277/detections.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created_at": "2021-05-21T02:11:27+0000", 5 | "geometry": "GjgKBm1weS1vchIYEgIAABgDIhAJliP0GxqmBgAA8AKlBgAPGgR0eXBlIgkKB3BvbHlnb24ogCB4AQ==", 6 | "image": { 7 | "geometry": { 8 | "type": "Point", 9 | "coordinates": [ 10 | -108.57081497222, 11 | 39.067357 12 | ] 13 | }, 14 | "id": "464249047982277" 15 | }, 16 | "value": "information--general-directions--g1", 17 | "id": "465612364512612" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/496980935069177.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_seen_at": "2017-08-23T21:32:26+0000", 3 | "last_seen_at": "2017-08-23T21:32:26+0000", 4 | "object_value": "complementary--both-directions--g2", 5 | "object_type": "trafficsign", 6 | "geometry": { 7 | "type": "Point", 8 | "coordinates": [ 9 | -83.417193328459, 10 | 41.341166490122 11 | ] 12 | }, 13 | "images": { 14 | "data": [ 15 | { 16 | "geometry": { 17 | "type": "Point", 18 | "coordinates": [ 19 | -83.41752502, 20 | 41.34126339 21 | ] 22 | }, 23 | "id": "133075088816573" 24 | }, 25 | { 26 | "geometry": { 27 | "type": "Point", 28 | "coordinates": [ 29 | -83.41764319, 30 | 41.34124814 31 | ] 32 | }, 33 | "id": "512146709982392" 34 | }, 35 | { 36 | "geometry": { 37 | "type": "Point", 38 | "coordinates": [ 39 | -83.41758216, 40 | 41.34124408 41 | ] 42 | }, 43 | "id": "828719391332432" 44 | } 45 | ] 46 | }, 47 | "id": "496980935069177" 48 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/496980935069177/detections.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "created_at": "2021-05-21T14:59:31+0000", 5 | "geometry": "GjYKBm1weS1vchIWEgIAABgDIg4Jkia4HxpYAACMAVcADxoEdHlwZSIJCgdwb2x5Z29uKIAgeAE=", 6 | "image": { 7 | "geometry": { 8 | "type": "Point", 9 | "coordinates": [ 10 | -83.41758216, 11 | 41.34124408 12 | ] 13 | }, 14 | "id": "828719391332432" 15 | }, 16 | "value": "complementary--both-directions--g2", 17 | "id": "835055007365537" 18 | }, 19 | { 20 | "created_at": "2021-05-21T14:59:31+0000", 21 | "geometry": "GjYKBm1weS1vchIWEgIAABgDIg4JwiekHxpoAACeAWcADxoEdHlwZSIJCgdwb2x5Z29uKIAgeAE=", 22 | "image": { 23 | "geometry": { 24 | "type": "Point", 25 | "coordinates": [ 26 | -83.41752502, 27 | 41.34126339 28 | ] 29 | }, 30 | "id": "133075088816573" 31 | }, 32 | "value": "complementary--both-directions--g2", 33 | "id": "139111688212913" 34 | }, 35 | { 36 | "created_at": "2021-05-21T14:59:31+0000", 37 | "geometry": "GjUKBm1weS1vchIVEgIAABgDIg0JsCTkHxpSAAB8UQAPGgR0eXBlIgkKB3BvbHlnb24ogCB4AQ==", 38 | "image": { 39 | "geometry": { 40 | "type": "Point", 41 | "coordinates": [ 42 | -83.41764319, 43 | 41.34124814 44 | ] 45 | }, 46 | "id": "512146709982392" 47 | }, 48 | "value": "complementary--both-directions--g2", 49 | "id": "518393049357758" 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/README.md: -------------------------------------------------------------------------------- 1 | # Entity responses 2 | All entity responses are formatted with `jq`. Please keep in mind that the formatting from the server is typically less human readable (i.e., no spacing, no newlines, etc.). 3 | 4 | ## Image 5 | This returns the metadata for an image. 6 | 7 | When used in tests, the output should be appropriately filtered if it is the return from an API call. 8 | 9 | ### Endpoint 10 | * https://graph.mapillary.com/:image\_id 11 | 12 | ### Fields 13 | * altitude 14 | * atomic\_scale 15 | * camera\_parameters 16 | * camera\_parameters 17 | * camera\_type 18 | * captured\_at 19 | * compass\_angle 20 | * computed\_altitude 21 | * computed\_compass\_angle 22 | * computed\_geometry 23 | * computed\_rotation 24 | * exif\_orientation 25 | * geometry 26 | * height 27 | * thumb\_256\_url 28 | * thumb\_1024\_url 29 | * thumb\_2048\_url 30 | * merge\_cc 31 | * mesh 32 | * quality\_score 33 | * sequence 34 | * sfm\_cluster 35 | * width 36 | 37 | ## Sequence 38 | Sequence entities represent a sequence of image IDS ordered by capture time. 39 | 40 | These are stored in image\_ids/:sequence\_id 41 | 42 | 43 | ### Endpoints 44 | * https://graph.mapillary.com/image\_ids?sequence\_id=:sequence\_id -- this is a collection endpoint, so the `data` value is an array. 45 | 46 | ### Fields 47 | * `id`: The identifier for the image in the sequence 48 | -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/application_request_limit_reached.json: -------------------------------------------------------------------------------- 1 | {"error":{"message":"Application request limit reached","type":"MLYApiException","is_transient":true,"code":4,"fbtrace_id":"AFJKU45YcZHFgmaRmycfmQ3"}} -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/image_ids/7nfcwfvjdtphz7yj6zat6a.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "id": "148137757289079" 5 | }, 6 | { 7 | "id": "311799370533334" 8 | }, 9 | { 10 | "id": "338231874314914" 11 | }, 12 | { 13 | "id": "4235112816526838" 14 | }, 15 | { 16 | "id": "464249047982277" 17 | }, 18 | { 19 | "id": "308609047601518" 20 | }, 21 | { 22 | "id": "135511895288847" 23 | }, 24 | { 25 | "id": "311681117131457" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/internal_server_error.json: -------------------------------------------------------------------------------- 1 | {"error":{"message":"Invalid OAuth 2.0 Access Token","type":"MLYApiException","code":190,"error_data":{},"fbtrace_id":"AMN5QfsCEBZg1LNVFA4bpvy"}} -------------------------------------------------------------------------------- /test/data/__files/api/v4/responses/graph/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | -------------------------------------------------------------------------------- /test/data/api/v3/requests/changeset.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "location", 3 | "changes": [ 4 | { 5 | "image_key": "7erPn382xDMtmfdh0xtvUw", 6 | "from": { 7 | "type": "Feature", 8 | "properties": { 9 | "ca": 0.0 10 | }, 11 | "geometry": { 12 | "type": "Point", 13 | "coordinates": [ 14 | 0.0, 15 | 0.0 16 | ] 17 | } 18 | }, 19 | "to": { 20 | "geometry": { 21 | "coordinates": [ 22 | 13.3328, 23 | 50.44619 24 | ], 25 | "type": "Point" 26 | }, 27 | "properties": { 28 | "ca": 0.0 29 | }, 30 | "type": "Feature" 31 | } 32 | }, 33 | { 34 | "image_key": "invalid image key will be ignored", 35 | "from": { 36 | "type": "Feature", 37 | "properties": { 38 | "ca": 0.0 39 | }, 40 | "geometry": { 41 | "type": "Point", 42 | "coordinates": [ 43 | 0.0, 44 | 0.0 45 | ] 46 | } 47 | }, 48 | "to": { 49 | "geometry": { 50 | "coordinates": [ 51 | 0.0, 52 | 0.0 53 | ], 54 | "type": "Point" 55 | }, 56 | "properties": { 57 | "ca": 13.4 58 | }, 59 | "type": "Feature" 60 | } 61 | }, 62 | { 63 | "image_key": "wMAqAFr3xE9072G8Al6WLQ", 64 | "from": { 65 | "type": "Feature", 66 | "properties": { 67 | "ca": 10.0 68 | }, 69 | "geometry": { 70 | "coordinates": [ 71 | 13.3323, 72 | 50.44612 73 | ], 74 | "type": "Point" 75 | } 76 | }, 77 | "to": { 78 | "type": "Feature", 79 | "geometry": { 80 | "coordinates": [ 81 | 13.4434, 82 | 50.66834 83 | ], 84 | "type": "Point" 85 | }, 86 | "properties": { 87 | "ca": 283.3 88 | } 89 | } 90 | } 91 | ], 92 | "request_comment": "JOSM-created" 93 | } 94 | -------------------------------------------------------------------------------- /test/data/api/v3/requests/rotation_only_changeset.json: -------------------------------------------------------------------------------- 1 | { 2 | "image_key": "rotationOnlyChangesetImageKey", 3 | "from": { 4 | "type": "Feature", 5 | "properties": { 6 | "ca": 10.0 7 | }, 8 | "geometry": { 9 | "type": "Point", 10 | "coordinates": [ 11 | 13.3323, 12 | 50.44612 13 | ] 14 | } 15 | }, 16 | "to": { 17 | "geometry": { 18 | "coordinates": [ 19 | 13.3323, 20 | 50.44612 21 | ], 22 | "type": "Point" 23 | }, 24 | "properties": { 25 | "ca": -70.3 26 | }, 27 | "type": "Feature" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/data/api/v3/requests/single_image_changeset.json: -------------------------------------------------------------------------------- 1 | { 2 | "image_key": "wMAqAFr3xE9072G8Al6WLQ", 3 | "from": { 4 | "type": "Feature", 5 | "properties": { 6 | "ca": 10.0 7 | }, 8 | "geometry": { 9 | "type": "Point", 10 | "coordinates": [ 11 | 13.3323, 12 | 50.44612 13 | ] 14 | } 15 | }, 16 | "to": { 17 | "geometry": { 18 | "coordinates": [ 19 | 13.4434, 20 | 50.66834 21 | ], 22 | "type": "Point" 23 | }, 24 | "properties": { 25 | "ca": 283.3 26 | }, 27 | "type": "Feature" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/data/api/v3/requests/translation_only_changeset.json: -------------------------------------------------------------------------------- 1 | { 2 | "image_key": "translationOnlyChangesetImageKey", 3 | "from": { 4 | "type": "Feature", 5 | "properties": { 6 | "ca": 10.0 7 | }, 8 | "geometry": { 9 | "type": "Point", 10 | "coordinates": [ 11 | 13.3323, 12 | 50.44612 13 | ] 14 | } 15 | }, 16 | "to": { 17 | "geometry": { 18 | "coordinates": [ 19 | 13.4434, 20 | 50.66834 21 | ], 22 | "type": "Point" 23 | }, 24 | "properties": { 25 | "ca": 10.0 26 | }, 27 | "type": "Feature" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/README.md: -------------------------------------------------------------------------------- 1 | This directory contains example data representative for what the APIv3 typically returns for certain queries. 2 | 3 | The examples are taken from https://www.mapillary.com/developer/api-documentation/ . 4 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/imageDetection.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "properties": { 4 | "area": 0.0015604496002197266, 5 | "image_key": "QhRcdlGS_Rn_a1_HTclefg", 6 | "key": "gn0llgitnnuqonecevbmf52ino", 7 | "layer": "trafficsign", 8 | "score": 0.710661225175, 9 | "shape": { 10 | "type": "Polygon", 11 | "coordinates": [ 12 | [ 13 | [ 14 | 0.330078125, 15 | 0.466064453125 16 | ], 17 | [ 18 | 0.3642578125, 19 | 0.466064453125 20 | ], 21 | [ 22 | 0.3642578125, 23 | 0.51171875 24 | ], 25 | [ 26 | 0.330078125, 27 | 0.51171875 28 | ], 29 | [ 30 | 0.330078125, 31 | 0.466064453125 32 | ] 33 | ] 34 | ] 35 | }, 36 | "value": "regulatory--no-overtaking-by-heavy-goods-vehicles--g1" 37 | }, 38 | "geometry": { 39 | "type": "Point", 40 | "coordinates": [ 41 | 10.805287, 42 | 55.321409 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/images_LwrHXqFRN_pszCopTKHF_Q.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "properties": { 4 | "ca": 323.0319999999999, 5 | "camera_make": "Apple", 6 | "camera_model": "iPhone5,4", 7 | "captured_at": "2016-03-14T13:44:53.860Z", 8 | "key": "LwrHXqFRN_pszCopTKHF_Q", 9 | "pano": false, 10 | "sequence_key": "LMlIPUNhaj24h_q9v4ArNw", 11 | "user_key": "AGfe-07BEJX0-kxpu9J3rA", 12 | "username": "pierregeo", 13 | "quality_score": 4 14 | }, 15 | "geometry": { 16 | "type": "Point", 17 | "coordinates": [ 18 | 16.432958, 19 | 7.246497 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/mapObject.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "properties": { 4 | "accuracy": 1, 5 | "altitude": 1.7983143, 6 | "first_seen_at": "2016-07-01T12:49:08.553Z", 7 | "key": "9f3tl0z2xanom2inyyks65negx", 8 | "last_seen_at": "2016-07-01T12:49:08.553Z", 9 | "layer": "trafficsign", 10 | "value": "regulatory--no-entry--g1", 11 | "detections": [] 12 | }, 13 | "geometry": { 14 | "type": "Point", 15 | "coordinates": [ 16 | 13.017088890075684, 17 | 55.60746765136719 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/searchImageDetections.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": { 7 | "area": 0.00010585784912109375, 8 | "image_key": "33zgql54_tBVvmIij0zrcA", 9 | "key": "bzqdn10wz1s1xd3lae3hawgja0", 10 | "layer": "trafficsign", 11 | "score": 0.000001, 12 | "shape": { 13 | "type": "Polygon", 14 | "coordinates": [ 15 | [ 16 | [ 17 | 0.42724609375, 18 | 0.69091796875 19 | ], 20 | [ 21 | 0.436279296875, 22 | 0.69091796875 23 | ], 24 | [ 25 | 0.436279296875, 26 | 0.70263671875 27 | ], 28 | [ 29 | 0.42724609375, 30 | 0.70263671875 31 | ], 32 | [ 33 | 0.42724609375, 34 | 0.69091796875 35 | ] 36 | ] 37 | ] 38 | }, 39 | "value": "information--pedestrians-crossing--g1" 40 | }, 41 | "geometry": { 42 | "type": "Point", 43 | "coordinates": [ 44 | 12.995127, 45 | 55.550739 46 | ] 47 | } 48 | }, 49 | { 50 | "type": "Feature", 51 | "properties": { 52 | "area": 0.00010585784912109375, 53 | "image_key": "33zgql54_tBVvmIij0zrcA", 54 | "key": "uzve1xkyk5qbjwrzaq0do09u1x", 55 | "layer": "trafficsign", 56 | "score": 0.000001, 57 | "shape": { 58 | "type": "Polygon", 59 | "coordinates": [ 60 | [ 61 | [ 62 | 0.42724609375, 63 | 0.69091796875 64 | ], 65 | [ 66 | 0.436279296875, 67 | 0.69091796875 68 | ], 69 | [ 70 | 0.436279296875, 71 | 0.70263671875 72 | ], 73 | [ 74 | 0.42724609375, 75 | 0.70263671875 76 | ], 77 | [ 78 | 0.42724609375, 79 | 0.69091796875 80 | ] 81 | ] 82 | ] 83 | }, 84 | "value": "information--pedestrians-crossing--g1" 85 | }, 86 | "geometry": { 87 | "type": "Point", 88 | "coordinates": [ 89 | 12.995127, 90 | 55.550739 91 | ] 92 | } 93 | } 94 | ] 95 | } 96 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/searchImages.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": { 7 | "ca": 232.73019999999997, 8 | "camera_make": "Apple", 9 | "captured_at": "2017-04-10T05:51:30.334Z", 10 | "key": "_yA5uXuSNugmsK5VucU6Bg", 11 | "pano": false, 12 | "user_key": "UtczWn8y3afb0GQVW-AiOQ", 13 | "username": "xtyou" 14 | }, 15 | "geometry": { 16 | "type": "Point", 17 | "coordinates": [ 18 | 2.215628000000038, 19 | 48.90262200000001 20 | ] 21 | } 22 | }, 23 | { 24 | "type": "Feature", 25 | "properties": { 26 | "ca": 237.21129999999994, 27 | "camera_make": "Apple", 28 | "captured_at": "2017-04-10T05:51:26.853Z", 29 | "key": "nmF-Wq4EvVTgAUmBicSCCg", 30 | "pano": false, 31 | "user_key": "UtczWn8y3afb0GQVW-AiOQ", 32 | "username": "xtyou" 33 | }, 34 | "geometry": { 35 | "type": "Point", 36 | "coordinates": [ 37 | 2.2156680000000506, 38 | 48.90267399999999 39 | ] 40 | } 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/searchMapObjects.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": { 7 | "accuracy": 1, 8 | "altitude": 3.688496, 9 | "first_seen_at": "2016-10-16T09:42:56.060Z", 10 | "key": "qpku21qv8rjn7fll1v671732th", 11 | "last_seen_at": "2016-10-16T09:42:56.060Z", 12 | "layer": "trafficsign", 13 | "value": "regulatory--no-parking--g1", 14 | "detections": [ 15 | { 16 | "detection_key": "cpatpdftmogffmhihau9792tua", 17 | "image_key": "bsw3H-ajJD42zZSg2P64hA" 18 | } 19 | ] 20 | }, 21 | "geometry": { 22 | "type": "Point", 23 | "coordinates": [ 24 | 13.005650520324707, 25 | 55.608367919921875 26 | ] 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/searchSequences.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": { 7 | "camera_make": "Apple", 8 | "captured_at": "2016-03-14T13:44:53.860Z", 9 | "created_at": "2016-03-17T10:47:53.106Z", 10 | "coordinateProperties": { 11 | "cas": [ 12 | 323.0319999999999, 13 | 320.8918, 14 | 333.62239999999997, 15 | 329.94820000000004 16 | ], 17 | "image_keys": [ 18 | "LwrHXqFRN_pszCopTKHF_Q", 19 | "Aufjv2hdCKwg9LySWWVSwg", 20 | "QEVZ1tp-PmrwtqhSwdW9fQ", 21 | "G_SIwxNcioYeutZuA8Rurw" 22 | ] 23 | }, 24 | "key": "LMlIPUNhaj24h_q9v4ArNw", 25 | "pano": false, 26 | "user_key": "AGfe-07BEJX0-kxpu9J3rA" 27 | }, 28 | "geometry": { 29 | "type": "LineString", 30 | "coordinates": [ 31 | [ 32 | 16.432958, 33 | 7.246497 34 | ], 35 | [ 36 | 16.432955, 37 | 7.246567 38 | ], 39 | [ 40 | 16.432971, 41 | 7.248372 42 | ], 43 | [ 44 | 16.432976, 45 | 7.249027 46 | ] 47 | ] 48 | } 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/searchSequencesTicket20211Area1.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type" : "FeatureCollection", 3 | "features" : [ 4 | { 5 | "type" : "Feature", 6 | "geometry" : { 7 | "type" : "LineString", 8 | "coordinates" : [ 9 | [ 10 | -108.560526, 11 | 39.065414 12 | ], 13 | [ 14 | -108.561343, 15 | 39.065418 16 | ], 17 | [ 18 | -108.562143, 19 | 39.065415 20 | ], 21 | [ 22 | -108.563105, 23 | 39.065425 24 | ], 25 | [ 26 | -108.563708, 27 | 39.065407 28 | ] 29 | ] 30 | }, 31 | "properties" : { 32 | "captured_at" : "2019-07-21T14:56:25.559Z", 33 | "username" : "vorpalblade", 34 | "camera_make" : "Essential Products", 35 | "pano" : false, 36 | "user_key" : "x0hTY8cakpy0m3ui1GaG1A", 37 | "key" : "yqly53hefz24ylz79bwc5x", 38 | "coordinateProperties" : { 39 | "image_keys" : [ 40 | "3d3y3_-3jKsAm2khDHLaMQ", 41 | "axRgdZfUfW6I3Pq05GZIEw", 42 | "eYCNyXzan1GEALnFO4A0Ow", 43 | "3hxG2Xi6KEN2zeIKwUu8lQ", 44 | "lz_OmSdoDAaoAEDgQXZ4_w" 45 | ], 46 | "cas" : [ 47 | 252.27, 48 | 252.08, 49 | 253.21, 50 | 251.92, 51 | 253.5 52 | ] 53 | }, 54 | "created_at" : "2019-07-25T00:46:42.003Z" 55 | } 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/sequence.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "properties": { 4 | "camera_make": "Apple", 5 | "captured_at": "2016-03-14T13:44:37.206Z", 6 | "created_at": "2016-03-15T08:48:40.592Z", 7 | "coordinateProperties": { 8 | "cas": [ 9 | 96.71454, 10 | 96.47705000000002 11 | ], 12 | "image_keys": [ 13 | "76P0YUrlDD_lF6J7Od3yoA", 14 | "Ap_8E0BwoAqqewhJaEbFyQ" 15 | ] 16 | }, 17 | "key": "cHBf9e8n0pG8O0ZVQHGFBQ", 18 | "pano": false, 19 | "user_key": "AGfe-07BEJX0-kxpu9J3rA" 20 | }, 21 | "geometry": { 22 | "type": "LineString", 23 | "coordinates": [ 24 | [ 25 | 16.43279, 26 | 7.246085 27 | ], 28 | [ 29 | 16.432799, 30 | 7.246082 31 | ] 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/userProfile.json: -------------------------------------------------------------------------------- 1 | { 2 | "about": "Mapillary and Mapping!", 3 | "avatar": "https://d4vkkeqw582u.cloudfront.net/3f9f044b34b498ddfb9afbb6/profile.png", 4 | "created_at": "2013-09-18T16:52:28.042Z", 5 | "key": "2BJl04nvnfW1y2GNaj7x5w", 6 | "username": "gyllen" 7 | } 8 | -------------------------------------------------------------------------------- /test/data/api/v3/responses/userProfile2.json: -------------------------------------------------------------------------------- 1 | { 2 | "about": "Having a non-image avatar", 3 | "avatar": "https://example.org", 4 | "created_at": "2016-01-31T01:47:28.000+0500", 5 | "key": "abcdefg1", 6 | "username": "mapillary_userÄ2!" 7 | } 8 | -------------------------------------------------------------------------------- /test/data/exifTestImages/dateTimeOnly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/exifTestImages/dateTimeOnly.jpg -------------------------------------------------------------------------------- /test/data/exifTestImages/dateTimeOnly.metadata.txt: -------------------------------------------------------------------------------- 1 | add Exif.Photo.DateTimeOriginal 2015:12:24 01:02:03 2 | -------------------------------------------------------------------------------- /test/data/exifTestImages/generateExifTaggedImages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm latLonOnly.jpg 3 | rm dateTimeOnly.jpg 4 | rm gpsDirectionOnly.jpg 5 | cp -T untagged.jpg latLonOnly.jpg 6 | cp -T untagged.jpg dateTimeOnly.jpg 7 | cp -T untagged.jpg gpsDirectionOnly.jpg 8 | exiv2 -m latLonOnly.metadata.txt latLonOnly.jpg 9 | exiv2 -m dateTimeOnly.metadata.txt dateTimeOnly.jpg 10 | exiv2 -m gpsDirectionOnly.metadata.txt gpsDirectionOnly.jpg 11 | -------------------------------------------------------------------------------- /test/data/exifTestImages/gpsDirectionOnly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/exifTestImages/gpsDirectionOnly.jpg -------------------------------------------------------------------------------- /test/data/exifTestImages/gpsDirectionOnly.metadata.txt: -------------------------------------------------------------------------------- 1 | add Exif.GPSInfo.GPSImgDirection 4273/100 2 | -------------------------------------------------------------------------------- /test/data/exifTestImages/latLonOnly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/exifTestImages/latLonOnly.jpg -------------------------------------------------------------------------------- /test/data/exifTestImages/latLonOnly.metadata.txt: -------------------------------------------------------------------------------- 1 | add Exif.GPSInfo.GPSLatitude 55/1 36/1 19/1 2 | add Exif.GPSInfo.GPSLatitudeRef N 3 | add Exif.GPSInfo.GPSLongitude 13/1 0/1 1/2 4 | add Exif.GPSInfo.GPSLongitudeRef E 5 | -------------------------------------------------------------------------------- /test/data/exifTestImages/untagged.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/exifTestImages/untagged.jpg -------------------------------------------------------------------------------- /test/data/exifTestImages/untagged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/exifTestImages/untagged.png -------------------------------------------------------------------------------- /test/data/preferences/preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/data/xmpTestImages/xmpProjectionOnly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/xmpTestImages/xmpProjectionOnly.jpg -------------------------------------------------------------------------------- /test/data/xmpTestImages/xmpProjectionOnly.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/data/zeroByteFile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JOSM/Mapillary/5bfeceebe95d8ea8b4a9e14942b1edadd04e8362/test/data/zeroByteFile -------------------------------------------------------------------------------- /test/resources: -------------------------------------------------------------------------------- 1 | data -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/datepicker/impl/GenericDateImplementationTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.datepicker.impl; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | import java.time.Instant; 8 | import java.time.LocalDate; 9 | import java.time.ZoneOffset; 10 | import java.util.Calendar; 11 | import java.util.Date; 12 | import java.util.stream.Stream; 13 | 14 | import org.junit.jupiter.params.ParameterizedTest; 15 | import org.junit.jupiter.params.provider.Arguments; 16 | import org.junit.jupiter.params.provider.MethodSource; 17 | import org.openstreetmap.josm.plugins.datepicker.IDatePicker; 18 | 19 | /** 20 | * Test method for date implementations. 21 | * The {@link #getDatePickers} method should be updated when new date pickers are implemented. 22 | */ 23 | class GenericDateImplementationTest { 24 | static Stream getDatePickers() { 25 | Calendar minCalendar = Calendar.getInstance(); 26 | minCalendar.setTime(new Date(Long.MIN_VALUE)); 27 | Calendar maxCalendar = Calendar.getInstance(); 28 | maxCalendar.setTime(new Date(Long.MAX_VALUE)); 29 | LocalDate zero = LocalDate.of(1, 1, 1); 30 | LocalDate dec = LocalDate.of(1, 12, 31); 31 | LocalDate current = LocalDate.now(ZoneOffset.UTC); 32 | // Don't use LocalDate.MAX and LocalDate.MIN due to conversions between Date and LocalDate 33 | LocalDate max = LocalDate.of(maxCalendar.get(Calendar.YEAR), maxCalendar.get(Calendar.MONTH), 34 | maxCalendar.get(Calendar.DAY_OF_MONTH)); 35 | LocalDate min = LocalDate.of(minCalendar.get(Calendar.YEAR), minCalendar.get(Calendar.MONTH), 36 | minCalendar.get(Calendar.DAY_OF_MONTH)); 37 | return Stream.of(new DatePickerJDatePicker(), new DatePickerSwing()) 38 | .flatMap(datePicker -> Stream.of(Arguments.of(datePicker, min), Arguments.of(datePicker, max), 39 | Arguments.of(datePicker, dec), Arguments.of(datePicker, current), Arguments.of(datePicker, zero), 40 | Arguments.of(datePicker, null))); 41 | } 42 | 43 | @MethodSource("getDatePickers") 44 | @ParameterizedTest 45 | void testSetGetDate(final IDatePicker datePicker, final LocalDate expected) { 46 | // This check does not test for set text listeners. 47 | final Instant expectedInstant = expected != null ? Instant.from(expected.atStartOfDay(ZoneOffset.UTC)) 48 | : Instant.EPOCH; 49 | assertDoesNotThrow(() -> datePicker.setInstant(expectedInstant)); 50 | assertEquals(expectedInstant, datePicker.getInstant()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/actions/MapObjectLayerActionTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.actions; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | 6 | import org.junit.jupiter.api.Test; 7 | import org.openstreetmap.josm.data.osm.DataSet; 8 | import org.openstreetmap.josm.gui.MainApplication; 9 | import org.openstreetmap.josm.gui.layer.OsmDataLayer; 10 | import org.openstreetmap.josm.plugins.mapillary.gui.layer.PointObjectLayer; 11 | import org.openstreetmap.josm.plugins.mapillary.testutils.annotations.MapillaryURLWireMock; 12 | import org.openstreetmap.josm.plugins.mapillary.testutils.annotations.MapillaryURLWireMockErrors; 13 | import org.openstreetmap.josm.testutils.annotations.BasicPreferences; 14 | import org.openstreetmap.josm.testutils.annotations.Main; 15 | import org.openstreetmap.josm.testutils.annotations.Projection; 16 | 17 | @BasicPreferences 18 | @Main 19 | @MapillaryURLWireMock 20 | @Projection 21 | class MapObjectLayerActionTest { 22 | @Test 23 | @MapillaryURLWireMockErrors 24 | void testAction() { 25 | assertEquals(0, MainApplication.getLayerManager().getLayers().size()); 26 | new MapObjectLayerAction().actionPerformed(null); 27 | assertEquals(0, MainApplication.getLayerManager().getLayers().size()); 28 | MainApplication.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "Test", null)); 29 | new MapObjectLayerAction().actionPerformed(null); 30 | assertEquals(2, MainApplication.getLayerManager().getLayers().size()); 31 | new MapObjectLayerAction().actionPerformed(null); 32 | assertEquals(2, MainApplication.getLayerManager().getLayers().size()); 33 | MainApplication.getLayerManager() 34 | .setActiveLayer(MainApplication.getLayerManager().getLayersOfType(PointObjectLayer.class).get(0)); 35 | new MapObjectLayerAction().actionPerformed(null); 36 | assertEquals(2, MainApplication.getLayerManager().getLayers().size()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/cache/CachesTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.cache; 3 | 4 | import org.junit.jupiter.api.Test; 5 | import org.openstreetmap.josm.plugins.mapillary.utils.TestUtil; 6 | import org.openstreetmap.josm.testutils.annotations.BasicPreferences; 7 | 8 | /** 9 | * Test class for {@link Caches} 10 | */ 11 | // Preferences are needed to get the cache directories 12 | @BasicPreferences 13 | class CachesTest { 14 | @Test 15 | void testUtilityClass() { 16 | TestUtil.testUtilityClass(Caches.class); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/oauth/OAuthPortListenerTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.oauth; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.net.HttpURLConnection; 10 | import java.net.URL; 11 | import java.nio.charset.StandardCharsets; 12 | 13 | import org.junit.jupiter.api.Test; 14 | import org.openstreetmap.josm.testutils.annotations.BasicPreferences; 15 | import org.openstreetmap.josm.testutils.annotations.HTTP; 16 | 17 | /** 18 | * Tests the {@link OAuthPortListener} class. 19 | * 20 | * @author nokutu 21 | * @see OAuthPortListener 22 | */ 23 | @BasicPreferences 24 | @HTTP 25 | class OAuthPortListenerTest { 26 | 27 | /** 28 | * Test that the threads responds when the browser makes the request. 29 | */ 30 | @Test 31 | void responseTest() throws IOException, InterruptedException { 32 | OAuthPortListener t = new OAuthPortListener(null); 33 | t.start(); 34 | Thread.sleep(500); 35 | URL url = new URL("http://localhost:" + OAuthPortListener.PORT + "?access_token=access_token"); 36 | HttpURLConnection con = (HttpURLConnection) url.openConnection(); 37 | try (BufferedReader in = new BufferedReader( 38 | new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) { 39 | in.readLine(); 40 | assertEquals(OAuthPortListener.RESPONSE, in.readLine()); 41 | } finally { 42 | t.join(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/testutils/annotations/AwaitThreadFinish.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.testutils.annotations; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import java.lang.annotation.Documented; 7 | import java.lang.annotation.ElementType; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | import java.util.concurrent.ForkJoinPool; 12 | import java.util.concurrent.TimeUnit; 13 | import java.util.concurrent.atomic.AtomicBoolean; 14 | 15 | import org.awaitility.Awaitility; 16 | import org.awaitility.Durations; 17 | import org.junit.jupiter.api.extension.AfterEachCallback; 18 | import org.junit.jupiter.api.extension.BeforeEachCallback; 19 | import org.junit.jupiter.api.extension.ExtendWith; 20 | import org.junit.jupiter.api.extension.ExtensionContext; 21 | import org.openstreetmap.josm.gui.MainApplication; 22 | import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryUtils; 23 | import org.openstreetmap.josm.testutils.annotations.ThreadSync; 24 | 25 | /** 26 | * An annotation that waits for threads to finish before continuing 27 | * 28 | * @author Taylor Smock 29 | */ 30 | @Documented 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Target({ ElementType.TYPE, ElementType.METHOD }) 33 | @ExtendWith(AwaitThreadFinish.AwaitThreadFinishExtension.class) 34 | @ExtendWith(ThreadSync.ThreadSyncExtension.class) 35 | public @interface AwaitThreadFinish { 36 | /** 37 | * An extension that waits for threads to finish, and then continues 38 | */ 39 | class AwaitThreadFinishExtension implements AfterEachCallback, BeforeEachCallback { 40 | @Override 41 | public void afterEach(ExtensionContext context) { 42 | // Wait for everything to finish 43 | final AtomicBoolean workerDone = new AtomicBoolean(); 44 | MainApplication.worker.submit(() -> workerDone.set(true)); 45 | Awaitility.await().atMost(Durations.FIVE_SECONDS).until(workerDone::get); 46 | 47 | assertTrue(ForkJoinPool.commonPool().awaitQuiescence(5, TimeUnit.SECONDS)); 48 | MapillaryUtils.forkJoinPoolsAwaitQuiescence(5, TimeUnit.SECONDS); 49 | } 50 | 51 | @Override 52 | public void beforeEach(ExtensionContext context) { 53 | context.getStore(ExtensionContext.Namespace.create(AwaitThreadFinish.class)).put(Thread.class, 54 | Thread.activeCount()); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/testutils/annotations/GuiWorkersStopper.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.testutils.annotations; 3 | 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | 11 | import org.awaitility.Awaitility; 12 | import org.awaitility.Durations; 13 | import org.junit.jupiter.api.extension.AfterEachCallback; 14 | import org.junit.jupiter.api.extension.ExtendWith; 15 | import org.junit.jupiter.api.extension.ExtensionContext; 16 | import org.openstreetmap.josm.testutils.annotations.BasicPreferences; 17 | 18 | @Documented 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Target({ ElementType.TYPE, ElementType.METHOD }) 21 | @BasicPreferences 22 | @ExtendWith(GuiWorkersStopper.MapillaryDownloader.class) 23 | @MapillaryLayerAnnotation 24 | public @interface GuiWorkersStopper { 25 | class MapillaryDownloader implements AfterEachCallback { 26 | @Override 27 | public void afterEach(ExtensionContext context) { 28 | AtomicBoolean done = new AtomicBoolean(); 29 | new org.openstreetmap.josm.plugins.mapillary.gui.workers.MapillaryNodesDownloader(nodes -> done.set(true), 30 | 1).execute(); 31 | Awaitility.await().atMost(Durations.FIVE_SECONDS).untilTrue(done); 32 | done.set(false); 33 | new org.openstreetmap.josm.plugins.mapillary.gui.workers.MapillarySequenceDownloader("", 34 | chunks -> done.set(true)).execute(); 35 | Awaitility.await().atMost(Durations.FIVE_SECONDS).untilTrue(done); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/testutils/annotations/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.testutils.annotations; 3 | 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Inherited; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | import org.junit.jupiter.api.Tag; 12 | 13 | /** 14 | * Mark tests as integration tests. 15 | * 16 | * @author Taylor Smock 17 | */ 18 | @Target({ ElementType.TYPE, ElementType.METHOD }) 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Documented 21 | @Inherited 22 | @Tag(IntegrationTest.TAG) 23 | public @interface IntegrationTest { 24 | /** This is the actual tag string added to the test */ 25 | String TAG = "integration"; 26 | } 27 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/testutils/annotations/MapillaryLayerAnnotation.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.testutils.annotations; 3 | 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | import org.junit.jupiter.api.extension.AfterEachCallback; 11 | import org.junit.jupiter.api.extension.BeforeEachCallback; 12 | import org.junit.jupiter.api.extension.ExtendWith; 13 | import org.junit.jupiter.api.extension.ExtensionContext; 14 | import org.openstreetmap.josm.gui.MainApplication; 15 | import org.openstreetmap.josm.plugins.mapillary.gui.layer.MapillaryLayer; 16 | import org.openstreetmap.josm.tools.Logging; 17 | 18 | /** 19 | * Ensure that the MapillaryLayer is cleaned up 20 | */ 21 | @Documented 22 | @Retention(RetentionPolicy.RUNTIME) 23 | @Target({ ElementType.TYPE, ElementType.METHOD }) 24 | @ExtendWith(MapillaryLayerAnnotation.MapillaryLayerExtension.class) 25 | @MapillaryURLWireMock 26 | public @interface MapillaryLayerAnnotation { 27 | class MapillaryLayerExtension implements AfterEachCallback, BeforeEachCallback { 28 | 29 | @Override 30 | public void afterEach(ExtensionContext context) { 31 | this.beforeEach(context); 32 | } 33 | 34 | @Override 35 | public void beforeEach(ExtensionContext context) { 36 | try { 37 | cleanup(); 38 | } catch (IllegalArgumentException illegalArgumentException) { 39 | // This happens when the layer isn't properly destroyed in a previous test 40 | Logging.trace(illegalArgumentException); 41 | } 42 | } 43 | 44 | void cleanup() { 45 | if (MapillaryLayer.hasInstance()) { 46 | final MapillaryLayer layer = MapillaryLayer.getInstance(); 47 | if (MainApplication.getLayerManager().containsLayer(layer)) { 48 | MainApplication.getLayerManager().removeLayer(layer); 49 | } 50 | layer.destroy(); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/testutils/annotations/ObjectDetectionsAnnotation.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.testutils.annotations; 3 | 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | import org.junit.jupiter.api.extension.AfterAllCallback; 11 | import org.junit.jupiter.api.extension.BeforeAllCallback; 12 | import org.junit.jupiter.api.extension.ExtendWith; 13 | import org.junit.jupiter.api.extension.ExtensionContext; 14 | import org.openstreetmap.josm.plugins.mapillary.data.mapillary.ObjectDetections; 15 | import org.openstreetmap.josm.testutils.annotations.BasicPreferences; 16 | import org.openstreetmap.josm.testutils.annotations.HTTP; 17 | import org.openstreetmap.josm.testutils.annotations.Projection; 18 | import org.openstreetmap.josm.testutils.annotations.TaggingPresets; 19 | 20 | /** 21 | * Annotation for ObjectDetections (ensures they have the appropriate presets) 22 | * 23 | * @author Taylor Smock 24 | */ 25 | @Documented 26 | @Target(ElementType.TYPE) 27 | @Retention(RetentionPolicy.RUNTIME) 28 | @BasicPreferences 29 | @HTTP 30 | @Projection 31 | @TaggingPresets 32 | @MapillaryURLWireMock // Needed since updatePresets calls an API endpoint 33 | @ExtendWith(ObjectDetectionsAnnotation.ObjectDetectionsExtension.class) 34 | public @interface ObjectDetectionsAnnotation { 35 | class ObjectDetectionsExtension implements AfterAllCallback, BeforeAllCallback { 36 | 37 | @Override 38 | public void afterAll(ExtensionContext context) { 39 | this.beforeAll(context); 40 | } 41 | 42 | @Override 43 | public void beforeAll(ExtensionContext context) { 44 | ObjectDetections.updatePresets(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/testutils/annotations/SecurityManagerTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.testutils.annotations; 3 | 4 | import java.security.Permission; 5 | 6 | import org.junit.jupiter.api.extension.AfterEachCallback; 7 | import org.junit.jupiter.api.extension.BeforeEachCallback; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.junit.jupiter.api.extension.ExtensionContext; 10 | 11 | /** 12 | * Used to indicate a security manager should be installed for a test. 13 | * This is mostly useful for non-regression tests for WebStart related issues. 14 | * 15 | * @author Taylor Smock 16 | */ 17 | @ExtendWith(SecurityManagerTest.SecurityManagerExtension.class) 18 | public @interface SecurityManagerTest { 19 | class SecurityManagerExtension implements AfterEachCallback, BeforeEachCallback { 20 | private static class TestSecurityManager extends SecurityManager { 21 | @Override 22 | public void checkPermission(Permission perm) { 23 | if (perm instanceof RuntimePermission && "setSecurityManager".equals(perm.getName())) { 24 | StackTraceElement stackTrace = Thread.currentThread().getStackTrace()[1]; 25 | if (SecurityManagerTest.SecurityManagerExtension.class.getCanonicalName() 26 | .equals(stackTrace.getClassName())) { 27 | return; 28 | } 29 | } 30 | super.checkPermission(perm); 31 | } 32 | } 33 | 34 | @Override 35 | public void afterEach(ExtensionContext context) { 36 | SecurityManager sm = System.getSecurityManager(); 37 | if (sm instanceof TestSecurityManager) { 38 | System.setSecurityManager(null); 39 | } 40 | } 41 | 42 | @Override 43 | public void beforeEach(ExtensionContext context) { 44 | if (System.getSecurityManager() == null) { 45 | TestSecurityManager securityManager = new TestSecurityManager(); 46 | System.setSecurityManager(securityManager); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/utils/ImageMetaDataUtilTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.nio.file.Files; 10 | import java.nio.file.Paths; 11 | 12 | import org.junit.jupiter.api.Test; 13 | import org.openstreetmap.josm.TestUtils; 14 | 15 | class ImageMetaDataUtilTest { 16 | @Test 17 | void testXmpXmlParse() throws IOException { 18 | boolean pano = ImageMetaDataUtil.checkXmpProjectionType( 19 | Files.readString(Paths.get(TestUtils.getTestDataRoot(), "xmpTestImages", "xmpProjectionOnly.xml")), 20 | "equirectangular"); 21 | assertTrue(pano); 22 | } 23 | 24 | @Test 25 | void testImageFileXMP() { 26 | final File xmpImageFile = Paths.get(TestUtils.getTestDataRoot(), "xmpTestImages", "xmpProjectionOnly.jpg") 27 | .toFile(); 28 | boolean pano = ImageMetaDataUtil.isPanorama(xmpImageFile); 29 | assertTrue(pano); 30 | } 31 | 32 | @Test 33 | void testImageStreamingXMP() throws IOException { 34 | try (InputStream xmpImageStream = Files 35 | .newInputStream(Paths.get(TestUtils.getTestDataRoot(), "xmpTestImages", "xmpProjectionOnly.jpg"))) { 36 | boolean pano = ImageMetaDataUtil.isPanorama(xmpImageStream); 37 | assertTrue(pano); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/utils/ImageUtilTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | 6 | import java.awt.image.BufferedImage; 7 | 8 | import javax.swing.ImageIcon; 9 | 10 | import org.junit.jupiter.api.Test; 11 | 12 | class ImageUtilTest { 13 | 14 | @Test 15 | void testUtilityClass() { 16 | TestUtil.testUtilityClass(ImageUtil.class); 17 | } 18 | 19 | @Test 20 | void testScaleImageIcon() { 21 | ImageIcon largeLandscape = new ImageIcon(new BufferedImage(72, 60, BufferedImage.TYPE_4BYTE_ABGR)); 22 | ImageIcon largePortrait = new ImageIcon(new BufferedImage(56, 88, BufferedImage.TYPE_4BYTE_ABGR)); 23 | ImageIcon smallLandscape = ImageUtil.scaleImageIcon(largeLandscape, 24); 24 | ImageIcon smallPortrait = ImageUtil.scaleImageIcon(largePortrait, 22); 25 | 26 | assertEquals(24, smallLandscape.getIconWidth()); 27 | assertEquals(20, smallLandscape.getIconHeight()); 28 | 29 | assertEquals(22, smallPortrait.getIconHeight()); 30 | assertEquals(14, smallPortrait.getIconWidth()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryColorSchemeTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 5 | 6 | import javax.swing.JComponent; 7 | 8 | import org.junit.jupiter.api.Test; 9 | 10 | class MapillaryColorSchemeTest { 11 | 12 | @Test 13 | void testUtilityClass() { 14 | TestUtil.testUtilityClass(MapillaryColorScheme.class); 15 | } 16 | 17 | @Test 18 | void testStyleAsDefaultPanel() { 19 | assertDoesNotThrow(() -> { 20 | MapillaryColorScheme.styleAsDefaultPanel(); 21 | MapillaryColorScheme.styleAsDefaultPanel((JComponent[]) null); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryPropertiesTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils; 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | class MapillaryPropertiesTest { 7 | @Test 8 | void test() { 9 | TestUtil.testUtilityClass(MapillaryProperties.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/utils/api/JsonDecoderTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils.api; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.IOException; 8 | import java.io.UncheckedIOException; 9 | import java.nio.charset.StandardCharsets; 10 | import java.util.function.Function; 11 | 12 | import jakarta.json.Json; 13 | import jakarta.json.JsonReader; 14 | import jakarta.json.JsonValue; 15 | import org.junit.jupiter.api.Test; 16 | import org.openstreetmap.josm.plugins.mapillary.utils.TestUtil; 17 | 18 | class JsonDecoderTest { 19 | 20 | @Test 21 | void testUtilityClass() { 22 | TestUtil.testUtilityClass(JsonDecoder.class); 23 | } 24 | 25 | @Test 26 | void testDecodeDoublePair() { 27 | assertArrayEquals(new double[0], JsonDecoder.decodeDoublePair(null)); 28 | } 29 | 30 | /** 31 | * Convert a series of strings to JSON 32 | * 33 | * @param parts The string parts to convert 34 | * @return A json value 35 | */ 36 | static JsonValue stringToJsonValue(final String... parts) { 37 | return stringToJsonValue(JsonReader::readValue, parts); 38 | } 39 | 40 | /** 41 | * Convert a series of strings to JSON 42 | * 43 | * @param parts The string parts to convert 44 | * @param function The conversion function 45 | * @param The type to return 46 | * @return A json value 47 | */ 48 | static T stringToJsonValue(final Function function, final String... parts) { 49 | try ( 50 | ByteArrayInputStream stream = new ByteArrayInputStream( 51 | String.join(" ", parts).getBytes(StandardCharsets.UTF_8)); 52 | JsonReader reader = Json.createReader(stream)) { 53 | return function.apply(reader); 54 | } catch (IOException e) { 55 | throw new UncheckedIOException(e); 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /test/unit/org/openstreetmap/josm/plugins/mapillary/utils/api/JsonImageDetectionDecoderTest.java: -------------------------------------------------------------------------------- 1 | // License: GPL. For details, see LICENSE file. 2 | package org.openstreetmap.josm.plugins.mapillary.utils.api; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.nio.charset.StandardCharsets; 8 | 9 | import jakarta.json.Json; 10 | import jakarta.json.JsonReader; 11 | import org.junit.jupiter.params.ParameterizedTest; 12 | import org.junit.jupiter.params.provider.ValueSource; 13 | import org.openstreetmap.josm.plugins.mapillary.testutils.annotations.MapillaryCaches; 14 | import org.openstreetmap.josm.plugins.mapillary.testutils.annotations.MapillaryURLWireMock; 15 | 16 | @MapillaryCaches 17 | @MapillaryURLWireMock 18 | class JsonImageDetectionDecoderTest { 19 | 20 | /** 21 | * This is a non-regression test for JOSM #21254 22 | * 23 | * @param geometry The geometry to check 24 | */ 25 | @ParameterizedTest 26 | @ValueSource(strings = { "GiB4AgoGbXB5LW9yKIAgEhEYAwgBIgsJxheqLxIEFQAeDw==" }) 27 | void testDecodeImageDetectionGeometryNonRegression21254(final String geometry) { 28 | final String jsonString = "{\"value\":\"construction--barrier--concrete-block\",\"id\":\"1\",\"geometry\":\"" 29 | + geometry + "\",\"image\":{\"id\":\"1\"}}"; 30 | try (JsonReader jsonReader = Json 31 | .createReader(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)))) { 32 | assertDoesNotThrow(() -> JsonImageDetectionDecoder.decodeImageDetection(jsonReader.read(), null)); 33 | } 34 | } 35 | } 36 | --------------------------------------------------------------------------------