summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/application/geo/VisualizeGeodesicDistances.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/application/geo/VisualizeGeodesicDistances.java')
-rw-r--r--src/de/lmu/ifi/dbs/elki/application/geo/VisualizeGeodesicDistances.java121
1 files changed, 79 insertions, 42 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/application/geo/VisualizeGeodesicDistances.java b/src/de/lmu/ifi/dbs/elki/application/geo/VisualizeGeodesicDistances.java
index bdc0f39a..75770ba7 100644
--- a/src/de/lmu/ifi/dbs/elki/application/geo/VisualizeGeodesicDistances.java
+++ b/src/de/lmu/ifi/dbs/elki/application/geo/VisualizeGeodesicDistances.java
@@ -32,20 +32,20 @@ import de.lmu.ifi.dbs.elki.application.AbstractApplication;
import de.lmu.ifi.dbs.elki.data.DoubleVector;
import de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox;
import de.lmu.ifi.dbs.elki.logging.Logging;
-import de.lmu.ifi.dbs.elki.math.GeoUtil;
-import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
+import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
+import de.lmu.ifi.dbs.elki.math.geodesy.EarthModel;
+import de.lmu.ifi.dbs.elki.math.geodesy.SphereUtil;
+import de.lmu.ifi.dbs.elki.math.geodesy.SphericalVincentyEarthModel;
import de.lmu.ifi.dbs.elki.utilities.exceptions.UnableToComplyException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
-import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterEqualConstraint;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.EnumParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
/**
* Visualization function for Cross-track distance function
*
- * TODO: make resolution configurable.
- *
* TODO: make origin point / rectangle configurable.
*
* @author Niels Dörre
@@ -66,7 +66,7 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
*/
public static enum Mode {
/** Cross track distance */
- CTD,
+ XTD,
/** Along track distance */
ATD,
/** Mindist */
@@ -81,7 +81,7 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
/**
* Image size.
*/
- final int width = 2000, height = 1000;
+ protected int width = 2000, height = 1000;
/**
* Number of steps for shades.
@@ -89,9 +89,14 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
protected int steps = 10;
/**
- * Visualization mode
+ * Visualization mode.
+ */
+ protected Mode mode = Mode.XTD;
+
+ /**
+ * Earth model.
*/
- private Mode mode = Mode.CTD;
+ protected EarthModel model;
/**
* Constructor.
@@ -99,12 +104,16 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
* @param out Output filename
* @param steps Number of steps in the color map
* @param mode Visualization mode
+ * @param model Earth model
*/
- public VisualizeGeodesicDistances(File out, int steps, Mode mode) {
+ public VisualizeGeodesicDistances(File out, int resolution, int steps, Mode mode, EarthModel model) {
super();
+ this.width = resolution;
+ this.height = resolution >> 1;
this.out = out;
this.steps = steps;
this.mode = mode;
+ this.model = model;
}
@Override
@@ -125,34 +134,20 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- final double max;
- switch(mode) {
- case ATD:
- // Currently half the circumference - we're missing the sign
- max = GeoUtil.EARTH_RADIUS * Math.PI;
- break;
- case CTD:
- // Quarter (!) the circumference is the maximum CTD!
- max = .5 * GeoUtil.EARTH_RADIUS * Math.PI;
- break;
- case MINDIST:
- // Half the circumference
- max = GeoUtil.EARTH_RADIUS * Math.PI;
- break;
- default:
- throw new AbortException("Invalid mode: " + mode);
- }
+ final double max = model.getEquatorialRadius() * Math.PI;
+
// Red: left off-course, green: right off-course
int red = 0xffff0000;
int green = 0xff00ff00;
+ FiniteProgress prog = LOG.isVerbose() ? new FiniteProgress("columns", width, LOG) : null;
for (int x = 0; x < width; x++) {
final double lon = x * 360. / width - 180.;
for (int y = 0; y < height; y++) {
final double lat = y * -180. / height + 90.;
switch(mode) {
case ATD: {
- final double atd = GeoUtil.alongTrackDistance(stap.doubleValue(0), stap.doubleValue(1), endp.doubleValue(0), endp.doubleValue(1), lat, lon);
+ final double atd = model.getEquatorialRadius() * SphereUtil.alongTrackDistanceDeg(stap.doubleValue(0), stap.doubleValue(1), endp.doubleValue(0), endp.doubleValue(1), lat, lon);
if (atd < 0) {
img.setRGB(x, y, colorMultiply(red, -atd / max, false));
} else {
@@ -160,8 +155,8 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
}
break;
}
- case CTD: {
- final double ctd = GeoUtil.crossTrackDistance(stap.doubleValue(0), stap.doubleValue(1), endp.doubleValue(0), endp.doubleValue(1), lat, lon);
+ case XTD: {
+ final double ctd = model.getEquatorialRadius() * SphereUtil.crossTrackDistanceDeg(stap.doubleValue(0), stap.doubleValue(1), endp.doubleValue(0), endp.doubleValue(1), lat, lon);
if (ctd < 0) {
img.setRGB(x, y, colorMultiply(red, -ctd / max, false));
} else {
@@ -170,7 +165,7 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
break;
}
case MINDIST: {
- final double dist = GeoUtil.latlngMinDistDeg(lat, lon, bb.getMin(0), bb.getMin(1), bb.getMax(0), bb.getMax(1));
+ final double dist = model.minDistDeg(lat, lon, bb.getMin(0), bb.getMin(1), bb.getMax(0), bb.getMax(1));
if (dist < 0) {
img.setRGB(x, y, colorMultiply(red, -dist / max, true));
} else {
@@ -180,6 +175,12 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
}
}
}
+ if (prog != null) {
+ prog.incrementProcessed(LOG);
+ }
+ }
+ if (prog != null) {
+ prog.ensureCompleted(LOG);
}
try {
@@ -192,10 +193,24 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
private int colorMultiply(int col, double reldist, boolean ceil) {
if (steps > 0) {
if (!ceil) {
- reldist = Math.round(reldist * steps) * 1. / steps;
+ reldist = Math.round(reldist * steps) / steps;
} else {
reldist = Math.ceil(reldist * steps) / steps;
}
+ } else if (steps < 0 && reldist > 0.) {
+ double s = reldist * -steps;
+ double off = Math.abs(s - Math.round(s));
+ double factor = -steps * 1. / 1000; // height;
+ if (off < factor) { // Blend with black:
+ factor = (off / factor);
+ int a = (col >> 24) & 0xFF;
+ a = (int) (a * Math.sqrt(reldist)) & 0xFF;
+ a = (int) ((1 - factor) * 0xFF + factor * a);
+ int r = (int) (factor * ((col >> 16) & 0xFF));
+ int g = (int) (factor * ((col >> 8) & 0xFF));
+ int b = (int) (factor * (col & 0xFF));
+ return a << 24 | r << 16 | g << 8 | b;
+ }
}
int a = (col >> 24) & 0xFF, r = (col >> 16) & 0xFF, g = (col >> 8) & 0xFF, b = (col) & 0xFF;
a = (int) (a * Math.sqrt(reldist)) & 0xFF;
@@ -208,7 +223,7 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
* @param args Parameters
*/
public static void main(String[] args) {
- VisualizeGeodesicDistances.runCLIApplication(VisualizeGeodesicDistances.class, args);
+ runCLIApplication(VisualizeGeodesicDistances.class, args);
}
/**
@@ -222,12 +237,17 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
/**
* Number of steps in the distance map.
*/
- public static final OptionID STEPS_ID = new OptionID("ctdvis.steps", "Number of steps for the distance map.");
+ public static final OptionID STEPS_ID = new OptionID("geodistvis.steps", "Number of steps for the distance map. Use negative numbers to get contour lines.");
+
+ /**
+ * Image resolution.
+ */
+ public static final OptionID RESOLUTION_ID = new OptionID("geodistvis.resolution", "Horizontal resolution for the image map (vertical resolution is horizonal / 2).");
/**
* Visualization mode.
*/
- public static final OptionID MODE_ID = new OptionID("ctdvis.mode", "Visualization mode.");
+ public static final OptionID MODE_ID = new OptionID("geodistvis.mode", "Visualization mode.");
/**
* Holds the file to print results to.
@@ -235,34 +255,51 @@ public class VisualizeGeodesicDistances extends AbstractApplication {
protected File out = null;
/**
- * Number of steps in the color map
+ * Number of steps in the color map.
*/
protected int steps = 0;
/**
- * Visualization mode
+ * Horizontal resolution.
+ */
+ protected int resolution = 2000;
+
+ /**
+ * Visualization mode.
*/
- protected Mode mode = Mode.CTD;
+ protected Mode mode = Mode.XTD;
+
+ /**
+ * Earth model to use.
+ */
+ protected EarthModel model;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
- out = super.getParameterOutputFile(config, "Output image file");
+ out = super.getParameterOutputFile(config, "Output image file name.");
IntParameter stepsP = new IntParameter(STEPS_ID);
stepsP.setOptional(true);
- stepsP.addConstraint(new GreaterEqualConstraint(0));
if (config.grab(stepsP)) {
steps = stepsP.intValue();
}
- EnumParameter<Mode> modeP = new EnumParameter<Mode>(MODE_ID, Mode.class, Mode.CTD);
+ IntParameter resolutionP = new IntParameter(RESOLUTION_ID, 2000);
+ if (config.grab(resolutionP)) {
+ resolution = resolutionP.intValue();
+ }
+ EnumParameter<Mode> modeP = new EnumParameter<>(MODE_ID, Mode.class, Mode.XTD);
if (config.grab(modeP)) {
mode = modeP.getValue();
}
+ ObjectParameter<EarthModel> modelP = new ObjectParameter<>(EarthModel.MODEL_ID, EarthModel.class, SphericalVincentyEarthModel.class);
+ if (config.grab(modelP)) {
+ model = modelP.instantiateClass(config);
+ }
}
@Override
protected VisualizeGeodesicDistances makeInstance() {
- return new VisualizeGeodesicDistances(out, steps, mode);
+ return new VisualizeGeodesicDistances(out, resolution, steps, mode, model);
}
}
}