From 10a36d0b6edfe5794ff0babdd66b0915cce8174f Mon Sep 17 00:00:00 2001 From: Justin Barno Date: Mon, 14 Sep 2020 09:28:32 -0700 Subject: [PATCH] CCT 1.0.10 Release Notes Features and improvements This is a smaller release focused around creating and using bounding polygons in the CCT map. Mapping * Includes the Leaflet Geoman library to support drawing and editing bounding boxes and arbitrary polygons on the map * Support for importing and exporting polygons is now included as a field in the calibration JSON definition as a GeoJSON formatted block * Include/exclude options to toggle activation status on event/station pairs based on if they are bounded by a polygon * Excludes require that both the station and the event meet the criteria, that is inside or outside the polygon, to be selected for disabling * Includes require that **either** the station and the event meet the criteria, that is inside or outside the polygon, to be selected for enabling * Added REST endpoints for managing polygon related tasks via service calls as well Plotting * Site/Measurement now plot the estimated corner frequency (~Fc) line on spectral plots when a fit is available. --- README.md | 6 +- calibration-gui/pom.xml | 8 +- .../calibration/gui/CodaGuiController.java | 16 +- .../AbstractMeasurementController.java | 24 +- .../CodaParamLoadingController.java | 5 + .../gui/controllers/DataController.java | 34 +-- .../controllers/MeasuredMwsController.java | 3 +- .../gui/controllers/SiteController.java | 7 +- .../controllers/SpectraPlotController.java | 10 +- .../parameters/SharedBandController.java | 2 +- .../converters/param/CodaJsonParamLoader.java | 6 + .../gui/converters/param/RawGeoJSON.java | 27 +++ .../gui/data/client/ParameterWebClient.java | 21 +- .../client/api/CalibrationJsonConstants.java | 5 +- .../gui/data/client/api/ParameterClient.java | 5 + .../data/exporters/JsonTempFileWriter.java | 9 +- .../gui/data/exporters/ParamExporter.java | 7 +- .../exporters/SwftStyleParamFileWriter.java | 2 +- .../exporters/api/ParamTempFileWriter.java | 4 +- .../gui/events/MapIconActivationCallback.java | 6 + .../gui/events/MapPolygonChangeHandler.java | 36 +++ .../gui/events/UpdateMapPolygonEvent.java | 27 +++ .../gui/plotting/CodaWaveformPlotManager.java | 8 +- .../gui/plotting/SpectralPlot.java | 53 +++-- .../src/main/resources/application.properties | 1 + .../param/CodaJsonParamLoaderTest.java | 97 ++++---- .../resources/calibration-params-test.json | 18 ++ .../src/test/resources/logback-test.xml | 1 - .../calibration-application/pom.xml | 2 +- .../web/ConfigurationItemJsonController.java | 13 ++ .../web/GeometryJsonController.java | 66 ++++++ .../calibration-integration/pom.xml | 2 +- calibration-service/calibration-model/pom.xml | 2 +- .../model/domain/GeoJsonPolygon.java | 80 +++++++ .../calibration/model/domain/Spectra.java | 33 ++- .../calibration-repository/pom.xml | 2 +- .../repository/PolygonRepository.java | 23 ++ .../calibration-service-api/pom.xml | 2 +- .../service/api/ConfigurationService.java | 4 + .../service/api/GeometryService.java | 22 ++ .../calibration-service-impl/pom.xml | 19 +- .../impl/ConfigurationServiceImpl.java | 18 +- .../service/impl/GeometryServiceImpl.java | 138 ++++++++++++ .../processing/MdacCalculatorService.java | 4 + .../impl/processing/SpectraCalculator.java | 14 +- .../service/impl/GeometryServiceImplTest.java | 200 ++++++++++++++++ calibration-service/pom.xml | 2 +- calibration-standalone/pom.xml | 2 +- .../data/client/ParameterLocalClient.java | 16 +- .../data/client/WaveformLocalClient.java | 16 +- .../coda/calibration/AssessAutopicker.java | 28 ++- common-gui/pom.xml | 2 +- .../gui/data/client/WaveformWebClient.java | 20 ++ .../gui/data/client/api/WaveformClient.java | 4 + .../gui/converters/sac/SacExporterTest.java | 22 +- .../gui/converters/sac/SacLoaderTest.java | 22 +- common-service/common-application/pom.xml | 2 +- .../application/config/WebSocketConfig.java | 3 +- .../common/util/NumberFormatFactoryTest.java | 8 +- common-service/common-model/pom.xml | 2 +- common-service/common-repository/pom.xml | 2 +- .../common/repository/WaveformRepository.java | 31 ++- common-service/common-service-api/pom.xml | 2 +- common-service/common-service-impl/pom.xml | 2 +- .../service/impl/WaveformServiceImpl.java | 2 +- common-service/pom.xml | 2 +- envelope-gui/pom.xml | 2 +- envelope-service/envelope-application/pom.xml | 2 +- envelope-service/envelope-model/pom.xml | 2 +- envelope-service/envelope-repository/pom.xml | 2 +- envelope-service/envelope-service-api/pom.xml | 2 +- .../envelope-service-impl/pom.xml | 2 +- envelope-service/pom.xml | 2 +- envelope-standalone/pom.xml | 2 +- externals/pom.xml | 2 +- .../plotting/jmultiaxisplot/VPickLine.java | 3 +- mapping/pom.xml | 2 +- .../apps/coda/common/mapping/LeafletMap.java | 60 +++-- .../common/mapping/LeafletMapController.java | 12 + .../mapping/MAP_CALLBACK_EVENT_TYPE.java | 4 +- .../coda/common/mapping/MapCallbackEvent.java | 14 ++ .../apps/coda/common/mapping/api/GeoMap.java | 6 +- .../apps/coda/common/mapping/api/Icon.java | 6 +- .../main/resources/leaflet/images/Circle.svg | 15 ++ .../resources/leaflet/images/CircleMarker.svg | 7 + .../resources/leaflet/images/Edit_Vertex.png | Bin 0 -> 2018 bytes .../resources/leaflet/images/Edit_Vertex.svg | 11 + .../main/resources/leaflet/images/Eraser.png | Bin 0 -> 2193 bytes .../main/resources/leaflet/images/Eraser.svg | 17 ++ .../main/resources/leaflet/images/Line.svg | 11 + .../main/resources/leaflet/images/Magnet.svg | 17 ++ .../main/resources/leaflet/images/Marker.svg | 17 ++ .../main/resources/leaflet/images/Move.png | Bin 0 -> 1456 bytes .../main/resources/leaflet/images/Move.svg | 11 + .../main/resources/leaflet/images/Polygon.png | Bin 0 -> 1847 bytes .../main/resources/leaflet/images/Polygon.svg | 11 + .../resources/leaflet/images/Rectangle.png | Bin 0 -> 2057 bytes .../resources/leaflet/images/Rectangle.svg | 11 + .../resources/leaflet/images/Scissors.svg | 17 ++ .../main/resources/leaflet/leaflet-geoman.css | 213 ++++++++++++++++++ .../resources/leaflet/leaflet-geoman.min.js | 1 + .../src/main/resources/leaflet/leaflet.html | 141 +++++++++++- pom.xml | 46 ++-- 103 files changed, 1682 insertions(+), 271 deletions(-) create mode 100644 calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/RawGeoJSON.java create mode 100644 calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/MapPolygonChangeHandler.java create mode 100644 calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/UpdateMapPolygonEvent.java delete mode 100644 calibration-gui/src/test/resources/logback-test.xml create mode 100644 calibration-service/calibration-application/src/main/java/gov/llnl/gnem/apps/coda/calibration/application/web/GeometryJsonController.java create mode 100644 calibration-service/calibration-model/src/main/java/gov/llnl/gnem/apps/coda/calibration/model/domain/GeoJsonPolygon.java create mode 100644 calibration-service/calibration-repository/src/main/java/gov/llnl/gnem/apps/coda/calibration/repository/PolygonRepository.java create mode 100644 calibration-service/calibration-service-api/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/api/GeometryService.java create mode 100644 calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/GeometryServiceImpl.java create mode 100644 calibration-service/calibration-service-impl/src/test/java/gov/llnl/gnem/apps/coda/calibration/service/impl/GeometryServiceImplTest.java create mode 100644 mapping/src/main/resources/leaflet/images/Circle.svg create mode 100644 mapping/src/main/resources/leaflet/images/CircleMarker.svg create mode 100644 mapping/src/main/resources/leaflet/images/Edit_Vertex.png create mode 100644 mapping/src/main/resources/leaflet/images/Edit_Vertex.svg create mode 100644 mapping/src/main/resources/leaflet/images/Eraser.png create mode 100644 mapping/src/main/resources/leaflet/images/Eraser.svg create mode 100644 mapping/src/main/resources/leaflet/images/Line.svg create mode 100644 mapping/src/main/resources/leaflet/images/Magnet.svg create mode 100644 mapping/src/main/resources/leaflet/images/Marker.svg create mode 100644 mapping/src/main/resources/leaflet/images/Move.png create mode 100644 mapping/src/main/resources/leaflet/images/Move.svg create mode 100644 mapping/src/main/resources/leaflet/images/Polygon.png create mode 100644 mapping/src/main/resources/leaflet/images/Polygon.svg create mode 100644 mapping/src/main/resources/leaflet/images/Rectangle.png create mode 100644 mapping/src/main/resources/leaflet/images/Rectangle.svg create mode 100644 mapping/src/main/resources/leaflet/images/Scissors.svg create mode 100644 mapping/src/main/resources/leaflet/leaflet-geoman.css create mode 100644 mapping/src/main/resources/leaflet/leaflet-geoman.min.js diff --git a/README.md b/README.md index 5ced1505..628caf7d 100644 --- a/README.md +++ b/README.md @@ -42,18 +42,18 @@ We don't presently deploy versioned artifacts into a public repository like the #### **As a single runnable JAR** ```shell -java -jar coda-calibration/calibration-standalone/target/calibration-standalone-1.0.9-runnable.jar +java -jar coda-calibration/calibration-standalone/target/calibration-standalone-1.0.10-runnable.jar ``` #### **GUI alone** ```shell -java -jar coda-calibration/calibration-gui/target/calibration-gui-1.0.9-runnable.jar +java -jar coda-calibration/calibration-gui/target/calibration-gui-1.0.10-runnable.jar ``` #### **Calibration REST service alone** ```shell -java -jar coda-calibration/calibration-service/application/target/application-1.0.9-runnable.jar +java -jar coda-calibration/calibration-service/application/target/application-1.0.10-runnable.jar ``` #### A note about HTTPS diff --git a/calibration-gui/pom.xml b/calibration-gui/pom.xml index 374102ca..6a7282a2 100644 --- a/calibration-gui/pom.xml +++ b/calibration-gui/pom.xml @@ -7,7 +7,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 calibration-gui @@ -102,10 +102,6 @@ spring-boot-starter-webflux - - ch.qos.logback - logback-classic - org.springframework spring-test @@ -177,7 +173,7 @@ org.springframework.boot spring-boot-loader - + diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/CodaGuiController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/CodaGuiController.java index 1151ed41..5e22855f 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/CodaGuiController.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/CodaGuiController.java @@ -50,9 +50,12 @@ import gov.llnl.gnem.apps.coda.calibration.gui.controllers.SiteController; import gov.llnl.gnem.apps.coda.calibration.gui.controllers.parameters.ParametersController; import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationClient; +import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.ParameterClient; import gov.llnl.gnem.apps.coda.calibration.gui.data.exporters.ParamExporter; import gov.llnl.gnem.apps.coda.calibration.gui.events.CalibrationStageShownEvent; import gov.llnl.gnem.apps.coda.calibration.gui.events.MapIconActivationCallback; +import gov.llnl.gnem.apps.coda.calibration.gui.events.MapPolygonChangeHandler; +import gov.llnl.gnem.apps.coda.calibration.gui.events.UpdateMapPolygonEvent; import gov.llnl.gnem.apps.coda.calibration.gui.plotting.WaveformGui; import gov.llnl.gnem.apps.coda.calibration.gui.util.CalibrationProgressListener; import gov.llnl.gnem.apps.coda.calibration.gui.util.FileDialogs; @@ -139,6 +142,8 @@ public class CodaGuiController { private GeoMap mapController; private WaveformClient waveformClient; + + private ParameterClient configClient; private EnvelopeLoadingController envelopeLoadingController; @@ -179,7 +184,7 @@ public class CodaGuiController { @Autowired public CodaGuiController(GeoMap mapController, WaveformClient waveformClient, EnvelopeLoadingController waveformLoadingController, CodaParamLoadingController codaParamLoadingController, ReferenceEventLoadingController refEventLoadingController, CalibrationClient calibrationClient, ParamExporter paramExporter, WaveformGui waveformGui, DataController data, - ParametersController param, ShapeController shape, PathController path, SiteController site, MeasuredMwsController measuredMws, EventBus bus) { + ParametersController param, ShapeController shape, PathController path, SiteController site, MeasuredMwsController measuredMws, ParameterClient configClient, EventBus bus) { super(); this.mapController = mapController; this.waveformClient = waveformClient; @@ -195,6 +200,7 @@ public CodaGuiController(GeoMap mapController, WaveformClient waveformClient, En this.path = path; this.site = site; this.measuredMws = measuredMws; + this.configClient = configClient; this.bus = bus; bus.register(this); @@ -335,6 +341,7 @@ public void initialize() { waveformFocus.selectedProperty().bindBidirectional(waveformGui.focusProperty()); mapController.registerEventCallback(new MapIconActivationCallback(waveformClient)); + mapController.registerEventCallback(new MapPolygonChangeHandler(configClient)); activeMapIcon = makeMapLabel(); showMapIcon = makeMapLabel(); @@ -450,6 +457,13 @@ private Label makeSnapshotLabel() { return label; } + @Subscribe + private void listener(UpdateMapPolygonEvent event) { + if (mapController != null && event != null && event.getGeoJSON() != null && !event.getGeoJSON().isEmpty()) { + mapController.setPolygonGeoJSON(event.getGeoJSON()); + } + } + //TODO: Move this to a controller @Subscribe private void listener(CalibrationStatusEvent event) { diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/AbstractMeasurementController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/AbstractMeasurementController.java index 2f10a390..5d19be9d 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/AbstractMeasurementController.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/AbstractMeasurementController.java @@ -14,8 +14,10 @@ package gov.llnl.gnem.apps.coda.calibration.gui.controllers; import java.awt.Color; +import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; @@ -52,8 +54,8 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; -import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.ParameterClient; import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.EventClient; +import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.ParameterClient; import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.SpectraClient; import gov.llnl.gnem.apps.coda.calibration.gui.plotting.MapPlottingUtilities; import gov.llnl.gnem.apps.coda.calibration.gui.plotting.SpectralPlot; @@ -397,11 +399,19 @@ public void initialize() { .asObject()); iconCol.setCellValueFactory(x -> Bindings.createObjectBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(pp -> { - ImageView imView = new ImageView(SwingFXUtils.toFXImage(SymbolFactory.createSymbol(pp.getStyle(), 0, 0, 2, pp.getColor(), pp.getColor(), pp.getColor(), "", true, false, 10.0) - .getBufferedImage(256), - null)); - imView.setFitHeight(12); - imView.setFitWidth(12); + BufferedImage iconLayer = SymbolFactory.createSymbol(pp.getStyle(), 0, 0, 2.0, pp.getColor(), Color.BLACK, pp.getColor(), "", true, false, 10.0).getBufferedImage(216); + BufferedImage backgroundLayer = SymbolFactory.createSymbol(pp.getStyle(), 0, 0, 2.0, Color.BLACK, Color.BLACK, Color.BLACK, "", true, false, 10.0).getBufferedImage(256); + + BufferedImage combined = new BufferedImage(backgroundLayer.getWidth(), backgroundLayer.getHeight(), BufferedImage.TYPE_INT_ARGB); + + Graphics g = combined.getGraphics(); + g.drawImage(backgroundLayer, 0, 0, null); + g.drawImage(iconLayer, 20, 20, null); + g.dispose(); + + ImageView imView = new ImageView(SwingFXUtils.toFXImage(combined, null)); + imView.setFitHeight(16); + imView.setFitWidth(16); return imView; }).orElseGet(() -> new ImageView()))); @@ -466,7 +476,7 @@ private void plotSpectra() { spectraControllers.forEach(spc -> { if (fittingSpectra != null) { - spc.getSpectralPlot().plotXYdata(toPlotPoints(filteredMeasurements, spc.getDataFunc()), SHOW_LEGEND, fittingSpectra); + spc.getSpectralPlot().plotXYdata(toPlotPoints(filteredMeasurements, spc.getDataFunc()), SHOW_LEGEND, fittingSpectra); } else { spc.getSpectralPlot().plotXYdata(toPlotPoints(filteredMeasurements, spc.getDataFunc()), HIDE_LEGEND); } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/CodaParamLoadingController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/CodaParamLoadingController.java index a3d3c093..e6de6731 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/CodaParamLoadingController.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/CodaParamLoadingController.java @@ -32,9 +32,11 @@ import com.google.common.eventbus.EventBus; import gov.llnl.gnem.apps.coda.calibration.gui.converters.api.FileToParameterConverter; +import gov.llnl.gnem.apps.coda.calibration.gui.converters.param.RawGeoJSON; import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.ParameterClient; import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.EventClient; import gov.llnl.gnem.apps.coda.calibration.gui.events.ParametersLoadedEvent; +import gov.llnl.gnem.apps.coda.calibration.gui.events.UpdateMapPolygonEvent; import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersFI; import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersPS; import gov.llnl.gnem.apps.coda.calibration.model.domain.ReferenceMwParameters; @@ -182,6 +184,9 @@ protected void convertFiles(List validFiles) { } else { log.error("Returned a null request from the parameter client while posting ShapeFitterConstraints {}", entry); } + } else if (res.get() instanceof RawGeoJSON) { + RawGeoJSON entry = (RawGeoJSON) res.get(); + bus.post(new UpdateMapPolygonEvent(entry.getRawGeoJSON())); } } } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/DataController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/DataController.java index 21cfd01b..7ebf9f2d 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/DataController.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/DataController.java @@ -80,7 +80,7 @@ public class DataController implements MapListeningController, RefreshableContro @FXML private ScrollPane scrollPane; - + @FXML private TableView tableView; @@ -101,7 +101,7 @@ public class DataController implements MapListeningController, RefreshableContro @FXML private TableColumn highFreqCol; - + @FXML private TableColumn depthCol; @@ -210,20 +210,21 @@ private void reloadTable(ActionEvent e) { @FXML public void initialize() { tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); - eventCol.setCellValueFactory( - x -> Bindings.createStringBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(Waveform::getEvent).map(Event::getEventId).orElseGet(String::new))); + eventCol.setCellValueFactory(x -> Bindings.createStringBinding(() -> Optional.ofNullable(x) + .map(CellDataFeatures::getValue) + .map(Waveform::getEvent) + .map(Event::getEventId) + .orElseGet(String::new))); eventCol.comparatorProperty().set(new MaybeNumericStringComparator()); CellBindingUtils.attachTextCellFactories(lowFreqCol, Waveform::getLowFrequency, dfmt2); CellBindingUtils.attachTextCellFactories(highFreqCol, Waveform::getHighFrequency, dfmt2); - - depthCol.setCellValueFactory( - x -> Bindings.createStringBinding( - () -> - dfmt2.format( - Optional.ofNullable(x).map(CellDataFeatures::getValue) - .map(Waveform::getEvent) - .map(ev->Double.toString(ev.getDepth())).orElseGet(String::new)))); + + depthCol.setCellValueFactory(x -> Bindings.createStringBinding(() -> Optional.ofNullable(x) + .map(CellDataFeatures::getValue) + .map(Waveform::getEvent) + .map(ev -> dfmt2.format(ev.getDepth())) + .orElseGet(String::new))); depthCol.comparatorProperty().set(new MaybeNumericStringComparator()); usedCol.setCellValueFactory(x -> Bindings.createObjectBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(waveform -> { @@ -243,9 +244,12 @@ public void initialize() { }).orElseGet(CheckBox::new))); usedCol.comparatorProperty().set((c1, c2) -> Boolean.compare(c1.isSelected(), c2.isSelected())); - stationCol.setCellValueFactory( - x -> Bindings.createStringBinding( - () -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(Waveform::getStream).map(Stream::getStation).map(Station::getStationName).orElseGet(String::new))); + stationCol.setCellValueFactory(x -> Bindings.createStringBinding(() -> Optional.ofNullable(x) + .map(CellDataFeatures::getValue) + .map(Waveform::getStream) + .map(Stream::getStation) + .map(Station::getStationName) + .orElseGet(String::new))); tableView.getSelectionModel().getSelectedItems().addListener(tableChangeListener); //Workaround for https://bugs.openjdk.java.net/browse/JDK-8095943, for now we just clear the selection to avoid dumping a stack trace in the logs and mucking up event bubbling diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/MeasuredMwsController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/MeasuredMwsController.java index ceb4dd9e..a5b36b48 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/MeasuredMwsController.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/MeasuredMwsController.java @@ -133,6 +133,7 @@ public double getProgress() { plot.addPlotObjectObserver(getPlotpointObserver(() -> spectra.getSymbolMap())); plot.setLabels("Moment Rate Spectra", X_AXIS_LABEL, "log10(dyne-cm)"); plot.setYaxisVisibility(true); + spectra.setShowCornerFrequencies(true); spectra.setYAxisResizable(true); spectraPlotSwingNode.setContent(plot); @@ -172,7 +173,7 @@ protected void preloadData() { List refEvs = referenceEventClient.getMeasuredEventDetails() .filter(ev -> ev.getEventId() != null) .collect(Collectors.toList()) - .subscribeOn(Schedulers.elastic()) + .subscribeOn(Schedulers.boundedElastic()) .block(Duration.ofSeconds(10l)); Collection measMws = mfs.getMeasuredMwDetails().values(); diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SiteController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SiteController.java index b60d597b..caabb7ec 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SiteController.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SiteController.java @@ -24,8 +24,6 @@ import javax.swing.SwingUtilities; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -52,8 +50,6 @@ @Component public class SiteController extends AbstractMeasurementController { - private static final Logger log = LoggerFactory.getLogger(SiteController.class); - private static final String X_AXIS_LABEL = "center freq"; private static final String displayName = "Site"; @@ -108,6 +104,7 @@ public void initialize() { plot.addPlotObjectObserver(getPlotpointObserver(() -> site.getSymbolMap())); plot.setLabels("Moment Rate Spectra", X_AXIS_LABEL, "log10(dyne-cm)"); plot.setYaxisVisibility(true); + site.setShowCornerFrequencies(true); site.setYAxisResizable(true); sitePlotSwingNode.setContent(plot); @@ -155,7 +152,7 @@ protected List getEvents() { return referenceEventClient.getMeasuredEventDetails() .filter(ev -> ev.getEventId() != null) .collect(Collectors.toList()) - .subscribeOn(Schedulers.elastic()) + .subscribeOn(Schedulers.boundedElastic()) .block(Duration.ofSeconds(10l)); } } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SpectraPlotController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SpectraPlotController.java index da63f08a..d8353730 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SpectraPlotController.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SpectraPlotController.java @@ -18,15 +18,11 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import gov.llnl.gnem.apps.coda.calibration.gui.plotting.SpectralPlot; import gov.llnl.gnem.apps.coda.calibration.model.domain.SpectraMeasurement; public class SpectraPlotController { - private final Logger log = LoggerFactory.getLogger(this.getClass()); - private SpectralPlot spectraPlot = new SpectralPlot();; + private SpectralPlot spectraPlot = new SpectralPlot(); private Map spectraSymbolMap = new ConcurrentHashMap<>(); private boolean isYaxisResizble = false; private Function dataFunction; @@ -61,4 +57,8 @@ public void setYAxisResizable(boolean isYaxisResizble) { public Function getDataFunc() { return dataFunction; } + + public void setShowCornerFrequencies(boolean showCornerFrequencies) { + this.spectraPlot.showCornerFrequency(showCornerFrequencies); + } } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SharedBandController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SharedBandController.java index 7da849fa..c1df87f2 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SharedBandController.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SharedBandController.java @@ -206,7 +206,7 @@ protected void requestData() { .filter(Objects::nonNull) .filter(value -> null != value.getId()) .doOnComplete(() -> Optional.ofNullable(codaSharedTableView).ifPresent(TableView::sort)) - .subscribe(value -> sharedFbData.add(value), err -> log.trace(err.getMessage(), err)); + .subscribe(value -> sharedFbData.add(value), err -> log.error(err.getMessage(), err)); Optional.ofNullable(codaSharedTableView).ifPresent(v -> v.refresh()); }); } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoader.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoader.java index 6647521f..feed7ade 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoader.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoader.java @@ -27,6 +27,7 @@ import static gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationJsonConstants.TYPE_VALUE; import static gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationJsonConstants.VALIDATION_EVENTS_FIELD; import static gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationJsonConstants.VELOCITY_CONFIGURATION; +import static gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationJsonConstants.POLYGON_FIELD; import java.io.File; import java.io.IOException; @@ -114,6 +115,7 @@ public List> convertJsonParamFile(File file) { results.addAll(convertJsonFields(node, VALIDATION_EVENTS_FIELD, x -> valEventsFromJsonNode(x))); results.addAll(convertJsonFields(node, VELOCITY_CONFIGURATION, x -> velocityConfigurationFromJsonNode(x))); results.addAll(convertJsonFields(node, SHAPE_CONSTRAINTS, x -> shapeConstraintsFromJsonNode(x))); + results.addAll(convertJsonFields(node, POLYGON_FIELD, x -> polygonFromJsonNode(x))); } else if (node.has(ENVELOPE_JOB_NODE)) { results.addAll(convertJsonFields(node, ENVELOPE_JOB_NODE, x -> envelopeJobBandsToSharedBands(x))); } @@ -124,6 +126,10 @@ public List> convertJsonParamFile(File file) { return results; } + private Result polygonFromJsonNode(JsonNode polygon) { + return new Result<>(true, new RawGeoJSON(polygon.toString())); + } + protected List> convertJsonFields(JsonNode node, String field, Function> func) { List> results = new ArrayList<>(); List nodes = node.findValues(field); diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/RawGeoJSON.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/RawGeoJSON.java new file mode 100644 index 00000000..28f5a2e9 --- /dev/null +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/RawGeoJSON.java @@ -0,0 +1,27 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.gui.converters.param; + +public class RawGeoJSON { + + private final String rawGeoJSON; + + public RawGeoJSON(String rawGeoJSON) { + this.rawGeoJSON = rawGeoJSON; + } + + public String getRawGeoJSON() { + return rawGeoJSON; + } +} diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/ParameterWebClient.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/ParameterWebClient.java index 09b37e62..5c18149e 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/ParameterWebClient.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/ParameterWebClient.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -16,8 +16,6 @@ import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; @@ -39,8 +37,6 @@ @Component public class ParameterWebClient implements ParameterClient { - private static final Logger log = LoggerFactory.getLogger(ParameterWebClient.class); - private WebClient client; @Autowired @@ -196,4 +192,19 @@ public Mono getShapeFitterConstraints() { public Mono updateShapeFitterConstraints(ShapeFitterConstraints conf) { return client.post().uri("/config/shape/update").accept(MediaType.APPLICATION_JSON).bodyValue(conf).exchange().flatMap(response -> response.bodyToMono(String.class)).onErrorReturn(""); } + + @Override + public Mono updateMapPolygon(String rawGeoJSON) { + return client.post().uri("/config/polygon/update").accept(MediaType.APPLICATION_JSON).bodyValue(rawGeoJSON).exchange().flatMap(response -> response.bodyToMono(String.class)).onErrorReturn(""); + } + + @Override + public Mono getMapPolygon() { + return client.get() + .uri("/config/polygon/") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .flatMap(response -> response.bodyToMono(String.class)) + .onErrorReturn(""); + } } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/api/CalibrationJsonConstants.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/api/CalibrationJsonConstants.java index bf868e19..206b5bbd 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/api/CalibrationJsonConstants.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/api/CalibrationJsonConstants.java @@ -27,6 +27,9 @@ public class CalibrationJsonConstants { public static final String VALIDATION_EVENTS_FIELD = "validation-events"; public static final String MEASURED_EVENTS_FIELD = "measured-events"; public static final String VELOCITY_CONFIGURATION = "velocity-configuration"; - public static final String SHAPE_CONSTRAINTS = "shape-constraints"; + public static final String SHAPE_CONSTRAINTS = "shape-constraints"; + public static final String POLYGON_FIELD = "polygons"; + + //For compatibility with stand-alone envelope tool. public static final String ENVELOPE_JOB_NODE = "frequencyBandConfiguration"; } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/api/ParameterClient.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/api/ParameterClient.java index c741553d..9b3dff37 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/api/ParameterClient.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/client/api/ParameterClient.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import gov.llnl.gnem.apps.coda.calibration.model.domain.ShapeFitterConstraints; +import gov.llnl.gnem.apps.coda.calibration.gui.converters.param.RawGeoJSON; import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersFI; import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersPS; import gov.llnl.gnem.apps.coda.calibration.model.domain.SiteFrequencyBandParameters; @@ -62,4 +63,8 @@ public interface ParameterClient { public Mono updateShapeFitterConstraints(ShapeFitterConstraints conf); + public Mono updateMapPolygon(String rawGeoJSON); + + public Mono getMapPolygon(); + } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/JsonTempFileWriter.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/JsonTempFileWriter.java index 5582a48b..c41c745e 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/JsonTempFileWriter.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/JsonTempFileWriter.java @@ -86,10 +86,10 @@ public JsonTempFileWriter() { @Override public void writeParams(Path folder, Map sharedParametersByFreqBand, Map> siteParameters, - List fi, List ps, VelocityConfiguration velocityConfig, ShapeFitterConstraints shapeConstraints) { + List fi, List ps, VelocityConfiguration velocityConfig, ShapeFitterConstraints shapeConstraints, String polygonGeoJSON) { try { JsonNode document = createOrGetDocument(folder, CALIBRATION_JSON_NAME); - writeParams(createOrGetFile(folder, CALIBRATION_JSON_NAME), document, sharedParametersByFreqBand, siteParameters, fi, ps, velocityConfig, shapeConstraints); + writeParams(createOrGetFile(folder, CALIBRATION_JSON_NAME), document, sharedParametersByFreqBand, siteParameters, fi, ps, velocityConfig, shapeConstraints, polygonGeoJSON); } catch (IOException e) { log.error(e.getMessage(), e); } @@ -138,7 +138,7 @@ public void writeMeasuredMws(Path folder, String filename, List sharedParametersByFreqBand, Map> siteParameters, List fi, List ps, VelocityConfiguration velocityConfig, - ShapeFitterConstraints shapeConstraints) throws IOException { + ShapeFitterConstraints shapeConstraints, String polygonGeoJSON) throws IOException { writeArrayNodeToFile(file, document, sharedParametersByFreqBand.values(), CalibrationJsonConstants.BAND_FIELD); if (siteParameters != null && !siteParameters.isEmpty()) { Map>> siteBands = siteParameters.entrySet() @@ -163,6 +163,9 @@ private void writeParams(File file, JsonNode document, Map fi = paramClient.getFiParameters().toStream().filter(Objects::nonNull).collect(Collectors.toList()); List ps = paramClient.getPsParameters().toStream().filter(Objects::nonNull).collect(Collectors.toList()); - VelocityConfiguration velocity = paramClient.getVelocityConfiguration().subscribeOn(Schedulers.elastic()).block(Duration.ofSeconds(5l)); - ShapeFitterConstraints shapeConstraints = paramClient.getShapeFitterConstraints().subscribeOn(Schedulers.elastic()).block(Duration.ofSeconds(5l)); + VelocityConfiguration velocity = paramClient.getVelocityConfiguration().subscribeOn(Schedulers.boundedElastic()).block(Duration.ofSeconds(5l)); + ShapeFitterConstraints shapeConstraints = paramClient.getShapeFitterConstraints().subscribeOn(Schedulers.boundedElastic()).block(Duration.ofSeconds(5l)); + String polygonGeoJSON = paramClient.getMapPolygon().subscribeOn(Schedulers.boundedElastic()).block(Duration.ofSeconds(5l)); for (ParamTempFileWriter writer : paramWriters) { - writer.writeParams(tmpFolder, sharedParametersByFreqBand, siteParameters, fi, ps, velocity, shapeConstraints); + writer.writeParams(tmpFolder, sharedParametersByFreqBand, siteParameters, fi, ps, velocity, shapeConstraints, polygonGeoJSON); } } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/SwftStyleParamFileWriter.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/SwftStyleParamFileWriter.java index eb951ce4..3fef411b 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/SwftStyleParamFileWriter.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/SwftStyleParamFileWriter.java @@ -94,7 +94,7 @@ private void writeParams(File paramFile, Map sharedParametersByFreqBand, Map> siteParameters, - List fi, List ps, VelocityConfiguration velocity, ShapeFitterConstraints shapeConstraints) { + List fi, List ps, VelocityConfiguration velocity, ShapeFitterConstraints shapeConstraints, String polygons) { File sharedParamFile = new File(folder.toFile(), "Shared.param"); sharedParamFile.deleteOnExit(); try { diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/api/ParamTempFileWriter.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/api/ParamTempFileWriter.java index bebf5a16..a3c73213 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/api/ParamTempFileWriter.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/data/exporters/api/ParamTempFileWriter.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -29,5 +29,5 @@ public interface ParamTempFileWriter { void writeParams(Path folder, Map sharedParametersByFreqBand, Map> siteParameters, - List fi, List ps, VelocityConfiguration velocity, ShapeFitterConstraints shapeConstraints); + List fi, List ps, VelocityConfiguration velocity, ShapeFitterConstraints shapeConstraints, String polygonGeoJSON); } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/MapIconActivationCallback.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/MapIconActivationCallback.java index 9fb7f924..6a0c2224 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/MapIconActivationCallback.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/MapIconActivationCallback.java @@ -38,6 +38,12 @@ public void accept(MapCallbackEvent evtVal) { case TRIANGLE_UP: client.setWaveformsActiveByStationName(icon.getFriendlyName(), evtVal.getFlag()).subscribe(); break; + case POLYGON_OUT: + client.setWaveformsActiveOutsidePolygon(evtVal.getFlag()).subscribe(); + break; + case POLYGON_IN: + client.setWaveformsActiveInsidePolygon(evtVal.getFlag()).subscribe(); + break; case DEFAULT: default: break; diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/MapPolygonChangeHandler.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/MapPolygonChangeHandler.java new file mode 100644 index 00000000..41ebccea --- /dev/null +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/MapPolygonChangeHandler.java @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.gui.events; + +import java.util.function.Consumer; + +import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.ParameterClient; +import gov.llnl.gnem.apps.coda.common.mapping.MAP_CALLBACK_EVENT_TYPE; +import gov.llnl.gnem.apps.coda.common.mapping.MapCallbackEvent; + +public class MapPolygonChangeHandler implements Consumer { + private ParameterClient client; + + public MapPolygonChangeHandler(ParameterClient configClient) { + this.client = configClient; + } + + @Override + public void accept(MapCallbackEvent evtVal) { + if (evtVal != null && MAP_CALLBACK_EVENT_TYPE.POLYGON_CHANGE.equals(evtVal.getType())) { + String polygonGeoJSON = evtVal.getBody(); + client.updateMapPolygon(polygonGeoJSON).subscribe(); + } + } + } diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/UpdateMapPolygonEvent.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/UpdateMapPolygonEvent.java new file mode 100644 index 00000000..5cbced42 --- /dev/null +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/events/UpdateMapPolygonEvent.java @@ -0,0 +1,27 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.gui.events; + +public class UpdateMapPolygonEvent { + + private String geoJSON; + + public UpdateMapPolygonEvent(String rawGeoJSON) { + this.geoJSON = rawGeoJSON; + } + + public String getGeoJSON() { + return geoJSON; + } +} diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/plotting/CodaWaveformPlotManager.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/plotting/CodaWaveformPlotManager.java index 77f8be02..71fcfc1a 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/plotting/CodaWaveformPlotManager.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/plotting/CodaWaveformPlotManager.java @@ -268,11 +268,11 @@ private void loadWaveformsForPage(int pageNumber) { clear(); List> results = new ArrayList<>(); if (allWaveformIDs.size() == 1) { - SyntheticCoda synth = waveformClient.getSyntheticFromWaveformId(allWaveformIDs.get(0)).publishOn(Schedulers.elastic()).block(Duration.ofSeconds(10)); + SyntheticCoda synth = waveformClient.getSyntheticFromWaveformId(allWaveformIDs.get(0)).publishOn(Schedulers.boundedElastic()).block(Duration.ofSeconds(10)); if (synth != null && synth.getId() != null) { results.add(createPlot(synth)); } else { - results.add(createPlot(waveformClient.getWaveformFromId(allWaveformIDs.get(0)).publishOn(Schedulers.elastic()).block(Duration.ofSeconds(10)))); + results.add(createPlot(waveformClient.getWaveformFromId(allWaveformIDs.get(0)).publishOn(Schedulers.boundedElastic()).block(Duration.ofSeconds(10)))); } } else { pagingLabel.setText(pageNumber + 1 + "/" + totalPages); @@ -285,7 +285,7 @@ private void loadWaveformsForPage(int pageNumber) { List synthetics = waveformClient.getSyntheticsFromWaveformIds(pageIds) .filter(synth -> synth != null && synth.getId() != null) .collectList() - .publishOn(Schedulers.elastic()) + .publishOn(Schedulers.boundedElastic()) .block(Duration.ofSeconds(10)); if (synthetics != null && !synthetics.isEmpty()) { pageIds.removeAll(synthetics.stream().map(synth -> synth.getSourceWaveform().getId()).collect(Collectors.toList())); @@ -295,7 +295,7 @@ private void loadWaveformsForPage(int pageNumber) { List waveforms = waveformClient.getWaveformsFromIds(pageIds) .filter(waveform -> waveform != null && waveform.getId() != null) .collectList() - .publishOn(Schedulers.elastic()) + .publishOn(Schedulers.boundedElastic()) .block(Duration.ofSeconds(10)); if (waveforms != null && !waveforms.isEmpty()) { results.addAll(createWaveformPlots(waveforms)); diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/plotting/SpectralPlot.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/plotting/SpectralPlot.java index 0be3b579..59b728ae 100644 --- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/plotting/SpectralPlot.java +++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/plotting/SpectralPlot.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -37,6 +37,7 @@ import llnl.gnem.core.gui.plotting.jmultiaxisplot.JSubplot; import llnl.gnem.core.gui.plotting.jmultiaxisplot.PlotProperties; import llnl.gnem.core.gui.plotting.jmultiaxisplot.TickScaleFunc; +import llnl.gnem.core.gui.plotting.jmultiaxisplot.VPickLine; import llnl.gnem.core.gui.plotting.plotobject.Line; import llnl.gnem.core.gui.plotting.plotobject.Symbol; import llnl.gnem.core.gui.plotting.plotobject.SymbolFactory; @@ -68,6 +69,9 @@ public class SpectralPlot extends JMultiAxisPlot { private double defaultYMax = 27.0; private final Map> symbolMap = new HashMap<>(); + private final NumberFormat dfmt = new DecimalFormat("#0.0#"); + + private transient boolean plotCorners = false; public SpectralPlot() { super(); @@ -151,8 +155,7 @@ public void plotXYdata(final List plots, Boolean showLegend) { * calibration spectra *

