From 00ea61a695457652bd3534913fd13bac02169b9d Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Mon, 15 Aug 2016 10:30:05 -0700 Subject: [PATCH 01/10] Adding multilos layer --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 269 ++++++++++++++++++ .../layer/terrain/MultiLOS/package.html | 3 + 2 files changed, 272 insertions(+) create mode 100644 src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java create mode 100644 src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/package.html diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java new file mode 100644 index 00000000..d9012fae --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -0,0 +1,269 @@ +package com.bbn.openmap.layer.terrain.MultiLOS; + +import java.awt.geom.Point2D; +import java.util.List; + +import com.bbn.openmap.dataAccess.dted.DTEDDirectoryHandler; +import com.bbn.openmap.dataAccess.dted.DTEDFrameCache; +import com.bbn.openmap.layer.OMGraphicHandlerLayer; +import com.bbn.openmap.omGraphics.OMCircle; +import com.bbn.openmap.omGraphics.OMColor; +import com.bbn.openmap.omGraphics.OMGraphicList; +import com.bbn.openmap.omGraphics.OMPoint; +import com.bbn.openmap.proj.Length; +import com.bbn.openmap.proj.Planet; +import com.bbn.openmap.proj.Projection; +import com.bbn.openmap.proj.coords.LatLonPoint; +import com.bbn.openmap.tools.terrain.LOSGenerator; +import com.bbn.openmap.util.PropUtils; +import java.awt.Color; +import java.awt.Component; +import java.awt.GridLayout; +import java.util.ArrayList; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * An OpenMap Layer to display an LOS map for a number of viewpoints, from a given altitude + * + *

+ *
+ * ############################
+ * # Example Properties for a MultiLOS layer
+ * multilos.class=com.bbn.openmap.layer.terrain.MultiLOS.MultiLOSLayer
+ * multilos.prettyName=MultiLOS
+ * 
+ * # Properties for the los calculations
+ * # Altitude, in MSL meters
+ * multilos.altitudeM=500
+ * # Max viable sensor distance, in KM
+ * multilos.maxRangeKM=200
+ * # viewpoints: Semicolon-separated list of lat,lon pairs separated by commas
+ * multilos.viewPoints=22.3,116.0;24.3,119.7
+ * # Whether to outline horizons, and show view points
+ * multilos.showHorizons=TRUE
+ * multilos.showViewPoints=TRUE
+ * # color of fill. Leaving out means we won't fill that type [canSee or canNotSee]
+ * multilos.canSeeColor=4400ff00
+ * multilos.canNotSeeColor=44ff0000
+ * # DTED
+ * multilos.dtedLevel=0
+ * multilos.dtedDir=/data/dted/dted0
+ * ############################
+ * 
+ * 
+ * + * @author Gary Briggs + */ +public class MultiLOSLayer extends OMGraphicHandlerLayer { + + // Properties from the user + double altitudeM = 500.0; + List viewPoints = new ArrayList(); + boolean showHorizons = true; + boolean showViewPoints = true; + String dtedDir = "/data/dted/dted0"; + int dtedLevel = 0; + Color canSeeColor = new Color(0, 255, 0, 100); + Color canNotSeeColor = null; + double maxRangeKM = 200; + + public final static String altMProperty = "altitudeM"; + public final static String viewPointsProperty = "viewPoints"; + public final static String showHorizonsProperty = "showHorizons"; + public final static String showViewPointsProperty = "showViewPoints"; + public final static String canSeeColorProperty = "canSeeColor"; + public final static String canNotSeeColorProperty = "canNotSeeColor"; + public final static String dtedLevelProperty = "dtedLevel"; + public final static String dtedDirProperty = "dtedDir"; + public final static String maxRangeKMProperty = "maxRangeKM"; + + // Internal use only members + DTEDFrameCache dted; + + public MultiLOSLayer() { + dted = new DTEDFrameCache(); + } + + @Override + public void setProperties(String prefix, Properties props) { + super.setProperties(prefix, props); + String realPrefix = PropUtils.getScopedPropertyPrefix(this); + + altitudeM = PropUtils.doubleFromProperties(props, realPrefix + altMProperty, altitudeM); + maxRangeKM = PropUtils.doubleFromProperties(props, realPrefix + maxRangeKMProperty, maxRangeKM); + + showHorizons = PropUtils.booleanFromProperties(props, realPrefix + showHorizonsProperty, showHorizons); + showViewPoints = PropUtils.booleanFromProperties(props, realPrefix + showViewPointsProperty, showViewPoints); + + dtedLevel = PropUtils.intFromProperties(props, realPrefix + dtedLevelProperty, dtedLevel); + dtedDir = props.getProperty(realPrefix + dtedDirProperty, dtedDir); + dted.addDTEDDirectoryHandler(new DTEDDirectoryHandler(dtedDir)); + + String csc = props.getProperty(realPrefix + canSeeColorProperty, + (null == canSeeColor?null:canSeeColor.toString())); + if(null == csc) { + canSeeColor = null; + } else { + canSeeColor = PropUtils.parseColor(csc, true); + } + + String cnsc = props.getProperty(realPrefix + canNotSeeColorProperty, + (null == canNotSeeColor?null:canNotSeeColor.toString())); + if(null == cnsc) { + canNotSeeColor = null; + } else { + canNotSeeColor = PropUtils.parseColor(cnsc, true); + } + + // Viewpoints are semicolon-separated lat,lon pairs separated by commas + viewPoints = new ArrayList(); + String viewPointSource = props.getProperty(realPrefix + viewPointsProperty, null); + String[] viewPointStrings = viewPointSource.split(";"); + for(String s : viewPointStrings) { + String[] oneLL = s.split(","); + if(oneLL.length != 2) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + s + "\" into a single LL pair"); + continue; + } + try { + Double lat = Double.valueOf(oneLL[0]); + Double lon = Double.valueOf(oneLL[1]); + viewPoints.add(new LatLonPoint.Double(lat, lon, false)); + } catch(NumberFormatException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + s + "\" numerically"); + } + } + } + + + @Override + public synchronized OMGraphicList prepare() { + OMGraphicList l = new OMGraphicList(); + + if(showHorizons) { + final double horizonKM = Length.KM.fromRadians(calculateHorizonDistRad()); + for (LatLonPoint tLoc : viewPoints) { + OMCircle circ = new OMCircle(tLoc.getLatitude(), tLoc.getLongitude(), horizonKM, Length.KM); + circ.setLinePaint(Color.BLACK); + l.add(circ); + } + } + if(showViewPoints) { + for (LatLonPoint tLoc : viewPoints) { + OMPoint p = new OMPoint(tLoc.getLatitude(), tLoc.getLongitude()); + l.add(p); + } + } + createMultiLOS(l); + l.generate(getProjection()); + return l; + } + + @Override + public Component getGUI() { + JPanel pan = new JPanel(new GridLayout(0, 2)); + + pan.add(new JLabel("Altitude (M): ")); + final JSpinner altSpinner = new JSpinner(new SpinnerNumberModel(altitudeM, 0.0, 10000.0, 20.0)); + pan.add(altSpinner); + altSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + altitudeM = (Double)altSpinner.getValue(); + doPrepare(); + } + }); + + pan.add(new JLabel("Max Range (KM): ")); + final JSpinner maxRangeSpinner = new JSpinner(new SpinnerNumberModel(maxRangeKM, 0.0, 10000.0, 20.0)); + pan.add(maxRangeSpinner); + maxRangeSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + maxRangeKM = (Double)maxRangeSpinner.getValue(); + doPrepare(); + } + }); + + return pan; + } + + public void createMultiLOS(OMGraphicList l) { + LOSGenerator los = new LOSGenerator(dted); + + Projection proj = getProjection(); + + Point2D ll1 = proj.getUpperLeft(); + Point2D ll2 = proj.getLowerRight(); + + double dLon = (ll2.getX() - ll1.getX()) / (proj.getWidth() / 4); + double dLat = (ll1.getY() - ll2.getY()) / (proj.getHeight() / 4); + + double maxRangeRad = Length.KM.toRadians(maxRangeKM); + + int maxProgress = (int) ((ll2.getX() - ll1.getX()) / dLon); + int currProgress = 0; + for (double testLon = ll1.getX(); testLon < ll2.getX(); testLon+=dLon) { + currProgress++; + System.out.println("Progress " + currProgress + " / " + maxProgress); + for (double testLat = ll2.getY(); testLat < ll1.getY(); testLat+=dLat) { + + LatLonPoint llp = new LatLonPoint.Double(testLat, testLon); + Point2D xyp = proj.forward(llp); + + int elevation = dted.getElevation((float) testLat, (float) testLon, dtedLevel); + if(elevation > 0) { + int losCount = 0; + + for (LatLonPoint oneVP : viewPoints) { + final double distanceRad = oneVP.distance(llp); + + if(distanceRad > maxRangeRad) { + // Broadphase - skip anything outside our sensor horizon + continue; + } +// + Point2D tXY = proj.forward(oneVP.getLatitude(), oneVP.getLongitude()); + int numPixBetween = (int) (Math.sqrt( + Math.pow(tXY.getX() - xyp.getX(), 2) + + Math.pow(tXY.getY() - xyp.getY(), 2) + ) / 5); +// int numPixBetween = 3; + + if (los.isLOS(oneVP, (int) altitudeM, false, llp, 0, + (int) numPixBetween)) { + losCount++; + // If one can see, that's sufficient for this layer's see/not see metric + break; + } + } + + if(0 < losCount && null != canSeeColor) { + OMPoint p = new OMPoint(testLat, testLon); + p.setLinePaint(OMColor.clear); + p.setFillPaint(canSeeColor); + l.add(p); + } else if(0 == losCount && null != canNotSeeColor) { + OMPoint p = new OMPoint(testLat, testLon); + p.setLinePaint(OMColor.clear); + p.setFillPaint(canNotSeeColor); + l.add(p); + } + } + } + } + } + + private double calculateHorizonDistRad() { + final double horizonDistM = Math.sqrt((2 * Planet.wgs84_earthEquatorialRadiusMeters_D * altitudeM) + (altitudeM * altitudeM)); + final double horizonDistRad = Length.METER.toRadians(horizonDistM); + return horizonDistRad; + } + +} diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/package.html b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/package.html new file mode 100644 index 00000000..f6ccee54 --- /dev/null +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/package.html @@ -0,0 +1,3 @@ + +MultiLOS is for answering the "what if I had multiple things" LOS question + From 2080d03a0a511dbd9a0b83bd4bf741b8d98c05b4 Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Mon, 15 Aug 2016 10:53:19 -0700 Subject: [PATCH 02/10] Cleanup, deal with thread premature cancellation --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 30 ++++++++++++------- .../layer/terrain/MultiLOS/package.html | 2 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index d9012fae..ca909d76 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -87,7 +87,7 @@ public class MultiLOSLayer extends OMGraphicHandlerLayer { // Internal use only members DTEDFrameCache dted; - + public MultiLOSLayer() { dted = new DTEDFrameCache(); } @@ -207,22 +207,28 @@ public void createMultiLOS(OMGraphicList l) { double maxRangeRad = Length.KM.toRadians(maxRangeKM); - int maxProgress = (int) ((ll2.getX() - ll1.getX()) / dLon); - int currProgress = 0; + int checkedPoints = 0; + int seenPoints = 0; + for (double testLon = ll1.getX(); testLon < ll2.getX(); testLon+=dLon) { - currProgress++; - System.out.println("Progress " + currProgress + " / " + maxProgress); for (double testLat = ll2.getY(); testLat < ll1.getY(); testLat+=dLat) { - LatLonPoint llp = new LatLonPoint.Double(testLat, testLon); - Point2D xyp = proj.forward(llp); + if(Thread.currentThread().isInterrupted()) { + // eg, if we're mid-render and someone moves the map again + return; + } + + checkedPoints++; + + LatLonPoint testp = new LatLonPoint.Double(testLat, testLon); + Point2D xyp = proj.forward(testp); int elevation = dted.getElevation((float) testLat, (float) testLon, dtedLevel); if(elevation > 0) { int losCount = 0; for (LatLonPoint oneVP : viewPoints) { - final double distanceRad = oneVP.distance(llp); + final double distanceRad = oneVP.distance(testp); if(distanceRad > maxRangeRad) { // Broadphase - skip anything outside our sensor horizon @@ -234,9 +240,8 @@ public void createMultiLOS(OMGraphicList l) { Math.pow(tXY.getX() - xyp.getX(), 2) + Math.pow(tXY.getY() - xyp.getY(), 2) ) / 5); -// int numPixBetween = 3; - if (los.isLOS(oneVP, (int) altitudeM, false, llp, 0, + if (los.isLOS(oneVP, (int) altitudeM, false, testp, 0, (int) numPixBetween)) { losCount++; // If one can see, that's sufficient for this layer's see/not see metric @@ -249,15 +254,20 @@ public void createMultiLOS(OMGraphicList l) { p.setLinePaint(OMColor.clear); p.setFillPaint(canSeeColor); l.add(p); + seenPoints++; } else if(0 == losCount && null != canNotSeeColor) { OMPoint p = new OMPoint(testLat, testLon); p.setLinePaint(OMColor.clear); p.setFillPaint(canNotSeeColor); l.add(p); } + } else { + // Skipped a point because it's elevation was zero or smaller + // System.out.println("elevation " + elevation); } } } + System.out.println("Last Render, " + seenPoints + "/" + checkedPoints + " points seen/total"); } private double calculateHorizonDistRad() { diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/package.html b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/package.html index f6ccee54..8cbfc146 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/package.html +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/package.html @@ -1,3 +1,3 @@ -MultiLOS is for answering the "what if I had multiple things" LOS question +MultiLOS is for answering the "what if I had multiple viewpoints" LOS question From a2b17276d208310fd7626a9f4b2544b590a3a9ae Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Tue, 16 Aug 2016 09:40:59 -0700 Subject: [PATCH 03/10] Add horizon and viewpoint checkboxes to gui --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index ca909d76..11990234 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -5,6 +5,9 @@ import com.bbn.openmap.dataAccess.dted.DTEDDirectoryHandler; import com.bbn.openmap.dataAccess.dted.DTEDFrameCache; +import com.bbn.openmap.event.ProgressEvent; +import com.bbn.openmap.event.ProgressSupport; +import com.bbn.openmap.gui.ProgressListenerGauge; import com.bbn.openmap.layer.OMGraphicHandlerLayer; import com.bbn.openmap.omGraphics.OMCircle; import com.bbn.openmap.omGraphics.OMColor; @@ -19,14 +22,18 @@ import java.awt.Color; import java.awt.Component; import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -87,6 +94,7 @@ public class MultiLOSLayer extends OMGraphicHandlerLayer { // Internal use only members DTEDFrameCache dted; + ProgressSupport progressSupport = null; public MultiLOSLayer() { dted = new DTEDFrameCache(); @@ -141,11 +149,15 @@ public void setProperties(String prefix, Properties props) { Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + s + "\" numerically"); } } + if(null == progressSupport) { + progressSupport = new ProgressSupport(this); + progressSupport.add(new ProgressListenerGauge("MultiLOS")); + } } @Override - public synchronized OMGraphicList prepare() { + public OMGraphicList prepare() { OMGraphicList l = new OMGraphicList(); if(showHorizons) { @@ -169,28 +181,43 @@ public synchronized OMGraphicList prepare() { @Override public Component getGUI() { - JPanel pan = new JPanel(new GridLayout(0, 2)); + JPanel pan = new JPanel(new GridLayout(0, 2, 2, 2)); - pan.add(new JLabel("Altitude (M): ")); + pan.add(new JLabel("Altitude (M)")); final JSpinner altSpinner = new JSpinner(new SpinnerNumberModel(altitudeM, 0.0, 10000.0, 20.0)); pan.add(altSpinner); - altSpinner.addChangeListener(new ChangeListener() { - public void stateChanged(ChangeEvent e) { - altitudeM = (Double)altSpinner.getValue(); - doPrepare(); - } - }); - pan.add(new JLabel("Max Range (KM): ")); + pan.add(new JLabel("Max Range (KM)")); final JSpinner maxRangeSpinner = new JSpinner(new SpinnerNumberModel(maxRangeKM, 0.0, 10000.0, 20.0)); pan.add(maxRangeSpinner); - maxRangeSpinner.addChangeListener(new ChangeListener() { + + pan.add(new JLabel("Show horizons")); + final JCheckBox showHorizonCB = new JCheckBox((String)null, showHorizons); + pan.add(showHorizonCB); + + pan.add(new JLabel("Show viewpoints")); + final JCheckBox showViewPointsCB = new JCheckBox((String)null, showViewPoints); + pan.add(showViewPointsCB); + + final ChangeListener cl = new ChangeListener() { public void stateChanged(ChangeEvent e) { maxRangeKM = (Double)maxRangeSpinner.getValue(); + altitudeM = (Double)altSpinner.getValue(); + doPrepare(); + } + }; + final ActionListener al = new ActionListener() { + public void actionPerformed(ActionEvent e) { + showHorizons = showHorizonCB.isSelected(); + showViewPoints = showViewPointsCB.isSelected(); doPrepare(); } - }); + }; + altSpinner.addChangeListener(cl); + maxRangeSpinner.addChangeListener(cl); + showHorizonCB.addActionListener(al); + showViewPointsCB.addActionListener(al); return pan; } @@ -210,7 +237,20 @@ public void createMultiLOS(OMGraphicList l) { int checkedPoints = 0; int seenPoints = 0; + final int maxProgress = (int) ((ll2.getX() - ll1.getX())/dLon); + int currProgress = 0; + final String taskName = "MultiLOS Render"; +// progressSupport.fireUpdate(ProgressEvent.START, taskName, currProgress, maxProgress); for (double testLon = ll1.getX(); testLon < ll2.getX(); testLon+=dLon) { + currProgress++; + // Need it to be final so it can be seen from the inner subclass +// final int progress = currProgress; +// SwingUtilities.invokeLater(new Runnable() { +// public void run() { +// progressSupport.fireUpdate(ProgressEvent.UPDATE, taskName, progress, maxProgress); +// } +// }); + for (double testLat = ll2.getY(); testLat < ll1.getY(); testLat+=dLat) { if(Thread.currentThread().isInterrupted()) { @@ -267,6 +307,7 @@ public void createMultiLOS(OMGraphicList l) { } } } +// progressSupport.fireUpdate(ProgressEvent.DONE, taskName, currProgress, maxProgress); System.out.println("Last Render, " + seenPoints + "/" + checkedPoints + " points seen/total"); } From 1782343c9533d893e8533b17d052ca1a523c4f50 Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Tue, 16 Aug 2016 09:54:33 -0700 Subject: [PATCH 04/10] Property saving --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index 11990234..4034ede6 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -155,7 +155,57 @@ public void setProperties(String prefix, Properties props) { } } - + @Override + public Properties getProperties(Properties props) { + props = super.getProperties(props); + + String prefix = PropUtils.getScopedPropertyPrefix(this); + + props.put(prefix + "class", this.getClass().getName()); + props.put(prefix + altMProperty, altitudeM); + props.put(prefix + showHorizonsProperty, Boolean.toString(showHorizons)); + props.put(prefix + showViewPointsProperty, Boolean.toString(showViewPoints)); + if(null != canSeeColor) { + props.put(prefix + canSeeColorProperty, canSeeColor.toString()); + } + if(null != canNotSeeColor) { + props.put(prefix + canNotSeeColorProperty, canNotSeeColor.toString()); + } + props.put(prefix + dtedLevelProperty, dtedLevel); + props.put(prefix + dtedDirProperty, dtedDir); + props.put(prefix + maxRangeKMProperty, maxRangeKM); + + StringBuilder vp_prop = new StringBuilder(); + for(int i = 0; i < viewPoints.size(); i++) { + LatLonPoint vp = viewPoints.get(i); + if(i > 0) { + vp_prop.append(";"); + } + vp_prop.append(vp.getLatitude()); + vp_prop.append(","); + vp_prop.append(vp.getLongitude()); + } + props.put(prefix + viewPointsProperty, vp_prop.toString()); + + return props; + } + + @Override + public Properties getPropertyInfo(Properties list) { + list = super.getPropertyInfo(list); + + list.put(altMProperty, "Altitude of viewpoints, in meters"); + list.put(showHorizonsProperty, "Whether to indicate horizons"); + list.put(showViewPointsProperty, "Whether to indicate viewpoints"); + list.put(canSeeColorProperty, "Color to indicate if a point can be seen."); + list.put(canNotSeeColorProperty, "Color to indicate if a point cannot be seen. Leave blank to not include points"); + list.put(dtedLevelProperty, "DTED Level"); + list.put(dtedDirProperty, "DTED data directory"); + list.put(maxRangeKMProperty, "Maximum sensor range, in KM"); + list.put(viewPointsProperty, "Semicolon-separated list of lat,lon pairs"); + + return list; + } @Override public OMGraphicList prepare() { OMGraphicList l = new OMGraphicList(); From 48d90a68bb17057404e782cbe4336249c597fa94 Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Wed, 17 Aug 2016 11:03:27 -0700 Subject: [PATCH 05/10] Make altitude configurable per-viewpoint Make altitudeunits configurable --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 153 +++++++++++------- 1 file changed, 93 insertions(+), 60 deletions(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index 4034ede6..327726ce 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -1,11 +1,9 @@ package com.bbn.openmap.layer.terrain.MultiLOS; import java.awt.geom.Point2D; -import java.util.List; import com.bbn.openmap.dataAccess.dted.DTEDDirectoryHandler; import com.bbn.openmap.dataAccess.dted.DTEDFrameCache; -import com.bbn.openmap.event.ProgressEvent; import com.bbn.openmap.event.ProgressSupport; import com.bbn.openmap.gui.ProgressListenerGauge; import com.bbn.openmap.layer.OMGraphicHandlerLayer; @@ -24,16 +22,18 @@ import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; -import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -41,39 +41,42 @@ * An OpenMap Layer to display an LOS map for a number of viewpoints, from a given altitude * *

- *
- * ############################
- * # Example Properties for a MultiLOS layer
- * multilos.class=com.bbn.openmap.layer.terrain.MultiLOS.MultiLOSLayer
- * multilos.prettyName=MultiLOS
- * 
- * # Properties for the los calculations
- * # Altitude, in MSL meters
- * multilos.altitudeM=500
- * # Max viable sensor distance, in KM
- * multilos.maxRangeKM=200
- * # viewpoints: Semicolon-separated list of lat,lon pairs separated by commas
- * multilos.viewPoints=22.3,116.0;24.3,119.7
- * # Whether to outline horizons, and show view points
- * multilos.showHorizons=TRUE
- * multilos.showViewPoints=TRUE
- * # color of fill. Leaving out means we won't fill that type [canSee or canNotSee]
- * multilos.canSeeColor=4400ff00
- * multilos.canNotSeeColor=44ff0000
- * # DTED
- * multilos.dtedLevel=0
- * multilos.dtedDir=/data/dted/dted0
- * ############################
- * 
- * 
+ + ############################ + # Example Properties for a MultiLOS layer + multilos.class=com.bbn.openmap.layer.terrain.MultiLOS.MultiLOSLayer + multilos.prettyName=MultiLOS + + # Properties for the los calculations + # Altitude is MSL. This is the default altitude if it is not specified on a viewpoint + multilos.altitude=500 + multilos.altitudeUnits=M + # Max viable sensor distance, in KM + multilos.maxRangeKM=200 + # viewpoints: Semicolon-separated list of lat,lon pairs separated by commas. + # Optionally, lat,lon may have a third item, ",altitude" which overrides the default altitude + multilos.viewPoints=22.3,116.0;24.3,119.7,100 + # Whether to outline horizons, and show view points + multilos.showHorizons=TRUE + multilos.showViewPoints=TRUE + # color of fill. Leaving out means we won't fill that type [canSee or canNotSee] + multilos.canSeeColor=4400ff00 + multilos.canNotSeeColor=44ff0000 + # DTED + multilos.dtedLevel=0 + multilos.dtedDir=/data/dted/dted0 + ############################ + + * * @author Gary Briggs */ public class MultiLOSLayer extends OMGraphicHandlerLayer { // Properties from the user - double altitudeM = 500.0; - List viewPoints = new ArrayList(); + double altitude = 500.0; + Length altitudeUnits = Length.METER; + Map viewPoints = new HashMap(); boolean showHorizons = true; boolean showViewPoints = true; String dtedDir = "/data/dted/dted0"; @@ -82,7 +85,8 @@ public class MultiLOSLayer extends OMGraphicHandlerLayer { Color canNotSeeColor = null; double maxRangeKM = 200; - public final static String altMProperty = "altitudeM"; + public final static String altProperty = "altitude"; + public final static String altUnitsProperty = "altitudeUnits"; public final static String viewPointsProperty = "viewPoints"; public final static String showHorizonsProperty = "showHorizons"; public final static String showViewPointsProperty = "showViewPoints"; @@ -105,7 +109,8 @@ public void setProperties(String prefix, Properties props) { super.setProperties(prefix, props); String realPrefix = PropUtils.getScopedPropertyPrefix(this); - altitudeM = PropUtils.doubleFromProperties(props, realPrefix + altMProperty, altitudeM); + altitude = PropUtils.doubleFromProperties(props, realPrefix + altProperty, altitude); + altitudeUnits = Length.get(props.getProperty(realPrefix + altUnitsProperty, altitudeUnits.getAbbr())); maxRangeKM = PropUtils.doubleFromProperties(props, realPrefix + maxRangeKMProperty, maxRangeKM); showHorizons = PropUtils.booleanFromProperties(props, realPrefix + showHorizonsProperty, showHorizons); @@ -132,21 +137,29 @@ public void setProperties(String prefix, Properties props) { } // Viewpoints are semicolon-separated lat,lon pairs separated by commas - viewPoints = new ArrayList(); + viewPoints = new HashMap(); String viewPointSource = props.getProperty(realPrefix + viewPointsProperty, null); String[] viewPointStrings = viewPointSource.split(";"); for(String s : viewPointStrings) { - String[] oneLL = s.split(","); - if(oneLL.length != 2) { - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + s + "\" into a single LL pair"); + String trimmed = s.trim(); + if(0 == trimmed.length()) { + continue; + } + String[] oneLL = trimmed.split(","); + if(oneLL.length != 2 && oneLL.length != 3) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + trimmed + "\" into a single LL pair"); continue; } try { Double lat = Double.valueOf(oneLL[0]); Double lon = Double.valueOf(oneLL[1]); - viewPoints.add(new LatLonPoint.Double(lat, lon, false)); + double thisAlt = altitude; + if(3 == oneLL.length) { + thisAlt = Double.valueOf(oneLL[2]); + } + viewPoints.put(new LatLonPoint.Double(lat, lon, false), thisAlt); } catch(NumberFormatException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + s + "\" numerically"); + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + trimmed + "\" numerically"); } } if(null == progressSupport) { @@ -162,7 +175,8 @@ public Properties getProperties(Properties props) { String prefix = PropUtils.getScopedPropertyPrefix(this); props.put(prefix + "class", this.getClass().getName()); - props.put(prefix + altMProperty, altitudeM); + props.put(prefix + altProperty, altitude); + props.put(prefix + altUnitsProperty, altitudeUnits.getAbbr()); props.put(prefix + showHorizonsProperty, Boolean.toString(showHorizons)); props.put(prefix + showViewPointsProperty, Boolean.toString(showViewPoints)); if(null != canSeeColor) { @@ -176,14 +190,16 @@ public Properties getProperties(Properties props) { props.put(prefix + maxRangeKMProperty, maxRangeKM); StringBuilder vp_prop = new StringBuilder(); - for(int i = 0; i < viewPoints.size(); i++) { - LatLonPoint vp = viewPoints.get(i); - if(i > 0) { - vp_prop.append(";"); - } + for(Entry ent : viewPoints.entrySet()) { + LatLonPoint vp = ent.getKey(); + Double thisAlt = ent.getValue(); + vp_prop.append(vp.getLatitude()); vp_prop.append(","); vp_prop.append(vp.getLongitude()); + vp_prop.append(","); + vp_prop.append(thisAlt); + vp_prop.append(";"); } props.put(prefix + viewPointsProperty, vp_prop.toString()); @@ -194,7 +210,8 @@ public Properties getProperties(Properties props) { public Properties getPropertyInfo(Properties list) { list = super.getPropertyInfo(list); - list.put(altMProperty, "Altitude of viewpoints, in meters"); + list.put(altProperty, "Default altitude for viewpoints, MSL"); + list.put(altUnitsProperty, "Units for altitude"); list.put(showHorizonsProperty, "Whether to indicate horizons"); list.put(showViewPointsProperty, "Whether to indicate viewpoints"); list.put(canSeeColorProperty, "Color to indicate if a point can be seen."); @@ -202,7 +219,7 @@ public Properties getPropertyInfo(Properties list) { list.put(dtedLevelProperty, "DTED Level"); list.put(dtedDirProperty, "DTED data directory"); list.put(maxRangeKMProperty, "Maximum sensor range, in KM"); - list.put(viewPointsProperty, "Semicolon-separated list of lat,lon pairs"); + list.put(viewPointsProperty, "Semicolon-separated list of lat,lon pairs with option ',alt' suffix"); return list; } @@ -211,16 +228,18 @@ public OMGraphicList prepare() { OMGraphicList l = new OMGraphicList(); if(showHorizons) { - final double horizonKM = Length.KM.fromRadians(calculateHorizonDistRad()); - for (LatLonPoint tLoc : viewPoints) { - OMCircle circ = new OMCircle(tLoc.getLatitude(), tLoc.getLongitude(), horizonKM, Length.KM); + for(Entry ent : viewPoints.entrySet()) { + LatLonPoint vp = ent.getKey(); + Double thisAlt = ent.getValue(); + final double horizonKM = Length.KM.fromRadians(calculateHorizonDistRad(thisAlt)); + OMCircle circ = new OMCircle(vp.getLatitude(), vp.getLongitude(), horizonKM, Length.KM); circ.setLinePaint(Color.BLACK); l.add(circ); } } if(showViewPoints) { - for (LatLonPoint tLoc : viewPoints) { - OMPoint p = new OMPoint(tLoc.getLatitude(), tLoc.getLongitude()); + for(LatLonPoint vp : viewPoints.keySet()) { + OMPoint p = new OMPoint(vp.getLatitude(), vp.getLongitude()); l.add(p); } } @@ -233,8 +252,9 @@ public OMGraphicList prepare() { public Component getGUI() { JPanel pan = new JPanel(new GridLayout(0, 2, 2, 2)); - pan.add(new JLabel("Altitude (M)")); - final JSpinner altSpinner = new JSpinner(new SpinnerNumberModel(altitudeM, 0.0, 10000.0, 20.0)); + final JButton setAltsButton = new JButton("Set all viewpoint alts to (" + altitudeUnits.getAbbr() + "):"); + pan.add(setAltsButton); + final JSpinner altSpinner = new JSpinner(new SpinnerNumberModel(altitude, 0.0, 10000.0, 1.0)); pan.add(altSpinner); pan.add(new JLabel("Max Range (KM)")); @@ -249,10 +269,20 @@ public Component getGUI() { final JCheckBox showViewPointsCB = new JCheckBox((String)null, showViewPoints); pan.add(showViewPointsCB); + ActionListener altAl = new ActionListener() { + public void actionPerformed(ActionEvent e) { + Double newAlt = (Double)altSpinner.getValue(); + for(LatLonPoint vp : viewPoints.keySet()) { + viewPoints.put(vp, newAlt); + } + doPrepare(); + } + }; + setAltsButton.addActionListener(altAl); + final ChangeListener cl = new ChangeListener() { public void stateChanged(ChangeEvent e) { maxRangeKM = (Double)maxRangeSpinner.getValue(); - altitudeM = (Double)altSpinner.getValue(); doPrepare(); } }; @@ -264,7 +294,6 @@ public void actionPerformed(ActionEvent e) { } }; - altSpinner.addChangeListener(cl); maxRangeSpinner.addChangeListener(cl); showHorizonCB.addActionListener(al); showViewPointsCB.addActionListener(al); @@ -317,7 +346,11 @@ public void createMultiLOS(OMGraphicList l) { if(elevation > 0) { int losCount = 0; - for (LatLonPoint oneVP : viewPoints) { + for (Entry ent : viewPoints.entrySet()) { + LatLonPoint oneVP = ent.getKey(); + Double thisAlt = ent.getValue(); + double thisAltM = Length.METER.fromRadians(altitudeUnits.toRadians(thisAlt)); + final double distanceRad = oneVP.distance(testp); if(distanceRad > maxRangeRad) { @@ -331,7 +364,7 @@ public void createMultiLOS(OMGraphicList l) { Math.pow(tXY.getY() - xyp.getY(), 2) ) / 5); - if (los.isLOS(oneVP, (int) altitudeM, false, testp, 0, + if (los.isLOS(oneVP, (int) thisAltM, false, testp, 0, (int) numPixBetween)) { losCount++; // If one can see, that's sufficient for this layer's see/not see metric @@ -361,8 +394,8 @@ public void createMultiLOS(OMGraphicList l) { System.out.println("Last Render, " + seenPoints + "/" + checkedPoints + " points seen/total"); } - private double calculateHorizonDistRad() { - final double horizonDistM = Math.sqrt((2 * Planet.wgs84_earthEquatorialRadiusMeters_D * altitudeM) + (altitudeM * altitudeM)); + private double calculateHorizonDistRad(Double alt) { + final double horizonDistM = Math.sqrt((2 * Planet.wgs84_earthEquatorialRadiusMeters_D * alt) + (alt * alt)); final double horizonDistRad = Length.METER.toRadians(horizonDistM); return horizonDistRad; } From 0e6b1ed8e08287540b0ccc9e5b1c0211472db0e8 Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Thu, 18 Aug 2016 09:02:57 -0700 Subject: [PATCH 06/10] MaxRange gets same treatment as Altitude: per-viewpoint, with defaults --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 153 ++++++++++++------ 1 file changed, 104 insertions(+), 49 deletions(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index 327726ce..8b18f4d5 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -22,9 +22,8 @@ import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; +import java.util.ArrayList; +import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -34,8 +33,6 @@ import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; /** * An OpenMap Layer to display an LOS map for a number of viewpoints, from a given altitude @@ -54,8 +51,8 @@ # Max viable sensor distance, in KM multilos.maxRangeKM=200 # viewpoints: Semicolon-separated list of lat,lon pairs separated by commas. - # Optionally, lat,lon may have a third item, ",altitude" which overrides the default altitude - multilos.viewPoints=22.3,116.0;24.3,119.7,100 + # lat,lon[,alt[,sensorRange]] + multilos.viewPoints=22.3,116.0;24.3,119.7,100,1000 # Whether to outline horizons, and show view points multilos.showHorizons=TRUE multilos.showViewPoints=TRUE @@ -76,25 +73,57 @@ public class MultiLOSLayer extends OMGraphicHandlerLayer { // Properties from the user double altitude = 500.0; Length altitudeUnits = Length.METER; - Map viewPoints = new HashMap(); + + private class MultiLOSViewPoint { + LatLonPoint p; + double altitude; + double maxRange; + + public MultiLOSViewPoint(LatLonPoint p, double altitude, double maxRange) { + this.p = p; + this.altitude = altitude; + this.maxRange = maxRange; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(p.getLatitude()); + sb.append(","); + sb.append(p.getLongitude()); + sb.append(","); + sb.append(altitude); + sb.append(","); + sb.append(maxRange); + return sb.toString(); + } + + + }; + + List viewPoints = new ArrayList(); boolean showHorizons = true; boolean showViewPoints = true; + boolean showMaxRanges = true; String dtedDir = "/data/dted/dted0"; int dtedLevel = 0; Color canSeeColor = new Color(0, 255, 0, 100); Color canNotSeeColor = null; - double maxRangeKM = 200; + double maxRange = 200; + Length maxRangeUnits = Length.KM; public final static String altProperty = "altitude"; public final static String altUnitsProperty = "altitudeUnits"; public final static String viewPointsProperty = "viewPoints"; public final static String showHorizonsProperty = "showHorizons"; public final static String showViewPointsProperty = "showViewPoints"; + public final static String showMaxRangesProperty = "showMaxRanges"; public final static String canSeeColorProperty = "canSeeColor"; public final static String canNotSeeColorProperty = "canNotSeeColor"; public final static String dtedLevelProperty = "dtedLevel"; public final static String dtedDirProperty = "dtedDir"; - public final static String maxRangeKMProperty = "maxRangeKM"; + public final static String maxRangeProperty = "maxRange"; + public final static String maxRangeUnitsProperty = "maxRangeUnits"; // Internal use only members DTEDFrameCache dted; @@ -111,9 +140,11 @@ public void setProperties(String prefix, Properties props) { altitude = PropUtils.doubleFromProperties(props, realPrefix + altProperty, altitude); altitudeUnits = Length.get(props.getProperty(realPrefix + altUnitsProperty, altitudeUnits.getAbbr())); - maxRangeKM = PropUtils.doubleFromProperties(props, realPrefix + maxRangeKMProperty, maxRangeKM); + maxRange = PropUtils.doubleFromProperties(props, realPrefix + maxRangeProperty, maxRange); + maxRangeUnits = Length.get(props.getProperty(realPrefix + maxRangeUnitsProperty, maxRangeUnits.getAbbr())); showHorizons = PropUtils.booleanFromProperties(props, realPrefix + showHorizonsProperty, showHorizons); + showMaxRanges = PropUtils.booleanFromProperties(props, realPrefix + showMaxRangesProperty, showMaxRanges); showViewPoints = PropUtils.booleanFromProperties(props, realPrefix + showViewPointsProperty, showViewPoints); dtedLevel = PropUtils.intFromProperties(props, realPrefix + dtedLevelProperty, dtedLevel); @@ -137,7 +168,7 @@ public void setProperties(String prefix, Properties props) { } // Viewpoints are semicolon-separated lat,lon pairs separated by commas - viewPoints = new HashMap(); + viewPoints = new ArrayList(); String viewPointSource = props.getProperty(realPrefix + viewPointsProperty, null); String[] viewPointStrings = viewPointSource.split(";"); for(String s : viewPointStrings) { @@ -146,18 +177,22 @@ public void setProperties(String prefix, Properties props) { continue; } String[] oneLL = trimmed.split(","); - if(oneLL.length != 2 && oneLL.length != 3) { - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + trimmed + "\" into a single LL pair"); + if(oneLL.length < 2) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error parsing \"" + trimmed + "\": must have at least lat,lon "); continue; } try { Double lat = Double.valueOf(oneLL[0]); Double lon = Double.valueOf(oneLL[1]); double thisAlt = altitude; - if(3 == oneLL.length) { + double thisMaxRange = maxRange; + if(3 <= oneLL.length) { thisAlt = Double.valueOf(oneLL[2]); } - viewPoints.put(new LatLonPoint.Double(lat, lon, false), thisAlt); + if(4 <= oneLL.length) { + thisMaxRange = Double.valueOf(oneLL[3]); + } + viewPoints.add(new MultiLOSViewPoint(new LatLonPoint.Double(lat, lon, false), thisAlt, thisMaxRange)); } catch(NumberFormatException ex) { Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + trimmed + "\" numerically"); } @@ -178,6 +213,7 @@ public Properties getProperties(Properties props) { props.put(prefix + altProperty, altitude); props.put(prefix + altUnitsProperty, altitudeUnits.getAbbr()); props.put(prefix + showHorizonsProperty, Boolean.toString(showHorizons)); + props.put(prefix + showMaxRangesProperty, Boolean.toString(showMaxRanges)); props.put(prefix + showViewPointsProperty, Boolean.toString(showViewPoints)); if(null != canSeeColor) { props.put(prefix + canSeeColorProperty, canSeeColor.toString()); @@ -187,18 +223,12 @@ public Properties getProperties(Properties props) { } props.put(prefix + dtedLevelProperty, dtedLevel); props.put(prefix + dtedDirProperty, dtedDir); - props.put(prefix + maxRangeKMProperty, maxRangeKM); + props.put(prefix + maxRangeProperty, maxRange); + props.put(prefix + maxRangeUnitsProperty, maxRangeUnits.getAbbr()); StringBuilder vp_prop = new StringBuilder(); - for(Entry ent : viewPoints.entrySet()) { - LatLonPoint vp = ent.getKey(); - Double thisAlt = ent.getValue(); - - vp_prop.append(vp.getLatitude()); - vp_prop.append(","); - vp_prop.append(vp.getLongitude()); - vp_prop.append(","); - vp_prop.append(thisAlt); + for(MultiLOSViewPoint mlvp : viewPoints) { + vp_prop.append(mlvp.toString()); vp_prop.append(";"); } props.put(prefix + viewPointsProperty, vp_prop.toString()); @@ -213,12 +243,14 @@ public Properties getPropertyInfo(Properties list) { list.put(altProperty, "Default altitude for viewpoints, MSL"); list.put(altUnitsProperty, "Units for altitude"); list.put(showHorizonsProperty, "Whether to indicate horizons"); + list.put(showMaxRangesProperty, "Whether to indicate max ranges"); list.put(showViewPointsProperty, "Whether to indicate viewpoints"); list.put(canSeeColorProperty, "Color to indicate if a point can be seen."); list.put(canNotSeeColorProperty, "Color to indicate if a point cannot be seen. Leave blank to not include points"); list.put(dtedLevelProperty, "DTED Level"); list.put(dtedDirProperty, "DTED data directory"); - list.put(maxRangeKMProperty, "Maximum sensor range, in KM"); + list.put(maxRangeProperty, "Maximum sensor range"); + list.put(maxRangeUnitsProperty, "Maximum sensor range units"); list.put(viewPointsProperty, "Semicolon-separated list of lat,lon pairs with option ',alt' suffix"); return list; @@ -228,17 +260,28 @@ public OMGraphicList prepare() { OMGraphicList l = new OMGraphicList(); if(showHorizons) { - for(Entry ent : viewPoints.entrySet()) { - LatLonPoint vp = ent.getKey(); - Double thisAlt = ent.getValue(); - final double horizonKM = Length.KM.fromRadians(calculateHorizonDistRad(thisAlt)); - OMCircle circ = new OMCircle(vp.getLatitude(), vp.getLongitude(), horizonKM, Length.KM); + for(MultiLOSViewPoint mlvp : viewPoints) { + LatLonPoint vp = mlvp.p; + final double thisAlt = mlvp.altitude; + final double thisAltM = Length.METER.fromRadians(altitudeUnits.toRadians(thisAlt)); + final double horizonRad = calculateHorizonDistRad(thisAltM); + OMCircle circ = new OMCircle(vp.getLatitude(), vp.getLongitude(), horizonRad, Length.RADIAN); circ.setLinePaint(Color.BLACK); l.add(circ); } } + if(showMaxRanges) { + for(MultiLOSViewPoint mlvp : viewPoints) { + LatLonPoint vp = mlvp.p; + final double maxRangeRad = maxRangeUnits.toRadians(mlvp.maxRange); + OMCircle circ = new OMCircle(vp.getLatitude(), vp.getLongitude(), maxRangeRad, Length.RADIAN); + circ.setLinePaint(Color.GRAY); + l.add(circ); + } + } if(showViewPoints) { - for(LatLonPoint vp : viewPoints.keySet()) { + for(MultiLOSViewPoint mlvp : viewPoints) { + LatLonPoint vp = mlvp.p; OMPoint p = new OMPoint(vp.getLatitude(), vp.getLongitude()); l.add(p); } @@ -257,14 +300,19 @@ public Component getGUI() { final JSpinner altSpinner = new JSpinner(new SpinnerNumberModel(altitude, 0.0, 10000.0, 1.0)); pan.add(altSpinner); - pan.add(new JLabel("Max Range (KM)")); - final JSpinner maxRangeSpinner = new JSpinner(new SpinnerNumberModel(maxRangeKM, 0.0, 10000.0, 20.0)); + final JButton setRangesButton = new JButton("Set all viewpoint ranges to (" + maxRangeUnits.getAbbr() + "):"); + pan.add(setRangesButton); + final JSpinner maxRangeSpinner = new JSpinner(new SpinnerNumberModel(maxRange, 0.0, 10000.0, 20.0)); pan.add(maxRangeSpinner); pan.add(new JLabel("Show horizons")); final JCheckBox showHorizonCB = new JCheckBox((String)null, showHorizons); pan.add(showHorizonCB); + pan.add(new JLabel("Show max ranges")); + final JCheckBox showMaxRangesCB = new JCheckBox((String)null, showMaxRanges); + pan.add(showMaxRangesCB); + pan.add(new JLabel("Show viewpoints")); final JCheckBox showViewPointsCB = new JCheckBox((String)null, showViewPoints); pan.add(showViewPointsCB); @@ -272,30 +320,36 @@ public Component getGUI() { ActionListener altAl = new ActionListener() { public void actionPerformed(ActionEvent e) { Double newAlt = (Double)altSpinner.getValue(); - for(LatLonPoint vp : viewPoints.keySet()) { - viewPoints.put(vp, newAlt); + for(MultiLOSViewPoint mlvp : viewPoints) { + mlvp.altitude = newAlt; } doPrepare(); } }; setAltsButton.addActionListener(altAl); - final ChangeListener cl = new ChangeListener() { - public void stateChanged(ChangeEvent e) { - maxRangeKM = (Double)maxRangeSpinner.getValue(); + ActionListener rangeAl = new ActionListener() { + public void actionPerformed(ActionEvent e) { + Double newMaxRange = (Double)maxRangeSpinner.getValue(); + for(MultiLOSViewPoint mlvp : viewPoints) { + mlvp.maxRange = newMaxRange; + } doPrepare(); } }; + setRangesButton.addActionListener(rangeAl); + final ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { showHorizons = showHorizonCB.isSelected(); + showMaxRanges = showMaxRangesCB.isSelected(); showViewPoints = showViewPointsCB.isSelected(); doPrepare(); } }; - maxRangeSpinner.addChangeListener(cl); showHorizonCB.addActionListener(al); + showMaxRangesCB.addActionListener(al); showViewPointsCB.addActionListener(al); return pan; } @@ -311,8 +365,6 @@ public void createMultiLOS(OMGraphicList l) { double dLon = (ll2.getX() - ll1.getX()) / (proj.getWidth() / 4); double dLat = (ll1.getY() - ll2.getY()) / (proj.getHeight() / 4); - double maxRangeRad = Length.KM.toRadians(maxRangeKM); - int checkedPoints = 0; int seenPoints = 0; @@ -346,14 +398,17 @@ public void createMultiLOS(OMGraphicList l) { if(elevation > 0) { int losCount = 0; - for (Entry ent : viewPoints.entrySet()) { - LatLonPoint oneVP = ent.getKey(); - Double thisAlt = ent.getValue(); + for (MultiLOSViewPoint mlvp : viewPoints) { + + LatLonPoint oneVP = mlvp.p; + double thisAlt = mlvp.altitude; + double thisMaxRangeRad = maxRangeUnits.toRadians(mlvp.maxRange); + double thisAltM = Length.METER.fromRadians(altitudeUnits.toRadians(thisAlt)); final double distanceRad = oneVP.distance(testp); - if(distanceRad > maxRangeRad) { + if(distanceRad > thisMaxRangeRad) { // Broadphase - skip anything outside our sensor horizon continue; } @@ -394,8 +449,8 @@ public void createMultiLOS(OMGraphicList l) { System.out.println("Last Render, " + seenPoints + "/" + checkedPoints + " points seen/total"); } - private double calculateHorizonDistRad(Double alt) { - final double horizonDistM = Math.sqrt((2 * Planet.wgs84_earthEquatorialRadiusMeters_D * alt) + (alt * alt)); + private double calculateHorizonDistRad(Double altM) { + final double horizonDistM = Math.sqrt((2 * Planet.wgs84_earthEquatorialRadiusMeters_D * altM) + (altM * altM)); final double horizonDistRad = Length.METER.toRadians(horizonDistM); return horizonDistRad; } From bf92a049b697ce7f716df172f22a2deb609d2bff Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Thu, 18 Aug 2016 09:16:23 -0700 Subject: [PATCH 07/10] Documentation and clarity --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index 8b18f4d5..717c9b08 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -48,14 +48,17 @@ # Altitude is MSL. This is the default altitude if it is not specified on a viewpoint multilos.altitude=500 multilos.altitudeUnits=M - # Max viable sensor distance, in KM - multilos.maxRangeKM=200 + # Max viable sensor distance + # This is the default range if it is not specified on a viewpoint + multilos.maxRange=200 + multilos.maxRangeUnits=KM # viewpoints: Semicolon-separated list of lat,lon pairs separated by commas. # lat,lon[,alt[,sensorRange]] multilos.viewPoints=22.3,116.0;24.3,119.7,100,1000 - # Whether to outline horizons, and show view points + # Whether to indicate viewpoint properties multilos.showHorizons=TRUE multilos.showViewPoints=TRUE + multilos.showMaxRanges=TRUE # color of fill. Leaving out means we won't fill that type [canSee or canNotSee] multilos.canSeeColor=4400ff00 multilos.canNotSeeColor=44ff0000 @@ -69,11 +72,7 @@ * @author Gary Briggs */ public class MultiLOSLayer extends OMGraphicHandlerLayer { - - // Properties from the user - double altitude = 500.0; - Length altitudeUnits = Length.METER; - + // Class that represents a viewpoint private class MultiLOSViewPoint { LatLonPoint p; double altitude; @@ -101,6 +100,9 @@ public String toString() { }; + // Properties from the user + double altitude = 500.0; + Length altitudeUnits = Length.METER; List viewPoints = new ArrayList(); boolean showHorizons = true; boolean showViewPoints = true; From 6047fa6564df122298d2b1ecdda35f7ccb54c798 Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Thu, 18 Aug 2016 09:46:31 -0700 Subject: [PATCH 08/10] Ability to generate viewpoints from a line --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 91 ++++++++++++++----- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index 717c9b08..d9a83f00 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -55,6 +55,9 @@ # viewpoints: Semicolon-separated list of lat,lon pairs separated by commas. # lat,lon[,alt[,sensorRange]] multilos.viewPoints=22.3,116.0;24.3,119.7,100,1000 + # If you don't want to specify a list of viewpoints, use this to specify a series of lines: + # semicolon-separated list, StartLat,StartLon,EndLat,EndLon,NumPointsBetweenStartEnd + multilos.viewPointLines= # Whether to indicate viewpoint properties multilos.showHorizons=TRUE multilos.showViewPoints=TRUE @@ -117,6 +120,7 @@ public String toString() { public final static String altProperty = "altitude"; public final static String altUnitsProperty = "altitudeUnits"; public final static String viewPointsProperty = "viewPoints"; + public final static String viewPointLinesProperty = "viewPointLines"; public final static String showHorizonsProperty = "showHorizons"; public final static String showViewPointsProperty = "showViewPoints"; public final static String showMaxRangesProperty = "showMaxRanges"; @@ -169,36 +173,77 @@ public void setProperties(String prefix, Properties props) { canNotSeeColor = PropUtils.parseColor(cnsc, true); } - // Viewpoints are semicolon-separated lat,lon pairs separated by commas viewPoints = new ArrayList(); + + // Viewpoints are semicolon-separated lat,lon pairs separated by commas String viewPointSource = props.getProperty(realPrefix + viewPointsProperty, null); - String[] viewPointStrings = viewPointSource.split(";"); - for(String s : viewPointStrings) { - String trimmed = s.trim(); - if(0 == trimmed.length()) { - continue; - } - String[] oneLL = trimmed.split(","); - if(oneLL.length < 2) { - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error parsing \"" + trimmed + "\": must have at least lat,lon "); - continue; + if(null != viewPointSource) { + String[] viewPointStrings = viewPointSource.split(";"); + for(String s : viewPointStrings) { + String trimmed = s.trim(); + if(0 == trimmed.length()) { + continue; + } + String[] oneLL = trimmed.split(","); + if(oneLL.length < 2) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error parsing \"" + trimmed + "\": must have at least lat,lon "); + continue; + } + try { + Double lat = Double.valueOf(oneLL[0]); + Double lon = Double.valueOf(oneLL[1]); + double thisAlt = altitude; + double thisMaxRange = maxRange; + if(3 <= oneLL.length) { + thisAlt = Double.valueOf(oneLL[2]); + } + if(4 <= oneLL.length) { + thisMaxRange = Double.valueOf(oneLL[3]); + } + viewPoints.add(new MultiLOSViewPoint(new LatLonPoint.Double(lat, lon, false), thisAlt, thisMaxRange)); + } catch(NumberFormatException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + trimmed + "\" numerically"); + } } - try { - Double lat = Double.valueOf(oneLL[0]); - Double lon = Double.valueOf(oneLL[1]); - double thisAlt = altitude; - double thisMaxRange = maxRange; - if(3 <= oneLL.length) { - thisAlt = Double.valueOf(oneLL[2]); + } + + + String viewPointLinesSource = props.getProperty(realPrefix + viewPointLinesProperty, null); + if(null != viewPointLinesSource) { + for(String oneViewPointLine : viewPointLinesSource.split(";")) { + String trimmed = oneViewPointLine.trim(); + if(0 == trimmed.length()) { + continue; } - if(4 <= oneLL.length) { - thisMaxRange = Double.valueOf(oneLL[3]); + String[] linePieces = trimmed.split(","); + if(5 != linePieces.length) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "ViewPointsLine \"" + trimmed + "\" must be formatted l,l,l,l,n"); + continue; + } + + try { + Double startLat = Double.valueOf(linePieces[0]); + Double startLon = Double.valueOf(linePieces[1]); + Double endLat = Double.valueOf(linePieces[2]); + Double endLon = Double.valueOf(linePieces[3]); + // Always do the two end points. Bonus: we can skip worrying about div0 + int piececnt = 2 + Integer.valueOf(linePieces[4]); + + double dLat = ((endLat-startLat)/piececnt); + double dLon = ((endLon-startLon)/piececnt); + + for(int i = 0; i < piececnt; i++) { + double lat = startLat + (i * dLat); + double lon = startLon + (i * dLon); + LatLonPoint.Double p = new LatLonPoint.Double(lat, lon, false); + viewPoints.add(new MultiLOSViewPoint(p, altitude, maxRange)); + } + } catch(NumberFormatException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + trimmed + "\" numerically"); } - viewPoints.add(new MultiLOSViewPoint(new LatLonPoint.Double(lat, lon, false), thisAlt, thisMaxRange)); - } catch(NumberFormatException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Cannot parse \"" + trimmed + "\" numerically"); } } + if(null == progressSupport) { progressSupport = new ProgressSupport(this); progressSupport.add(new ProgressListenerGauge("MultiLOS")); From 9a3752f07e24fa9265c97a2fdbafae8f5648d3dc Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Tue, 23 Aug 2016 20:55:51 -0700 Subject: [PATCH 09/10] Give user control over render resolution Option to label viewpoints with their index --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 117 ++++++++++++------ 1 file changed, 76 insertions(+), 41 deletions(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index d9a83f00..bfa372e6 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -4,13 +4,12 @@ import com.bbn.openmap.dataAccess.dted.DTEDDirectoryHandler; import com.bbn.openmap.dataAccess.dted.DTEDFrameCache; -import com.bbn.openmap.event.ProgressSupport; -import com.bbn.openmap.gui.ProgressListenerGauge; import com.bbn.openmap.layer.OMGraphicHandlerLayer; import com.bbn.openmap.omGraphics.OMCircle; import com.bbn.openmap.omGraphics.OMColor; import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.omGraphics.OMPoint; +import com.bbn.openmap.omGraphics.OMText; import com.bbn.openmap.proj.Length; import com.bbn.openmap.proj.Planet; import com.bbn.openmap.proj.Projection; @@ -33,6 +32,8 @@ import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; /** * An OpenMap Layer to display an LOS map for a number of viewpoints, from a given altitude @@ -62,6 +63,13 @@ multilos.showHorizons=TRUE multilos.showViewPoints=TRUE multilos.showMaxRanges=TRUE + multilos.showNumberPoints=TRUE + # LOS is calculated per-screen-point, with + # n_samples = pixels_between_viewpoint_and_screen_point / pixelSkip + # Number of pixels per point - high numbers are faster/lower resolution. don't go below 1 + multilos.pixelsPerPoint=2 + # Multiplier to make rendering faster but less accurate. 1 == "slowest, most accurate" + multilos.pixelSkip=3 # color of fill. Leaving out means we won't fill that type [canSee or canNotSee] multilos.canSeeColor=4400ff00 multilos.canNotSeeColor=44ff0000 @@ -110,8 +118,11 @@ public String toString() { boolean showHorizons = true; boolean showViewPoints = true; boolean showMaxRanges = true; + boolean showNumberPoints = true; String dtedDir = "/data/dted/dted0"; int dtedLevel = 0; + int pixelsPerPoint = 2; + double pixelSkip = 2.0; Color canSeeColor = new Color(0, 255, 0, 100); Color canNotSeeColor = null; double maxRange = 200; @@ -130,10 +141,12 @@ public String toString() { public final static String dtedDirProperty = "dtedDir"; public final static String maxRangeProperty = "maxRange"; public final static String maxRangeUnitsProperty = "maxRangeUnits"; + public final static String pixelsPerPointProperty = "pixelsPerPoint"; + public final static String pixelSkipProperty = "pixelSkip"; + public final static String showNumberPointsProperty = "showNumberPoints"; // Internal use only members DTEDFrameCache dted; - ProgressSupport progressSupport = null; public MultiLOSLayer() { dted = new DTEDFrameCache(); @@ -152,7 +165,11 @@ public void setProperties(String prefix, Properties props) { showHorizons = PropUtils.booleanFromProperties(props, realPrefix + showHorizonsProperty, showHorizons); showMaxRanges = PropUtils.booleanFromProperties(props, realPrefix + showMaxRangesProperty, showMaxRanges); showViewPoints = PropUtils.booleanFromProperties(props, realPrefix + showViewPointsProperty, showViewPoints); - + showNumberPoints = PropUtils.booleanFromProperties(props, realPrefix + showNumberPointsProperty, showNumberPoints); + + pixelSkip = PropUtils.doubleFromProperties(props, realPrefix + pixelSkipProperty, pixelSkip); + pixelsPerPoint = Math.max(1, PropUtils.intFromProperties(props, realPrefix + pixelsPerPointProperty, pixelsPerPoint)); + dtedLevel = PropUtils.intFromProperties(props, realPrefix + dtedLevelProperty, dtedLevel); dtedDir = props.getProperty(realPrefix + dtedDirProperty, dtedDir); dted.addDTEDDirectoryHandler(new DTEDDirectoryHandler(dtedDir)); @@ -243,11 +260,6 @@ public void setProperties(String prefix, Properties props) { } } } - - if(null == progressSupport) { - progressSupport = new ProgressSupport(this); - progressSupport.add(new ProgressListenerGauge("MultiLOS")); - } } @Override @@ -259,6 +271,9 @@ public Properties getProperties(Properties props) { props.put(prefix + "class", this.getClass().getName()); props.put(prefix + altProperty, altitude); props.put(prefix + altUnitsProperty, altitudeUnits.getAbbr()); + props.put(prefix + showNumberPointsProperty, Boolean.toString(showNumberPoints)); + props.put(prefix + pixelSkipProperty, pixelSkip); + props.put(prefix + pixelsPerPointProperty, pixelsPerPoint); props.put(prefix + showHorizonsProperty, Boolean.toString(showHorizons)); props.put(prefix + showMaxRangesProperty, Boolean.toString(showMaxRanges)); props.put(prefix + showViewPointsProperty, Boolean.toString(showViewPoints)); @@ -292,10 +307,13 @@ public Properties getPropertyInfo(Properties list) { list.put(showHorizonsProperty, "Whether to indicate horizons"); list.put(showMaxRangesProperty, "Whether to indicate max ranges"); list.put(showViewPointsProperty, "Whether to indicate viewpoints"); + list.put(showNumberPointsProperty, "Whether to indicate numbers next to points"); list.put(canSeeColorProperty, "Color to indicate if a point can be seen."); list.put(canNotSeeColorProperty, "Color to indicate if a point cannot be seen. Leave blank to not include points"); list.put(dtedLevelProperty, "DTED Level"); list.put(dtedDirProperty, "DTED data directory"); + list.put(pixelsPerPointProperty, "Pixels per point"); + list.put(pixelsPerPointProperty, "Pixel Skip"); list.put(maxRangeProperty, "Maximum sensor range"); list.put(maxRangeUnitsProperty, "Maximum sensor range units"); list.put(viewPointsProperty, "Semicolon-separated list of lat,lon pairs with option ',alt' suffix"); @@ -327,10 +345,15 @@ public OMGraphicList prepare() { } } if(showViewPoints) { - for(MultiLOSViewPoint mlvp : viewPoints) { + for(int i = 0; i < viewPoints.size(); i++) { + MultiLOSViewPoint mlvp = viewPoints.get(i); LatLonPoint vp = mlvp.p; OMPoint p = new OMPoint(vp.getLatitude(), vp.getLongitude()); l.add(p); + if(showNumberPoints) { + OMText t = new OMText(vp.getLatitude(), vp.getLongitude(), Integer.toString(i), OMText.JUSTIFY_LEFT); + l.add(t); + } } } createMultiLOS(l); @@ -344,14 +367,26 @@ public Component getGUI() { final JButton setAltsButton = new JButton("Set all viewpoint alts to (" + altitudeUnits.getAbbr() + "):"); pan.add(setAltsButton); - final JSpinner altSpinner = new JSpinner(new SpinnerNumberModel(altitude, 0.0, 10000.0, 1.0)); + final SpinnerNumberModel altSpinnerModel = new SpinnerNumberModel(altitude, 0.0, 1000000.0, 1.0); + final JSpinner altSpinner = new JSpinner(altSpinnerModel); pan.add(altSpinner); final JButton setRangesButton = new JButton("Set all viewpoint ranges to (" + maxRangeUnits.getAbbr() + "):"); pan.add(setRangesButton); - final JSpinner maxRangeSpinner = new JSpinner(new SpinnerNumberModel(maxRange, 0.0, 10000.0, 20.0)); + final SpinnerNumberModel maxRangeSpinnerModel = new SpinnerNumberModel(maxRange, 0.0, 1000000.0, 20.0); + final JSpinner maxRangeSpinner = new JSpinner(maxRangeSpinnerModel); pan.add(maxRangeSpinner); + pan.add(new JLabel("Pixel Skip")); + final SpinnerNumberModel pixelSkipSpinnerModel = new SpinnerNumberModel(pixelSkip, 0.01, 1000.0, 1); + final JSpinner pixelSkipSpinner = new JSpinner(pixelSkipSpinnerModel); + pan.add(pixelSkipSpinner); + + pan.add(new JLabel("Pixels per Point")); + final SpinnerNumberModel pixelsPerPointSpinnerModel = new SpinnerNumberModel(pixelsPerPoint, 1, 1000, 1); + final JSpinner pixelPerPointSpinner = new JSpinner(pixelsPerPointSpinnerModel); + pan.add(pixelPerPointSpinner); + pan.add(new JLabel("Show horizons")); final JCheckBox showHorizonCB = new JCheckBox((String)null, showHorizons); pan.add(showHorizonCB); @@ -364,9 +399,13 @@ public Component getGUI() { final JCheckBox showViewPointsCB = new JCheckBox((String)null, showViewPoints); pan.add(showViewPointsCB); + pan.add(new JLabel("Show Point Numbering")); + final JCheckBox showNumberPointsCB = new JCheckBox((String)null, showNumberPoints); + pan.add(showNumberPointsCB); + ActionListener altAl = new ActionListener() { public void actionPerformed(ActionEvent e) { - Double newAlt = (Double)altSpinner.getValue(); + Double newAlt = altSpinnerModel.getNumber().doubleValue(); for(MultiLOSViewPoint mlvp : viewPoints) { mlvp.altitude = newAlt; } @@ -377,7 +416,7 @@ public void actionPerformed(ActionEvent e) { ActionListener rangeAl = new ActionListener() { public void actionPerformed(ActionEvent e) { - Double newMaxRange = (Double)maxRangeSpinner.getValue(); + Double newMaxRange = maxRangeSpinnerModel.getNumber().doubleValue(); for(MultiLOSViewPoint mlvp : viewPoints) { mlvp.maxRange = newMaxRange; } @@ -388,6 +427,7 @@ public void actionPerformed(ActionEvent e) { final ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { + showNumberPoints = showNumberPointsCB.isSelected(); showHorizons = showHorizonCB.isSelected(); showMaxRanges = showMaxRangesCB.isSelected(); showViewPoints = showViewPointsCB.isSelected(); @@ -395,6 +435,17 @@ public void actionPerformed(ActionEvent e) { } }; + final ChangeListener spinnerListener = new ChangeListener() { + public void stateChanged(ChangeEvent e) { + pixelsPerPoint = pixelsPerPointSpinnerModel.getNumber().intValue(); + pixelSkip = pixelSkipSpinnerModel.getNumber().doubleValue(); + doPrepare(); + } + }; + pixelPerPointSpinner.addChangeListener(spinnerListener); + pixelSkipSpinner.addChangeListener(spinnerListener); + + showNumberPointsCB.addActionListener(al); showHorizonCB.addActionListener(al); showMaxRangesCB.addActionListener(al); showViewPointsCB.addActionListener(al); @@ -406,31 +457,12 @@ public void createMultiLOS(OMGraphicList l) { Projection proj = getProjection(); - Point2D ll1 = proj.getUpperLeft(); - Point2D ll2 = proj.getLowerRight(); - - double dLon = (ll2.getX() - ll1.getX()) / (proj.getWidth() / 4); - double dLat = (ll1.getY() - ll2.getY()) / (proj.getHeight() / 4); - int checkedPoints = 0; int seenPoints = 0; - final int maxProgress = (int) ((ll2.getX() - ll1.getX())/dLon); - int currProgress = 0; - final String taskName = "MultiLOS Render"; -// progressSupport.fireUpdate(ProgressEvent.START, taskName, currProgress, maxProgress); - for (double testLon = ll1.getX(); testLon < ll2.getX(); testLon+=dLon) { - currProgress++; - // Need it to be final so it can be seen from the inner subclass -// final int progress = currProgress; -// SwingUtilities.invokeLater(new Runnable() { -// public void run() { -// progressSupport.fireUpdate(ProgressEvent.UPDATE, taskName, progress, maxProgress); -// } -// }); - - for (double testLat = ll2.getY(); testLat < ll1.getY(); testLat+=dLat) { - + for (int x = 0; x < proj.getWidth(); x+=pixelsPerPoint) { +// System.out.println(String.format("MultiLOS Render: %d/%d", x, proj.getWidth())); + for (int y = 0; y < proj.getHeight(); y+=pixelsPerPoint) { if(Thread.currentThread().isInterrupted()) { // eg, if we're mid-render and someone moves the map again return; @@ -438,8 +470,10 @@ public void createMultiLOS(OMGraphicList l) { checkedPoints++; - LatLonPoint testp = new LatLonPoint.Double(testLat, testLon); - Point2D xyp = proj.forward(testp); + LatLonPoint testp = new LatLonPoint.Double(); + proj.inverse(x, y, testp); + double testLat = testp.getLatitude(); + double testLon = testp.getLongitude(); int elevation = dted.getElevation((float) testLat, (float) testLon, dtedLevel); if(elevation > 0) { @@ -462,9 +496,9 @@ public void createMultiLOS(OMGraphicList l) { // Point2D tXY = proj.forward(oneVP.getLatitude(), oneVP.getLongitude()); int numPixBetween = (int) (Math.sqrt( - Math.pow(tXY.getX() - xyp.getX(), 2) + - Math.pow(tXY.getY() - xyp.getY(), 2) - ) / 5); + Math.pow(tXY.getX() - x, 2) + + Math.pow(tXY.getY() - y, 2) + ) / pixelSkip); if (los.isLOS(oneVP, (int) thisAltM, false, testp, 0, (int) numPixBetween)) { @@ -478,6 +512,7 @@ public void createMultiLOS(OMGraphicList l) { OMPoint p = new OMPoint(testLat, testLon); p.setLinePaint(OMColor.clear); p.setFillPaint(canSeeColor); + p.setRadius(pixelsPerPoint / 2); l.add(p); seenPoints++; } else if(0 == losCount && null != canNotSeeColor) { From fb3718c7b656db7bfa175e560b5e408b14904d75 Mon Sep 17 00:00:00 2001 From: Gary Briggs Date: Wed, 24 Aug 2016 17:41:20 -0700 Subject: [PATCH 10/10] Fixing spinnermodel usage --- .../layer/terrain/MultiLOS/MultiLOSLayer.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java index bfa372e6..27c4ee08 100644 --- a/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java +++ b/src/core/src/main/java/com/bbn/openmap/layer/terrain/MultiLOS/MultiLOSLayer.java @@ -367,24 +367,20 @@ public Component getGUI() { final JButton setAltsButton = new JButton("Set all viewpoint alts to (" + altitudeUnits.getAbbr() + "):"); pan.add(setAltsButton); - final SpinnerNumberModel altSpinnerModel = new SpinnerNumberModel(altitude, 0.0, 1000000.0, 1.0); - final JSpinner altSpinner = new JSpinner(altSpinnerModel); + final JSpinner altSpinner = new JSpinner(new SpinnerNumberModel(altitude, 0.0, 1000000.0, 1.0)); pan.add(altSpinner); final JButton setRangesButton = new JButton("Set all viewpoint ranges to (" + maxRangeUnits.getAbbr() + "):"); pan.add(setRangesButton); - final SpinnerNumberModel maxRangeSpinnerModel = new SpinnerNumberModel(maxRange, 0.0, 1000000.0, 20.0); - final JSpinner maxRangeSpinner = new JSpinner(maxRangeSpinnerModel); + final JSpinner maxRangeSpinner = new JSpinner(new SpinnerNumberModel(maxRange, 0.0, 1000000.0, 20.0)); pan.add(maxRangeSpinner); pan.add(new JLabel("Pixel Skip")); - final SpinnerNumberModel pixelSkipSpinnerModel = new SpinnerNumberModel(pixelSkip, 0.01, 1000.0, 1); - final JSpinner pixelSkipSpinner = new JSpinner(pixelSkipSpinnerModel); + final JSpinner pixelSkipSpinner = new JSpinner(new SpinnerNumberModel(pixelSkip, 0.01, 1000.0, 1)); pan.add(pixelSkipSpinner); pan.add(new JLabel("Pixels per Point")); - final SpinnerNumberModel pixelsPerPointSpinnerModel = new SpinnerNumberModel(pixelsPerPoint, 1, 1000, 1); - final JSpinner pixelPerPointSpinner = new JSpinner(pixelsPerPointSpinnerModel); + final JSpinner pixelPerPointSpinner = new JSpinner(new SpinnerNumberModel(pixelsPerPoint, 1, 1000, 1)); pan.add(pixelPerPointSpinner); pan.add(new JLabel("Show horizons")); @@ -405,7 +401,7 @@ public Component getGUI() { ActionListener altAl = new ActionListener() { public void actionPerformed(ActionEvent e) { - Double newAlt = altSpinnerModel.getNumber().doubleValue(); + Double newAlt = ((SpinnerNumberModel)altSpinner.getModel()).getNumber().doubleValue(); for(MultiLOSViewPoint mlvp : viewPoints) { mlvp.altitude = newAlt; } @@ -416,7 +412,7 @@ public void actionPerformed(ActionEvent e) { ActionListener rangeAl = new ActionListener() { public void actionPerformed(ActionEvent e) { - Double newMaxRange = maxRangeSpinnerModel.getNumber().doubleValue(); + Double newMaxRange = ((SpinnerNumberModel)maxRangeSpinner.getModel()).getNumber().doubleValue(); for(MultiLOSViewPoint mlvp : viewPoints) { mlvp.maxRange = newMaxRange; } @@ -437,8 +433,8 @@ public void actionPerformed(ActionEvent e) { final ChangeListener spinnerListener = new ChangeListener() { public void stateChanged(ChangeEvent e) { - pixelsPerPoint = pixelsPerPointSpinnerModel.getNumber().intValue(); - pixelSkip = pixelSkipSpinnerModel.getNumber().doubleValue(); + pixelsPerPoint = ((SpinnerNumberModel)pixelPerPointSpinner.getModel()).getNumber().intValue(); + pixelSkip = ((SpinnerNumberModel)pixelSkipSpinner.getModel()).getNumber().doubleValue(); doPrepare(); } };