*/ - public void plotXYdata(final List plots, Boolean showLegend, List spectra) { - + public void plotXYdata(final List plots, Boolean showLegend, List spectra) { symbolMap.clear(); // line based legends for trending Legend legend = new Legend(getTitle().getFontName(), getTitle().getFontSize(), HorizPinEdge.RIGHT, VertPinEdge.TOP, 5, 5); @@ -177,6 +180,9 @@ public void plotXYdata(final List plots, Boolean showLegend, List (s1.getType() == SPECTRA_TYPES.UQ1 || s1.getType() == SPECTRA_TYPES.UQ2) ? -1 : 1); for (Spectra spec : spectra) { + if (plotCorners && spec.getCornerFrequency() != null) { + plotCornerFrequency(spec.getCornerFrequency()); + } plotSpectraObject(jsubplot, spec, legend); } } @@ -192,6 +198,10 @@ public void plotXYdata(final List plots, Boolean showLegend, List netMwValues = spectra.getSpectraXY().stream().map(d -> new PlotPoint(d.getX(), d.getY(), null, null)).collect(Collectors.toList()); @@ -210,7 +220,7 @@ private void plotSpectraObject(JSubplot jsubplot, Spectra spectra, Legend legend break; case VAL: line = new Line(x, y, Color.BLUE, PaintMode.COPY, PenStyle.DASHDOT, 2); - break; + break; case UQ1: line = new Line(x, y, Color.LIGHT_GRAY, PaintMode.COPY, PenStyle.DASH, 2); break; @@ -330,18 +340,17 @@ public final void plotXYdata(List data) { } else { label = ""; } - Symbol symbol = SymbolFactory.createSymbol( - v.getStyle(), - v.getX(), - v.getY(), - properties.getSymbolSize(), - v.getColor(), - properties.getSymbolEdgeColor(), - v.getColor(), - label, - true, - false, - 10.0); + Symbol symbol = SymbolFactory.createSymbol(v.getStyle(), + v.getX(), + v.getY(), + properties.getSymbolSize(), + v.getColor(), + properties.getSymbolEdgeColor(), + v.getColor(), + label, + true, + false, + 10.0); symbolMap.computeIfAbsent(new Point2D.Double(v.getX(), v.getY()), key -> new ArrayList<>()).add(symbol); return symbol; }).forEach(jsubplot::AddPlotObject); @@ -370,7 +379,7 @@ public void rescalePlot(double x, double y) { } @Override - public void setAllXlimits(double xmin, double xmax) { + public void setAllXlimits(double xmin, double xmax) { super.setAllXlimits(xmin, xmax); properties.setMaxXAxisValue(xmax); properties.setMinXAxisValue(xmin); @@ -383,13 +392,13 @@ public void setAllXlimits() { properties.setMinXAxisValue(xmin); } - public void setAllYlimits(double ymin, double ymax) { + public void setAllYlimits(double ymin, double ymax) { jsubplot.setYlimits(ymin, ymax); this.ymin = ymin; this.ymax = ymax; } - public void setAllYlimits() { + public void setAllYlimits() { jsubplot.setYlimits(defaultYMin, defaultYMax); this.ymin = defaultYMin; this.ymax = defaultYMax; @@ -416,7 +425,7 @@ public void refreshPlotAxes() { xMin = properties.getMinXAxisValue(); xMax = properties.getMaxXAxisValue(); } - jsubplot.setAxisLimits(xMin, xMax, yMin, yMax); + jsubplot.setAxisLimits(xMin, xMax, yMin, yMax); } /** Set the Title, X and Y axis labels simultaneously */ @@ -503,4 +512,8 @@ public void deselectPoint(Point2D.Double xyPoint) { } repaint(); } + + public void showCornerFrequency(boolean showCornerFreq) { + this.plotCorners = showCornerFreq; + } } diff --git a/calibration-gui/src/main/resources/application.properties b/calibration-gui/src/main/resources/application.properties index d35e6960..a2093e16 100644 --- a/calibration-gui/src/main/resources/application.properties +++ b/calibration-gui/src/main/resources/application.properties @@ -1,4 +1,5 @@ spring.output.ansi.enabled=ALWAYS +logging.level.javafx.*=off logging.level.org.springframework.web.socket.*=off logging.level.org.springframework.web.reactive.function.client.*=off webclient.basePath=localhost:53921 diff --git a/calibration-gui/src/test/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoaderTest.java b/calibration-gui/src/test/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoaderTest.java index eed5b4c0..59817330 100644 --- a/calibration-gui/src/test/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoaderTest.java +++ b/calibration-gui/src/test/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoaderTest.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -21,12 +21,13 @@ import java.util.Collections; import java.util.stream.Stream; -import org.junit.Assert; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import gov.llnl.gnem.apps.coda.calibration.model.domain.GeoJsonPolygon; import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersFI; import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersPS; import gov.llnl.gnem.apps.coda.calibration.model.domain.ReferenceMwParameters; @@ -58,10 +59,7 @@ protected Flux> convertFile(String filePath) { @MethodSource("filePaths") public final void testValidBands(String filePath) throws Exception { Flux> results = convertFile(filePath); - Assert.assertEquals( - "Expected to have 14 valid band definitions", - Long.valueOf(14l), - results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof SharedFrequencyBandParameters).count().block()); + Assertions.assertEquals(Long.valueOf(14l), results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof SharedFrequencyBandParameters).count().block()); } @ParameterizedTest @@ -72,72 +70,81 @@ public final void testValidSiteCorrections(String filePath) throws Exception { .blockFirst() .getResultPayload() .orElseGet(null); - Assert.assertNotNull("Expected to have 1 site correction object", siteCorrections); - Assert.assertEquals("Expected to have 1 networks", 1, siteCorrections.getSiteCorrections().stream().map(sc -> sc.getStation().getNetworkName()).distinct().count()); - Assert.assertEquals("Expected to have 3 stations", 3, siteCorrections.getSiteCorrections().stream().map(sc -> sc.getStation().getStationName()).distinct().count()); - Assert.assertEquals( - "Expected to have 14 bands for the first station", - 14, - siteCorrections.getSiteCorrections() - .stream() - .filter( - sfb -> sfb.getStation() - .getStationName() - .equalsIgnoreCase(siteCorrections.getSiteCorrections().stream().map(sc -> sc.getStation().getStationName()).findFirst().orElseGet(null))) - .count()); - Assert.assertEquals("Expected to have 42 site correction bands", 42, siteCorrections.getSiteCorrections().size()); + Assertions.assertNotNull(siteCorrections, "Expected to have 1 site correction object"); + Assertions.assertEquals(1, siteCorrections.getSiteCorrections().stream().map(sc -> sc.getStation().getNetworkName()).distinct().count(), "Expected to have 1 networks"); + Assertions.assertEquals(3, siteCorrections.getSiteCorrections().stream().map(sc -> sc.getStation().getStationName()).distinct().count(), "Expected to have 3 stations"); + Assertions.assertEquals(14, + siteCorrections.getSiteCorrections() + .stream() + .filter(sfb -> sfb.getStation() + .getStationName() + .equalsIgnoreCase(siteCorrections.getSiteCorrections() + .stream() + .map(sc -> sc.getStation().getStationName()) + .findFirst() + .orElseGet(null))) + .count(), + "Expected to have 14 bands for the first station"); + Assertions.assertEquals(42, siteCorrections.getSiteCorrections().size(), "Expected to have 42 site correction bands"); } @ParameterizedTest @MethodSource("filePaths") public final void testValidPs(String filePath) throws Exception { Flux> results = convertFile(filePath); - Assert.assertEquals( - "Expected to have 1 valid MDAC FI definition", - Long.valueOf(1l), - results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof MdacParametersFI).count().block()); + Assertions.assertEquals(Long.valueOf(1l), + results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof MdacParametersFI).count().block(), + "Expected to have 1 valid MDAC FI definition"); } @ParameterizedTest @MethodSource("filePaths") public final void testFi(String filePath) throws Exception { Flux> results = convertFile(filePath); - Assert.assertEquals( - "Expected to have 4 valid MDAC PS definitions", - Long.valueOf(4l), - results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof MdacParametersPS).count().block()); + Assertions.assertEquals(Long.valueOf(4l), + results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof MdacParametersPS).count().block(), + "Expected to have 4 valid MDAC PS definitions"); } @ParameterizedTest @MethodSource("filePaths") public final void testRefMw(String filePath) throws Exception { Flux> results = convertFile(filePath); - Assert.assertEquals( - "Expected to have 2 valid reference event definitions", - Long.valueOf(2l), - results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof ReferenceMwParameters).count().block()); + Assertions.assertEquals(Long.valueOf(2l), + results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof ReferenceMwParameters).count().block(), + "Expected to have 2 valid reference event definitions"); } - + @ParameterizedTest @MethodSource("filePaths") public final void testValidationMw(String filePath) throws Exception { Flux> results = convertFile(filePath); - Assert.assertEquals( - "Expected to have 2 valid validation event definitions", - Long.valueOf(2l), - results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof ValidationMwParameters).count().block()); - } + Assertions.assertEquals(Long.valueOf(2l), + results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof ValidationMwParameters).count().block(), + "Expected to have 14 valid band definitions"); + } + + @ParameterizedTest + @MethodSource("filePaths") + public final void testMultiplePolygons(String filePath) throws Exception { + Flux> results = convertFile(filePath); + RawGeoJSON result = (RawGeoJSON) results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof RawGeoJSON).blockFirst().getResultPayload().get(); + + Assertions.assertEquals("{\"features\":[{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[0.0,3.0],[3.0,3.0],[3.0,0.0],[0.0,0.0],[0.0,3.0]]]}}]}", + result.getRawGeoJSON(), + "Expected RawGeoJSON collection to match contents of calibration JSON"); + } @ParameterizedTest @MethodSource("filePaths") public final void testShapeConstraint(String filePath) throws Exception { Flux> results = convertFile(filePath); - Assert.assertEquals( - "Expected to have 1 valid shape constraint definition", - Long.valueOf(1l), - results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof ShapeFitterConstraints).count().block()); - assertThat(((ShapeFitterConstraints) results.filter(r -> r.getResultPayload().orElse(null) instanceof ShapeFitterConstraints).blockFirst().getResultPayload().get()).getMaxBeta()).isCloseTo( - -11.0E-4, - within(0.001)).describedAs("Expected values containing 'E-' scientific notation serialize correctly"); + Assertions.assertEquals(Long.valueOf(1l), + results.filter(r -> r.isSuccess() && r.getResultPayload().orElse(null) instanceof ShapeFitterConstraints).count().block(), + "Expected to have 1 valid shape constraint definition"); + assertThat(((ShapeFitterConstraints) results.filter(r -> r.getResultPayload().orElse(null) instanceof ShapeFitterConstraints) + .blockFirst() + .getResultPayload() + .get()).getMaxBeta()).isCloseTo(-11.0E-4, within(0.001)).describedAs("Expected values containing 'E-' scientific notation serialize correctly"); } } diff --git a/calibration-gui/src/test/resources/calibration-params-test.json b/calibration-gui/src/test/resources/calibration-params-test.json index 86caf0b6..016d600a 100644 --- a/calibration-gui/src/test/resources/calibration-params-test.json +++ b/calibration-gui/src/test/resources/calibration-params-test.json @@ -200,6 +200,24 @@ "apparentStressInMpa": 0.7 } ], + "polygons": { + "features": [{ + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [0.0, 3.0], + [3.0, 3.0], + [3.0, 0.0], + [0.0, 0.0], + [0.0, 3.0] + ] + ] + } + }] + }, "shape-constraints": { "maxVP1": 1600.0, "minVP1": 150.0, diff --git a/calibration-gui/src/test/resources/logback-test.xml b/calibration-gui/src/test/resources/logback-test.xml deleted file mode 100644 index adfa02c6..00000000 --- a/calibration-gui/src/test/resources/logback-test.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/calibration-service/calibration-application/pom.xml b/calibration-service/calibration-application/pom.xml index 15316612..f183dc94 100644 --- a/calibration-service/calibration-application/pom.xml +++ b/calibration-service/calibration-application/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.calibration calibration-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/calibration-service/calibration-application/src/main/java/gov/llnl/gnem/apps/coda/calibration/application/web/ConfigurationItemJsonController.java b/calibration-service/calibration-application/src/main/java/gov/llnl/gnem/apps/coda/calibration/application/web/ConfigurationItemJsonController.java index 5043ea4c..f76c8f67 100644 --- a/calibration-service/calibration-application/src/main/java/gov/llnl/gnem/apps/coda/calibration/application/web/ConfigurationItemJsonController.java +++ b/calibration-service/calibration-application/src/main/java/gov/llnl/gnem/apps/coda/calibration/application/web/ConfigurationItemJsonController.java @@ -69,4 +69,17 @@ public ResponseEntity updateShapeFitterConstraints(@Valid @RequestBody ShapeF configService.update(entry); return ResponseEntity.ok().build(); } + + @GetMapping(value = "/polygon", name = "getPolygon") + public ResponseEntity getPolygon() { + return ResponseEntity.ok().body(configService.getPolygonGeoJSON()); + } + + @PostMapping(value = "/polygon/update", name = "updatePolygon") + public ResponseEntity updatePolygon(@Valid @RequestBody String rawGeoJSON, BindingResult result) { + if (result.hasErrors()) { + return ResponseEntity.status(HttpStatus.CONFLICT).body(result); + } + return ResponseEntity.ok().body(configService.updatePolygon(rawGeoJSON)); + } } diff --git a/calibration-service/calibration-application/src/main/java/gov/llnl/gnem/apps/coda/calibration/application/web/GeometryJsonController.java b/calibration-service/calibration-application/src/main/java/gov/llnl/gnem/apps/coda/calibration/application/web/GeometryJsonController.java new file mode 100644 index 00000000..6b7231ee --- /dev/null +++ b/calibration-service/calibration-application/src/main/java/gov/llnl/gnem/apps/coda/calibration/application/web/GeometryJsonController.java @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.application.web; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import gov.llnl.gnem.apps.coda.calibration.service.api.GeometryService; + +@RestController +@RequestMapping(value = "/api/v1/geometry", name = "GeometryJsonController", produces = MediaType.APPLICATION_JSON_VALUE) +public class GeometryJsonController { + + private static final Logger log = LoggerFactory.getLogger(GeometryJsonController.class); + + private GeometryService service; + + @Autowired + public GeometryJsonController(GeometryService service) { + this.service = service; + } + + @PostMapping(value = "/set-active/waveforms-inside-polygon/{active}", name = "measureMws") + public ResponseEntity setActiveFlagInsidePolygon(@PathVariable Boolean active) { + ResponseEntity resp = null; + try { + service.setActiveFlagInsidePolygon(active); + resp = ResponseEntity.ok().build(); + } catch (RuntimeException ex) { + log.trace(ex.getLocalizedMessage()); + } + return resp == null ? ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build() : resp; + } + + @PostMapping(value = "/set-active/waveforms-outside-polygon/{active}", name = "measureMws") + public ResponseEntity setActiveFlagOutsidePolygon(@PathVariable Boolean active) { + ResponseEntity resp = null; + try { + service.setActiveFlagOutsidePolygon(active); + resp = ResponseEntity.ok().build(); + } catch (RuntimeException ex) { + log.trace(ex.getLocalizedMessage()); + } + return resp == null ? ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build() : resp; + } +} diff --git a/calibration-service/calibration-integration/pom.xml b/calibration-service/calibration-integration/pom.xml index 001db916..7a50a639 100644 --- a/calibration-service/calibration-integration/pom.xml +++ b/calibration-service/calibration-integration/pom.xml @@ -4,7 +4,7 @@ gov.llnl.gnem.apps.coda.calibration calibration-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/calibration-service/calibration-model/pom.xml b/calibration-service/calibration-model/pom.xml index cc931d11..d2e99094 100644 --- a/calibration-service/calibration-model/pom.xml +++ b/calibration-service/calibration-model/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.calibration calibration-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/calibration-service/calibration-model/src/main/java/gov/llnl/gnem/apps/coda/calibration/model/domain/GeoJsonPolygon.java b/calibration-service/calibration-model/src/main/java/gov/llnl/gnem/apps/coda/calibration/model/domain/GeoJsonPolygon.java new file mode 100644 index 00000000..b96774a8 --- /dev/null +++ b/calibration-service/calibration-model/src/main/java/gov/llnl/gnem/apps/coda/calibration/model/domain/GeoJsonPolygon.java @@ -0,0 +1,80 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.model.domain; + +import java.io.Serializable; +import java.util.Objects; + +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Lob; +import javax.persistence.Table; +import javax.persistence.Version; + +@Entity +@Table(name = "Polygons") +public class GeoJsonPolygon implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "ID") + private Long id; + + @Version + private Integer version = 0; + + @Lob + @Basic + private String rawGeoJson = ""; + + public String getRawGeoJson() { + return rawGeoJson; + } + + public GeoJsonPolygon setRawGeoJson(String rawGeoJson) { + this.rawGeoJson = rawGeoJson; + return this; + } + + @Override + public int hashCode() { + return Objects.hash(id, rawGeoJson, version); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof GeoJsonPolygon)) { + return false; + } + GeoJsonPolygon other = (GeoJsonPolygon) obj; + return Objects.equals(id, other.id) && Objects.equals(rawGeoJson, other.rawGeoJson) && Objects.equals(version, other.version); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("GeoJsonPolygon [id=").append(id).append(", version=").append(version).append(", rawGeoJson=").append(rawGeoJson).append("]"); + return builder.toString(); + } + +} \ No newline at end of file diff --git a/calibration-service/calibration-model/src/main/java/gov/llnl/gnem/apps/coda/calibration/model/domain/Spectra.java b/calibration-service/calibration-model/src/main/java/gov/llnl/gnem/apps/coda/calibration/model/domain/Spectra.java index e5a1b6ec..e198819a 100644 --- a/calibration-service/calibration-model/src/main/java/gov/llnl/gnem/apps/coda/calibration/model/domain/Spectra.java +++ b/calibration-service/calibration-model/src/main/java/gov/llnl/gnem/apps/coda/calibration/model/domain/Spectra.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -25,6 +25,7 @@ public class Spectra { private List xyVals; private double apparentStress = -1; private double mw = -1; + private Double cornerFrequency = null; private SPECTRA_TYPES type; /** @@ -34,7 +35,7 @@ public class Spectra { * @param mw * @param stress */ - public Spectra(SPECTRA_TYPES type, List xyVals, Double mw, Double stress) { + public Spectra(SPECTRA_TYPES type, List xyVals, Double mw, Double stress, Double cornerFrequency) { this.type = type; this.xyVals = xyVals; if (mw != null) { @@ -43,6 +44,9 @@ public Spectra(SPECTRA_TYPES type, List xyVals, Do if (stress != null) { this.apparentStress = stress; } + if (cornerFrequency != null) { + this.cornerFrequency = cornerFrequency; + } } public Spectra() { @@ -66,9 +70,13 @@ public SPECTRA_TYPES getType() { return type; } + public Double getCornerFrequency() { + return cornerFrequency; + } + @Override public int hashCode() { - return Objects.hash(apparentStress, mw, type, xyVals); + return Objects.hash(apparentStress, cornerFrequency, mw, type, xyVals); } @Override @@ -80,16 +88,25 @@ public boolean equals(Object obj) { return false; } Spectra other = (Spectra) obj; - return Double.doubleToLongBits(apparentStress) == Double.doubleToLongBits(other.apparentStress) - && Double.doubleToLongBits(mw) == Double.doubleToLongBits(other.mw) - && type == other.type - && Objects.equals(xyVals, other.xyVals); + return Double.doubleToLongBits(apparentStress) == Double.doubleToLongBits(other.apparentStress) && Objects.equals(cornerFrequency, other.cornerFrequency) + && Double.doubleToLongBits(mw) == Double.doubleToLongBits(other.mw) && type == other.type && Objects.equals(xyVals, other.xyVals); } @Override public String toString() { + final int maxLen = 10; StringBuilder builder = new StringBuilder(); - builder.append("Spectra [xyVals=").append(xyVals).append(", apparentStress=").append(apparentStress).append(", mw=").append(mw).append(", type=").append(type).append("]"); + builder.append("Spectra [xyVals=") + .append(xyVals != null ? xyVals.subList(0, Math.min(xyVals.size(), maxLen)) : null) + .append(", apparentStress=") + .append(apparentStress) + .append(", mw=") + .append(mw) + .append(", cornerFrequency=") + .append(cornerFrequency) + .append(", type=") + .append(type) + .append("]"); return builder.toString(); } } diff --git a/calibration-service/calibration-repository/pom.xml b/calibration-service/calibration-repository/pom.xml index 6b424794..a2660b2c 100644 --- a/calibration-service/calibration-repository/pom.xml +++ b/calibration-service/calibration-repository/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.calibration calibration-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/calibration-service/calibration-repository/src/main/java/gov/llnl/gnem/apps/coda/calibration/repository/PolygonRepository.java b/calibration-service/calibration-repository/src/main/java/gov/llnl/gnem/apps/coda/calibration/repository/PolygonRepository.java new file mode 100644 index 00000000..73a6892a --- /dev/null +++ b/calibration-service/calibration-repository/src/main/java/gov/llnl/gnem/apps/coda/calibration/repository/PolygonRepository.java @@ -0,0 +1,23 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.repository; + +import org.springframework.transaction.annotation.Transactional; + +import gov.llnl.gnem.apps.coda.calibration.model.domain.GeoJsonPolygon; +import gov.llnl.gnem.apps.coda.common.repository.DetachableJpaRepository; + +@Transactional +public interface PolygonRepository extends DetachableJpaRepository { +} diff --git a/calibration-service/calibration-service-api/pom.xml b/calibration-service/calibration-service-api/pom.xml index e8ea6d36..519598bb 100644 --- a/calibration-service/calibration-service-api/pom.xml +++ b/calibration-service/calibration-service-api/pom.xml @@ -4,7 +4,7 @@ gov.llnl.gnem.apps.coda.calibration calibration-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/calibration-service/calibration-service-api/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/api/ConfigurationService.java b/calibration-service/calibration-service-api/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/api/ConfigurationService.java index 39a5b1e0..b1c1810a 100644 --- a/calibration-service/calibration-service-api/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/api/ConfigurationService.java +++ b/calibration-service/calibration-service-api/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/api/ConfigurationService.java @@ -25,4 +25,8 @@ public interface ConfigurationService { public ShapeFitterConstraints update(ShapeFitterConstraints entry); public ShapeFitterConstraints getCalibrationShapeFitterConstraints(); + + public String updatePolygon(String rawGeoJSON); + + public String getPolygonGeoJSON(); } diff --git a/calibration-service/calibration-service-api/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/api/GeometryService.java b/calibration-service/calibration-service-api/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/api/GeometryService.java new file mode 100644 index 00000000..87cb0ea9 --- /dev/null +++ b/calibration-service/calibration-service-api/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/api/GeometryService.java @@ -0,0 +1,22 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.service.api; + +import java.util.List; + +public interface GeometryService { + public List setActiveFlagOutsidePolygon(boolean active); + + public List setActiveFlagInsidePolygon(boolean active); +} diff --git a/calibration-service/calibration-service-impl/pom.xml b/calibration-service/calibration-service-impl/pom.xml index 1bf4766a..b2f719e1 100644 --- a/calibration-service/calibration-service-impl/pom.xml +++ b/calibration-service/calibration-service-impl/pom.xml @@ -1,11 +1,10 @@ - gov.llnl.gnem.apps.coda.calibration calibration-service - 1.0.9 + 1.0.10 4.0.0 @@ -101,7 +100,7 @@ assertj-core test - + org.springframework.boot spring-boot-starter-test test @@ -116,6 +115,18 @@ h2 test + + org.locationtech.jts + jts-core + + + org.locationtech.jts.io + jts-io-common + + + org.wololo + jts2geojson + diff --git a/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/ConfigurationServiceImpl.java b/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/ConfigurationServiceImpl.java index 1e3fa0e9..58c5f4c1 100644 --- a/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/ConfigurationServiceImpl.java +++ b/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/ConfigurationServiceImpl.java @@ -20,11 +20,13 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import gov.llnl.gnem.apps.coda.calibration.model.domain.GeoJsonPolygon; import gov.llnl.gnem.apps.coda.calibration.model.domain.ShapeFitterConstraints; import gov.llnl.gnem.apps.coda.calibration.model.domain.VelocityConfiguration; import gov.llnl.gnem.apps.coda.calibration.model.messaging.GvDataChangeEvent; import gov.llnl.gnem.apps.coda.calibration.model.messaging.ShapeConstraintsChangeEvent; import gov.llnl.gnem.apps.coda.calibration.repository.CalibrationShapeFitterConstraintsRepository; +import gov.llnl.gnem.apps.coda.calibration.repository.PolygonRepository; import gov.llnl.gnem.apps.coda.calibration.repository.VelocityConfigurationRepository; import gov.llnl.gnem.apps.coda.calibration.service.api.ConfigurationService; import gov.llnl.gnem.apps.coda.common.service.api.NotificationService; @@ -36,18 +38,20 @@ public class ConfigurationServiceImpl implements ConfigurationService { private EntityManager em; private VelocityConfigurationRepository velConfRepository; private CalibrationShapeFitterConstraintsRepository shapeConstraintsRepository; + private PolygonRepository polygonRepository; private VelocityConfiguration defaultVelConf; private ShapeFitterConstraints defaultShapeFitterConstraint; private NotificationService notificationService; @Autowired public ConfigurationServiceImpl(EntityManager em, VelocityConfigurationRepository velConfRepository, CalibrationShapeFitterConstraintsRepository shapeConstraintsRepository, - VelocityConfiguration defaultVelConf, ShapeFitterConstraints defaultShapeFitterConstraint, NotificationService notificationService) { + VelocityConfiguration defaultVelConf, ShapeFitterConstraints defaultShapeFitterConstraint, PolygonRepository polygonRepository, NotificationService notificationService) { this.em = em; this.velConfRepository = velConfRepository; this.shapeConstraintsRepository = shapeConstraintsRepository; this.defaultVelConf = defaultVelConf; this.defaultShapeFitterConstraint = defaultShapeFitterConstraint; + this.polygonRepository = polygonRepository; this.notificationService = notificationService; } @@ -104,4 +108,16 @@ public ShapeFitterConstraints getCalibrationShapeFitterConstraints() { em.detach(res); return res; } + + @Override + public String updatePolygon(String rawGeoJSON) { + //TODO: Support multiples/additive updates + polygonRepository.deleteAll(); + return polygonRepository.save(new GeoJsonPolygon().setRawGeoJson(rawGeoJSON)).getRawGeoJson(); + }; + + @Override + public String getPolygonGeoJSON() { + return polygonRepository.findAll().stream().findAny().orElseGet(GeoJsonPolygon::new).getRawGeoJson(); + } } diff --git a/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/GeometryServiceImpl.java b/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/GeometryServiceImpl.java new file mode 100644 index 00000000..21ff3ee0 --- /dev/null +++ b/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/GeometryServiceImpl.java @@ -0,0 +1,138 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.service.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +import org.locationtech.jts.algorithm.locate.IndexedPointInAreaLocator; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.Location; +import org.locationtech.jts.geom.util.GeometryCombiner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.wololo.geojson.Feature; +import org.wololo.geojson.FeatureCollection; +import org.wololo.geojson.GeoJSONFactory; +import org.wololo.jts2geojson.GeoJSONReader; + +import gov.llnl.gnem.apps.coda.calibration.model.domain.GeoJsonPolygon; +import gov.llnl.gnem.apps.coda.calibration.repository.PolygonRepository; +import gov.llnl.gnem.apps.coda.calibration.service.api.GeometryService; +import gov.llnl.gnem.apps.coda.common.model.domain.Waveform; +import gov.llnl.gnem.apps.coda.common.model.messaging.WaveformChangeEvent; +import gov.llnl.gnem.apps.coda.common.repository.WaveformRepository; +import gov.llnl.gnem.apps.coda.common.service.api.NotificationService; + +@Service +public class GeometryServiceImpl implements GeometryService { + + private static final Logger log = LoggerFactory.getLogger(GeometryServiceImpl.class); + + private WaveformRepository waveformRepository; + private PolygonRepository polygonRepository; + private NotificationService notificationService; + + @Autowired + public GeometryServiceImpl(WaveformRepository waveformRepository, PolygonRepository polygonRepository, NotificationService notificationService) { + this.waveformRepository = waveformRepository; + this.polygonRepository = polygonRepository; + this.notificationService = notificationService; + } + + @Override + public List setActiveFlagOutsidePolygon(boolean active) { + return toggleActiveByPolygon(false, active); + } + + @Override + public List setActiveFlagInsidePolygon(boolean active) { + return toggleActiveByPolygon(true, active); + } + + private List toggleActiveByPolygon(boolean inside, boolean active) { + List ids = new ArrayList<>(); + + List geoJSON = polygonRepository.findAll(); + List selectedWaveformIds = findIdsByPolygonAndActiveStatus(geoJSON, inside, !active); + + if (!selectedWaveformIds.isEmpty()) { + int updatedRows = waveformRepository.setActiveIn(active, selectedWaveformIds); + if (updatedRows > 0) { + ids.addAll(selectedWaveformIds); + } + } + + if (!ids.isEmpty()) { + notificationService.post(new WaveformChangeEvent(ids).setAddOrUpdate(true)); + } + return ids; + } + + private List findIdsByPolygonAndActiveStatus(List geoJSON, boolean inside, boolean active) { + List selectedWaveformIds = new ArrayList<>(); + if (geoJSON != null && !geoJSON.isEmpty()) { + try { + FeatureCollection featureCollection = (FeatureCollection) GeoJSONFactory.create(geoJSON.get(0).getRawGeoJson()); + + GeoJSONReader reader = new GeoJSONReader(); + + //Combine the geometries + List geoms = new ArrayList<>(); + for (Feature feature : featureCollection.getFeatures()) { + geoms.add(reader.read(feature.getGeometry())); + } + + Geometry geo = GeometryCombiner.combine(geoms); + + Geometry bounds = geo.getEnvelope(); + //minx miny, maxx miny, maxx maxy, minx maxy, minx miny + if (bounds.getNumPoints() == 5) { + IndexedPointInAreaLocator locator = new IndexedPointInAreaLocator(geo); + Coordinate[] coords = bounds.getCoordinates(); + + //Test for polygon intersection and drop any that fail + List possibleWaveforms; + BiFunction test; + if (inside) { + possibleWaveforms = waveformRepository.getMetadataInsideBounds(active, + Math.min(coords[0].getY(), coords[2].getY()), + Math.min(coords[0].getX(), coords[2].getX()), + Math.max(coords[0].getY(), coords[2].getY()), + Math.max(coords[0].getX(), coords[2].getX())); + test = (resEv, resSta) -> resEv != Location.EXTERIOR || resSta != Location.EXTERIOR; + } else { + possibleWaveforms = waveformRepository.getWaveformMetadataByActive(active); + test = (resEv, resSta) -> resEv == Location.EXTERIOR && resSta == Location.EXTERIOR; + } + + selectedWaveformIds.addAll(possibleWaveforms.stream().filter(w -> { + int resEv = locator.locate(new Coordinate(w.getEvent().getLongitude(), w.getEvent().getLatitude())); + int resSta = locator.locate(new Coordinate(w.getStream().getStation().getLongitude(), w.getStream().getStation().getLatitude())); + return test.apply(resEv, resSta); + }).map(w -> w.getId()).collect(Collectors.toList())); + } + } catch (RuntimeException ex) { + log.error(ex.getLocalizedMessage()); + } + + } + return selectedWaveformIds; + } +} diff --git a/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/processing/MdacCalculatorService.java b/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/processing/MdacCalculatorService.java index 26f78257..a3e0ccea 100644 --- a/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/processing/MdacCalculatorService.java +++ b/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/processing/MdacCalculatorService.java @@ -129,4 +129,8 @@ public double getMwInDyne(double testMw) { public double getCornerFrequency(Function mdacFunc) { return mdacFunc.apply(Double.valueOf(1.0))[MdacCalculator.ANGULAR_CORNER_FREQ_IDX] / (Math.PI * 2.0); } + + public double getCornerFrequency(MdacParametersPS mdacPs, MdacParametersFI stress, double mw) { + return getCornerFrequency(getCalculateMdacSourceSpectraFunction(mdacPs, stress, mw)); + } } diff --git a/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/processing/SpectraCalculator.java b/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/processing/SpectraCalculator.java index 8425dea9..977e0898 100644 --- a/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/processing/SpectraCalculator.java +++ b/calibration-service/calibration-service-impl/src/main/java/gov/llnl/gnem/apps/coda/calibration/service/impl/processing/SpectraCalculator.java @@ -443,7 +443,7 @@ public Spectra computeFitSpectra(MeasuredMwParameters event, Collection bands, PICK_TYPES selectedPhase, SPECTRA_TYPES type) { - MdacParametersFI mdacFiEntry = mdacFiService.findFirst(); + MdacParametersFI mdacFiEntry = new MdacParametersFI(mdacFiService.findFirst()); MdacParametersPS psRows = mdacPsService.findMatchingPhase(selectedPhase.getPhase()); List xyPoints = new ArrayList<>(); @@ -454,7 +454,11 @@ public Spectra computeSpecificSpectra(Double mw, Double apparentStress, Collecti } Function mdacFunction = mdacService.getCalculateMdacAmplitudeForMwFunction(psRows, mdacFiEntry, mw, selectedPhase); + double cornerFrequency = -1; + if (type != null && type.equals(SPECTRA_TYPES.FIT)) { + cornerFrequency = mdacService.getCornerFrequency(psRows, mdacFiEntry.setPsi(0.0).setSigma(apparentStress), mw); + } for (FrequencyBand band : bands) { double centerFreq = band.getLowFrequency() + (band.getHighFrequency() - band.getLowFrequency()) / 2.; double logFreq = Math.log10(centerFreq); @@ -467,7 +471,7 @@ public Spectra computeSpecificSpectra(Double mw, Double apparentStress, Collecti } } Collections.sort(xyPoints, (p1, p2) -> Double.compare(p1.getX(), p2.getX())); - return new Spectra(type, xyPoints, mw, apparentStress); + return new Spectra(type, xyPoints, mw, apparentStress, cornerFrequency); } /** @@ -572,7 +576,7 @@ public double value(double[] point) { } double fit = WCVRMSD(weightMap, dataMap); - double corner = mdacService.getCornerFrequency(mdacService.getCalculateMdacSourceSpectraFunction(mdacPs, mdacFi.setPsi(0.0).setSigma(testSigma), testMw)); + double corner = mdacService.getCornerFrequency(mdacService.getCalculateMdacSourceSpectraFunction(mdacPs, new MdacParametersFI(mdacFi).setPsi(0.0).setSigma(testSigma), testMw)); stats.addValue(new double[] { testMw, testSigma, fit, corner }); optimizerMeasurements.add(new ImmutableTriple<>(fit, testMw, testSigma)); return fit; @@ -606,7 +610,7 @@ public double value(double[] point) { for (double mw = minMW; mw < maxMW; mw = mw + ((maxMW - minMW) / 100.)) { for (double stress = minApparentStress; stress < maxApparentStress; stress = stress + ((maxApparentStress - minApparentStress) / 100.)) { double res = mdacFunction.value(new double[] { mw, stress }); - double corner = mdacService.getCornerFrequency(mdacService.getCalculateMdacSourceSpectraFunction(mdacPs, mdacFi.setPsi(0.0).setSigma(stress), mw)); + double corner = mdacService.getCornerFrequency(mdacPs, mdacFi.setPsi(0.0).setSigma(stress), mw); stats.addValue(new double[] { mw, stress, res, corner }); optimizerMeasurements.add(new ImmutableTriple<>(res, mw, stress)); if (res < best) { @@ -692,7 +696,7 @@ public double value(double[] point) { result[APP_2_MIN] = result[APP_STRESS]; result[APP_2_MAX] = result[APP_STRESS]; } - result[CORNER_FREQ] = mdacService.getCornerFrequency(mdacService.getCalculateMdacSourceSpectraFunction(mdacPs, mdacFi.setPsi(0.0).setSigma(result[APP_STRESS]), result[MW_FIT])); + result[CORNER_FREQ] = mdacService.getCornerFrequency(mdacService.getCalculateMdacSourceSpectraFunction(mdacPs, new MdacParametersFI(mdacFi).setPsi(0.0).setSigma(result[APP_STRESS]), result[MW_FIT])); result[ITR_COUNT] = iterations; return result; } diff --git a/calibration-service/calibration-service-impl/src/test/java/gov/llnl/gnem/apps/coda/calibration/service/impl/GeometryServiceImplTest.java b/calibration-service/calibration-service-impl/src/test/java/gov/llnl/gnem/apps/coda/calibration/service/impl/GeometryServiceImplTest.java new file mode 100644 index 00000000..650c5c1e --- /dev/null +++ b/calibration-service/calibration-service-impl/src/test/java/gov/llnl/gnem/apps/coda/calibration/service/impl/GeometryServiceImplTest.java @@ -0,0 +1,200 @@ +/* +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* CODE-743439. +* All rights reserved. +* This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. +* +* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at: +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and limitations under the license. +* +* This work was performed under the auspices of the U.S. Department of Energy +* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. +*/ +package gov.llnl.gnem.apps.coda.calibration.service.impl; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.ArrayUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import gov.llnl.gnem.apps.coda.calibration.model.domain.GeoJsonPolygon; +import gov.llnl.gnem.apps.coda.calibration.repository.PolygonRepository; +import gov.llnl.gnem.apps.coda.common.model.domain.Event; +import gov.llnl.gnem.apps.coda.common.model.domain.Station; +import gov.llnl.gnem.apps.coda.common.model.domain.Stream; +import gov.llnl.gnem.apps.coda.common.model.domain.Waveform; +import gov.llnl.gnem.apps.coda.common.repository.WaveformRepository; +import gov.llnl.gnem.apps.coda.common.service.api.NotificationService; + +@ExtendWith(MockitoExtension.class) +public class GeometryServiceImplTest { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @InjectMocks + private GeometryServiceImpl geometryService; + + @Mock + private WaveformRepository waveformRepository; + + @Mock + private PolygonRepository polygonRepository; + + @Mock + private NotificationService notificationService; + + private List waveforms = new ArrayList<>(); + + private List polygons = new ArrayList<>(); + + @BeforeEach + protected void setUp() throws Exception { + Waveform w1 = createWaveform(); + w1.setId(0l); + w1.setActive(false); + w1.getEvent().setLatitude(-2.0); + w1.getEvent().setLongitude(-2.0); + w1.getStream().getStation().setLatitude(-1.0); + w1.getStream().getStation().setLongitude(-1.0); + waveforms.add(w1); + + Waveform w2 = createWaveform(); + w2.setId(1l); + w2.setActive(true); + w2.getEvent().setEventId("2345"); + w2.getEvent().setLatitude(-2.0); + w2.getEvent().setLongitude(2.0); + w2.getStream().getStation().setLatitude(-1.0); + w2.getStream().getStation().setLongitude(1.0); + waveforms.add(w2); + + Waveform w3 = createWaveform(); + w3.setId(2l); + w3.setActive(true); + w3.getStream().getStation().setStationName("TEST2"); + w3.getEvent().setLatitude(2.0); + w3.getEvent().setLongitude(-2.0); + w3.getStream().getStation().setLatitude(1.0); + w3.getStream().getStation().setLongitude(-1.0); + waveforms.add(w3); + + Waveform w4 = createWaveform(); + w4.setId(3l); + w4.setActive(false); + w4.getEvent().setEventId("2345"); + w4.getStream().getStation().setStationName("TEST2"); + w4.getEvent().setLatitude(2.0); + w4.getEvent().setLongitude(2.0); + w4.getStream().getStation().setLatitude(1.0); + w4.getStream().getStation().setLongitude(1.0); + waveforms.add(w4); + + polygons.add(new GeoJsonPolygon().setRawGeoJson("{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-3.0,-3.0],[3.0,-3.0],[3.0,0.0],[-3.0,0.0],[-3.0,-3.0]]]}}]}")); + Mockito.when(polygonRepository.findAll()).thenReturn(polygons); + + Mockito.when(waveformRepository.setActiveIn(Mockito.anyBoolean(), Mockito.anyList())) + .thenAnswer(invocation -> { + boolean active = (boolean) invocation.getArgument(0); + List ids = (List) invocation.getArgument(1); + List selectedWaveforms = waveforms.stream().filter(w -> ids.contains(w.getId())).collect(Collectors.toList()); + selectedWaveforms.forEach(w->w.setActive(active)); + return selectedWaveforms.size(); + }); + } + + @AfterEach + protected void tearDown() throws Exception { + waveforms.clear(); + } + + @Test + public void testExcludeInside() throws Exception { + testInside(false); + } + + @Test + public void testIncludeInside() throws Exception { + testInside(true); + } + + private void testInside(boolean active) { + Mockito.when(waveformRepository.getMetadataInsideBounds(Mockito.anyBoolean(), Mockito.anyDouble(), Mockito.anyDouble(), Mockito.anyDouble(), Mockito.anyDouble())).thenReturn(waveforms); + List ids = geometryService.setActiveFlagInsidePolygon(active); + List activeIds = waveforms.stream().filter(w -> w.getActive() == active).map(w -> w.getId()).collect(Collectors.toList()); + + Assertions.assertArrayEquals(new long[] { 0l, 1l }, ArrayUtils.toPrimitive(ids.toArray(new Long[0])), "Expecting the first and second waveforms to toggle their active status."); + Assertions.assertTrue(activeIds.containsAll(ids), "Expecting the included/excluded waveform list to contain the selected ids"); + } + + @Test + public void testExcludeOutside() throws Exception { + testOutside(false, 2l); + } + + @Test + public void testIncludeOutside() throws Exception { + testOutside(true, 3l); + } + + private void testOutside(boolean active, long... expectedIds) { + Mockito.when(waveformRepository.getWaveformMetadataByActive(Mockito.anyBoolean())) + .then(invocation -> waveforms.stream().filter(w -> w.getActive() == (boolean) invocation.getArgument(0)).collect(Collectors.toList())); + + List ids = geometryService.setActiveFlagOutsidePolygon(active); + List activeIds = waveforms.stream().filter(w -> w.getActive() == active).map(w -> w.getId()).collect(Collectors.toList()); + Assertions.assertArrayEquals(expectedIds, ArrayUtils.toPrimitive(ids.toArray(new Long[0]))); + Assertions.assertTrue(activeIds.containsAll(ids), "Expecting the included/excluded waveform list to contain the selected ids"); + } + + private Waveform createWaveform() { + Date startTime = Date.from(Instant.now()); + Date endTime = Date.from(startTime.toInstant().plusSeconds(1l)); + + Event event = new Event(); + event.setEventId("1234"); + event.setLatitude(1.0); + event.setLongitude(1.0); + + Station station = new Station(); + station.setLatitude(1.0); + station.setLongitude(1.0); + station.setStationName("TEST"); + station.setNetworkName(null); + + Stream s1 = new Stream(); + s1.setChannelName("BHE"); + s1.setStation(station); + + double[] data = new double[400]; + Arrays.fill(data, 0, 200, 1000.0); + Arrays.fill(data, 2, 400, 2000.0); + Waveform w1 = new Waveform(); + w1.setEvent(event); + w1.setStream(s1); + w1.setSegment(data); + w1.setBeginTime(startTime); + w1.setEndTime(endTime); + w1.setSampleRate(16d); + w1.setLowFrequency(0d); + w1.setHighFrequency(1d); + return w1; + } + +} diff --git a/calibration-service/pom.xml b/calibration-service/pom.xml index 2e05cae8..afe55f4f 100644 --- a/calibration-service/pom.xml +++ b/calibration-service/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 4.0.0 diff --git a/calibration-standalone/pom.xml b/calibration-standalone/pom.xml index 8068f722..3d5512d0 100644 --- a/calibration-standalone/pom.xml +++ b/calibration-standalone/pom.xml @@ -6,7 +6,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 4.0.0 diff --git a/calibration-standalone/src/main/java/gov/llnl/gnem/apps/coda/calibration/standalone/data/client/ParameterLocalClient.java b/calibration-standalone/src/main/java/gov/llnl/gnem/apps/coda/calibration/standalone/data/client/ParameterLocalClient.java index d625310c..ebfb6654 100644 --- a/calibration-standalone/src/main/java/gov/llnl/gnem/apps/coda/calibration/standalone/data/client/ParameterLocalClient.java +++ b/calibration-standalone/src/main/java/gov/llnl/gnem/apps/coda/calibration/standalone/data/client/ParameterLocalClient.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -17,8 +17,6 @@ import java.util.List; import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; @@ -45,8 +43,6 @@ @Primary public class ParameterLocalClient implements ParameterClient { - private static final Logger log = LoggerFactory.getLogger(ParameterLocalClient.class); - private SharedFrequencyBandParametersService sharedParamsService; private SiteFrequencyBandParametersService siteParamsService; private MdacParametersFiService mdacFiService; @@ -145,5 +141,15 @@ public Mono getShapeFitterConstraints() { public Mono updateShapeFitterConstraints(ShapeFitterConstraints conf) { return Mono.just(Optional.ofNullable(configService.update(conf)).map(v -> v.toString()).orElseGet(() -> "")); } + + @Override + public Mono updateMapPolygon(String rawGeoJSON) { + return Mono.just(configService.updatePolygon(rawGeoJSON)).onErrorReturn(""); + } + + @Override + public Mono getMapPolygon() { + return Mono.just(configService.getPolygonGeoJSON()).onErrorReturn(""); + } } diff --git a/calibration-standalone/src/main/java/gov/llnl/gnem/apps/coda/calibration/standalone/data/client/WaveformLocalClient.java b/calibration-standalone/src/main/java/gov/llnl/gnem/apps/coda/calibration/standalone/data/client/WaveformLocalClient.java index 9adb9834..106d8f84 100644 --- a/calibration-standalone/src/main/java/gov/llnl/gnem/apps/coda/calibration/standalone/data/client/WaveformLocalClient.java +++ b/calibration-standalone/src/main/java/gov/llnl/gnem/apps/coda/calibration/standalone/data/client/WaveformLocalClient.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; +import gov.llnl.gnem.apps.coda.calibration.service.api.GeometryService; import gov.llnl.gnem.apps.coda.calibration.service.api.SyntheticService; import gov.llnl.gnem.apps.coda.common.gui.data.client.api.WaveformClient; import gov.llnl.gnem.apps.coda.common.model.domain.SyntheticCoda; @@ -36,13 +37,15 @@ @Primary public class WaveformLocalClient implements WaveformClient { - private WaveformService service; + private WaveformService service; private SyntheticService synthService; + private GeometryService geometryService; @Autowired - public WaveformLocalClient(WaveformService service, SyntheticService synthService) { + public WaveformLocalClient(WaveformService service, SyntheticService synthService, GeometryService geometryService) { this.service = service; this.synthService = synthService; + this.geometryService = geometryService; } @Override @@ -110,4 +113,13 @@ public Flux setWaveformsActiveByStationName(String id, boolean active) { return Flux.just(service.setActiveFlagByStationName(id, active).toString()); } + @Override + public Flux setWaveformsActiveOutsidePolygon(boolean active) { + return Flux.just(geometryService.setActiveFlagOutsidePolygon(active).toString()); + } + + @Override + public Flux setWaveformsActiveInsidePolygon(boolean active) { + return Flux.just(geometryService.setActiveFlagInsidePolygon(active).toString()); + } } diff --git a/calibration-standalone/src/test/java/gov/llnl/gnem/apps/coda/calibration/AssessAutopicker.java b/calibration-standalone/src/test/java/gov/llnl/gnem/apps/coda/calibration/AssessAutopicker.java index 645c0ea1..ba2e2b1a 100644 --- a/calibration-standalone/src/test/java/gov/llnl/gnem/apps/coda/calibration/AssessAutopicker.java +++ b/calibration-standalone/src/test/java/gov/llnl/gnem/apps/coda/calibration/AssessAutopicker.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -27,7 +27,7 @@ import java.util.stream.Stream; import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; -import org.junit.Assert; +import org.junit.jupiter.api.Assertions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,13 +61,12 @@ public static void main(String[] args) { } List waveforms = loader.convertFiles(files) - .doOnError(error -> Assert.fail(error.getMessage())) + .doOnError(error -> Assertions.fail(error.getMessage())) .filter(Objects::nonNull) .filter(r -> r.getResultPayload() != null && r.getResultPayload().isPresent()) .map(r -> r.getResultPayload().get()) - .filter( - w -> w.getAssociatedPicks() != null - && w.getAssociatedPicks().stream().filter(pick -> PICK_TYPES.F.getPhase().equalsIgnoreCase(pick.getPickType())).findAny().isPresent()) + .filter(w -> w.getAssociatedPicks() != null + && w.getAssociatedPicks().stream().filter(pick -> PICK_TYPES.F.getPhase().equalsIgnoreCase(pick.getPickType())).findAny().isPresent()) .collectList() .block(Duration.ofSeconds(10l)); @@ -79,15 +78,14 @@ public static void main(String[] args) { Double maxTime = halfSeries.getMaxTime()[0]; double startTime = series.getTime().getEpochTime() + maxTime; - double stopTime = picker.getEndTime( - series.getData(), - series.getSamprate(), - startTime, - series.getIndexForTime(startTime), - 0, - 1200, - 0.0, - WaveformUtils.getNoiseFloor(WaveformUtils.floatsToDoubles(series.getData()))); + double stopTime = picker.getEndTime(series.getData(), + series.getSamprate(), + startTime, + series.getIndexForTime(startTime), + 0, + 1200, + 0.0, + WaveformUtils.getNoiseFloor(WaveformUtils.floatsToDoubles(series.getData()))); if (new TimeT(stopTime).gt(new TimeT(startTime))) { stopTime = stopTime + series.getTime().subtractD(new TimeT(w.getEvent().getOriginTime())); } diff --git a/common-gui/pom.xml b/common-gui/pom.xml index af8bbc27..f082abe4 100644 --- a/common-gui/pom.xml +++ b/common-gui/pom.xml @@ -7,7 +7,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 gov.llnl.gnem.apps.coda.common diff --git a/common-gui/src/main/java/gov/llnl/gnem/apps/coda/common/gui/data/client/WaveformWebClient.java b/common-gui/src/main/java/gov/llnl/gnem/apps/coda/common/gui/data/client/WaveformWebClient.java index c24e99b8..eab9e0b8 100644 --- a/common-gui/src/main/java/gov/llnl/gnem/apps/coda/common/gui/data/client/WaveformWebClient.java +++ b/common-gui/src/main/java/gov/llnl/gnem/apps/coda/common/gui/data/client/WaveformWebClient.java @@ -175,4 +175,24 @@ public Flux setWaveformsActiveByStationName(String id, boolean active) { .exchange() .flatMapMany(resp -> Flux.just(resp.toString())); } + + @Override + public Flux setWaveformsActiveOutsidePolygon(boolean active) { + return client.post() + .uri("/geometry/set-active/waveforms-outside-polygon/" + active) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .exchange() + .flatMapMany(resp -> Flux.just(resp.toString())); + } + + @Override + public Flux setWaveformsActiveInsidePolygon(boolean active) { + return client.post() + .uri("/geometry/set-active/waveforms-inside-polygon/" + active) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .exchange() + .flatMapMany(resp -> Flux.just(resp.toString())); + } } diff --git a/common-gui/src/main/java/gov/llnl/gnem/apps/coda/common/gui/data/client/api/WaveformClient.java b/common-gui/src/main/java/gov/llnl/gnem/apps/coda/common/gui/data/client/api/WaveformClient.java index 13d7bd8f..be367763 100644 --- a/common-gui/src/main/java/gov/llnl/gnem/apps/coda/common/gui/data/client/api/WaveformClient.java +++ b/common-gui/src/main/java/gov/llnl/gnem/apps/coda/common/gui/data/client/api/WaveformClient.java @@ -51,4 +51,8 @@ public interface WaveformClient { public Flux setWaveformsActiveByEventId(String id, boolean active); public Flux setWaveformsActiveByStationName(String id, boolean active); + + public Flux setWaveformsActiveOutsidePolygon(boolean active); + + public Flux setWaveformsActiveInsidePolygon(boolean active); } diff --git a/common-gui/src/test/java/gov/llnl/gnem/apps/coda/common/gui/converters/sac/SacExporterTest.java b/common-gui/src/test/java/gov/llnl/gnem/apps/coda/common/gui/converters/sac/SacExporterTest.java index 4809c73d..c667f5bb 100644 --- a/common-gui/src/test/java/gov/llnl/gnem/apps/coda/common/gui/converters/sac/SacExporterTest.java +++ b/common-gui/src/test/java/gov/llnl/gnem/apps/coda/common/gui/converters/sac/SacExporterTest.java @@ -20,19 +20,15 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.sql.Date; -import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Locale; import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import org.junit.Assert; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -111,7 +107,7 @@ public void testWriteWaveformToDirectory(Waveform input, ArgumentsAccessor argum @MethodSource("testParamSet") public void testGetFileName(Waveform input, String expectedFilename) throws Exception { String actual = exporter.getFileName(input); - Assert.assertEquals(expectedFilename, actual); + Assertions.assertEquals(expectedFilename, actual); } @Test @@ -119,31 +115,31 @@ public void testEventDepthPopulated() throws Exception { //GMPAPPS-1947 Envelope tool was dropping event depth info during import/export. Waveform waveform = createValidWaveform(); SACHeader header = exporter.sacHeaderFromWaveform(waveform); - Assert.assertTrue("Expect that the waveform should have a populated event depth if the original file had it.", header.evdp != 0 && !SACHeader.isDefault(header.evdp)); + Assertions.assertTrue(header.evdp != 0 && !SACHeader.isDefault(header.evdp), "Expect that the waveform should have a populated event depth if the original file had it."); } private static Consumer> waveformNotValidAssertions() throws Exception { return res -> { - Assert.assertFalse("Result on an invalid waveform should be false", res.isSuccess()); + Assertions.assertFalse(res.isSuccess(), "Result on an invalid waveform should be false"); try { java.util.stream.Stream stream = Files.list(testDir.toPath()); - Assert.assertFalse("Files should never be created for an invalid waveform", stream.findFirst().isPresent()); + Assertions.assertFalse(stream.findFirst().isPresent(), "Files should never be created for an invalid waveform"); stream.close(); } catch (IOException e) { - Assert.fail("Unable to list the contents of the test directory: " + testDir.getAbsolutePath() + " : " + e.toString()); + Assertions.fail("Unable to list the contents of the test directory: " + testDir.getAbsolutePath() + " : " + e.toString()); } }; } private static Consumer> waveformValidAssertions() { return res -> { - Assert.assertTrue("Result on an valid waveform should be true: " + res.getResultPayload().get(), res.isSuccess()); + Assertions.assertTrue(res.isSuccess(), "Result on an valid waveform should be true: " + res.getResultPayload().get()); Path filePath = testDir.toPath().resolve(res.getResultPayload().get()); - Assert.assertTrue("File should be created for valid waveforms", Files.exists(filePath)); + Assertions.assertTrue(Files.exists(filePath), "File should be created for valid waveforms"); try { Files.delete(filePath); } catch (IOException e) { - Assert.fail("Temporary files should never exist after a test is complete but an error occured during deletion: " + e.toString()); + Assertions.fail("Temporary files should never exist after a test is complete but an error occured during deletion: " + e.toString()); } }; } diff --git a/common-gui/src/test/java/gov/llnl/gnem/apps/coda/common/gui/converters/sac/SacLoaderTest.java b/common-gui/src/test/java/gov/llnl/gnem/apps/coda/common/gui/converters/sac/SacLoaderTest.java index 9470c52b..fe80b2eb 100644 --- a/common-gui/src/test/java/gov/llnl/gnem/apps/coda/common/gui/converters/sac/SacLoaderTest.java +++ b/common-gui/src/test/java/gov/llnl/gnem/apps/coda/common/gui/converters/sac/SacLoaderTest.java @@ -27,8 +27,8 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -import org.junit.Assert; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -60,10 +60,10 @@ public void teardown() { @ParameterizedTest @MethodSource("singleFile") public void testConvertFile(File inputFile) throws Exception { - Result res = loader.convertFile(inputFile).doOnError(error -> Assert.fail(error.getMessage())).block(Duration.ofSeconds(10l)); - Assert.assertTrue("Expect that waveform results should all complete successfully", res.isSuccess()); - Assert.assertTrue("Expect that waveform results should have no error or warning messages", res.getErrors().isEmpty()); - Assert.assertTrue("Expect that waveform results should have a Waveform payload", res.getResultPayload().isPresent()); + Result res = loader.convertFile(inputFile).doOnError(error -> Assertions.fail(error.getMessage())).block(Duration.ofSeconds(10l)); + Assertions.assertTrue(res.isSuccess(), "Expect that waveform results should all complete successfully"); + Assertions.assertTrue(res.getErrors().isEmpty(), "Expect that waveform results should have no error or warning messages"); + Assertions.assertTrue(res.getResultPayload().isPresent(), "Expect that waveform results should have a Waveform payload"); } public static Collection singleFile() throws IOException { @@ -84,11 +84,11 @@ public void testConvertFiles() throws Exception { return null; } }).filter(o -> o != null).collect(Collectors.toList()); - List> results = loader.convertFiles(multipleFiles.get(0)).doOnError(error -> Assert.fail(error.getMessage())).collectList().block(Duration.ofSeconds(10l)); + List> results = loader.convertFiles(multipleFiles.get(0)).doOnError(error -> Assertions.fail(error.getMessage())).collectList().block(Duration.ofSeconds(10l)); for (Result res : results) { - Assert.assertTrue("Expect that waveform results should all complete successfully", res.isSuccess()); - Assert.assertTrue("Expect that waveform results should have no error or warning messages", res.getErrors().isEmpty()); - Assert.assertTrue("Expect that waveform results should have a Waveform payload", res.getResultPayload().isPresent()); + Assertions.assertTrue(res.isSuccess(), "Expect that waveform results should all complete successfully"); + Assertions.assertTrue(res.getErrors().isEmpty(), "Expect that waveform results should have no error or warning messages"); + Assertions.assertTrue(res.getResultPayload().isPresent(), "Expect that waveform results should have a Waveform payload"); } } @@ -103,9 +103,9 @@ public void testEventDepthPopulated() throws Exception { return null; } }).filter(o -> o != null).collect(Collectors.toList()); - List> results = loader.convertFiles(multipleFiles.get(0)).doOnError(error -> Assert.fail(error.getMessage())).collectList().block(Duration.ofSeconds(10l)); + List> results = loader.convertFiles(multipleFiles.get(0)).doOnError(error -> Assertions.fail(error.getMessage())).collectList().block(Duration.ofSeconds(10l)); for (Result res : results) { - Assert.assertTrue("Expect that the waveform should have a populated event depth if the original file had it.", res.getResultPayload().get().getEvent().getDepth() != 0); + Assertions.assertTrue(res.getResultPayload().get().getEvent().getDepth() != 0, "Expect that the waveform should have a populated event depth if the original file had it."); } } } diff --git a/common-service/common-application/pom.xml b/common-service/common-application/pom.xml index ec7dbdbe..71a7b649 100644 --- a/common-service/common-application/pom.xml +++ b/common-service/common-application/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.common common-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/common-service/common-application/src/main/java/gov/llnl/gnem/apps/coda/common/application/config/WebSocketConfig.java b/common-service/common-application/src/main/java/gov/llnl/gnem/apps/coda/common/application/config/WebSocketConfig.java index 1c96c5bd..43c1c1bb 100644 --- a/common-service/common-application/src/main/java/gov/llnl/gnem/apps/coda/common/application/config/WebSocketConfig.java +++ b/common-service/common-application/src/main/java/gov/llnl/gnem/apps/coda/common/application/config/WebSocketConfig.java @@ -27,9 +27,10 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/websocket-guide").setAllowedOrigins("*").withSockJS(); + registry.addEndpoint("/websocket-guide").withSockJS(); } + @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/queue/", "/topic/").setTaskScheduler(new DefaultManagedTaskScheduler()); diff --git a/common-service/common-application/src/test/java/gov/llnl/gnem/apps/coda/common/util/NumberFormatFactoryTest.java b/common-service/common-application/src/test/java/gov/llnl/gnem/apps/coda/common/util/NumberFormatFactoryTest.java index 12d1f278..a96568e7 100644 --- a/common-service/common-application/src/test/java/gov/llnl/gnem/apps/coda/common/util/NumberFormatFactoryTest.java +++ b/common-service/common-application/src/test/java/gov/llnl/gnem/apps/coda/common/util/NumberFormatFactoryTest.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -20,7 +20,7 @@ import java.util.Collection; import java.util.List; -import org.junit.Assert; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.aggregator.ArgumentsAccessor; import org.junit.jupiter.params.provider.MethodSource; @@ -34,7 +34,7 @@ public final void testTwoDecimalOneLeadingZeroFormattingExpectations(Number inpu String expectedTwoDigit = args.getString(1); NumberFormat formatter = NumberFormatFactory.twoDecimalOneLeadingZero(); String actual = formatter.format(input); - Assert.assertEquals(expectedTwoDigit, actual); + Assertions.assertEquals(expectedTwoDigit, actual); } @ParameterizedTest @@ -43,7 +43,7 @@ public final void testFourDecimalOneLeadingZeroFormattingExpectations(Number inp String expectedFourDigit = args.getString(2); NumberFormat formatter = NumberFormatFactory.fourDecimalOneLeadingZero(); String actual = formatter.format(input); - Assert.assertEquals(expectedFourDigit, actual); + Assertions.assertEquals(expectedFourDigit, actual); } @SuppressWarnings("unused") diff --git a/common-service/common-model/pom.xml b/common-service/common-model/pom.xml index 6497be2f..62032946 100644 --- a/common-service/common-model/pom.xml +++ b/common-service/common-model/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.common common-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/common-service/common-repository/pom.xml b/common-service/common-repository/pom.xml index 330ea915..79d76f44 100644 --- a/common-service/common-repository/pom.xml +++ b/common-service/common-repository/pom.xml @@ -4,7 +4,7 @@ gov.llnl.gnem.apps.coda.common common-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/common-service/common-repository/src/main/java/gov/llnl/gnem/apps/coda/common/repository/WaveformRepository.java b/common-service/common-repository/src/main/java/gov/llnl/gnem/apps/coda/common/repository/WaveformRepository.java index 0f5eae6a..a5050665 100644 --- a/common-service/common-repository/src/main/java/gov/llnl/gnem/apps/coda/common/repository/WaveformRepository.java +++ b/common-service/common-repository/src/main/java/gov/llnl/gnem/apps/coda/common/repository/WaveformRepository.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -28,7 +28,6 @@ import gov.llnl.gnem.apps.coda.common.model.domain.Stream; import gov.llnl.gnem.apps.coda.common.model.domain.Waveform; import gov.llnl.gnem.apps.coda.common.model.domain.WaveformPick; -import gov.llnl.gnem.apps.coda.common.repository.DetachableJpaRepository; @Transactional public interface WaveformRepository extends DetachableJpaRepository { @@ -43,6 +42,9 @@ public Waveform findOneByAllFields(@Param("beginTime") Date beginTime, @Param("e @Query("select new Waveform(w.id, w.version, w.event, w.stream, w.beginTime, w.endTime, w.segmentType, w.segmentUnits, w.lowFrequency, w.highFrequency, w.sampleRate, w.active) from Waveform w order by w.id desc") public Set getWaveformMetadata(); + + @Query("select new Waveform(w.id, w.version, w.event, w.stream, w.beginTime, w.endTime, w.segmentType, w.segmentUnits, w.lowFrequency, w.highFrequency, w.sampleRate, w.active) from Waveform w where w.active = :active order by w.id desc") + public List getWaveformMetadataByActive(@Param("active") boolean active); @Query("select new Waveform(w.id, w.version, w.event, w.stream, w.beginTime, w.endTime, w.segmentType, w.segmentUnits, w.lowFrequency, w.highFrequency, w.sampleRate, w.active) from Waveform w where w.id in :ids order by w.id desc") public List findAllMetadataByIds(@Param("ids") List ids); @@ -64,6 +66,26 @@ public Waveform findOneByAllFields(@Param("beginTime") Date beginTime, @Param("e @Query("update Waveform w SET w.active = :active where w.stream.station.stationName = :stationName") public int setActiveByStationName(@Param("stationName") String stationName, @Param("active") boolean active); + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query("update Waveform w SET w.active = :active") + public void setAllActive(boolean active); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query("update Waveform w SET w.active = :active where w.id in (:ids)") + public int setActiveIn(@Param("active") boolean active, @Param("ids") List waveformIds); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query("update Waveform w SET w.active = :active where w.id not in (:ids)") + public int setActiveNotIn(@Param("active") boolean active, @Param("ids") List waveformIds); + + @Query("select new Waveform(w.id, w.version, w.event, w.stream, w.beginTime, w.endTime, w.segmentType, w.segmentUnits, w.lowFrequency, w.highFrequency, w.sampleRate, w.active) from Waveform w " + + "where w.active = :active and" + + "(w.stream.station.latitude between :minX and :maxX " + + "and w.stream.station.longitude between :minY and :maxY) " + + "or (w.event.latitude between :minX and :maxX " + + "and w.event.longitude between :minY and :maxY)") + public List getMetadataInsideBounds(@Param("active") boolean active, @Param("minX") Double minX, @Param("minY") Double minY, @Param("maxX") Double maxX, @Param("maxY") Double maxY); + @Query("select w.id from Waveform w where w.event.eventId = :eventId") public List findAllIdsByEventId(@Param("eventId") String eventId); @@ -76,4 +98,9 @@ public Waveform findOneByAllFields(@Param("beginTime") Date beginTime, @Param("e @Query("select w from Waveform w where w.active = true and w.event.eventId = :eventId and w.stream.channelName = 'STACK' and w.stream.station.stationName in :stationNames") public List findAllActiveStacksByEventIdAndStationNames(@Param("eventId") String eventId, @Param("stationNames") List stationNames); + @Query("select w.id from Waveform w where w.active = false") + public List findAllInactiveIds(); + + @Query("select w.id from Waveform w where w.id not in (:ids)") + public List findIdsNotIn(@Param("ids") List ids); } diff --git a/common-service/common-service-api/pom.xml b/common-service/common-service-api/pom.xml index 96dc89ba..23a7a55f 100644 --- a/common-service/common-service-api/pom.xml +++ b/common-service/common-service-api/pom.xml @@ -4,7 +4,7 @@ gov.llnl.gnem.apps.coda.common common-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/common-service/common-service-impl/pom.xml b/common-service/common-service-impl/pom.xml index f401e5ac..be38ea52 100644 --- a/common-service/common-service-impl/pom.xml +++ b/common-service/common-service-impl/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.common common-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/common-service/common-service-impl/src/main/java/gov/llnl/gnem/apps/coda/common/service/impl/WaveformServiceImpl.java b/common-service/common-service-impl/src/main/java/gov/llnl/gnem/apps/coda/common/service/impl/WaveformServiceImpl.java index 56302a65..129285d8 100644 --- a/common-service/common-service-impl/src/main/java/gov/llnl/gnem/apps/coda/common/service/impl/WaveformServiceImpl.java +++ b/common-service/common-service-impl/src/main/java/gov/llnl/gnem/apps/coda/common/service/impl/WaveformServiceImpl.java @@ -44,7 +44,7 @@ @Service public class WaveformServiceImpl implements WaveformService { - private WaveformRepository waveformRepository; + private WaveformRepository waveformRepository; private NotificationService notificationService; private ExampleMatcher ignoreStandardFieldsMatcher = ExampleMatcher.matching().withIgnoreNullValues().withIgnoreCase().withIgnorePaths("id", "version", "associatedPicks", "segment"); diff --git a/common-service/pom.xml b/common-service/pom.xml index b6e677fc..72f2fe06 100644 --- a/common-service/pom.xml +++ b/common-service/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 gov.llnl.gnem.apps.coda.common diff --git a/envelope-gui/pom.xml b/envelope-gui/pom.xml index 093fda9b..fbb7cc97 100644 --- a/envelope-gui/pom.xml +++ b/envelope-gui/pom.xml @@ -7,7 +7,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 envelope-gui diff --git a/envelope-service/envelope-application/pom.xml b/envelope-service/envelope-application/pom.xml index f93a4aff..d749d480 100644 --- a/envelope-service/envelope-application/pom.xml +++ b/envelope-service/envelope-application/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.envelope envelope-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/envelope-service/envelope-model/pom.xml b/envelope-service/envelope-model/pom.xml index d4904595..df2e4ab5 100644 --- a/envelope-service/envelope-model/pom.xml +++ b/envelope-service/envelope-model/pom.xml @@ -4,7 +4,7 @@ gov.llnl.gnem.apps.coda.envelope envelope-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/envelope-service/envelope-repository/pom.xml b/envelope-service/envelope-repository/pom.xml index 4aad408d..f174c627 100644 --- a/envelope-service/envelope-repository/pom.xml +++ b/envelope-service/envelope-repository/pom.xml @@ -4,7 +4,7 @@ gov.llnl.gnem.apps.coda.envelope envelope-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/envelope-service/envelope-service-api/pom.xml b/envelope-service/envelope-service-api/pom.xml index 15cacf0a..d136eccb 100644 --- a/envelope-service/envelope-service-api/pom.xml +++ b/envelope-service/envelope-service-api/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.envelope envelope-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/envelope-service/envelope-service-impl/pom.xml b/envelope-service/envelope-service-impl/pom.xml index cbc31199..98c904e8 100644 --- a/envelope-service/envelope-service-impl/pom.xml +++ b/envelope-service/envelope-service-impl/pom.xml @@ -6,7 +6,7 @@ gov.llnl.gnem.apps.coda.envelope envelope-service - 1.0.9 + 1.0.10 4.0.0 diff --git a/envelope-service/pom.xml b/envelope-service/pom.xml index 00e61912..bfb4ffa5 100644 --- a/envelope-service/pom.xml +++ b/envelope-service/pom.xml @@ -5,7 +5,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 gov.llnl.gnem.apps.coda.envelope diff --git a/envelope-standalone/pom.xml b/envelope-standalone/pom.xml index ee8a5ae7..a8976067 100644 --- a/envelope-standalone/pom.xml +++ b/envelope-standalone/pom.xml @@ -6,7 +6,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 4.0.0 diff --git a/externals/pom.xml b/externals/pom.xml index 5b885ade..983d8e4b 100644 --- a/externals/pom.xml +++ b/externals/pom.xml @@ -7,7 +7,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 externals diff --git a/externals/src/main/java/llnl/gnem/core/gui/plotting/jmultiaxisplot/VPickLine.java b/externals/src/main/java/llnl/gnem/core/gui/plotting/jmultiaxisplot/VPickLine.java index d25b9581..25a67dca 100755 --- a/externals/src/main/java/llnl/gnem/core/gui/plotting/jmultiaxisplot/VPickLine.java +++ b/externals/src/main/java/llnl/gnem/core/gui/plotting/jmultiaxisplot/VPickLine.java @@ -229,9 +229,10 @@ public void setWidth(int v) { * @param v * The new draggable value */ - public void setDraggable(boolean v) { + public VPickLine setDraggable(boolean v) { canDragX = v; window.setCanDragX(canDragX); + return this; } /** diff --git a/mapping/pom.xml b/mapping/pom.xml index 36f09f82..23d9ea98 100644 --- a/mapping/pom.xml +++ b/mapping/pom.xml @@ -7,7 +7,7 @@ gov.llnl.gnem.apps.coda.calibration coda-calibration - 1.0.9 + 1.0.10 gov.llnl.gnem.apps.coda.common diff --git a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/LeafletMap.java b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/LeafletMap.java index 423a1aa8..2724ef2c 100644 --- a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/LeafletMap.java +++ b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/LeafletMap.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -33,6 +33,7 @@ import gov.llnl.gnem.apps.coda.common.mapping.api.GeoShape; import gov.llnl.gnem.apps.coda.common.mapping.api.Icon; import gov.llnl.gnem.apps.coda.common.mapping.api.Icon.IconStyles; +import gov.llnl.gnem.apps.coda.common.mapping.api.Icon.IconTypes; import gov.llnl.gnem.apps.coda.common.mapping.api.Line; import javafx.application.Platform; import javafx.collections.FXCollections; @@ -49,6 +50,9 @@ public class LeafletMap { + private static final LeafletIcon POLYGON_OUT_ICON = new LeafletIcon(null, null, IconTypes.POLYGON_OUT); + private static final LeafletIcon POLYGON_IN_ICON = new LeafletIcon(null, null, IconTypes.POLYGON_IN); + private static final Logger log = LoggerFactory.getLogger(LeafletMap.class); private WebView webView; @@ -59,11 +63,16 @@ public class LeafletMap { private AtomicBoolean mapReady = new AtomicBoolean(false); private Map> callbackMap = new HashMap<>(); private IconCallbackHandler iconCallbackHandler; + private PolygonChangeCallbackHandler polygonChangeCallbackHandler; private List> eventCallbacks = new ArrayList<>(); private ContextMenu contextMenu; private MenuItem reload = new MenuItem("Reload"); private MenuItem include = new MenuItem("Include"); private MenuItem exclude = new MenuItem("Exclude"); + private MenuItem excludeOutPolygon = new MenuItem("Exclude outside"); + private MenuItem includeOutPolygon = new MenuItem("Include outside"); + private MenuItem excludeInPolygon = new MenuItem("Exclude inside"); + private MenuItem includeInPolygon = new MenuItem("Include inside"); public class IconCallbackHandler { private BiConsumer iconCallbackHandler; @@ -77,6 +86,18 @@ public void accept(Boolean selected, String value) { } } + public class PolygonChangeCallbackHandler { + private Consumer polygonChangeCallbackHandler; + + public PolygonChangeCallbackHandler(Consumer polygonChangeCallbackHandler) { + this.polygonChangeCallbackHandler = polygonChangeCallbackHandler; + } + + public void accept(String value) { + polygonChangeCallbackHandler.accept(value); + } + } + public LeafletMap() { iconCallbackHandler = new IconCallbackHandler((selected, id) -> { BiConsumer callback = callbackMap.get(id); @@ -85,6 +106,12 @@ public LeafletMap() { } }); + polygonChangeCallbackHandler = new PolygonChangeCallbackHandler(geoJSON -> { + List> callbacks = new ArrayList<>(eventCallbacks); + MapCallbackEvent event = new MapCallbackEvent(null, MAP_CALLBACK_EVENT_TYPE.POLYGON_CHANGE, true, geoJSON); + callbacks.forEach(cb -> cb.accept(event)); + }); + Platform.runLater(() -> { webView = new WebView(); webView.getEngine().setJavaScriptEnabled(true); @@ -97,6 +124,7 @@ public LeafletMap() { WebEngine engine = webView.getEngine(); contextMenu.getItems().clear(); Object activeIconId = engine.executeScript("getActiveIcon();"); + Object activePolygonId = engine.executeScript("getActivePolygon();"); if (activeIconId instanceof String) { icons.stream().filter(icon -> icon.getId().equalsIgnoreCase((String) activeIconId)).findFirst().ifPresent(icon -> { include.setOnAction(e -> invokeActivationCallbacks(icon, true)); @@ -104,6 +132,13 @@ public LeafletMap() { contextMenu.getItems().addAll(include, exclude); contextMenu.show(webView, event.getScreenX(), event.getScreenY()); }); + } else if (activePolygonId instanceof Boolean && ((boolean) activePolygonId == true)) { + excludeOutPolygon.setOnAction(e -> invokeActivationCallbacks(POLYGON_OUT_ICON, false)); + includeOutPolygon.setOnAction(e -> invokeActivationCallbacks(POLYGON_OUT_ICON, true)); + excludeInPolygon.setOnAction(e -> invokeActivationCallbacks(POLYGON_IN_ICON, false)); + includeInPolygon.setOnAction(e -> invokeActivationCallbacks(POLYGON_IN_ICON, true)); + contextMenu.getItems().addAll(excludeOutPolygon, includeOutPolygon, excludeInPolygon, includeInPolygon); + contextMenu.show(webView, event.getScreenX(), event.getScreenY()); } else { contextMenu.getItems().addAll(reload); contextMenu.show(webView, event.getScreenX(), event.getScreenY()); @@ -119,6 +154,7 @@ public LeafletMap() { layers.forEach(this::addLayerToMap); JSObject wind = (JSObject) webView.getEngine().executeScript("window"); wind.setMember("iconCallbackHandler", iconCallbackHandler); + wind.setMember("polygonChangeCallbackHandler", polygonChangeCallbackHandler); return; } }); @@ -363,18 +399,8 @@ private String createJsIconRepresentation(Icon icon) { } private String addCallbacks(String id, String name) { - return ".on('click', function() { iconCallbackHandler.accept(true, \"" - + id - + "\"); }).bindPopup('" - + name - + "').on('popupclose', function() { iconCallbackHandler.accept(false, \"" - + id - + "\"); }).on('mouseover', function() { if (\"" - + id - + "\" !== mouseoverIconId) { mouseoverIconId = \"" - + id - + "\"; }}).on('mouseout', function() { if (\"" - + id + return ".on('click', function() { iconCallbackHandler.accept(true, \"" + id + "\"); }).bindPopup('" + name + "').on('popupclose', function() { iconCallbackHandler.accept(false, \"" + id + + "\"); }).on('mouseover', function() { if (\"" + id + "\" !== mouseoverIconId) { mouseoverIconId = \"" + id + "\"; }}).on('mouseout', function() { if (\"" + id + "\" === mouseoverIconId) { mouseoverIconId = null; }})"; } @@ -450,4 +476,12 @@ public void setShowOverlay(boolean showOverlay) { public Boolean hasVisibleTileLayers() { return (Boolean) webView.getEngine().executeScript("hasVisibleTiles();"); } + + public String getPolygonGeoJSON() { + return (String) webView.getEngine().executeScript("getPolygonGeoJSON();"); + } + + public void setPolygonGeoJSON(String geoJSON) { + webView.getEngine().executeScript("setPolygonGeoJSON('" + geoJSON + "');"); + } } diff --git a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/LeafletMapController.java b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/LeafletMapController.java index 869ef1b3..234caf28 100644 --- a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/LeafletMapController.java +++ b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/LeafletMapController.java @@ -179,6 +179,18 @@ public void removeEventCallback(Consumer callback) { mapImpl.removeEventCallback(callback); } + @Override + public String getPolygonGeoJSON() { + return mapImpl.getPolygonGeoJSON(); + } + + @Override + public void setPolygonGeoJSON(String geoJSON) { + Platform.runLater(() -> { + mapImpl.setPolygonGeoJSON(geoJSON); + }); + } + @Override public int hashCode() { final int prime = 31; diff --git a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/MAP_CALLBACK_EVENT_TYPE.java b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/MAP_CALLBACK_EVENT_TYPE.java index 6cce09b8..fff69e01 100644 --- a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/MAP_CALLBACK_EVENT_TYPE.java +++ b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/MAP_CALLBACK_EVENT_TYPE.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2019, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * @@ -15,7 +15,7 @@ public enum MAP_CALLBACK_EVENT_TYPE { - SELECTION("selection"), ACTIVATION("activation"); + SELECTION("selection"), ACTIVATION("activation"), POLYGON_CHANGE("polygon_update"); private String type; private MAP_CALLBACK_EVENT_TYPE(String type) { diff --git a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/MapCallbackEvent.java b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/MapCallbackEvent.java index bbbe825c..9c637807 100644 --- a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/MapCallbackEvent.java +++ b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/MapCallbackEvent.java @@ -19,12 +19,22 @@ public class MapCallbackEvent { private final MAP_CALLBACK_EVENT_TYPE type; private final boolean flag; private final Icon icon; + private final String body; public MapCallbackEvent(Icon icon, MAP_CALLBACK_EVENT_TYPE type, boolean flag) { super(); this.icon = icon; this.type = type; this.flag = flag; + this.body = null; + } + + public MapCallbackEvent(Icon icon, MAP_CALLBACK_EVENT_TYPE type, boolean flag, String body) { + super(); + this.icon = icon; + this.type = type; + this.flag = flag; + this.body = body; } public Icon getIcon() { @@ -38,4 +48,8 @@ public boolean getFlag() { public MAP_CALLBACK_EVENT_TYPE getType() { return type; } + + public String getBody() { + return body; + } } diff --git a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/api/GeoMap.java b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/api/GeoMap.java index 38ff6109..aaee49fa 100644 --- a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/api/GeoMap.java +++ b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/api/GeoMap.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -47,4 +47,8 @@ public interface GeoMap { public void removeEventCallback(Consumer callback); public void show(); + + public String getPolygonGeoJSON(); + + public void setPolygonGeoJSON(String geoJSON); } diff --git a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/api/Icon.java b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/api/Icon.java index 4abd060a..dd0db512 100644 --- a/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/api/Icon.java +++ b/mapping/src/main/java/gov/llnl/gnem/apps/coda/common/mapping/api/Icon.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory +* Copyright (c) 2020, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory * CODE-743439. * All rights reserved. * This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool. @@ -18,10 +18,10 @@ public interface Icon { - public static final String FOCUS_TAG = "!!"; + public static final String FOCUS_TAG = "!!"; public enum IconTypes { - DEFAULT, CIRCLE, TRIANGLE_UP + DEFAULT, CIRCLE, TRIANGLE_UP, POLYGON_OUT, POLYGON_IN } public enum IconStyles { diff --git a/mapping/src/main/resources/leaflet/images/Circle.svg b/mapping/src/main/resources/leaflet/images/Circle.svg new file mode 100644 index 00000000..5263da9f --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Circle.svg @@ -0,0 +1,15 @@ + + Atoms/Icons/Tools/Circle + Created with Sketch. + + + + + + + + + + + + diff --git a/mapping/src/main/resources/leaflet/images/CircleMarker.svg b/mapping/src/main/resources/leaflet/images/CircleMarker.svg new file mode 100644 index 00000000..5b71e7a8 --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/CircleMarker.svg @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/mapping/src/main/resources/leaflet/images/Edit_Vertex.png b/mapping/src/main/resources/leaflet/images/Edit_Vertex.png new file mode 100644 index 0000000000000000000000000000000000000000..9c639eedf8f950524d5ec6aee5144ca3c9964bd1 GIT binary patch literal 2018 zcmV<82Oao{P)EX>4Tx04R}tkv&MmKpe$i(@Iq;9qgdukfAzR5ET(zvs^dzd7t}p^eB0g0X~st?f%Ws^E4huXpVr0^D#1Ue#*v4`jvy!0_PY_2HRik_% z>$1Xmi?dp;vgSSc3qyHrd5P;Z2a&)67LkGo8C7hc3=1(@HBwBZX+Q4aA8`CBa>?Y{ z03*jdDo`Oge(*o|-K|*|A9IsJaiHVHwm*h|;4aXp+4lFbZ8uH;|1)rYT&=zG#7LvkcPO`%W#-p}ZpazO7b(7o#R*4)SG1CXJvk~hG? zAuwE|>@|;fceeNT@0n(QKY`(Lty!nefB*mh24YJ`L;(K){{a7>y{D4^000SaNLh0L z0E%e<0E%e=v1PL|00007bV*G`2jmF^5E}$>4yxe*00rJjL_t(|+U;9?Y!p=x|IORw zT2mlb4Q(JuO#C>JVl=t-Ep0dxMNy+gQ6vpQqCpf4NDUQ>LZ~2MB7`6x#sZ>5B_L`V z6a)StC8hh?BO23)h#y2C2BWl!m0sJu@sD1Urn%j=$L{s6*ZJp?eKV7p-_DzvH}95^ zCR9{ZbUP7k2T)?e5+$OY%v_ZhI5bNse>woO^)&tDE6~Htb)ePWWW?tUV(D3Kg*yt4iB&A#p zUV#TTY)o-RYXKZhJ4KtOBsgRYZvn5K(!3efW5fBQ6Mnoc!KjLKj zbCzY@5e|nh^?Vo%2CvmL?OOoX_r{T#Cp9!Q{E&XHBCEWCtz9D(YQtlF)keeu*(ZhZ_^s=R@+SgevjL-G2de+pzHc{ z8<`7f2Y}D#`##p*_IBp=U@$l)PRYEEnK#B!b*ZJL zlcs4W4Z~Q*%wNV5>n`7YSg0br6+>P*Tcsd)6k?`Gg|CFpL~#UIn1sq2+Cf*Aw(XA1S5g#E!bDSp}q&Gnx4mfR}8X zzXD*TrfFjVtd50re`!K67|cm_8SGaC6c!fVD1>+mzyl6!p95H;l=`IyU^mBR0y6;Q z_T%t#%;)nxSX*2BUrGQ_TwI)OS=Mp@F9XQ7VfzihQl-?Vc6tJVfbRGEC-%ttFFH(n zj%u1#dg8>1wm}8JFpRsIc^iORZCE-1Y}a-D)w;U6%LB|K`ch-3xz^Y^ffqj4S+x(py%f1KF`c+0F1KX zzXYICDOH_>Z2d?i64@6B1ZI2L7>QU&PWAi!-!SuL8|N9oUSBusFvPWMg%1H(Xqx7Eqz*kTrEFD7E%CAwJOg05QtDx)R4O^&O^Xe~*yIHO zSBR*pwY7D!QtAj&n3%a-O8J_bTc9QyjlR&>*mxG{Lo20}?MkV&gFO#Oi2Bh9_LnM^ zQX7(X8cac2Zx}{JCIbLwenU#RC}RPLZR4#{$_1GUKsN|Gq?Au)DgfQS>@f_ZEK>mh z0F9a7lTyyeQ~-dkS>=8y2d_YP$EmHvix@MSrG8q5>=<`6Qr>SFS0jzhd zi$qZ&#G#=Izyu;XYMSP+ZqEbKrsgyAGj7fU(y#R+nqN>*kTsM6*n+O>HoHU6n2{q# z&K!~e5YaBB)KVha(Z@+};ZOu%PhMW$0sx$smvOf+ z`;d8dr~q)VrKM#~I2^Wmg?Tjqr%Td#B_$=J(j9=$va+(u;@ttpZlgYNkR8?8*;$ru z05tbVcwbnSHQVVHxUXbLM9-xa07SGAz*hiv3n3m0hr{ho{HAFh2hikD4em4yLndO& zptQoVZ-nk0pxE00wmN`N06-1pPH-=Pe{I&j)->&4LeZE`?XO`N+j}%W9RNNCuvsb9 zkf_eIIt?=OD*)O7Gz%eidhrd>Fb&f%4O2$Z|3f1tv}+5QivR!s07*qoM6N<$f + + + + + + + + + + diff --git a/mapping/src/main/resources/leaflet/images/Eraser.png b/mapping/src/main/resources/leaflet/images/Eraser.png new file mode 100644 index 0000000000000000000000000000000000000000..3a6529d2bb7ad23af09515b17ce2ee1ef50393a6 GIT binary patch literal 2193 zcmV;C2yXX@P)EX>4Tx04R}tkv&MmKpe$i(@Iq;9qgdukfAzR5ET(zvs^dzd7t}p^eB0g0X~st?f%Ws^E4huXpVr0^D#1Ue#*v4`jvy!0_PY_2HRik_% z>$1Xmi?dp;vgSSc3qyHrd5P;Z2a&)67LkGo8C7hc3=1(@HBwBZX+Q4aA8`CBa>?Y{ z03*jdDo`Oge(*o|-K|*|A9IsJaiHVHwm*h|;4aXp+4lFbZ8uH;|1)rYT&=zG#7LvkcPO`%W#-p}ZpazO7b(7o#R*4)SG1CXJvk~hG? zAuwE|>@|;fceeNT@0n(QKY`(Lty!nefB*mh24YJ`L;(K){{a7>y{D4^000SaNLh0L z0E%e<0E%e=v1PL|00007bV*G`2jmF^5E?i~dgmtq00xaoL_t(|+U;9wY*a-Q{?6V) zgVqRWsNk#wNF++5(e8HcQdt!rXyv6SiV>qRzTYwUNYtn?YK)ImeyTCXKr{r!f+d0q z)Jo@UF9v80!Kkrz@0x&3t5)mMy&ZqF8Zh^6cenR$x7hFRnVp&Q?U{4tJF^RnV;tl7 zKZ8nbLsH6R0B!~_4?rJ)CL&s^l=|+tCZMXSs=T72;ytbPbuQ*UB6>h6^_Ji38l@76 zvu4eD2f!*1`vd?>g%DG#tE;yiJa|waR}o;E=1W@Z$8sFL(Q%yBmSy!F7X(NtZv&8T zXty|yv&^!r!(*BN(=@NpT5kqWmiNYqz9*u(mX?-p$0Px!X;x{in*p3Wf@!+6*2@!# zM024Nghs>pXf!%QYuz|P=Kg=VJ*ngf zFirC*0CyE(sYRJg=F3b8?=A`f z@p$|M$8oj|Y5G#>dt5GrXtQnmK%iA15{Ve;bb392C`u161YQOW!+0IQGL$CfMx)U= zfe|33dqbjm=7D|8+~F$$Qp(v{>xQA4 zTguQxw8qyY7>Put0%!y<&BfdcpreFB|4F6PcHanyL?ROn!`J{|u8Y|La8oE0swSdc zCE)zqN~st8RD)y~##;aude|Ri=8s!iTDp3BdlvzCcNG2qw7a|eE?>2Pl=4LY_j;IL zX6Ap{K6L1iW83zoa5&sE)C(x4B5ZdYr>?E7tloUH#If=IgCg;hlm;g%nZ=^--&2}Qfi-X4Uu8m z*gp_aOeu9JN2Pcw5q$_?K>*J816ab$pXMqRheb3Rok2u9Jjz{HC=^<#l=>;x9on}2 z=aeZ^)=!)`aVCIseJ0?3W_~{(t(+CZw6XspqAQhBd-L7pKgm%D(Kl30{78<^GxN*& zHVd-p`U(C0{U5=-jjaLP!pw~$*|BZgUxmZrZvZUD;45&Uwf=o(zAxX;Wvv27jvT26 zu*k!_hMCv<5wl9EjYKpbz)uBE(bU`9d&|(5;tv5*$|tqfcYB!MWM*HLpHgZc5t#s5 z^Ze)m0L$Ck+tY=t8}e}edH~OPgj!=yPtQF;)Gnpe&xT>diD+GpVSkv2mNIj9!3`Xj za(6y}EgrRgkK;It+uGXx3aWs2c6Mfx$>c{u2m%n#k{tgaqRW(0?IT&wEduJ{-ox)8 zq9vAP^%g_AmY0`54`9EC-O*aFQc77PU8wB8^0_Bd;|ClZPM#d2Os`80q#J*>WMDq?;OXuY&dD_OBu9n+Y&;| z08s6bG_Mgt9I(0=P8Dg$>dHU#E$^3@)&oX<2bSD z)2BD2QmJ%-&Krhdd;s8553zMCGk+3f-pMM4nE71*R|4qq7;>p$7|pR*?2LlgAACn# z?qPnEnb#p;Y(I;8jSScb}qLlhNkEHhqfLF4JtviZQc5`ZqCK8Enh$seN zkH?T1TI*e=XqTGd#qfSg z+e$=%>J6>+Ys{?jCg7;VRS)lXfw6#<%)BAzBXBe<%W|0cJ|cPuzyQWL3Vs_@O4Sq5 zN(}z5=l@5*5D6OrEF_}CW0ioikxszON=jJ^;8`Ln8w*ZrtvfM}ag1Xe;{g5!T!~p| TFCg=@00000NkvXXu0mjf+kFdc literal 0 HcmV?d00001 diff --git a/mapping/src/main/resources/leaflet/images/Eraser.svg b/mapping/src/main/resources/leaflet/images/Eraser.svg new file mode 100644 index 00000000..1c2c2779 --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Eraser.svg @@ -0,0 +1,17 @@ + + + + Atoms/Icons/Tools/Eraser + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/mapping/src/main/resources/leaflet/images/Line.svg b/mapping/src/main/resources/leaflet/images/Line.svg new file mode 100644 index 00000000..783fc687 --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Line.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mapping/src/main/resources/leaflet/images/Magnet.svg b/mapping/src/main/resources/leaflet/images/Magnet.svg new file mode 100644 index 00000000..0eb37d59 --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Magnet.svg @@ -0,0 +1,17 @@ + + + + Atoms/Icons/Tools/Magnet + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/mapping/src/main/resources/leaflet/images/Marker.svg b/mapping/src/main/resources/leaflet/images/Marker.svg new file mode 100644 index 00000000..bd95fbd0 --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Marker.svg @@ -0,0 +1,17 @@ + + + + Atoms/Icons/Tools/Marker + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/mapping/src/main/resources/leaflet/images/Move.png b/mapping/src/main/resources/leaflet/images/Move.png new file mode 100644 index 0000000000000000000000000000000000000000..977236ffbe5f1f12ad8682f3dcde1c22c791e9a3 GIT binary patch literal 1456 zcmV;h1yA~kP)EX>4Tx04R}tkv&MmKpe$i(@Iq;9qgdukfAzR5ET(zvs^dzd7t}p^eB0g0X~st?f%Ws^E4huXpVr0^D#1Ue#*v4`jvy!0_PY_2HRik_% z>$1Xmi?dp;vgSSc3qyHrd5P;Z2a&)67LkGo8C7hc3=1(@HBwBZX+Q4aA8`CBa>?Y{ z03*jdDo`Oge(*o|-K|*|A9IsJaiHVHwm*h|;4aXp+4lFbZ8uH;|1)rYT&=zG#7LvkcPO`%W#-p}ZpazO7b(7o#R*4)SG1CXJvk~hG? zAuwE|>@|;fceeNT@0n(QKY`(Lty!nefB*mh24YJ`L;(K){{a7>y{D4^000SaNLh0L z0E%e<0E%e=v1PL|00007bV*G`2jmF^5E~YPx7(=z00XQ^L_t(|+U=UpYZE~f$G7&(%@a_!5>BRpjQzO-n8hYe}HHUf{0o$UMeLsTJWZ% zl!D;mK{2JbYPaJhmKqx~o6PKwr0hpv;57ga zU`$F`>KXxv=r8~Y;9%{eD(BoQm&+?1F8~qs0w@DGQukE_KtW1bjWQn|<&Wj_c?ZDb zJ&Ff_9Duo8E|=+80UXDf0WkKTOGf+p`tC)VQ-nkR0)X2ZmkztG`_1?L_Z`E4UBu67 z-m(>yGq4DXuP454MB)t0a`BCbuN&5#!5Rdc5MMW}JA*X=G>ESoR-M7IH1u_euN&5! zfmtX%Eb(>2iZd|7#kWfQ*qnhGEWTah$KnjJbc3Gf%_*fO|4M|hc_BnG>RdRwJb0VK zzCZ2)+RcHtF^mTQEG6J2zVke9C{h7D&pWP^DgziwfB*wZsU;#BjYI$%=v1oOz zL_dH9BAO0+qxKp*pU*p)Oy-VK>PA9&<^Z_wdEU`%HhXz-aq*Y25kN$}j^jK_aPd2# zl$zSy+)NB{*o~C@hhuT*FP?S=Z z7!geYcmUu)mo|~YHVEKRm}Re&GW52Z$t^J=QXwuc)!uw{&vk&5 zaw7a3U0M~>NGog9`Ddj9<>?DBi zDTm!DDdkK{-JlTSEn}qsEWP`M&?zb=|K3 zCJaCNij?w+>3pr66ZC!mgX_A7030*)$cIwOTQ+jF<^n+wOapjjqOnKDJ5xVx>~qN}T`(oWVHpV_68b=nPhf9~lG6*n0sDXRu2A z*ac|f4AzOCh;FcfGekoC#I(b8&JY>#V})P?XZQhNAu8hU6~6%$D&X?M;z6$f0000< KMNUMnLSTZ&P@o_H literal 0 HcmV?d00001 diff --git a/mapping/src/main/resources/leaflet/images/Move.svg b/mapping/src/main/resources/leaflet/images/Move.svg new file mode 100644 index 00000000..a62cc593 --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Move.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mapping/src/main/resources/leaflet/images/Polygon.png b/mapping/src/main/resources/leaflet/images/Polygon.png new file mode 100644 index 0000000000000000000000000000000000000000..820ce834ea6948cabce7335e90108258daad8eb6 GIT binary patch literal 1847 zcmV-72gvw|P)EX>4Tx04R}tkv&MmKpe$i(@Iq;9qgdukfAzR5ET(zvs^dzd7t}p^eB0g0X~st?f%Ws^E4huXpVr0^D#1Ue#*v4`jvy!0_PY_2HRik_% z>$1Xmi?dp;vgSSc3qyHrd5P;Z2a&)67LkGo8C7hc3=1(@HBwBZX+Q4aA8`CBa>?Y{ z03*jdDo`Oge(*o|-K|*|A9IsJaiHVHwm*h|;4aXp+4lFbZ8uH;|1)rYT&=zG#7LvkcPO`%W#-p}ZpazO7b(7o#R*4)SG1CXJvk~hG? zAuwE|>@|;fceeNT@0n(QKY`(Lty!nefB*mh24YJ`L;(K){{a7>y{D4^000SaNLh0L z0E%e<0E%e=v1PL|00007bV*G`2jmF^5E~2OvA1vl00lEiL_t(|+U;9SY#UV&{${gL z!hy=BLK~=k1S=G(ipy?g7{NBl`G5(h*%G=Kp0LLE@ZffkSoH$oS0xBuUeY zi;I7{%`p(wovW&9hM9i^@Faj?hiC2su%DUVNhXs6#bWXDPT2vZs%jR%Yi*7@Cxmzt z07rTUsH&O)@ScyMPb3lvE|p4`BfA6aGk+DppwB5xBHE|x`nAmuq$m+!2RtY6D@62? zEX%uOS>8oNF90YwJSQ{rN0HnC>2!KvTgt{9Eh2*172gw+|A4<9i}qM zi|_%PXjpWlm_j9cgbGigEsht!?S0E5O3YyC6TIuiGF8hr>~L#e%i7tniWDb zcLc@;OBfz^96$ z9LeYNR-|5sTY%pH@IHWVU54KxqVvprN(k{seuD2i0sRKwR|3KSzHbDC1$cOU6;TAeP13=ckuKK1Q;5AJfWoEaQ_kRG+GxN!%rKRO|2_RKfPXIU$ z|M!PI13xh_A+4^iW&nJQ)`F=TfG-q9$>egmx)%cc>hJ;szqYoPW#(7g8An7}(=-n^ zw#&Ea1Ut~-1+wj9vDg%VcYO@qCrOgkR41ruT8f#kqO)uBqe6)9dU)oqpfjD|<6Cct zsbTfc066S0aD|8_Hw8(SWsNiQ41iQfvROO+-64>mt*Nd{I=sNax9Oi@7{-H}De`t9 z)I}X$pytEBSUeuz>r@GLO@|kx`SFjLyQ33y)8U21-25XVb}EJcc9~=xz?@?pEz1X7 z1WA(sO5HAR0esaB|CqVt76exTG-~b&0LJVywY5y%U9Z=F!*(g!Ez7bV@OnS*)l#XH z9E-))0o>oAf9r-}D4Rjha~gz49Uc*Vuj~5Tz1Y&Ks{R1rNGJZGnNCoWr0IIS{<=e< z;Z=uMW9C!6I@8SjB@w;RiGKj5T}$C&vG{K?nH&J{tWO`Ogb){cML?-k`X`Y{$N-+{ zz`xn14G~?}GXT!{nEb4wD4+K_vMY*`A)>60dLb)>_-tDmbzyookw`Frr_lP3RVERg zuq^At`T6;JuL&p=3Oq70@{1%%7J#Qcr1F}*^2gBdkFk~w5mi+mv3mlC9I}G}V2+4p z8s(=!nf>zi34rGvs@Qb^IRMi_h`)Swgc?%Ns2x>_h)U&hdD%V-^{TurhH)({{@t@M+y7!7AI&6IR(Jpa002ovPDHLkV1kF*S5E){ literal 0 HcmV?d00001 diff --git a/mapping/src/main/resources/leaflet/images/Polygon.svg b/mapping/src/main/resources/leaflet/images/Polygon.svg new file mode 100644 index 00000000..1b169a3f --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Polygon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mapping/src/main/resources/leaflet/images/Rectangle.png b/mapping/src/main/resources/leaflet/images/Rectangle.png new file mode 100644 index 0000000000000000000000000000000000000000..957337228fd66db72891147e034a1c116ea09ced GIT binary patch literal 2057 zcmah~`8yPP7ypiBXrwWPTxH8-dn_ZaZk8F%Vkv8xiXr9IXe^l-T-3PcwcROY7?LH; zC?YW>dzQEuZy|+C3E9drS&A{^c&lkeWMXN&>CReA3Uk8r zUFpYlab?(XH?U(tEw0(RYmE{)U#}=8u$e1XRN7eojNJrXZth0^Q5+qKaV_)!<9&1a zbo*tKcg+jyL!({u(&>eK&hgeZ9h7g;w_n-O(Y50B++=HHX_3h$D)%w1og0jC}D zVCN@z%_W(;${wndcLV^pC_f3Qyi#>+SCor%b|uKo?2%DAgg89lw(Bue)){}&D`sSo zL<&_Vs%>xQQkeLV^8t@rzdgG4hTwGSnBSehljImi>N**x@drL55lJ$g3MQ5{dQxaf zFupLI1zS_}_qdo-^$~Ax%16H-jXoT!$&i}w*+NI2s;#nE?5Q5eM(s@dzGdu0zh%r~ zf?6P)nCip?-@)IM8@Sl-t*20FagVJc*pe^-UDk&}y&(srk97$8JyDeq;OiAwe_ z`C`b2!~2J6L}Hy-EdE5(H|zdU2Wpd=L`g~k`S~&*|8*e>@&N()RHdt{YoMBn>2kKW zEU2vzG zpxg~dk2E2x(b1Ue0UzBY|9S;&u#eQL0|1GnBm-6`K#gK;q~!5+q^$VK35xu zxT3jQ^kySNa1T=CHw-6bi)LID0`xLH^YZeHfM&j4%bNsQg~9KJoZytnbmeNk~=oi+V#k zPHIl$)pyTy_AsvU_pq4He4cpmV}~Fw`SH>diq9y5-0`<3_O^VpmUlptG9}D)FicG# zrbR_mUf3cHR6~K8L&q>hO~5`tmVtZDL#ejdP5t{S=gSMrg7ul1h--G_JhJe4ZxX>yV*XzM_J0D8!2~UR7~{&GHrp#MFCPhG z=<6UxQS|n9C6txjB{B>x%LyQDVL(aFhKK3BM%7!O>sGB6lN(fO$K-g$0rE*&Z-x0$mcLWvQcTuR=ju}@#3 z)U~^R=p#6C%-%2b*!aA^uy6EXV>Twepio|>hJH=Bp`H}dh-A*1Pm-b2>p zCE0YE-*9WsaFidrSezU8su|i@f?C}K3yS;G+*hm?{Dv>b#Z+lr{!V=Q_rlrfb31bC zRPoZ-UCq~ttlt|B$pIa_tochUjzzk_aDCzxOel~)#Too2VzSU}-l+zXoLGtm1g|_Y zy7K(LG9eKaDs3e6opNcaKzRS5fiNzKGF1M;bHzO3wYy9=7=6$v#VlWSvtxx?HGZgF zJY8D%u#=LliETc6)VQTExTY*EmDjlMH`t}dd;Ldva5k&u*xu>I-%_giLVxL)2y4m2 zk3DXs(n#lp%CH-$j)fTxcZAnD8!=hA@Gg;?#p*1+I?7rCT&TBP4X)qnoWjgU`Z(aZ z+DvII>jNVpjqQ07&*dd9uN8$rx`fe3u+v>$#KknyM4AptDZ~VdRTn l*XWf#72`Q(5>8IvcZ|Bitj9GQo1d=)I1}9PeC(x!{{bQ1%q;)_ literal 0 HcmV?d00001 diff --git a/mapping/src/main/resources/leaflet/images/Rectangle.svg b/mapping/src/main/resources/leaflet/images/Rectangle.svg new file mode 100644 index 00000000..930702f7 --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Rectangle.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mapping/src/main/resources/leaflet/images/Scissors.svg b/mapping/src/main/resources/leaflet/images/Scissors.svg new file mode 100644 index 00000000..a6eb272c --- /dev/null +++ b/mapping/src/main/resources/leaflet/images/Scissors.svg @@ -0,0 +1,17 @@ + + + + Atoms/Icons/Tools/Scissors + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/mapping/src/main/resources/leaflet/leaflet-geoman.css b/mapping/src/main/resources/leaflet/leaflet-geoman.css new file mode 100644 index 00000000..3d4a8daa --- /dev/null +++ b/mapping/src/main/resources/leaflet/leaflet-geoman.css @@ -0,0 +1,213 @@ +.marker-icon, +.marker-icon:focus { + background-color: #ffffff; + border: 1px solid #3388ff; + border-radius: 50%; + margin: -8px 0 0 -8px !important; + width: 14px !important; + height: 14px !important; + outline: 0; + transition: opacity ease 0.3s; +} + +.marker-icon-middle, +.marker-icon-middle:focus { + opacity: 0.7; + margin: -6px 0 0 -6px !important; + width: 10px !important; + height: 10px !important; +} + +.leaflet-pm-draggable { + cursor: move !important; +} + +.cursor-marker { + cursor: crosshair; + pointer-events: none; + display: none; +} + +.cursor-marker.visible { + display: block !important; +} + +.leaflet-pm-invalid { + stroke: red; + transition: fill ease 0s, stroke ease 0s; +} + +.rect-style-marker, +.rect-start-marker { + opacity: 0; +} + +.rect-style-marker.visible, +.rect-start-marker.visible { + opacity: 1 !important; +} + +.hidden { + display: none; +} + +.vertexmarker-disabled { + opacity: 0.7; +} + +.leaflet-pm-toolbar {} + +.leaflet-pm-toolbar .leaflet-buttons-control-button { + padding: 5px; + box-sizing: border-box; + position: relative; + z-index: 3; +} + +.leaflet-pm-toolbar .leaflet-pm-actions-container a:first-child:not(.pos-right) { + border-radius: 0 !important; +} + +.leaflet-pm-toolbar .leaflet-pm-actions-container a:last-child.pos-right { + border-radius: 0 !important; +} + +.leaflet-pm-toolbar .button-container .leaflet-buttons-control-button { + border-radius: 0 !important; +} + +.leaflet-pm-toolbar .button-container:last-child .leaflet-buttons-control-button { + border-radius: 0 0 2px 2px !important; +} + +.leaflet-pm-toolbar .button-container:first-child .leaflet-buttons-control-button { + border-radius: 2px 2px 0 0 !important; +} + +.leaflet-pm-toolbar .control-fa-icon { + font-size: 19px; + line-height: 24px; +} + +.leaflet-pm-toolbar .control-icon { + width: 100%; + height: 100%; + box-sizing: border-box; + background-size: contain; + background-repeat: no-repeat; + background-position: center center; +} + +.leaflet-pm-toolbar .leaflet-pm-icon-marker { + background-image: url(images/Marker.svg); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-polygon { + background-image: url(images/Polygon.png); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-polyline { + background-image: url(images/Line.svg); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-circle { + background-image: url(images/Circle.svg); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-circle-marker { + background-image: url(images/CircleMarker.svg); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-rectangle { + background-image: url(images/Rectangle.png); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-delete { + background-image: url(images/Eraser.png); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-edit { + background-image: url(images/Edit_Vertex.png); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-drag { + background-image: url(images/Move.png); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-cut { + background-image: url(images/Scissors.svg); +} + +.leaflet-pm-toolbar .leaflet-pm-icon-snapping { + background-image: url(images/Magnet.svg); +} + +.leaflet-buttons-control-button:hover { + cursor: pointer; + background-color: #f4f4f4; +} + +.active .leaflet-buttons-control-button { + box-shadow: inset 0 -1px 5px 2px rgba(81, 77, 77, 0.31); +} + +.leaflet-buttons-control-text-hide { + display: none; +} + +.button-container { + position: relative; +} + +.button-container .leaflet-pm-actions-container { + z-index: 2; + position: absolute; + top: 0; + left: 100%; + display: none; + white-space: nowrap; +} + +.leaflet-right .leaflet-pm-toolbar .button-container .leaflet-pm-actions-container { + right: 100%; + left: auto; +} + +.button-container.active .leaflet-pm-actions-container { + display: block; +} + +.button-container .leaflet-pm-actions-container:not(.pos-right) .leaflet-pm-action:last-child { + border-radius: 0px 3px 3px 0px !important; + border-right: 0px; +} + +.button-container .leaflet-pm-actions-container.pos-right .leaflet-pm-action:first-child { + border-radius: 3px 0px 0px 3px !important; +} + +.button-container .leaflet-pm-actions-container.pos-right .leaflet-pm-action:last-child { + border-right: 0px; +} + +.button-container .leaflet-pm-actions-container .leaflet-pm-action { + padding: 0px 10px; + background-color: #666; + color: #fff; + display: inline-block; + width: auto; + border-right: 1px solid #eee; + user-select: none; +} + +.button-container .leaflet-pm-actions-container .leaflet-pm-action:hover { + cursor: pointer; + background-color: #777; +} + + +/* That the active control is always over the other controls */ + +.leaflet-pm-toolbar.activeChild { + z-index: 801; +} diff --git a/mapping/src/main/resources/leaflet/leaflet-geoman.min.js b/mapping/src/main/resources/leaflet/leaflet-geoman.min.js new file mode 100644 index 00000000..261ad4a5 --- /dev/null +++ b/mapping/src/main/resources/leaflet/leaflet-geoman.min.js @@ -0,0 +1 @@ +!function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)r.d(n,i,function(e){return t[e]}.bind(null,i));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=60)}([function(t,e,r){"use strict";function n(t,e,r){void 0===r&&(r={});var n={type:"Feature"};return 0!==r.id&&!r.id||(n.id=r.id),r.bbox&&(n.bbox=r.bbox),n.properties=e||{},n.geometry=t,n}function i(t,e,r){return void 0===r&&(r={}),n({type:"Point",coordinates:t},e,r)}function a(t,e,r){void 0===r&&(r={});for(var i=0,a=t;i line1 must only contain 2 coordinates");if(2!==n.length)throw new Error(" line2 must only contain 2 coordinates");var o=r[0][0],s=r[0][1],l=r[1][0],h=r[1][1],c=n[0][0],u=n[0][1],p=n[1][0],f=n[1][1],d=(f-u)*(l-o)-(p-c)*(h-s);if(0==d)return null;var g=((p-c)*(s-u)-(f-u)*(o-c))/d,_=((l-o)*(s-u)-(h-s)*(o-c))/d;if(0<=g&&g<=1&&0<=_&&_<=1){var m=o+g*(l-o),y=s+g*(h-s);return i.point([m,y])}return null}e.default=function(t,e){var r={},n=[];if("LineString"===t.type&&(t=i.feature(t)),"LineString"===e.type&&(e=i.feature(e)),"Feature"===t.type&&"Feature"===e.type&&null!==t.geometry&&null!==e.geometry&&"LineString"===t.geometry.type&&"LineString"===e.geometry.type&&2===t.geometry.coordinates.length&&2===e.geometry.coordinates.length){var c=h(t,e);return c&&n.push(c),i.featureCollection(n)}var u=l.default();return u.load(o.default(e)),s.featureEach(o.default(t),(function(t){s.featureEach(u.search(t),(function(e){var i=h(t,e);if(i){var o=a.getCoords(i).join(",");r[o]||(r[o]=!0,n.push(i))}}))})),i.featureCollection(n)}},function(t,e,r){var n=r(18),i=r(76),a=r(77),o=n?n.toStringTag:void 0;t.exports=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":o&&o in Object(t)?i(t):a(t)}},function(t,e,r){var n=r(64),i=r(65),a=r(66),o=r(67),s=r(68);function l(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e>1],s=n-1,l=i+1;;){for(;a(e[++s],o)<0;);for(;0n[0]?1:r[0]n[1]?1:-1:function(t,e,r,n){return t.left===e.left?0===l(r,t.otherEvent.point,e.otherEvent.point)?!t.isSubject&&e.isSubject?1:-1:t.isBelow(e.otherEvent.point)?-1:1:t.left?1:-1}(t,e,r)}function c(t,e,r){var n=new o(e,!1,t,t.isSubject),i=new o(e,!0,t.otherEvent,t.isSubject);return s(t.point,t.otherEvent.point)&&console.warn("what is that, a collapsed segment?",t),n.contourId=i.contourId=t.contourId,0e.contourId?1:-1):1===h(t,e)?1:-1}function g(t,e,r,n){var i=t+1,a=e.length;if(a-1>1)-1;0<=r;r--)this._down(r)}function v(t,e){return t>1,a=e[i];if(0<=r(n,a))break;e[t]=a,t=i}e[t]=n},_down:function(t){for(var e=this.data,r=this.compare,n=this.length>>1,i=e[t];tn[2]||n[0]>r[2]||r[1]>n[3]||n[1]>r[3])&&(0===i?a=w:2===i?a=t:1!==i&&3!==i||(a=t.concat(e))),a}(t,e,o,s,n))?a===w?null:a:function(t,e){var r,n,i,a=function(t){var e,r,n,i,a=[];for(r=0,n=t.length;rg||2===s&&_.point[0]>a[2])break;if(_.left){h=l=u.insert(_),l=l!==(c=u.minNode())?u.prev(l):null,h=u.next(h);var m=l?l.key:null;if(i(_,m,s),h&&2===f(_,h.key,t)&&(i(_,m,s),i(_,h.key,s)),l&&2===f(l.key,_,t)){var y=l;i(m,(y=y!==c?u.prev(y):null)?y.key:null,s),i(_,m,s)}}else _=_.otherEvent,h=l=u.find(_),l&&h&&(l=l!==c?u.prev(l):null,h=u.next(h),u.remove(_),h&&l&&f(l.key,h.key,t))}return p}(l,0,0,o,s,n),n)}var x={UNION:1,DIFFERENCE:2,INTERSECTION:0,XOR:3};t.union=function(t,e){return C(t,e,1)},t.diff=function(t,e){return C(t,e,2)},t.xor=function(t,e){return C(t,e,3)},t.intersection=function(t,e){return C(t,e,0)},t.operations=x,Object.defineProperty(t,"__esModule",{value:!0})}(e)},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=r(3),i=6378137;function a(t){var e=0;if(t&&0>>0,n=arguments[1],i=0;i>>0,n=arguments[1],i=0;i>>0;if(0==n)return!1;for(var i,a,o=0|e,s=Math.max(0<=o?o:n-Math.abs(o),0);s=t.minX&&e.maxY>=t.minY}function g(t){return{children:t,height:1,leaf:!0,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0}}function _(t,e,r,i,a){for(var o,s=[e,r];s.length;)(r=s.pop())-(e=s.pop())<=i||(o=e+Math.ceil((r-e)/i/2)*i,n(t,o,e,r,a),s.push(e,o,o,r))}i.prototype={all:function(){return this._all(this.data,[])},search:function(t){var e=this.data,r=[],n=this.toBBox;if(!d(t,e))return r;for(var i,a,o,s,l=[];e;){for(i=0,a=e.children.length;ithis._maxEntries;)this._split(a,e),e--;this._adjustParentBBoxes(i,a,e)},_split:function(t,e){var r=t[e],n=r.children.length,i=this._minEntries;this._chooseSplitAxis(r,i,n);var a=this._chooseSplitIndex(r,i,n),s=g(r.children.splice(a,r.children.length-a));s.height=r.height,s.leaf=r.leaf,o(r,this.toBBox),o(s,this.toBBox),e?t[e-1].children.push(s):this._splitRoot(r,s)},_splitRoot:function(t,e){this.data=g([t,e]),this.data.height=t.height+1,this.data.leaf=!1,o(this.data,this.toBBox)},_chooseSplitIndex:function(t,e,r){var n,i,a,o,l,h,c,p,f,d,g,_,m,y;for(h=c=1/0,n=e;n<=r-e;n++)f=i=s(t,0,n,this.toBBox),d=a=s(t,n,r,this.toBBox),g=Math.max(f.minX,d.minX),_=Math.max(f.minY,d.minY),m=Math.min(f.maxX,d.maxX),y=Math.min(f.maxY,d.maxY),o=Math.max(0,m-g)*Math.max(0,y-_),l=u(i)+u(a),ot[0]&&(e[0]=t[0]),e[1]>t[1]&&(e[1]=t[1]),e[2]t.length)&&(e=t.length);for(var r=0,n=new Array(e);rt.length)&&(e=t.length);for(var r=0,n=new Array(e);rt.length)&&(e=t.length);for(var r=0,n=new Array(e);r=u.length?void 0:o+1),l!==h){var p=u[h],f=u[l];!0!==this.options.hideMiddleMarkers&&this._createMiddleMarker(p,f)}u.splice(o,1),this._fireEdit(),this._layer.fire("pm:vertexremoved",{layer:this._layer,marker:r,indexPath:a})}},findDeepMarkerIndex:function(t,e){var r;t.some(function t(n){return function(i,a){var o=n.concat(a);return i._leaflet_id===e._leaflet_id?(r=o,!0):Array.isArray(i)&&i.some(t(o))}}([]));var n={};return r&&(n={indexPath:r,index:r[r.length-1],parentPath:r.slice(0,r.length-1)}),n},updatePolygonCoordsFromMarkerDrag:function(t){var e=this._layer.getLatLngs(),r=t.getLatLng(),n=this.findDeepMarkerIndex(this._markers,t),i=n.indexPath,a=n.index,o=n.parentPath;(1 + + @@ -16,6 +18,7 @@