mirror of
https://github.com/octoleo/plantuml.git
synced 2024-12-22 10:59:01 +00:00
Version 7177
This commit is contained in:
parent
df0e7faa11
commit
7cee7b4601
373
src/com/ctreber/acearth/ACearth.java
Normal file
373
src/com/ctreber/acearth/ACearth.java
Normal file
@ -0,0 +1,373 @@
|
||||
package com.ctreber.acearth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import com.ctreber.acearth.gui.CanvasACearth;
|
||||
import com.ctreber.acearth.plugins.Plugin;
|
||||
import com.ctreber.acearth.plugins.markers.Marker;
|
||||
import com.ctreber.acearth.plugins.markers.PluginMarkers;
|
||||
import com.ctreber.acearth.projection.Projection;
|
||||
import com.ctreber.acearth.projection.ProjectionCyl;
|
||||
import com.ctreber.acearth.projection.ProjectionMerc;
|
||||
import com.ctreber.acearth.projection.ProjectionOrtho;
|
||||
import com.ctreber.acearth.renderer.Renderer;
|
||||
import com.ctreber.acearth.renderer.RowTypeRendererScanBit;
|
||||
import com.ctreber.acearth.renderer.RowTypeRendererScanDot;
|
||||
import com.ctreber.acearth.scanbit.BitGeneratorMap;
|
||||
import com.ctreber.acearth.scanbit.BitGeneratorMapDefault;
|
||||
import com.ctreber.acearth.scanbit.BitGeneratorMapOrtho;
|
||||
import com.ctreber.acearth.scandot.DotGeneratorLines;
|
||||
import com.ctreber.acearth.scandot.DotGeneratorStars;
|
||||
import com.ctreber.acearth.scandot.ScanDot;
|
||||
import com.ctreber.acearth.scandot.ScanDotGenerator;
|
||||
import com.ctreber.acearth.shader.Shader;
|
||||
import com.ctreber.acearth.shader.ShaderDefault;
|
||||
import com.ctreber.acearth.shader.ShaderFlat;
|
||||
import com.ctreber.acearth.shader.ShaderOrtho;
|
||||
import com.ctreber.acearth.util.Coordinate;
|
||||
import com.ctreber.acearth.util.SunPositionCalculator;
|
||||
import com.ctreber.acearth.util.Toolkit;
|
||||
import com.ctreber.aclib.sort.CTSort;
|
||||
import com.ctreber.aclib.sort.QuickSort;
|
||||
|
||||
/**
|
||||
* <h1>AC.earth - XEarth for Java
|
||||
* <h1>
|
||||
*
|
||||
* <p>
|
||||
* The original XEarth was written by Kirk Johnson in July 1993 - thank you for
|
||||
* writing this great little program and making it available for free!
|
||||
*
|
||||
* <p>
|
||||
* I wanted to extend the program, but not in C. So I created this Java version,
|
||||
* and found the process quite <strike>painfull</strike> interesting. The
|
||||
* biggest effort went into resolving references between C files and
|
||||
* eliminatiing pointers.
|
||||
*
|
||||
* <h1>License</h1>
|
||||
*
|
||||
* <p>
|
||||
* AC.earth Copyright (c) 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* <p>
|
||||
* AC.earth is based on XEarth by Kirk Johnson
|
||||
*
|
||||
* <p>
|
||||
* To comply with the XEarth license I include the following text:
|
||||
*
|
||||
* <pre>
|
||||
* XEarth Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson
|
||||
* Parts of the source code are:
|
||||
* Copyright (C) 1989, 1990, 1991 by Jim Frost
|
||||
* Copyright (C) 1992 by Jamie Zawinski <jwz@lucid.com>
|
||||
* Permission to use, copy, modify and freely distribute xearth for
|
||||
* non-commercial and not-for-profit purposes is hereby granted
|
||||
* without fee, provided that both the above copyright notice and this
|
||||
* permission notice appear in all copies and in supporting
|
||||
* documentation.
|
||||
* [Section refering to GIF omitted because it doesn't apply to this version]
|
||||
* The author makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
|
||||
* OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The license for this program (AC.earth) is the same as the quoted license
|
||||
* above, with one change: The "copyright notice and permission notice" shall
|
||||
* include the entire text of this section.
|
||||
*
|
||||
* todo Phase 2: Make grid value stuff more meaningful ("every n degrees") todo
|
||||
* Phase 2: Enter fixed time as data and time, not seconds since epoch todo
|
||||
* Phase 2: Compact map data into binary file
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*/
|
||||
public class ACearth {
|
||||
public static final String VERSION = "1.1";
|
||||
public static final String BUILD = "22.11.2002 004";
|
||||
|
||||
// private static long fsStartTime = 0;
|
||||
|
||||
private ConfigurationACearth fConf = new ConfigurationACearth();
|
||||
private long fCurrentTime;
|
||||
|
||||
private CanvasACearth fCanvas;
|
||||
|
||||
private Coordinate fViewPos;
|
||||
private double fViewRotation;
|
||||
|
||||
private List fPlugins;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Well, the main class.
|
||||
* @param markers
|
||||
*/
|
||||
public ACearth(List<Marker> markers) {
|
||||
// fsStartTime = System.currentTimeMillis();
|
||||
|
||||
fPlugins = new ArrayList();
|
||||
fPlugins.add(new PluginMarkers(markers));
|
||||
|
||||
}
|
||||
|
||||
public void exportPng(OutputStream os) throws IOException {
|
||||
fCanvas = new CanvasACearth(this, fConf.getInt("imageWidth"), fConf.getInt("imageHeight"));
|
||||
update();
|
||||
fCanvas.saveToImage(os);
|
||||
}
|
||||
|
||||
public void update() throws IOException {
|
||||
Projection lProjection = null;
|
||||
Shader lShader = null;
|
||||
BitGeneratorMap lScanner = null;
|
||||
if (fConf.is("projection", "Cylindrical")) {
|
||||
lProjection = new ProjectionCyl();
|
||||
lScanner = new BitGeneratorMapDefault(lProjection);
|
||||
lShader = new ShaderDefault();
|
||||
}
|
||||
|
||||
if (fConf.is("projection", "Mercator")) {
|
||||
lProjection = new ProjectionMerc();
|
||||
lScanner = new BitGeneratorMapDefault(lProjection);
|
||||
lShader = new ShaderDefault();
|
||||
}
|
||||
|
||||
if (fConf.is("projection", "Orthographic")) {
|
||||
lProjection = new ProjectionOrtho();
|
||||
lScanner = new BitGeneratorMapOrtho(lProjection);
|
||||
lShader = new ShaderOrtho();
|
||||
}
|
||||
|
||||
computePositions();
|
||||
lProjection.setImageWidth(fConf.getInt("imageWidth"));
|
||||
lProjection.setImageHeight(fConf.getInt("imageHeight"));
|
||||
lProjection.setShiftX(fConf.getInt("shiftX"));
|
||||
lProjection.setShiftY(fConf.getInt("shiftY"));
|
||||
lProjection.setViewMagnification(fConf.getDouble("viewMagnification"));
|
||||
lProjection.setViewPos(fViewPos);
|
||||
lProjection.setViewRotation(fViewRotation);
|
||||
|
||||
lScanner.setImageWidth(fConf.getInt("imageWidth"));
|
||||
lScanner.setImageHeight(fConf.getInt("imageHeight"));
|
||||
lScanner.setMapData(MapDataReader.readMapData());
|
||||
// Process the map (produces ScanBit-s).
|
||||
lScanner.generateScanBits();
|
||||
|
||||
// Process stars and lines (produces ScanDots-s).
|
||||
List lScanDots = new ArrayList();
|
||||
if (fConf.getBoolean("starsP")) {
|
||||
ScanDotGenerator lGenerator = new DotGeneratorStars(fConf.getInt("imageWidth"),
|
||||
fConf.getInt("imageHeight"), fConf.getDouble("starFrequency"), fConf.getInt("bigStars"), new Random(fCurrentTime));
|
||||
lGenerator.generateScanDots();
|
||||
lScanDots.addAll(lGenerator.getScanDots());
|
||||
}
|
||||
|
||||
if (fConf.getBoolean("gridP")) {
|
||||
ScanDotGenerator lGenerator = new DotGeneratorLines(lProjection, fConf.getInt("gridDivision"), fConf
|
||||
.getInt("gridPixelDivision"));
|
||||
lGenerator.generateScanDots();
|
||||
lScanDots.addAll(lGenerator.getScanDots());
|
||||
}
|
||||
|
||||
final CTSort lSort = new QuickSort();
|
||||
ScanDot[] lScanDotsArray = (ScanDot[]) lScanDots.toArray(new ScanDot[0]);
|
||||
lSort.sort(lScanDotsArray);
|
||||
|
||||
if (!fConf.getBoolean("shadeP")) {
|
||||
lShader = new ShaderFlat();
|
||||
}
|
||||
lShader.setProjection(lProjection);
|
||||
lShader.setSunPos(fConf.getSunPos());
|
||||
lShader.setDaySideBrightness(fConf.getInt("daySideBrightness"));
|
||||
lShader.setTerminatorDiscontinuity(fConf.getInt("terminatorDiscontinuity"));
|
||||
lShader.setNightSideBrightness(fConf.getInt("nightSideBrightness"));
|
||||
lShader.init();
|
||||
|
||||
Renderer lRenderer = new Renderer(fCanvas);
|
||||
|
||||
RowTypeRendererScanBit lRowRendererScanBit = new RowTypeRendererScanBit();
|
||||
lRowRendererScanBit.setScanBits(lScanner.getScanBits());
|
||||
lRenderer.addRowTypeRenderer(lRowRendererScanBit);
|
||||
|
||||
RowTypeRendererScanDot lRowRendererScanDot = new RowTypeRendererScanDot();
|
||||
lRowRendererScanDot.setScanDots(lScanDotsArray);
|
||||
lRenderer.addRowTypeRenderer(lRowRendererScanDot);
|
||||
|
||||
lRenderer.setShader(lShader);
|
||||
lRenderer.render();
|
||||
|
||||
// Apply plugins
|
||||
Iterator lIt = fPlugins.iterator();
|
||||
while (lIt.hasNext()) {
|
||||
Plugin lPlugin = (Plugin) lIt.next();
|
||||
lPlugin.setProjection(lProjection);
|
||||
lPlugin.setRenderTarget(fCanvas);
|
||||
lPlugin.setParent(this);
|
||||
lPlugin.render();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is repeated when time changes since this influences the position of
|
||||
* Earth.
|
||||
*/
|
||||
private void computePositions() {
|
||||
// Determine time for rendering
|
||||
if (fConf.getInt("fixedTime") == 0) {
|
||||
// No fixed time.
|
||||
// final long lTimePassed = System.currentTimeMillis() - fsStartTime;
|
||||
// fCurrentTime = fsStartTime + (long) (fConf.getDouble("timeWarpFactor") * lTimePassed);
|
||||
fCurrentTime = System.currentTimeMillis();
|
||||
} else {
|
||||
// Fixed time.
|
||||
fCurrentTime = fConf.getInt("fixedTime") * 1000L;
|
||||
}
|
||||
|
||||
if (fConf.getBoolean("sunMovesP")) {
|
||||
fConf.setSunPos(SunPositionCalculator.getSunPositionOnEarth(fCurrentTime));
|
||||
}
|
||||
|
||||
// Determine viewing position
|
||||
if (fConf.is("viewPositionType", "Fixed")) {
|
||||
fViewPos = fConf.getViewPos();
|
||||
} else if (fConf.is("viewPositionType", "Sun-relative")) {
|
||||
fViewPos = getSunRelativePosition();
|
||||
} else if (fConf.is("viewPositionType", "Orbit")) {
|
||||
fViewPos = getOrbitPosition(fCurrentTime);
|
||||
} else if (fConf.is("viewPositionType", "Random")) {
|
||||
fViewPos = getRandomPosition();
|
||||
} else if (fConf.is("viewPositionType", "Moon")) {
|
||||
fViewPos = SunPositionCalculator.getMoonPositionOnEarth(fCurrentTime);
|
||||
}
|
||||
|
||||
// for ViewRotGalactic, compute appropriate viewing rotation
|
||||
if (fConf.is("viewRotationType", "Galactic")) {
|
||||
fViewRotation = (Toolkit.degsToRads(fConf.getSunPos().getLat()
|
||||
* Math.sin((fViewPos.getLong() - fConf.getSunPos().getLong()))));
|
||||
} else {
|
||||
fViewRotation = fConf.getDouble("viewRotation");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Add sun position and position relative to sun, straighten out the result.
|
||||
*
|
||||
* @return Position relativ to sun position as defined by fSunPosRel.
|
||||
*/
|
||||
private Coordinate getSunRelativePosition() {
|
||||
final Coordinate lPos = fConf.getSunPos();
|
||||
lPos.add(fConf.getSunPosRel());
|
||||
|
||||
return lPos;
|
||||
}
|
||||
|
||||
private Coordinate getOrbitPosition(long pTimeMillis) {
|
||||
double x, y, z;
|
||||
double a, c, s;
|
||||
double t1, t2;
|
||||
|
||||
/* start at 0 N 0 E */
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 1;
|
||||
|
||||
/*
|
||||
* rotate in about y axis (from z towards x) according to the number of
|
||||
* orbits we've completed
|
||||
*/
|
||||
a = (double) pTimeMillis / (fConf.getDouble("orbitPeriod") * 3600 * 1000) * 2 * Math.PI;
|
||||
c = Math.cos(a);
|
||||
s = Math.sin(a);
|
||||
t1 = c * z - s * x;
|
||||
t2 = s * z + c * x;
|
||||
z = t1;
|
||||
x = t2;
|
||||
|
||||
/*
|
||||
* rotate about z axis (from x towards y) according to the inclination
|
||||
* of the orbit
|
||||
*/
|
||||
a = Toolkit.degsToRads(fConf.getDouble("orbitInclination"));
|
||||
c = Math.cos(a);
|
||||
s = Math.sin(a);
|
||||
t1 = c * x - s * y;
|
||||
t2 = s * x + c * y;
|
||||
x = t1;
|
||||
y = t2;
|
||||
|
||||
/*
|
||||
* rotate about y axis (from x towards z) according to the number of
|
||||
* rotations the earth has made
|
||||
*/
|
||||
a = ((double) pTimeMillis / 86400000) * (2 * Math.PI);
|
||||
c = Math.cos(a);
|
||||
s = Math.sin(a);
|
||||
t1 = c * x - s * z;
|
||||
t2 = s * x + c * z;
|
||||
x = t1;
|
||||
z = t2;
|
||||
|
||||
return new Coordinate(Toolkit.radsToDegs(Math.asin(y)), Toolkit.radsToDegs(Math.atan2(x, z)));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Pick a position (lat, lon) at random
|
||||
*
|
||||
* @return A random position.
|
||||
*/
|
||||
private static Coordinate getRandomPosition() {
|
||||
|
||||
/* select a vector at random */
|
||||
final double[] pos = new double[3];
|
||||
double mag = 0;
|
||||
do {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
pos[i] = ((Math.random() * 20000) * 1e-4) - 1;
|
||||
mag += pos[i] * pos[i];
|
||||
}
|
||||
} while ((mag > 1.0) || (mag < 0.01));
|
||||
|
||||
/* normalize the vector */
|
||||
mag = Math.sqrt(mag);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
pos[i] /= mag;
|
||||
}
|
||||
|
||||
/* convert to (lat, lon) */
|
||||
final double s_lat = pos[1];
|
||||
final double c_lat = Math.sqrt(1 - s_lat * s_lat);
|
||||
final double s_lon = pos[0] / c_lat;
|
||||
final double c_lon = pos[2] / c_lat;
|
||||
|
||||
return new Coordinate(Math.atan2(s_lat, c_lat) * (180 / Math.PI), Math.atan2(s_lon, c_lon) * (180 / Math.PI));
|
||||
}
|
||||
|
||||
// public static long getStartTime() {
|
||||
// return fsStartTime;
|
||||
// }
|
||||
|
||||
public ConfigurationACearth getConf() {
|
||||
return fConf;
|
||||
}
|
||||
|
||||
}
|
108
src/com/ctreber/acearth/Configuration.java
Normal file
108
src/com/ctreber/acearth/Configuration.java
Normal file
@ -0,0 +1,108 @@
|
||||
package com.ctreber.acearth;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ctreber.aclib.gui.MOBoolean;
|
||||
import com.ctreber.aclib.gui.MODouble;
|
||||
import com.ctreber.aclib.gui.MOEnum;
|
||||
import com.ctreber.aclib.gui.MOInteger;
|
||||
import com.ctreber.aclib.gui.MOString;
|
||||
import com.ctreber.aclib.gui.MonitoredObject;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com (06.10.2002)
|
||||
* </p>
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class Configuration {
|
||||
private Map fValues = new HashMap();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Item must be added before it can be set or get.
|
||||
*
|
||||
* @param pID
|
||||
* Item name.
|
||||
* @param pObject
|
||||
* Item value container.
|
||||
*/
|
||||
public void add(String pID, MonitoredObject pObject) {
|
||||
fValues.put(pID, pObject);
|
||||
}
|
||||
|
||||
public void setString(String pID, String pValue) {
|
||||
((MOString) fValues.get(pID)).set(pValue);
|
||||
}
|
||||
|
||||
public void setBoolean(String pID, boolean pValue) {
|
||||
((MOBoolean) fValues.get(pID)).set(pValue);
|
||||
}
|
||||
|
||||
public void setInt(String pID, int pValue) {
|
||||
((MOInteger) fValues.get(pID)).set(pValue);
|
||||
}
|
||||
|
||||
public void setDouble(String pID, double pValue) {
|
||||
((MODouble) fValues.get(pID)).set(pValue);
|
||||
}
|
||||
|
||||
public void setEnum(String pID, Object pValue) {
|
||||
((MOEnum) fValues.get(pID)).set(pValue);
|
||||
}
|
||||
|
||||
public String getString(String pID) {
|
||||
return ((MOString) fValues.get(pID)).get();
|
||||
}
|
||||
|
||||
public boolean getBoolean(String pID) {
|
||||
return ((MOBoolean) fValues.get(pID)).get();
|
||||
}
|
||||
|
||||
public int getInt(String pID) {
|
||||
return ((MOInteger) fValues.get(pID)).get();
|
||||
}
|
||||
|
||||
public double getDouble(String pID) {
|
||||
return ((MODouble) fValues.get(pID)).get();
|
||||
}
|
||||
|
||||
public boolean is(String pID, Object pValue) {
|
||||
return ((MOEnum) fValues.get(pID)).is(pValue);
|
||||
}
|
||||
|
||||
public MOBoolean getMOBoolean(String pID) {
|
||||
return (MOBoolean) getMO(pID);
|
||||
}
|
||||
|
||||
public MOString getMOString(String pID) {
|
||||
return (MOString) getMO(pID);
|
||||
}
|
||||
|
||||
public MOEnum getMOEnum(String pID) {
|
||||
return (MOEnum) getMO(pID);
|
||||
}
|
||||
|
||||
public MOInteger getMOInteger(String pID) {
|
||||
return (MOInteger) getMO(pID);
|
||||
}
|
||||
|
||||
public MODouble getMODouble(String pID) {
|
||||
return (MODouble) getMO(pID);
|
||||
}
|
||||
|
||||
public MonitoredObject getMO(String pID) {
|
||||
final MonitoredObject lMO = (MonitoredObject) fValues.get(pID);
|
||||
if (lMO == null) {
|
||||
throw new IllegalArgumentException("Unknown conf item '" + pID + "'");
|
||||
}
|
||||
|
||||
return lMO;
|
||||
}
|
||||
}
|
152
src/com/ctreber/acearth/ConfigurationACearth.java
Normal file
152
src/com/ctreber/acearth/ConfigurationACearth.java
Normal file
@ -0,0 +1,152 @@
|
||||
package com.ctreber.acearth;
|
||||
|
||||
import com.ctreber.acearth.util.Coordinate;
|
||||
import com.ctreber.aclib.gui.MOBoolean;
|
||||
import com.ctreber.aclib.gui.MODouble;
|
||||
import com.ctreber.aclib.gui.MOEnum;
|
||||
import com.ctreber.aclib.gui.MOInteger;
|
||||
import com.ctreber.aclib.gui.MOString;
|
||||
import com.ctreber.aclib.gui.MonitoredObject;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* How to avoid writing all the accessors? Code generator that creates derived
|
||||
* class from template class? Configuration items in data structure?
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com (06.10.2002)
|
||||
* </p>
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ConfigurationACearth extends Configuration {
|
||||
private static final int DEFAULT_DIMENSION = 512;
|
||||
|
||||
public ConfigurationACearth() {
|
||||
final MOEnum lProjection = new MOEnum();
|
||||
lProjection.addValidValue("Mercator");
|
||||
lProjection.addValidValue("Orthographic");
|
||||
lProjection.addValidValue("Cylindrical");
|
||||
lProjection.set("Orthographic");
|
||||
add("projection", (MonitoredObject) lProjection);
|
||||
|
||||
final MOEnum lPositionType = new MOEnum();
|
||||
lPositionType.addValidValue("Fixed");
|
||||
lPositionType.addValidValue("Sun-relative");
|
||||
lPositionType.addValidValue("Orbit");
|
||||
lPositionType.addValidValue("Random");
|
||||
lPositionType.addValidValue("Moon");
|
||||
lPositionType.set("Sun-relative");
|
||||
add("viewPositionType", lPositionType);
|
||||
|
||||
final MOEnum lViewRotationType = new MOEnum();
|
||||
lViewRotationType.addValidValue("North");
|
||||
lViewRotationType.addValidValue("Galactic");
|
||||
lViewRotationType.set("North");
|
||||
add("viewRotationType", lViewRotationType);
|
||||
|
||||
final MOString lOutputMode = new MOString("gui");
|
||||
add("outputMode", lOutputMode);
|
||||
|
||||
// Only relevant if view type is "Fixed"./
|
||||
final MODouble lViewPosLat = new MODouble(0, -90, +90);
|
||||
add("viewPosLat", lViewPosLat);
|
||||
final MODouble lViewPosLong = new MODouble(0, -180, +180);
|
||||
add("viewPosLong", lViewPosLong);
|
||||
// Only relevant if view type is "Sun-relative".
|
||||
final MODouble lSunPosRelLat = new MODouble(0, -90, +90);
|
||||
add("sunPosRelLat", lSunPosRelLat);
|
||||
final MODouble lSunPosRelLong = new MODouble(0, -180, +180);
|
||||
add("sunPosRelLong", lSunPosRelLong);
|
||||
|
||||
final MOBoolean lSunMovesP = new MOBoolean(true);
|
||||
add("sunMovesP", lSunMovesP);
|
||||
// Only relevant if sun does not move.
|
||||
final MODouble lSunPosLat = new MODouble(0, -90, +90);
|
||||
add("sunPosLat", lSunPosLat);
|
||||
final MODouble lSunPosLong = new MODouble(0, -180, +180);
|
||||
add("sunPosLong", lSunPosLong);
|
||||
|
||||
final MODouble lTimeWarpFactor = new MODouble(1.0, 0, Double.MAX_VALUE);
|
||||
add("timeWarpFactor", lTimeWarpFactor);
|
||||
final MOInteger lFixedTime = new MOInteger(0, 0, Integer.MAX_VALUE);
|
||||
add("fixedTime", lFixedTime);
|
||||
final MOInteger lWaitTime = new MOInteger(300, 0, Integer.MAX_VALUE);
|
||||
add("waitTime", lWaitTime);
|
||||
|
||||
final MODouble lOrbitPeriod = new MODouble(1, 0.0001, Double.MAX_VALUE);
|
||||
add("orbitPeriod", lOrbitPeriod);
|
||||
final MODouble lOrbitInclination = new MODouble(45.0, 0, 90);
|
||||
add("orbitInclination", lOrbitInclination);
|
||||
|
||||
final MOBoolean lLabelP = new MOBoolean(false);
|
||||
add("labelP", lLabelP);
|
||||
|
||||
final MOInteger lImageWidth = new MOInteger(DEFAULT_DIMENSION, 0, Integer.MAX_VALUE);
|
||||
add("imageWidth", lImageWidth);
|
||||
final MOInteger lImageHeight = new MOInteger(DEFAULT_DIMENSION, 0, Integer.MAX_VALUE);
|
||||
add("imageHeight", lImageHeight);
|
||||
|
||||
final MOBoolean lStarsP = new MOBoolean(true);
|
||||
add("starsP", lStarsP);
|
||||
final MODouble lStarFrequency = new MODouble(0.002, 0, Double.MAX_VALUE);
|
||||
add("starFrequency", lStarFrequency);
|
||||
final MOInteger lBigStars = new MOInteger(0, 0, 100);
|
||||
add("bigStars", lBigStars);
|
||||
|
||||
final MOBoolean lGridP = new MOBoolean(true);
|
||||
add("gridP", lGridP);
|
||||
final MOInteger lGridDivision = new MOInteger(6, 0, Integer.MAX_VALUE);
|
||||
add("gridDivision", lGridDivision);
|
||||
final MOInteger lGridPixelDevision = new MOInteger(15, 0, Integer.MAX_VALUE);
|
||||
add("gridPixelDivision", lGridPixelDevision);
|
||||
|
||||
final MOInteger lShiftX = new MOInteger(0, 0, Integer.MAX_VALUE);
|
||||
add("shiftX", lShiftX);
|
||||
final MOInteger lShiftY = new MOInteger(0, 0, Integer.MAX_VALUE);
|
||||
add("shiftY", lShiftY);
|
||||
final MODouble lViewMagnification = new MODouble(1.0, 0, Double.MAX_VALUE);
|
||||
add("viewMagnification", lViewMagnification);
|
||||
|
||||
final MOBoolean lShadeP = new MOBoolean(true);
|
||||
add("shadeP", lShadeP);
|
||||
final MOInteger lDaySideBrightness = new MOInteger(100, 0, 100);
|
||||
add("daySideBrightness", lDaySideBrightness);
|
||||
final MOInteger lNightSideBrightness = new MOInteger(5, 0, 100);
|
||||
add("nightSideBrightness", lNightSideBrightness);
|
||||
final MOInteger lTerminatorDiscontinuity = new MOInteger(1, 0, 100);
|
||||
add("terminatorDiscontinuity", lTerminatorDiscontinuity);
|
||||
|
||||
final MODouble lViewRotation = new MODouble(0, 0, Double.MAX_VALUE);
|
||||
add("viewRotation", lViewRotation);
|
||||
}
|
||||
|
||||
public Coordinate getViewPos() {
|
||||
return new Coordinate(getDouble("viewPosLat"), getDouble("viewPosLong"));
|
||||
}
|
||||
|
||||
public void setViewPos(Coordinate pViewPos) {
|
||||
setDouble("viewPosLat", pViewPos.getLat());
|
||||
setDouble("viewPosLong", pViewPos.getLong());
|
||||
}
|
||||
|
||||
public Coordinate getSunPos() {
|
||||
return new Coordinate(getDouble("sunPosLat"), getDouble("sunPosLong"));
|
||||
}
|
||||
|
||||
public void setSunPos(Coordinate pSunPos) {
|
||||
setDouble("sunPosLat", pSunPos.getLat());
|
||||
setDouble("sunPosLong", pSunPos.getLong());
|
||||
}
|
||||
|
||||
public Coordinate getSunPosRel() {
|
||||
return new Coordinate(getDouble("sunPosRelLat"), getDouble("sunPosRelLong"));
|
||||
}
|
||||
|
||||
public void setSunPosRel(Coordinate pSunPosRel) {
|
||||
setDouble("sunPosRelLat", pSunPosRel.getLat());
|
||||
setDouble("sunPosRelLong", pSunPosRel.getLong());
|
||||
}
|
||||
}
|
6835
src/com/ctreber/acearth/MapData.java
Normal file
6835
src/com/ctreber/acearth/MapData.java
Normal file
File diff suppressed because it is too large
Load Diff
110
src/com/ctreber/acearth/MapDataReader.java
Normal file
110
src/com/ctreber/acearth/MapDataReader.java
Normal file
@ -0,0 +1,110 @@
|
||||
package com.ctreber.acearth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import com.ctreber.acearth.util.Point3D;
|
||||
import com.ctreber.acearth.util.Polygon;
|
||||
|
||||
/**
|
||||
* The map data file is a big array of short (16-bit) ints, as follows: - it is
|
||||
* a sequence of closed curves - the first value in a curve is the number of
|
||||
* points in the curve - the second value in a curve indicates land/water (1 or
|
||||
* -1, respectively) - this is followed by an [x,y,z] triple that indicates a
|
||||
* point on the unit sphere (each of x, y, and z has been scaled by 30000),
|
||||
* where the x axis points "to the right" (towards 0 N 90 E), the y axis points
|
||||
* "up" (towards the north pole), and the z axis points "out of the screen"
|
||||
* (towards 0 N 0 E). this is the starting point of the curve. - this is
|
||||
* followed by (one less than the number of points in the curve) triples
|
||||
* [dx,dy,dz]; the [x,y,z] triple for each successive point in the curve is
|
||||
* obtained by adding [dx,dy,dz] onto the previous [x,y,z] values. - the curves
|
||||
* are [must be!] non-self-intersecting and traced in a counter-clockwise
|
||||
* direction
|
||||
*
|
||||
* the curves are sampled at a (roughly) a 20 mile resolution.
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class MapDataReader {
|
||||
/** Point value scale (devide value by this number). */
|
||||
private static final double MAP_DATA_SCALE = 30000.0;
|
||||
|
||||
private static List fData;
|
||||
private static List fPolygons;
|
||||
private static int fIndex;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Read map data.
|
||||
*
|
||||
* @param pFileName
|
||||
* Map data file name.
|
||||
* @return Array of map polygons.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static Polygon[] readMapData() throws IOException {
|
||||
final List lines = new MapData().getLines();
|
||||
|
||||
fData = new ArrayList();
|
||||
for (Iterator it = lines.iterator(); it.hasNext(); ) {
|
||||
String lLine = (String) it.next();
|
||||
if (lLine.indexOf("/*") != -1) {
|
||||
// Filter out comments.
|
||||
continue;
|
||||
}
|
||||
|
||||
StringTokenizer lST = new StringTokenizer(lLine, ", ");
|
||||
while (lST.hasMoreTokens()) {
|
||||
String lToken = lST.nextToken();
|
||||
final Integer lValue = new Integer(lToken);
|
||||
fData.add(lValue);
|
||||
}
|
||||
}
|
||||
|
||||
fPolygons = new ArrayList();
|
||||
fIndex = 0;
|
||||
while (getValue(fIndex) != 0) {
|
||||
processCurve();
|
||||
}
|
||||
|
||||
return (Polygon[]) fPolygons.toArray(new Polygon[0]);
|
||||
}
|
||||
|
||||
private static void processCurve() {
|
||||
final int lNPoint = getValue(fIndex++);
|
||||
final int lType = getValue(fIndex++);
|
||||
|
||||
final Point3D[] lPoints = new Point3D[lNPoint];
|
||||
final Point3D lPoint3D = new Point3D(getValue(fIndex++) / MAP_DATA_SCALE, getValue(fIndex++) / MAP_DATA_SCALE,
|
||||
getValue(fIndex++) / MAP_DATA_SCALE);
|
||||
|
||||
lPoints[0] = lPoint3D;
|
||||
for (int i = 1; i < lNPoint; i++) {
|
||||
lPoints[i] = new Point3D(lPoints[i - 1].getX() + getValue(fIndex++) / MAP_DATA_SCALE, lPoints[i - 1].getY()
|
||||
+ getValue(fIndex++) / MAP_DATA_SCALE, lPoints[i - 1].getZ() + getValue(fIndex++) / MAP_DATA_SCALE);
|
||||
}
|
||||
|
||||
final Polygon lPolygon = new Polygon(lType, lPoints);
|
||||
fPolygons.add(lPolygon);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Get value of raw data at specified point.
|
||||
*
|
||||
* @param pIndex
|
||||
* Index of value.
|
||||
* @return Value of raw data at specified point.
|
||||
*/
|
||||
private static int getValue(int pIndex) {
|
||||
return ((Integer) fData.get(pIndex)).intValue();
|
||||
}
|
||||
|
||||
}
|
21
src/com/ctreber/acearth/gui/CanvasACearth.java
Normal file
21
src/com/ctreber/acearth/gui/CanvasACearth.java
Normal file
@ -0,0 +1,21 @@
|
||||
package com.ctreber.acearth.gui;
|
||||
|
||||
import com.ctreber.acearth.ACearth;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Adds some mouse magic to the normal PixelCanvas.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com (Nov 8, 2002)
|
||||
* </p>
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class CanvasACearth extends PixelCanvas {
|
||||
public CanvasACearth(ACearth pParent, int pWidth, int pHeight) {
|
||||
super(pWidth, pHeight);
|
||||
}
|
||||
}
|
72
src/com/ctreber/acearth/gui/PixelCanvas.java
Normal file
72
src/com/ctreber/acearth/gui/PixelCanvas.java
Normal file
@ -0,0 +1,72 @@
|
||||
package com.ctreber.acearth.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.ctreber.acearth.renderer.RenderTarget;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Swing compatible drawing surface for images and graphics.
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class PixelCanvas implements RenderTarget {
|
||||
final private int fImageWidth;
|
||||
final private int fImageHeight;
|
||||
final private BufferedImage fEarthImage2;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Construct a canvas of the specified size.
|
||||
*
|
||||
* @param pWidth
|
||||
* Width
|
||||
* @param pHeight
|
||||
* Height
|
||||
*/
|
||||
public PixelCanvas(int pWidth, int pHeight) {
|
||||
fImageWidth = pWidth;
|
||||
fImageHeight = pHeight;
|
||||
fEarthImage2 = new BufferedImage(fImageWidth, fImageHeight, BufferedImage.TYPE_INT_RGB);
|
||||
}
|
||||
|
||||
public Graphics2D getGraphics2D() {
|
||||
return fEarthImage2.createGraphics();
|
||||
}
|
||||
|
||||
public void setPixel(int pX, int pY, int pA, int pR, int pG, int pB) {
|
||||
setPixel(pX, pY, new Color(pR, pG, pB, pA));
|
||||
}
|
||||
|
||||
public void setPixel(int pX, int pY, Color pColor) {
|
||||
fEarthImage2.setRGB(pX, pY, pColor.getRGB());
|
||||
}
|
||||
|
||||
public int getImageWidth() {
|
||||
return fImageWidth;
|
||||
}
|
||||
|
||||
public int getImageHeight() {
|
||||
return fImageHeight;
|
||||
}
|
||||
|
||||
public boolean saveToImage(String pFileName, String pFormat) throws IOException {
|
||||
return ImageIO.write(fEarthImage2, pFormat, new File(pFileName));
|
||||
}
|
||||
|
||||
public void saveToImage(OutputStream os) throws IOException {
|
||||
ImageIO.write(fEarthImage2, "png", os);
|
||||
}
|
||||
|
||||
}
|
46
src/com/ctreber/acearth/plugins/Plugin.java
Normal file
46
src/com/ctreber/acearth/plugins/Plugin.java
Normal file
@ -0,0 +1,46 @@
|
||||
package com.ctreber.acearth.plugins;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import com.ctreber.acearth.ACearth;
|
||||
import com.ctreber.acearth.gui.PixelCanvas;
|
||||
import com.ctreber.acearth.projection.Projection;
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 6, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
abstract public class Plugin implements ActionListener
|
||||
{
|
||||
protected ACearth fParent;
|
||||
protected boolean fActiveP = true;
|
||||
protected Projection fProjection;
|
||||
protected PixelCanvas fRenderTarget;
|
||||
|
||||
public void actionPerformed(ActionEvent e)
|
||||
{
|
||||
}
|
||||
|
||||
abstract public boolean hasGUIP();
|
||||
|
||||
abstract public void render();
|
||||
|
||||
public void setProjection(Projection pProjection)
|
||||
{
|
||||
fProjection = pProjection;
|
||||
}
|
||||
|
||||
public void setRenderTarget(PixelCanvas pRenderTarget)
|
||||
{
|
||||
fRenderTarget = pRenderTarget;
|
||||
}
|
||||
|
||||
public void setParent(ACearth pParent)
|
||||
{
|
||||
fParent = pParent;
|
||||
}
|
||||
}
|
191
src/com/ctreber/acearth/plugins/markers/Marker.java
Normal file
191
src/com/ctreber/acearth/plugins/markers/Marker.java
Normal file
@ -0,0 +1,191 @@
|
||||
package com.ctreber.acearth.plugins.markers;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.ctreber.acearth.gui.PixelCanvas;
|
||||
import com.ctreber.acearth.projection.Projection;
|
||||
import com.ctreber.acearth.projection.ProjectionOrtho;
|
||||
import com.ctreber.acearth.util.Coordinate;
|
||||
import com.ctreber.acearth.util.Point2D;
|
||||
import com.ctreber.acearth.util.Point3D;
|
||||
import com.ctreber.acearth.util.StringParser;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Marks a location on the globe.
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class Marker {
|
||||
private static final int MARKER_SIZE = 4;
|
||||
|
||||
// types of marker label alignment
|
||||
private static final int MarkerAlignDefault = 0;
|
||||
private static final int MarkerAlignLeft = 1;
|
||||
private static final int MarkerAlignRight = 2;
|
||||
private static final int MarkerAlignAbove = 3;
|
||||
private static final int MarkerAlignBelow = 4;
|
||||
|
||||
private Marker(Coordinate pCoordinate, String pLabel, int pAlign) {
|
||||
fCoordinate = pCoordinate;
|
||||
fLabel = pLabel;
|
||||
fAlign = pAlign;
|
||||
}
|
||||
|
||||
private Coordinate fCoordinate;
|
||||
private String fLabel;
|
||||
private int fAlign;
|
||||
|
||||
// private static List fMarkers;
|
||||
|
||||
/*
|
||||
* builtin_marker_data[] contains the "built-in" marker data that is
|
||||
* compiled into AC.earth. (My apologies for misspellings, omissions of your
|
||||
* favorite location, or geographic inaccuracies. This is primarily just a
|
||||
* pile of data that I had handy instead of an attempt to provide a sample
|
||||
* that is "globally correct" in some sense.)
|
||||
*/
|
||||
// public static List loadMarkerFile(String pFileName) throws IOException {
|
||||
// fMarkers = new ArrayList();
|
||||
//
|
||||
// final LineNumberReader lReader = new LineNumberReader(new
|
||||
// FileReader(pFileName));
|
||||
// String lLine;
|
||||
// while ((lLine = lReader.readLine()) != null) {
|
||||
// processLine(lLine);
|
||||
// }
|
||||
//
|
||||
// lReader.close();
|
||||
//
|
||||
// return fMarkers;
|
||||
// }
|
||||
//
|
||||
// private static void processLine(String pLine) {
|
||||
// final int lPos = pLine.indexOf('#');
|
||||
// if (lPos != -1) {
|
||||
// // Remove comment
|
||||
// pLine = pLine.substring(0, lPos);
|
||||
// }
|
||||
//
|
||||
// final Marker lMarkerInfo = createFromLine(pLine);
|
||||
// if (lMarkerInfo != null) {
|
||||
// fMarkers.add(lMarkerInfo);
|
||||
// }
|
||||
// }
|
||||
private static Marker createFromLine(String pLine) {
|
||||
final List lWords = StringParser.parse(pLine);
|
||||
|
||||
final double lLat = Double.parseDouble((String) lWords.get(0));
|
||||
final double lLong = Double.parseDouble((String) lWords.get(1));
|
||||
final String lLabel = (String) lWords.get(2);
|
||||
|
||||
int lAlign = MarkerAlignDefault;
|
||||
if (lWords.size() >= 4) {
|
||||
String lAlignString = (String) lWords.get(3);
|
||||
if (lAlignString.equalsIgnoreCase("left")) {
|
||||
lAlign = MarkerAlignLeft;
|
||||
}
|
||||
if (lAlignString.equalsIgnoreCase("right")) {
|
||||
lAlign = MarkerAlignRight;
|
||||
}
|
||||
if (lAlignString.equalsIgnoreCase("above")) {
|
||||
lAlign = MarkerAlignAbove;
|
||||
}
|
||||
if (lAlignString.equalsIgnoreCase("below")) {
|
||||
lAlign = MarkerAlignBelow;
|
||||
}
|
||||
}
|
||||
|
||||
final Coordinate lPos = new Coordinate(lLat, lLong);
|
||||
if (!lPos.check()) {
|
||||
// ACearth.logError("latitude must be between -90 and 90, and
|
||||
// longitude must be between -180 and 180");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Marker(lPos, lLabel, lAlign);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return fLabel + " (" + fCoordinate + "), align: " + fAlign;
|
||||
}
|
||||
|
||||
// --Recycle Bin START (10/28/02 2:24 PM):
|
||||
// public String getLabel()
|
||||
// {
|
||||
// return fLabel;
|
||||
// }
|
||||
// --Recycle Bin STOP (10/28/02 2:24 PM)
|
||||
|
||||
// --Recycle Bin START (10/28/02 2:24 PM):
|
||||
// public int getAlign()
|
||||
// {
|
||||
// return fAlign;
|
||||
// }
|
||||
// --Recycle Bin STOP (10/28/02 2:24 PM)
|
||||
|
||||
// --Recycle Bin START (10/28/02 2:24 PM):
|
||||
// public Coordinate getLocation()
|
||||
// {
|
||||
// return fCoordinate;
|
||||
// }
|
||||
// --Recycle Bin STOP (10/28/02 2:24 PM)
|
||||
|
||||
public void render(PixelCanvas pCanvas, Projection pProjection) {
|
||||
final Point3D lPos = pProjection.rotate(fCoordinate.getPoint3D());
|
||||
|
||||
if ((pProjection instanceof ProjectionOrtho) && (lPos.getZ() <= 0)) {
|
||||
// Back side of the Earth.
|
||||
// Insight: We don't need to check if the marker is visible in other
|
||||
// projections because they always show the whole earth - and all
|
||||
// markers!
|
||||
return;
|
||||
}
|
||||
|
||||
Point2D lPoint = pProjection.finalize(pProjection.project2D(lPos));
|
||||
final int lX = (int) lPoint.getX();
|
||||
final int lY = (int) lPoint.getY();
|
||||
|
||||
// Draw a circle
|
||||
Graphics2D g2d = pCanvas.getGraphics2D();
|
||||
g2d.setColor(Color.red);
|
||||
// pCanvas.drawCircle(lX, lY, MARKER_SIZE);
|
||||
g2d.drawOval(lX, lY, MARKER_SIZE, MARKER_SIZE);
|
||||
|
||||
if (fLabel != null) {
|
||||
switch (fAlign) {
|
||||
case Marker.MarkerAlignLeft:
|
||||
break;
|
||||
|
||||
case Marker.MarkerAlignRight:
|
||||
case Marker.MarkerAlignDefault:
|
||||
// pCanvas.drawText(lX + MARKER_SIZE, lY + 4, fLabel);
|
||||
// fRenderTarget.setTextFont(fRenderTarget.getTextFont().deriveFont(9.0f));
|
||||
g2d.setFont(new Font("", Font.PLAIN, 9));
|
||||
g2d.drawString(fLabel, lX + MARKER_SIZE + 1, lY + 2);
|
||||
break;
|
||||
|
||||
case Marker.MarkerAlignAbove:
|
||||
break;
|
||||
|
||||
case Marker.MarkerAlignBelow:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Marker loadMarkerFile(String line) {
|
||||
return createFromLine(line);
|
||||
}
|
||||
}
|
74
src/com/ctreber/acearth/plugins/markers/PluginMarkers.java
Normal file
74
src/com/ctreber/acearth/plugins/markers/PluginMarkers.java
Normal file
@ -0,0 +1,74 @@
|
||||
package com.ctreber.acearth.plugins.markers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.ctreber.acearth.ACearth;
|
||||
import com.ctreber.acearth.plugins.Plugin;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Renders markers to the render target. a
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class PluginMarkers extends Plugin {
|
||||
private List fMarkers;
|
||||
|
||||
// private String fMarkerFileName = ACearth.getHomeDir() +
|
||||
// "markersDefault.txt";
|
||||
|
||||
public PluginMarkers(List<Marker> markers) {
|
||||
// ACearth.indent("AC.earth Markers plug-in");
|
||||
//
|
||||
// ACearth.log("Reading markers");
|
||||
//
|
||||
// if(fMarkerFileName == null)
|
||||
// {
|
||||
// throw new RuntimeException("Marker file name not set");
|
||||
// }
|
||||
|
||||
// try
|
||||
// {
|
||||
// fMarkers = Marker.loadMarkerFile(fMarkerFileName);
|
||||
// } catch(IOException e)
|
||||
// {
|
||||
// ACearth.logError("Marker file not found");
|
||||
// return;
|
||||
// }
|
||||
|
||||
fMarkers = markers;
|
||||
|
||||
// ACearth.outdent();
|
||||
}
|
||||
|
||||
public boolean hasGUIP() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if (!fActiveP) {
|
||||
return;
|
||||
}
|
||||
|
||||
// fRenderTarget.setTextFont(fRenderTarget.getTextFont().deriveFont(9.0f));
|
||||
Iterator lIt = fMarkers.iterator();
|
||||
while (lIt.hasNext()) {
|
||||
Marker lMarker = (Marker) lIt.next();
|
||||
lMarker.render(fRenderTarget, fProjection);
|
||||
}
|
||||
}
|
||||
|
||||
// public void setMarkerFileName(String pMarkerFileName)
|
||||
// {
|
||||
// fMarkerFileName = pMarkerFileName;
|
||||
// }
|
||||
|
||||
public String toString() {
|
||||
return "AC.earth Markers plug-in";
|
||||
}
|
||||
}
|
271
src/com/ctreber/acearth/projection/Projection.java
Normal file
271
src/com/ctreber/acearth/projection/Projection.java
Normal file
@ -0,0 +1,271 @@
|
||||
package com.ctreber.acearth.projection;
|
||||
|
||||
import com.ctreber.acearth.util.*;
|
||||
|
||||
/**
|
||||
* <p>A projection for a globe on a flat surface (must be subclassed).
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
abstract public class Projection
|
||||
{
|
||||
// Target information
|
||||
int fImageHeight;
|
||||
int fImageWidth;
|
||||
private double fXOffset;
|
||||
private double fYOffset;
|
||||
|
||||
//Viewing information
|
||||
private int fShiftX;
|
||||
private int fShiftY;
|
||||
double fScale;
|
||||
|
||||
private Coordinate fViewPos;
|
||||
/** <p>In rads */
|
||||
private double fViewRotation;
|
||||
double fViewMagnification;
|
||||
|
||||
|
||||
//Transformation matrix parameters */
|
||||
private double fCosLat;
|
||||
private double fSinLat;
|
||||
private double fCosLon;
|
||||
private double fSinLon;
|
||||
private double fCosRot;
|
||||
private double fSinRot;
|
||||
|
||||
/**
|
||||
* <p>Initialize transform parameters, set offset to center of image
|
||||
* (plus shifts), set scale
|
||||
*/
|
||||
public void initTransformTable()
|
||||
{
|
||||
// Set transformation parameters
|
||||
fCosLat = Math.cos(Toolkit.degsToRads(fViewPos.getLat()));
|
||||
fSinLat = Math.sin(Toolkit.degsToRads(fViewPos.getLat()));
|
||||
fCosLon = Math.cos(Toolkit.degsToRads(fViewPos.getLong()));
|
||||
fSinLon = Math.sin(Toolkit.degsToRads(fViewPos.getLong()));
|
||||
fCosRot = Math.cos(Toolkit.degsToRads(fViewRotation));
|
||||
fSinRot = Math.sin(Toolkit.degsToRads(fViewRotation));
|
||||
|
||||
fXOffset = (double)fImageWidth / 2 + fShiftX;
|
||||
fYOffset = (double)fImageHeight / 2 + fShiftY;
|
||||
|
||||
setScale();
|
||||
}
|
||||
|
||||
abstract protected void setScale();
|
||||
|
||||
/**
|
||||
* <p>Project 3D point on y axis.
|
||||
*/
|
||||
abstract public double projectY(double pY);
|
||||
|
||||
abstract public double inverseProjectY(double pY);
|
||||
|
||||
/**
|
||||
* <p>Project 3D point on x axis.
|
||||
*/
|
||||
abstract protected double projectX(double pX, double pZ);
|
||||
|
||||
abstract public double inverseProjectX(double pX);
|
||||
|
||||
public abstract boolean isVisible(Point3D pPoint);
|
||||
|
||||
public boolean isWithinImage(Point2D pPoint)
|
||||
{
|
||||
return (pPoint.getX() >= 0) && (pPoint.getX() < fImageWidth) &&
|
||||
(pPoint.getY() >= 0) && (pPoint.getY() < fImageHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Translate screen point into coordinate on Earth.
|
||||
*
|
||||
* @param pX
|
||||
* @param pY
|
||||
* @return
|
||||
*/
|
||||
abstract public Coordinate getLocation(int pX, int pY);
|
||||
|
||||
/**
|
||||
* <p>Imagine view the globe, N is up, S is down, and N0E0 is in the center.
|
||||
* x is right/left, y is up/down, and z is front/rear.
|
||||
*
|
||||
* <p>Map points are located on the surface of a unit sphere (diameter = 1).
|
||||
* Latitude is the angle between x and y or z and y. Longitude is the angle
|
||||
* between x and z.
|
||||
*
|
||||
* <p>Why? The way we choose our global coordinate system, longitude circles
|
||||
* (latidude variable) always have the same size while the size of
|
||||
* latidude circles (longitude variable) depends on the latitude.
|
||||
*
|
||||
* @param pPoint
|
||||
* @return
|
||||
*/
|
||||
public Point2D project2D(Point3D pPoint)
|
||||
{
|
||||
return new Point2D(projectX(pPoint.getX(), pPoint.getZ()),
|
||||
projectY(pPoint.getY()));
|
||||
}
|
||||
|
||||
public Point2D finalize(Point2D pPoint)
|
||||
{
|
||||
return new Point2D(finalizeX(pPoint.getX()), finalizeY(pPoint.getY()));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Since the final mapping is relative to the center of the image
|
||||
* -PI and PI get mapped to the left and right border respectively.
|
||||
* But see ProjectionOrtho.setScale().
|
||||
*/
|
||||
public double finalizeX(double pX)
|
||||
{
|
||||
return fXOffset + fScale * pX;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Since the final mapping is relative to the center of the image
|
||||
* -PI and PI get mapped to the bottom and top border respectively.
|
||||
* But see ProjectionOrtho.setScale().
|
||||
*/
|
||||
public double finalizeY(double pY)
|
||||
{
|
||||
return fYOffset - fScale * pY;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Transform screen to image coordinates.
|
||||
*/
|
||||
public double inverseFinalizeX(double x)
|
||||
{
|
||||
return (x - fXOffset) / fScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Transform screen to image coordinates.
|
||||
*/
|
||||
public double inverseFinalizeY(double y)
|
||||
{
|
||||
return (fYOffset - y) / fScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Rotate the point according to the current rotation of Earth.
|
||||
*/
|
||||
public Point3D rotate(Point3D pPoint)
|
||||
{
|
||||
double lX = pPoint.getX();
|
||||
double lY = pPoint.getY();
|
||||
double lZ = pPoint.getZ();
|
||||
|
||||
// Do NOT inline vars - it does not work (just inline _t_ for a try).
|
||||
double _c_ = fCosLon;
|
||||
double _s_ = fSinLon;
|
||||
double _t_ = _c_ * lX - _s_ * lZ;
|
||||
lZ = _s_ * lX + _c_ * lZ;
|
||||
lX = _t_;
|
||||
|
||||
_c_ = fCosLat;
|
||||
_s_ = fSinLat;
|
||||
_t_ = (_c_ * lY) - (_s_ * lZ);
|
||||
lZ = (_s_ * lY) + (_c_ * lZ);
|
||||
lY = _t_;
|
||||
|
||||
_c_ = fCosRot;
|
||||
_s_ = fSinRot;
|
||||
_t_ = (_c_ * lX) - (_s_ * lY);
|
||||
lY = (_s_ * lX) + (_c_ * lY);
|
||||
lX = _t_;
|
||||
|
||||
return new Point3D(lX, lY, lZ);
|
||||
}
|
||||
|
||||
public Point3D rotateReverse(Point3D pPoint)
|
||||
{
|
||||
// Set transformation parameters
|
||||
final double fCosLat = Math.cos(Toolkit.degsToRads(-fViewPos.getLat()));
|
||||
final double fSinLat = Math.sin(Toolkit.degsToRads(-fViewPos.getLat()));
|
||||
final double fCosLon = Math.cos(Toolkit.degsToRads(-fViewPos.getLong()));
|
||||
final double fSinLon = Math.sin(Toolkit.degsToRads(-fViewPos.getLong()));
|
||||
final double fCosRot = Math.cos(Toolkit.degsToRads(-fViewRotation));
|
||||
final double fSinRot = Math.sin(Toolkit.degsToRads(-fViewRotation));
|
||||
|
||||
double lX = pPoint.getX();
|
||||
double lY = pPoint.getY();
|
||||
double lZ = pPoint.getZ();
|
||||
|
||||
// Do NOT inline vars - it does not work (just inline lTmp for a try).
|
||||
double lCosFac;
|
||||
double lSinFac;
|
||||
double lTmp;
|
||||
|
||||
// Note that the order of the three rotation had to be reversed as well.
|
||||
lCosFac = fCosRot;
|
||||
lSinFac = fSinRot;
|
||||
lTmp = (lCosFac * lX) - (lSinFac * lY);
|
||||
lY = (lSinFac * lX) + (lCosFac * lY);
|
||||
lX = lTmp;
|
||||
|
||||
lCosFac = fCosLat;
|
||||
lSinFac = fSinLat;
|
||||
lTmp = (lCosFac * lY) - (lSinFac * lZ);
|
||||
lZ = (lSinFac * lY) + (lCosFac * lZ);
|
||||
lY = lTmp;
|
||||
|
||||
lCosFac = fCosLon;
|
||||
lSinFac = fSinLon;
|
||||
lTmp = (lCosFac * lX) - (lSinFac * lZ);
|
||||
lZ = (lSinFac * lX) + (lCosFac * lZ);
|
||||
lX = lTmp;
|
||||
|
||||
return new Point3D(lX, lY, lZ);
|
||||
}
|
||||
|
||||
public double getScale()
|
||||
{
|
||||
return fScale;
|
||||
}
|
||||
|
||||
public Coordinate getViewPos()
|
||||
{
|
||||
return fViewPos;
|
||||
}
|
||||
|
||||
public void setViewMagnification(double pViewMagnification)
|
||||
{
|
||||
fViewMagnification = pViewMagnification;
|
||||
setScale();
|
||||
}
|
||||
|
||||
public void setViewPos(Coordinate pViewPos)
|
||||
{
|
||||
fViewPos = pViewPos;
|
||||
}
|
||||
|
||||
public void setShiftX(int pX)
|
||||
{
|
||||
fShiftX = pX;
|
||||
}
|
||||
|
||||
public void setShiftY(int pY)
|
||||
{
|
||||
fShiftY = pY;
|
||||
}
|
||||
|
||||
public void setViewRotation(double pViewRotation)
|
||||
{
|
||||
fViewRotation = pViewRotation;
|
||||
}
|
||||
|
||||
public void setImageWidth(int pImageWidth)
|
||||
{
|
||||
fImageWidth = pImageWidth;
|
||||
}
|
||||
|
||||
public void setImageHeight(int pImageHeight)
|
||||
{
|
||||
fImageHeight = pImageHeight;
|
||||
}
|
||||
}
|
72
src/com/ctreber/acearth/projection/ProjectionCyl.java
Normal file
72
src/com/ctreber/acearth/projection/ProjectionCyl.java
Normal file
@ -0,0 +1,72 @@
|
||||
package com.ctreber.acearth.projection;
|
||||
|
||||
import com.ctreber.acearth.util.Coordinate;
|
||||
import com.ctreber.acearth.util.Point3D;
|
||||
|
||||
/**
|
||||
* <p>Cylindrical projection. Show Earth flatly spread out on rectangle.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ProjectionCyl extends Projection
|
||||
{
|
||||
/**
|
||||
* <p>All of Earth is visible.
|
||||
*
|
||||
* @param pPoint
|
||||
* @return
|
||||
*/
|
||||
public boolean isVisible(Point3D pPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public Coordinate getLocation(int pX, int pY)
|
||||
{
|
||||
final Coordinate lRaw = new Coordinate(Math.atan(inverseFinalizeY(pY)),
|
||||
inverseFinalizeX(pX));
|
||||
|
||||
return rotateReverse(lRaw.getPoint3DRads()).getCoordinate();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The scale is set so that a value of
|
||||
* 2PI gets mapped to the full image width times the magnification.
|
||||
* But see ProjectionOrtho.setScale().
|
||||
*/
|
||||
protected void setScale()
|
||||
{
|
||||
// Makes 2PI come out as full image width
|
||||
fScale = fViewMagnification * fImageWidth / (2 * Math.PI);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Longitude (-PI to PI), linearly on x axis.
|
||||
*/
|
||||
public double projectX(double pX, double pZ)
|
||||
{
|
||||
return Math.atan2(pX, pZ);
|
||||
}
|
||||
|
||||
public double inverseProjectX(double pX)
|
||||
{
|
||||
return Math.sin(pX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Latitude (-PI/2 to PI/2), projected from center of Earth on
|
||||
* y axis with a linear scale.
|
||||
*/
|
||||
public double projectY(double pY)
|
||||
{
|
||||
return (pY >= 0.9999999999) ? 1e6 :
|
||||
(pY <= -0.9999999999) ? -1e6 : Math.tan(Math.asin(pY));
|
||||
}
|
||||
|
||||
public double inverseProjectY(double y)
|
||||
{
|
||||
return Math.sin(Math.atan(y));
|
||||
}
|
||||
}
|
75
src/com/ctreber/acearth/projection/ProjectionMerc.java
Normal file
75
src/com/ctreber/acearth/projection/ProjectionMerc.java
Normal file
@ -0,0 +1,75 @@
|
||||
package com.ctreber.acearth.projection;
|
||||
|
||||
import com.ctreber.acearth.util.Coordinate;
|
||||
import com.ctreber.acearth.util.Point3D;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Mercator projection. Show Earth flatly spread out on rectangle.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ProjectionMerc extends Projection
|
||||
{
|
||||
/**
|
||||
* <p>All of Earth is visible.
|
||||
*
|
||||
* @param pPoint
|
||||
* @return
|
||||
*/
|
||||
public boolean isVisible(Point3D pPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public Coordinate getLocation(int pX, int pY)
|
||||
{
|
||||
final Coordinate lRaw = new Coordinate(
|
||||
2 * (Math.atan(Math.exp(inverseFinalizeY(pY))) - Math.PI / 4),
|
||||
inverseFinalizeX(pX));
|
||||
|
||||
return rotateReverse(lRaw.getPoint3DRads()).getCoordinate();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The scale is set so that a value of
|
||||
* 2PI gets mapped to the full image width times the magnification.
|
||||
* But see ProjectionOrtho.setScale().
|
||||
*/
|
||||
protected void setScale()
|
||||
{
|
||||
// Makes 2PI come out as full image width
|
||||
fScale = fViewMagnification * fImageWidth / (2 * Math.PI);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Longitude (-PI to PI), linearly on x axis.
|
||||
*/
|
||||
public double projectX(double pX, double pZ)
|
||||
{
|
||||
return Math.atan2(pX, pZ);
|
||||
}
|
||||
|
||||
public double inverseProjectX(double pX)
|
||||
{
|
||||
return Math.sin(pX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Latitude (-PI/2 to PI/2), projected from center of Earth on
|
||||
* y axis with a twist and a log scale.
|
||||
*/
|
||||
public double projectY(double pY)
|
||||
{
|
||||
return (pY >= 0.9999999999) ? 1e6
|
||||
: (pY <= -0.9999999999) ? -1e6
|
||||
: Math.log(Math.tan(Math.asin(pY) / 2 + Math.PI / 4));
|
||||
}
|
||||
|
||||
public double inverseProjectY(double y)
|
||||
{
|
||||
return Math.sin(2 * (Math.atan(Math.exp(y)) - Math.PI / 4));
|
||||
}
|
||||
}
|
71
src/com/ctreber/acearth/projection/ProjectionOrtho.java
Normal file
71
src/com/ctreber/acearth/projection/ProjectionOrtho.java
Normal file
@ -0,0 +1,71 @@
|
||||
package com.ctreber.acearth.projection;
|
||||
|
||||
import com.ctreber.acearth.util.Coordinate;
|
||||
import com.ctreber.acearth.util.Point3D;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Orthographic projection (show Earth as a ball).
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ProjectionOrtho extends Projection
|
||||
{
|
||||
/**
|
||||
* <p>All of Earth is visible.
|
||||
*
|
||||
* @param pPoint
|
||||
* @return
|
||||
*/
|
||||
public boolean isVisible(Point3D pPoint)
|
||||
{
|
||||
return pPoint.getZ() >= 0;
|
||||
}
|
||||
|
||||
public Coordinate getLocation(int pX, int pY)
|
||||
{
|
||||
final double lX = inverseFinalizeX(pX);
|
||||
final double lY = inverseFinalizeY(pY);
|
||||
final double lZ = Math.sqrt(1 - lX * lX - lY * lY);
|
||||
final Point3D lP = new Point3D(lX, lY, lZ);
|
||||
|
||||
return rotateReverse(lP).getCoordinate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Longitude, not in rad but from -1 to 1.
|
||||
*/
|
||||
public double projectX(double pX, double pZ)
|
||||
{
|
||||
return pX;
|
||||
}
|
||||
|
||||
public double inverseProjectX(double pX)
|
||||
{
|
||||
return pX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Latitude, not in rad but from -1 to 1.
|
||||
*/
|
||||
public double projectY(double pY)
|
||||
{
|
||||
return pY;
|
||||
}
|
||||
|
||||
public double inverseProjectY(double pY)
|
||||
{
|
||||
return pY;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The scale is not from -PI to PI but from -1 to 1 in this case
|
||||
* (the range of x, y, z of the points).
|
||||
*/
|
||||
protected void setScale()
|
||||
{
|
||||
fScale = Math.min(fImageHeight, fImageWidth) * fViewMagnification * 0.99 / 2;
|
||||
}
|
||||
}
|
24
src/com/ctreber/acearth/renderer/RenderTarget.java
Normal file
24
src/com/ctreber/acearth/renderer/RenderTarget.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.ctreber.acearth.renderer;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* <p>.
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public interface RenderTarget {
|
||||
|
||||
public void setPixel(int pX, int pY, int pA, int pR, int pG, int pB);
|
||||
|
||||
public void setPixel(int pX, int pY, Color pColor);
|
||||
|
||||
public int getImageWidth();
|
||||
|
||||
public int getImageHeight();
|
||||
|
||||
}
|
91
src/com/ctreber/acearth/renderer/Renderer.java
Normal file
91
src/com/ctreber/acearth/renderer/Renderer.java
Normal file
@ -0,0 +1,91 @@
|
||||
package com.ctreber.acearth.renderer;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import com.ctreber.acearth.shader.Shader;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Uses defined RowTypeRenderers and Shader to render to render target.
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class Renderer {
|
||||
private Shader fShader;
|
||||
private RenderTarget fRenderTarget;
|
||||
private List fRowTypeRenderers = new ArrayList();
|
||||
|
||||
public Renderer(RenderTarget pRenderTarget) {
|
||||
fRenderTarget = pRenderTarget;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
final Iterator lIt = fRowTypeRenderers.iterator();
|
||||
while (lIt.hasNext()) {
|
||||
RowTypeRenderer lRowRenderer = (RowTypeRenderer) lIt.next();
|
||||
lRowRenderer.startNewRun();
|
||||
}
|
||||
renderRows();
|
||||
}
|
||||
|
||||
private void renderRows() {
|
||||
for (int lRowNo = 0; lRowNo < fRenderTarget.getImageHeight(); lRowNo++) {
|
||||
int[] lPixelTypes = getPixelTypes(lRowNo);
|
||||
renderRow(lRowNo, lPixelTypes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Get pixel types for whole row from all registered RowRenderers.
|
||||
*
|
||||
* @param pRowNo
|
||||
* Row number.
|
||||
* @return Pixel types for row.
|
||||
*/
|
||||
private int[] getPixelTypes(int pRowNo) {
|
||||
// Create the types array
|
||||
final int[] lPixelTypes = new int[fRenderTarget.getImageWidth()];
|
||||
|
||||
final Iterator lIt = fRowTypeRenderers.iterator();
|
||||
while (lIt.hasNext()) {
|
||||
RowTypeRenderer lRowRenderer = (RowTypeRenderer) lIt.next();
|
||||
lRowRenderer.getPixelTypes(pRowNo, lPixelTypes);
|
||||
}
|
||||
|
||||
return lPixelTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* With help of Shader, render pixel types to actual colored pixels.
|
||||
*
|
||||
* @param pRowNo
|
||||
* @param pPixelTypes
|
||||
*/
|
||||
private void renderRow(int pRowNo, int[] pPixelTypes) {
|
||||
// For each pixel in row, render it.
|
||||
final Color[] lPixelColors = fShader.getShadedColors(pRowNo, pPixelTypes);
|
||||
for (int lColNo = 0; lColNo < fRenderTarget.getImageWidth(); lColNo++) {
|
||||
fRenderTarget.setPixel(lColNo, pRowNo, lPixelColors[lColNo]);
|
||||
}
|
||||
}
|
||||
|
||||
public void setShader(Shader pShader) {
|
||||
fShader = pShader;
|
||||
}
|
||||
|
||||
public void setRenderTarget(RenderTarget pRenderTarget) {
|
||||
fRenderTarget = pRenderTarget;
|
||||
}
|
||||
|
||||
public void addRowTypeRenderer(RowTypeRenderer pRowRenderer) {
|
||||
fRowTypeRenderers.add(pRowRenderer);
|
||||
}
|
||||
}
|
26
src/com/ctreber/acearth/renderer/RowTypeRenderer.java
Normal file
26
src/com/ctreber/acearth/renderer/RowTypeRenderer.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.ctreber.acearth.renderer;
|
||||
|
||||
/**
|
||||
* <p>Renders a row of pixel types.</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public interface RowTypeRenderer
|
||||
{
|
||||
/**
|
||||
* <p>Each time when rendering an image, call startNewRun() first.
|
||||
*/
|
||||
public void startNewRun();
|
||||
|
||||
/**
|
||||
* <p>Set pixel type for specified row number. Note some pixel types
|
||||
* might be already set. The renderer can build on this information
|
||||
* or overwrite it.
|
||||
*
|
||||
* @param pRowNo
|
||||
* @param pPixelTypes
|
||||
*/
|
||||
public void getPixelTypes(int pRowNo, final int[] pPixelTypes);
|
||||
}
|
82
src/com/ctreber/acearth/renderer/RowTypeRendererScanBit.java
Normal file
82
src/com/ctreber/acearth/renderer/RowTypeRendererScanBit.java
Normal file
@ -0,0 +1,82 @@
|
||||
package com.ctreber.acearth.renderer;
|
||||
|
||||
import com.ctreber.acearth.scanbit.ScanBit;
|
||||
import com.ctreber.acearth.scanbit.BitGeneratorMap;
|
||||
|
||||
/**
|
||||
* <p>Renders a row of ScanBits to pixel types.</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class RowTypeRendererScanBit implements RowTypeRenderer
|
||||
{
|
||||
private int fScanBitIndex;
|
||||
private ScanBit[] fScanBits;
|
||||
private final int[] fScanToPixelType = new int[256];
|
||||
|
||||
public void startNewRun()
|
||||
{
|
||||
fScanBitIndex = 0;
|
||||
generateScanToPixelTypeTable();
|
||||
}
|
||||
|
||||
public void getPixelTypes(int pRowNo, int[] pPixelTypes)
|
||||
{
|
||||
// For all ScanBits in specified row...
|
||||
while((fScanBitIndex < fScanBits.length) &&
|
||||
(fScanBits[fScanBitIndex].getY() == pRowNo))
|
||||
{
|
||||
for(int i = fScanBits[fScanBitIndex].getlXFrom();
|
||||
i <= fScanBits[fScanBitIndex].getXTo(); i++)
|
||||
{
|
||||
/**
|
||||
* This is weird... why summing up the types? Note the row stays the
|
||||
* same, but it possibly gets paved over a couple of times (There
|
||||
* might be ScanBits painting on the same pixels).
|
||||
*
|
||||
* The polygons specify -1 as water and 1 as land.
|
||||
* The type table says space is 0, Water is 1 to 64, Land is 65+.
|
||||
*
|
||||
* The outline paints the whole world as water (64). Adding a
|
||||
* land pixel (1) creates a value of 65 (land). Adding a water
|
||||
* pixel (-1) changes this back to 64 (water).
|
||||
*/
|
||||
pPixelTypes[i] += fScanBits[fScanBitIndex].getType();
|
||||
}
|
||||
fScanBitIndex++;
|
||||
}
|
||||
|
||||
// Translate generateScanBits values into pixels types.
|
||||
for(int lCol = 0; lCol < pPixelTypes.length; lCol++)
|
||||
{
|
||||
pPixelTypes[lCol] = fScanToPixelType[pPixelTypes[lCol] & 0xff];
|
||||
}
|
||||
}
|
||||
|
||||
private void generateScanToPixelTypeTable()
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
if(i == 0)
|
||||
{
|
||||
// 0 is Space.
|
||||
fScanToPixelType[i] = BitGeneratorMap.PixTypeSpace;
|
||||
} else if(i > 64)
|
||||
{
|
||||
// Above 64 it's land.
|
||||
fScanToPixelType[i] = BitGeneratorMap.PixTypeLand;
|
||||
} else
|
||||
{
|
||||
// From 1 to 64 incl. it's water
|
||||
fScanToPixelType[i] = BitGeneratorMap.PixTypeWater;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setScanBits(ScanBit[] pScanBits)
|
||||
{
|
||||
fScanBits = pScanBits;
|
||||
}
|
||||
}
|
60
src/com/ctreber/acearth/renderer/RowTypeRendererScanDot.java
Normal file
60
src/com/ctreber/acearth/renderer/RowTypeRendererScanDot.java
Normal file
@ -0,0 +1,60 @@
|
||||
package com.ctreber.acearth.renderer;
|
||||
|
||||
import com.ctreber.acearth.scanbit.BitGeneratorMap;
|
||||
import com.ctreber.acearth.scandot.ScanDot;
|
||||
|
||||
/**
|
||||
* <p>Renders a row of ScanDots to pixel types.</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class RowTypeRendererScanDot implements RowTypeRenderer
|
||||
{
|
||||
private int fScanDotIndex;
|
||||
private ScanDot[] fScanDots;
|
||||
|
||||
public void startNewRun()
|
||||
{
|
||||
fScanDotIndex = 0;
|
||||
}
|
||||
|
||||
public void getPixelTypes(int pRowNo, int[] pPixelTypes)
|
||||
{
|
||||
// For all ScanDots in specified row...
|
||||
while((fScanDotIndex < fScanDots.length) &&
|
||||
(fScanDots[fScanDotIndex].getY() == pRowNo))
|
||||
{
|
||||
ScanDot lDot = fScanDots[fScanDotIndex];
|
||||
|
||||
if(lDot.getType() == ScanDot.DotTypeStar)
|
||||
{
|
||||
if(pPixelTypes[lDot.getX()] == BitGeneratorMap.PixTypeSpace)
|
||||
{
|
||||
// Stars get only painted on Space.
|
||||
pPixelTypes[lDot.getX()] = BitGeneratorMap.PixTypeStar;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// The only other type for a dot (so far) is "grid".
|
||||
switch(pPixelTypes[lDot.getX()])
|
||||
{
|
||||
case BitGeneratorMap.PixTypeLand:
|
||||
pPixelTypes[lDot.getX()] = BitGeneratorMap.PixTypeGridLand;
|
||||
break;
|
||||
|
||||
case BitGeneratorMap.PixTypeWater:
|
||||
pPixelTypes[lDot.getX()] = BitGeneratorMap.PixTypeGridWater;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fScanDotIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
public void setScanDots(ScanDot[] pScanDots)
|
||||
{
|
||||
fScanDots = pScanDots;
|
||||
}
|
||||
}
|
120
src/com/ctreber/acearth/scanbit/BitGeneratorMap.java
Normal file
120
src/com/ctreber/acearth/scanbit/BitGeneratorMap.java
Normal file
@ -0,0 +1,120 @@
|
||||
package com.ctreber.acearth.scanbit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.ctreber.acearth.projection.Projection;
|
||||
import com.ctreber.acearth.util.*;
|
||||
import com.ctreber.aclib.sort.CTSort;
|
||||
import com.ctreber.aclib.sort.QuickSort;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A BitGeneratorMap scans a map into ScanBits.
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public abstract class BitGeneratorMap extends ScanBitGenerator {
|
||||
// Types of pixels.
|
||||
public static final int PixTypeSpace = 0;
|
||||
public static final int PixTypeLand = 1;
|
||||
public static final int PixTypeWater = 2;
|
||||
public static final int PixTypeStar = 3;
|
||||
public static final int PixTypeGridLand = 4;
|
||||
public static final int PixTypeGridWater = 5;
|
||||
|
||||
// Parameters influencing generateScanBits buffer genertion.
|
||||
private Polygon[] fMapData;
|
||||
Projection fProjection;
|
||||
private List fScanbitsVector = new ArrayList();
|
||||
// Created by scanPolygon
|
||||
List fEdgeCrossings;
|
||||
|
||||
abstract protected ScanBuf scanOutline();
|
||||
|
||||
abstract protected void handleCrossings(ScanBuf pScanBuf, EdgeCrossing[] pEdgeCrossings);
|
||||
|
||||
abstract protected Comparator getEdgeXingComparator();
|
||||
|
||||
abstract protected void scanPolygon(ScanBuf pScanBuf, Point3D[] pPoints3D, Point2D[] pPoints2D, int pIndex);
|
||||
|
||||
public BitGeneratorMap(Projection pProjection) {
|
||||
fProjection = pProjection;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create outline for the map, scan all polygons.
|
||||
*/
|
||||
public void generateScanBits() {
|
||||
// Prepare data.
|
||||
fScanbitsVector = new ArrayList();
|
||||
fProjection.setImageWidth(fImageWidth);
|
||||
fProjection.setImageHeight(fImageHeight);
|
||||
fProjection.initTransformTable();
|
||||
|
||||
// Trace outling and polygons.
|
||||
final ScanBuf lScanBuf = scanOutline();
|
||||
fScanbitsVector.addAll(lScanBuf.getScanbits(64));
|
||||
scanPolygons();
|
||||
|
||||
// Dress results.
|
||||
final CTSort lSort = new QuickSort();
|
||||
fScanBitsArray = (ScanBit[]) fScanbitsVector.toArray(new ScanBit[0]);
|
||||
lSort.sort(fScanBitsArray);
|
||||
}
|
||||
|
||||
private void scanPolygons() {
|
||||
for (int lPolyNo = 0; lPolyNo < fMapData.length; lPolyNo++) {
|
||||
Polygon lPolygon = fMapData[lPolyNo];
|
||||
|
||||
Point3D[] lPoints3D = new Point3D[lPolygon.getSize()];
|
||||
Point2D[] lPoints2D = new Point2D[lPolygon.getSize()];
|
||||
transformPolygonPoints(lPolygon, lPoints3D, lPoints2D);
|
||||
|
||||
// For all points in polygon...
|
||||
fEdgeCrossings = new ArrayList();
|
||||
ScanBuf lScanBuf = new ScanBuf(fImageHeight, fImageWidth);
|
||||
for (int i = 0; i < lPoints2D.length; i++) {
|
||||
scanPolygon(lScanBuf, lPoints3D, lPoints2D, i);
|
||||
}
|
||||
|
||||
if (fEdgeCrossings.size() > 0) {
|
||||
// Edge crossings have been generated, deal with them.
|
||||
final EdgeCrossing[] xings = (EdgeCrossing[]) fEdgeCrossings.toArray(new EdgeCrossing[0]);
|
||||
final CTSort lSort = new QuickSort();
|
||||
lSort.sort(xings, getEdgeXingComparator());
|
||||
handleCrossings(lScanBuf, xings);
|
||||
}
|
||||
|
||||
if (lScanBuf.containsPoints()) {
|
||||
// Scan lines have been generated, transform them into ScanBit.
|
||||
fScanbitsVector.addAll(lScanBuf.getScanbits(lPolygon.getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The transformation rotates 3D and projects 2D points from it
|
||||
*/
|
||||
private void transformPolygonPoints(Polygon pPolygon, Point3D[] pPoints3D, Point2D[] pPoints2D) {
|
||||
for (int i = 0; i < pPolygon.getPoints().length; i++) {
|
||||
Point3D lPoint = pPolygon.getPoints()[i];
|
||||
|
||||
Point3D lPointRotated = fProjection.rotate(lPoint);
|
||||
pPoints3D[i] = lPointRotated;
|
||||
pPoints2D[i] = fProjection.project2D(lPointRotated);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMapData(Polygon[] pMapData) {
|
||||
fMapData = pMapData;
|
||||
}
|
||||
|
||||
protected void addEdgeXing(EdgeCrossing pEdgeXing) {
|
||||
fEdgeCrossings.add(pEdgeXing);
|
||||
}
|
||||
}
|
263
src/com/ctreber/acearth/scanbit/BitGeneratorMapDefault.java
Normal file
263
src/com/ctreber/acearth/scanbit/BitGeneratorMapDefault.java
Normal file
@ -0,0 +1,263 @@
|
||||
package com.ctreber.acearth.scanbit;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.ctreber.acearth.projection.Projection;
|
||||
import com.ctreber.acearth.util.*;
|
||||
|
||||
/**
|
||||
* <p>Map scanner for mercator and cylindrical projections.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class BitGeneratorMapDefault extends BitGeneratorMap
|
||||
{
|
||||
public BitGeneratorMapDefault(Projection pProjection)
|
||||
{
|
||||
super(pProjection);
|
||||
}
|
||||
|
||||
protected Comparator getEdgeXingComparator()
|
||||
{
|
||||
return new EdgeXingComparator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Seems to: walk along outline of projected area.
|
||||
*/
|
||||
protected ScanBuf scanOutline()
|
||||
{
|
||||
final ScanBuf lScanBuf = new ScanBuf(fImageHeight, fImageWidth);
|
||||
|
||||
final double lLeft = fProjection.finalizeX(-Math.PI);
|
||||
final double lRight = fProjection.finalizeX(Math.PI);
|
||||
// Will be adjusted to fit height.
|
||||
final double lTop = fProjection.finalizeY(1e6);
|
||||
final double lBottom = fProjection.finalizeY(-1e6);
|
||||
|
||||
// Top
|
||||
lScanBuf.addLine(lRight, lTop, lLeft, lTop);
|
||||
// Left
|
||||
lScanBuf.addLine(lLeft, lTop, lLeft, lBottom);
|
||||
// Bottom
|
||||
lScanBuf.addLine(lLeft, lBottom, lRight, lBottom);
|
||||
// Right
|
||||
lScanBuf.addLine(lRight, lBottom, lRight, lTop);
|
||||
|
||||
return lScanBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Look at 2 neighboring points in polygon and find edge crossings -
|
||||
* edge of the globe?! Edge of image?
|
||||
*/
|
||||
protected void scanPolygon(ScanBuf pScanBuf,
|
||||
Point3D[] pPoints3D, Point2D[] pPoints2D, int pIndex)
|
||||
{
|
||||
final Point2D lCurr = pPoints2D[pIndex];
|
||||
final int lIndexPrev = pIndex - 1 >= 0 ? pIndex - 1 : pPoints2D.length - 1;
|
||||
final Point2D lPrev = pPoints2D[lIndexPrev];
|
||||
double dx = lCurr.getX() - lPrev.getX();
|
||||
|
||||
if(Math.abs(dx) <= Math.PI)
|
||||
{
|
||||
// Perimeter not crossed.
|
||||
pScanBuf.addLine(
|
||||
fProjection.finalizeX(lPrev.getX()), fProjection.finalizeY(lPrev.getY()),
|
||||
fProjection.finalizeX(lCurr.getX()), fProjection.finalizeY(lCurr.getY()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Perimeter crossed, we need to wrap the line around the edge.
|
||||
int lAngle;
|
||||
double mx;
|
||||
double my = getYMidPoint(pPoints3D[lIndexPrev], pPoints3D[pIndex]);
|
||||
if(dx > 0)
|
||||
{
|
||||
// Curve runs right
|
||||
mx = -Math.PI;
|
||||
lAngle = 2;
|
||||
} else
|
||||
{
|
||||
mx = Math.PI;
|
||||
lAngle = 0;
|
||||
}
|
||||
|
||||
// From previous point to edge...
|
||||
pScanBuf.addLine(
|
||||
fProjection.finalizeX(lPrev.getX()), fProjection.finalizeY(lPrev.getY()),
|
||||
fProjection.finalizeX(mx), fProjection.finalizeY(my));
|
||||
addEdgeXing(new EdgeCrossing(EdgeCrossing.XingTypeExit, pIndex, mx, my, lAngle));
|
||||
|
||||
if(dx > 0)
|
||||
{
|
||||
mx = Math.PI;
|
||||
lAngle = 0;
|
||||
} else
|
||||
{
|
||||
mx = -Math.PI;
|
||||
lAngle = 2;
|
||||
}
|
||||
|
||||
// ...and from edge to current point.
|
||||
pScanBuf.addLine(
|
||||
fProjection.finalizeX(mx), fProjection.finalizeY(my),
|
||||
fProjection.finalizeX(lCurr.getX()), fProjection.finalizeY(lCurr.getY()));
|
||||
addEdgeXing(new EdgeCrossing(EdgeCrossing.XingTypeEntry, pIndex, mx, my, lAngle));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>My educated guess is that the mid point between the current and
|
||||
* the previous point is calculated, and - kind of - y of that point
|
||||
* is returned.
|
||||
*/
|
||||
private double getYMidPoint(Point3D pPrev, Point3D pCurr)
|
||||
{
|
||||
double lY;
|
||||
final double lZ;
|
||||
|
||||
if(pCurr.getX() != 0)
|
||||
{
|
||||
// if xPrev is twice xCurr, ratio is 2
|
||||
double ratio = (pPrev.getX() / pCurr.getX());
|
||||
lY = pPrev.getY() - ratio * pCurr.getY();
|
||||
lZ = pPrev.getZ() - ratio * pCurr.getZ();
|
||||
} else
|
||||
{
|
||||
lY = pCurr.getY();
|
||||
lZ = pCurr.getZ();
|
||||
}
|
||||
|
||||
final double lDistance = Math.sqrt((lY * lY) + (lZ * lZ));
|
||||
lY *= ((lZ > 0) ? -1 : 1) / lDistance;
|
||||
|
||||
return fProjection.projectY(lY);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Side effect: Creates ScanBuf lines.
|
||||
*/
|
||||
protected void handleCrossings(ScanBuf pScanBuf, EdgeCrossing[] xings)
|
||||
{
|
||||
EdgeCrossing from;
|
||||
EdgeCrossing to;
|
||||
int lStart;
|
||||
|
||||
if(xings[0].getType() == EdgeCrossing.XingTypeExit)
|
||||
{
|
||||
lStart = 0;
|
||||
} else
|
||||
{
|
||||
// Type "entry".
|
||||
from = xings[xings.length - 1];
|
||||
to = xings[0];
|
||||
addEdgeToScanbuf(pScanBuf, from, to);
|
||||
lStart = 1;
|
||||
}
|
||||
|
||||
for(int i = lStart; i < xings.length - 1; i += 2)
|
||||
{
|
||||
from = xings[i];
|
||||
to = xings[i + 1];
|
||||
addEdgeToScanbuf(pScanBuf, from, to);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>For handleCrossing(). Side effect: Creates ScanBuf lines.
|
||||
*
|
||||
* @param pScanBuf
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
private void addEdgeToScanbuf(ScanBuf pScanBuf, EdgeCrossing from,
|
||||
EdgeCrossing to)
|
||||
{
|
||||
int lAngleFrom = (int)from.getAngle();
|
||||
double lXFrom = fProjection.finalizeX(from.getX());
|
||||
double lYFrom = fProjection.finalizeY(from.getY());
|
||||
|
||||
// Step around in 90 degree increments until target angle is reached
|
||||
while(lAngleFrom != (int)to.getAngle())
|
||||
{
|
||||
int lAngleNew = 0;
|
||||
double lXNew = 0;
|
||||
double lYNew = 0;
|
||||
|
||||
switch(lAngleFrom)
|
||||
{
|
||||
case 0:
|
||||
// Top right
|
||||
lXNew = fProjection.finalizeX(Math.PI);
|
||||
lYNew = fProjection.finalizeY(1e6);
|
||||
lAngleNew = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Top left
|
||||
lXNew = fProjection.finalizeX(-Math.PI);
|
||||
lYNew = fProjection.finalizeY(1e6);
|
||||
lAngleNew = 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Bottom left
|
||||
lXNew = fProjection.finalizeX(-Math.PI);
|
||||
lYNew = fProjection.finalizeY(-1e6);
|
||||
lAngleNew = 3;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Bottom right
|
||||
lXNew = fProjection.finalizeX(Math.PI);
|
||||
lYNew = fProjection.finalizeY(-1e6);
|
||||
lAngleNew = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
pScanBuf.addLine(lXFrom, lYFrom, lXNew, lYNew);
|
||||
|
||||
lAngleFrom = lAngleNew;
|
||||
lXFrom = lXNew;
|
||||
lYFrom = lYNew;
|
||||
}
|
||||
|
||||
// ...and from last to final.
|
||||
pScanBuf.addLine(lXFrom, lYFrom, fProjection.finalizeX(to.getX()),
|
||||
fProjection.finalizeY(to.getY()));
|
||||
}
|
||||
|
||||
private static class EdgeXingComparator implements Comparator
|
||||
{
|
||||
public int compare(Object o1, Object o2)
|
||||
{
|
||||
final EdgeCrossing a = (EdgeCrossing)o1;
|
||||
final EdgeCrossing b = (EdgeCrossing)o2;
|
||||
|
||||
if(a.getAngle() < b.getAngle())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(a.getAngle() > b.getAngle())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Angles are equal.
|
||||
if(a.getAngle() == 0)
|
||||
{
|
||||
return (a.getY() < b.getY()) ? -1 : (a.getY() > b.getY()) ? 1 : 0;
|
||||
}
|
||||
|
||||
if(a.getAngle() == 2)
|
||||
{
|
||||
return (a.getY() > b.getY()) ? -1 : (a.getY() < b.getY()) ? 1 : 0;
|
||||
}
|
||||
|
||||
throw new RuntimeException("No result");
|
||||
}
|
||||
}
|
||||
}
|
168
src/com/ctreber/acearth/scanbit/BitGeneratorMapOrtho.java
Normal file
168
src/com/ctreber/acearth/scanbit/BitGeneratorMapOrtho.java
Normal file
@ -0,0 +1,168 @@
|
||||
package com.ctreber.acearth.scanbit;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.ctreber.acearth.projection.Projection;
|
||||
import com.ctreber.acearth.util.*;
|
||||
|
||||
/**
|
||||
* <p>Map scanner for orthographic projection.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class BitGeneratorMapOrtho extends BitGeneratorMap
|
||||
{
|
||||
public BitGeneratorMapOrtho(Projection pProjection)
|
||||
{
|
||||
super(pProjection);
|
||||
}
|
||||
|
||||
protected Comparator getEdgeXingComparator()
|
||||
{
|
||||
return new EdgeCrossingComparator();
|
||||
}
|
||||
|
||||
protected ScanBuf scanOutline()
|
||||
{
|
||||
final ScanBuf lScanBuf = new ScanBuf(fImageHeight, fImageWidth);
|
||||
addArcToScanbuf(lScanBuf, 1.0, 0.0, 0.0, 1.0, 0.0, 2 * Math.PI);
|
||||
|
||||
return lScanBuf;
|
||||
}
|
||||
|
||||
private void addArcToScanbuf(ScanBuf pScanBuf, double pXFrom, double pYFrom,
|
||||
double pAngleFrom, double pXTo, double pYTo, double pAngleTo)
|
||||
{
|
||||
double step = 1 / fProjection.getScale() * 10;
|
||||
if(step > 0.05)
|
||||
{
|
||||
step = 0.05;
|
||||
}
|
||||
final int lAngleFrom = (int)Math.ceil(pAngleFrom / step);
|
||||
final int lAngleTo = (int)Math.floor(pAngleTo / step);
|
||||
|
||||
double prev_x = fProjection.finalizeX(pXFrom);
|
||||
double prev_y = fProjection.finalizeY(pYFrom);
|
||||
double curr_x;
|
||||
double curr_y;
|
||||
if(lAngleFrom <= lAngleTo)
|
||||
{
|
||||
double c_step = Math.cos(step);
|
||||
double s_step = Math.sin(step);
|
||||
|
||||
double angle = lAngleFrom * step;
|
||||
double arc_x = Math.cos(angle);
|
||||
double arc_y = Math.sin(angle);
|
||||
|
||||
for(int i = lAngleFrom; i <= lAngleTo; i++)
|
||||
{
|
||||
curr_x = fProjection.finalizeX(arc_x);
|
||||
curr_y = fProjection.finalizeY(arc_y);
|
||||
pScanBuf.addLine(prev_x, prev_y, curr_x, curr_y);
|
||||
|
||||
/* instead of repeatedly calling cos() and sin() to get the next
|
||||
* values for arc_x and arc_y, simply rotate the existing values
|
||||
*/
|
||||
double tmp = (c_step * arc_x) - (s_step * arc_y);
|
||||
arc_y = (s_step * arc_x) + (c_step * arc_y);
|
||||
arc_x = tmp;
|
||||
|
||||
prev_x = curr_x;
|
||||
prev_y = curr_y;
|
||||
}
|
||||
}
|
||||
|
||||
curr_x = fProjection.finalizeX(pXTo);
|
||||
curr_y = fProjection.finalizeY(pYTo);
|
||||
pScanBuf.addLine(prev_x, prev_y, curr_x, curr_y);
|
||||
}
|
||||
|
||||
protected void scanPolygon(ScanBuf pScanBuf,
|
||||
Point3D[] pPoints3D, Point2D[] pPoints2D, int pIndex)
|
||||
{
|
||||
Point3D extra;
|
||||
|
||||
Point3D lCurr = pPoints3D[pIndex];
|
||||
final int lIndexPrev = pIndex - 1 >= 0 ? pIndex - 1 : pPoints2D.length - 1;
|
||||
Point3D lPrev = pPoints3D[lIndexPrev];
|
||||
|
||||
if(lPrev.getZ() <= 0)
|
||||
{
|
||||
if(lCurr.getZ() <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Previous point not visible, but current one is: horizon crossed.
|
||||
extra = findEdgeCrossing(lPrev, lCurr);
|
||||
addEdgeXing(new EdgeCrossing(EdgeCrossing.XingTypeEntry, pIndex,
|
||||
extra.getX(), extra.getY(), Math.atan2(extra.getY(), extra.getX())));
|
||||
lPrev = extra;
|
||||
} else
|
||||
{
|
||||
if(lCurr.getZ() <= 0)
|
||||
{
|
||||
// Previous point visible, but current is not: horizon crossed.
|
||||
extra = findEdgeCrossing(lPrev, lCurr);
|
||||
addEdgeXing(new EdgeCrossing(EdgeCrossing.XingTypeExit, pIndex,
|
||||
extra.getX(), extra.getY(), Math.atan2(extra.getY(), extra.getX())));
|
||||
lCurr = extra;
|
||||
}
|
||||
}
|
||||
|
||||
pScanBuf.addLine(
|
||||
fProjection.finalizeX(lPrev.getX()), fProjection.finalizeY(lPrev.getY()),
|
||||
fProjection.finalizeX(lCurr.getX()), fProjection.finalizeY(lCurr.getY()));
|
||||
}
|
||||
|
||||
private Point3D findEdgeCrossing(Point3D pPrev, Point3D pCurr)
|
||||
{
|
||||
double tmp = pCurr.getZ() / (pCurr.getZ() - pPrev.getZ());
|
||||
final double r0 = pCurr.getX() - tmp * (pCurr.getX() - pPrev.getX());
|
||||
final double r1 = pCurr.getY() - tmp * (pCurr.getY() - pPrev.getY());
|
||||
|
||||
tmp = Math.sqrt((r0 * r0) + (r1 * r1));
|
||||
|
||||
return new Point3D(r0 / tmp, r1 / tmp, 0);
|
||||
}
|
||||
|
||||
protected void handleCrossings(ScanBuf pScanBuf, EdgeCrossing[] xings)
|
||||
{
|
||||
EdgeCrossing from;
|
||||
EdgeCrossing to;
|
||||
int lStart;
|
||||
|
||||
if(xings[0].getType() == EdgeCrossing.XingTypeExit)
|
||||
{
|
||||
lStart = 0;
|
||||
} else
|
||||
{
|
||||
from = xings[xings.length - 1];
|
||||
to = xings[0];
|
||||
addArcToScanbuf(pScanBuf, from.getX(), from.getY(), from.getAngle(),
|
||||
to.getX(), to.getY(), to.getAngle() + 2 * Math.PI);
|
||||
lStart = 1;
|
||||
}
|
||||
|
||||
for(int i = lStart; i < xings.length - 1; i += 2)
|
||||
{
|
||||
from = xings[i];
|
||||
to = xings[i + 1];
|
||||
addArcToScanbuf(pScanBuf, from.getX(), from.getY(), from.getAngle(),
|
||||
to.getX(), to.getY(), to.getAngle());
|
||||
}
|
||||
}
|
||||
|
||||
private static class EdgeCrossingComparator implements Comparator
|
||||
{
|
||||
public int compare(Object o1, Object o2)
|
||||
{
|
||||
final EdgeCrossing a = (EdgeCrossing)o1;
|
||||
final EdgeCrossing b = (EdgeCrossing)o2;
|
||||
|
||||
return (a.getAngle() < b.getAngle()) ? -1 : (a.getAngle() > b.getAngle()) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
62
src/com/ctreber/acearth/scanbit/ScanBit.java
Normal file
62
src/com/ctreber/acearth/scanbit/ScanBit.java
Normal file
@ -0,0 +1,62 @@
|
||||
package com.ctreber.acearth.scanbit;
|
||||
|
||||
/**
|
||||
* <p>Instruction to paint points xFrom to xTo on line y.
|
||||
*
|
||||
* <p>What I don't understand: why do values get summed to determine the
|
||||
* pixel type?
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ScanBit implements Comparable
|
||||
{
|
||||
private int fY;
|
||||
private int lXFrom;
|
||||
private int fXTo;
|
||||
private int fType;
|
||||
|
||||
public ScanBit(int pY, int pLoX, int pHiX, int pType)
|
||||
{
|
||||
fY = pY;
|
||||
lXFrom = pLoX;
|
||||
fXTo = pHiX;
|
||||
fType = pType;
|
||||
}
|
||||
|
||||
public int compareTo(Object o)
|
||||
{
|
||||
if(o instanceof ScanBit)
|
||||
{
|
||||
ScanBit lOther = (ScanBit)o;
|
||||
return (fY > lOther.fY) ? 1 : (fY < lOther.fY) ? -1 : 0;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Can't compare with " + o.getClass());
|
||||
}
|
||||
|
||||
public int getY()
|
||||
{
|
||||
return fY;
|
||||
}
|
||||
|
||||
public int getlXFrom()
|
||||
{
|
||||
return lXFrom;
|
||||
}
|
||||
|
||||
public int getXTo()
|
||||
{
|
||||
return fXTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>See values for
|
||||
* @see com.ctreber.acearth.util.Polygon
|
||||
*/
|
||||
public int getType()
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
}
|
32
src/com/ctreber/acearth/scanbit/ScanBitGenerator.java
Normal file
32
src/com/ctreber/acearth/scanbit/ScanBitGenerator.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.ctreber.acearth.scanbit;
|
||||
|
||||
/**
|
||||
* <p>A ScanBitGenerator produces ScanBits.</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
abstract public class ScanBitGenerator
|
||||
{
|
||||
int fImageHeight;
|
||||
int fImageWidth;
|
||||
protected ScanBit[] fScanBitsArray;
|
||||
|
||||
abstract public void generateScanBits();
|
||||
|
||||
public void setImageHeight(int pImageHeight)
|
||||
{
|
||||
fImageHeight = pImageHeight;
|
||||
}
|
||||
|
||||
public void setImageWidth(int pImageWidth)
|
||||
{
|
||||
fImageWidth = pImageWidth;
|
||||
}
|
||||
|
||||
public ScanBit[] getScanBits()
|
||||
{
|
||||
return fScanBitsArray;
|
||||
}
|
||||
}
|
193
src/com/ctreber/acearth/scanbit/ScanBuf.java
Normal file
193
src/com/ctreber/acearth/scanbit/ScanBuf.java
Normal file
@ -0,0 +1,193 @@
|
||||
package com.ctreber.acearth.scanbit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.ctreber.aclib.sort.CTSort;
|
||||
import com.ctreber.aclib.sort.QuickSort;
|
||||
|
||||
/**
|
||||
* <p>For each line, the scanbuffer (= a raster divice) records the points hit
|
||||
* I.e., line 5 (y=5) contains the values 2, 6, 40, and 46 (these line have
|
||||
* been crossed). The values always come as pairs because we're dealing with
|
||||
* polygons, which have a left and a right side which consists of a line.
|
||||
* The points in between two values painted as filled.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
class ScanBuf
|
||||
{
|
||||
private List[] fScanbuf;
|
||||
private int fLineMin;
|
||||
private int fLineMax;
|
||||
private final int fLines;
|
||||
private final int fPoints;
|
||||
private boolean fScanBufsAdded;
|
||||
|
||||
/**
|
||||
* <p>Create a list for each line.
|
||||
*
|
||||
* @param pLines Number of lines aka screen height.
|
||||
* @param pPoints Number of points per line aka screen width.
|
||||
*/
|
||||
public ScanBuf(int pLines, int pPoints)
|
||||
{
|
||||
fLines = pLines;
|
||||
fPoints = pPoints;
|
||||
|
||||
fLineMin = Integer.MAX_VALUE;
|
||||
fLineMax = Integer.MIN_VALUE;
|
||||
fScanBufsAdded = false;
|
||||
|
||||
fScanbuf = new ArrayList[fLines];
|
||||
for(int i = 0; i < fScanbuf.length; i++)
|
||||
{
|
||||
fScanbuf[i] = new ArrayList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Add a line to the generateScanBits buffer.
|
||||
*/
|
||||
public void addLine(double pXFrom, double pYFrom, double pXTo, double pYTo)
|
||||
{
|
||||
int lYFrom;
|
||||
int lYTo;
|
||||
|
||||
// Do some rounding (but not in the way we expect it), limit values
|
||||
if(pYFrom < pYTo)
|
||||
{
|
||||
// Round lYFrom (but .5 is handled oddly)
|
||||
// 1.5001 - 2.5 -> 1.0001 - 2.0 -> 2
|
||||
lYFrom = (int)Math.ceil(pYFrom - 0.5);
|
||||
// Round lYTo, substract 1
|
||||
// 1.5 - 2.4999 -> 1.0 - 1.9999 -> 1
|
||||
lYTo = (int)Math.floor(pYTo - 0.5);
|
||||
|
||||
/**
|
||||
* I don't know if this is intended, but in Java 3 == 3.001 is false
|
||||
* (the left arg is converted to double), so the expr is true only when
|
||||
* pYTo - 0.5 is exactly lYTo
|
||||
*/
|
||||
if(lYTo == pYTo - 0.5)
|
||||
{
|
||||
lYTo--;
|
||||
}
|
||||
} else
|
||||
{
|
||||
lYFrom = (int)Math.ceil(pYTo - 0.5);
|
||||
lYTo = (int)Math.floor(pYFrom - 0.5);
|
||||
|
||||
if(lYTo == pYFrom - 0.5)
|
||||
{
|
||||
lYTo--;
|
||||
}
|
||||
}
|
||||
|
||||
// Limit y to size of image
|
||||
if(lYFrom < 0)
|
||||
{
|
||||
lYFrom = 0;
|
||||
}
|
||||
if(lYTo >= fLines)
|
||||
{
|
||||
lYTo = fLines - 1;
|
||||
}
|
||||
|
||||
if(lYFrom > lYTo)
|
||||
{
|
||||
// No lines crossed.
|
||||
return;
|
||||
}
|
||||
|
||||
// Note min/max settings so far
|
||||
if(lYFrom < fLineMin)
|
||||
{
|
||||
fLineMin = lYFrom;
|
||||
}
|
||||
if(lYTo > fLineMax)
|
||||
{
|
||||
fLineMax = lYTo;
|
||||
}
|
||||
|
||||
// todo Curious: What happens if yFrom and yTo are equal? Shit? Or can't they be?
|
||||
double lDx = (pXTo - pXFrom) / (pYTo - pYFrom);
|
||||
double lX = pXFrom + lDx * ((lYFrom + 0.5) - pYFrom);
|
||||
|
||||
// Record the x value for every line (y).
|
||||
for(int lLineNo = lYFrom; lLineNo <= lYTo; lLineNo++)
|
||||
{
|
||||
fScanbuf[lLineNo].add(new Double(lX));
|
||||
lX += lDx;
|
||||
}
|
||||
fScanBufsAdded = true;
|
||||
}
|
||||
|
||||
public boolean containsPoints()
|
||||
{
|
||||
return fScanBufsAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>For each line, for each x value pair in line, create one ScanBit.
|
||||
*/
|
||||
public List getScanbits(int pCurveType)
|
||||
{
|
||||
final List fScanBits = new ArrayList();
|
||||
|
||||
// For each generateScanBits line containing points
|
||||
for(int lLineNo = fLineMin; lLineNo <= fLineMax; lLineNo++)
|
||||
{
|
||||
// Sort so that lowest x values come first.
|
||||
Double[] lScanLine = (Double[])fScanbuf[lLineNo].toArray(new Double[0]);
|
||||
CTSort lSort = new QuickSort();
|
||||
lSort.sort(lScanLine);
|
||||
|
||||
// The length will be divisible by 2 because we render closed polyons,
|
||||
// so every generateScanBits line is crossed twice (left and right edge of polygon,
|
||||
// no intersections allowed!).
|
||||
for(int n = 0; n < lScanLine.length; n += 2)
|
||||
{
|
||||
// Round lLineFrom (but .5 is handled oddly)
|
||||
// 1.5001 - 2.5 -> 1.0001 - 2.0 -> 2
|
||||
int lXLo = (int)Math.ceil(lScanLine[n].doubleValue() - 0.5);
|
||||
// Round lLineTo, substract 1
|
||||
// 1.5 - 2.4999 -> 1.0 - 1.9999 -> 1
|
||||
int lXHi = (int)Math.floor(lScanLine[n + 1].doubleValue() - 0.5);
|
||||
|
||||
// Limit low and high x to image dimensions
|
||||
if(lXLo < 0)
|
||||
{
|
||||
lXLo = 0;
|
||||
}
|
||||
if(lXHi >= fPoints)
|
||||
{
|
||||
lXHi = fPoints - 1;
|
||||
}
|
||||
|
||||
if(lXLo <= lXHi)
|
||||
{
|
||||
/**
|
||||
* Shouldn't that always be true since we sorted? "Yes", BUT the
|
||||
* rounding might create lo 3.6 -> 4.0 and hi 3.7 -> 3.0
|
||||
*/
|
||||
fScanBits.add(new ScanBit(lLineNo, lXLo, lXHi, pCurveType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fScanBits;
|
||||
}
|
||||
|
||||
public int getYMax()
|
||||
{
|
||||
return fLineMax;
|
||||
}
|
||||
|
||||
public int getYMin()
|
||||
{
|
||||
return fLineMin;
|
||||
}
|
||||
}
|
70
src/com/ctreber/acearth/scandot/DotGeneratorLines.java
Normal file
70
src/com/ctreber/acearth/scandot/DotGeneratorLines.java
Normal file
@ -0,0 +1,70 @@
|
||||
package com.ctreber.acearth.scandot;
|
||||
|
||||
import com.ctreber.acearth.projection.Projection;
|
||||
import com.ctreber.acearth.util.*;
|
||||
|
||||
/**
|
||||
* <p>Generate latitude and longitude grid as dots.
|
||||
*
|
||||
* <p>Refactored 08.11.2002
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class DotGeneratorLines extends ScanDotGenerator
|
||||
{
|
||||
private Projection fProjection;
|
||||
private int fLineDivider;
|
||||
private int fPointDivider;
|
||||
private static final double PI = Math.PI;
|
||||
private static final double TWOPI = 2 * PI;
|
||||
private static final double HALFPI = PI / 2;
|
||||
|
||||
public DotGeneratorLines(Projection pProjection,
|
||||
int pLineDevider, int pPointDivider)
|
||||
{
|
||||
fProjection = pProjection;
|
||||
fLineDivider = pLineDevider;
|
||||
fPointDivider = pPointDivider;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Paint grid.
|
||||
*/
|
||||
public void generateScanDots()
|
||||
{
|
||||
double lLonStep = TWOPI / (fLineDivider * 4);
|
||||
double lLatStep = PI / (fLineDivider * 2 * fPointDivider);
|
||||
for(double lLon = -PI; lLon <= PI; lLon += lLonStep)
|
||||
{
|
||||
for(double lLat = -HALFPI; lLat <= HALFPI; lLat += lLatStep)
|
||||
{
|
||||
transformAndAddDot(new Coordinate(lLat, lLon));
|
||||
}
|
||||
}
|
||||
|
||||
lLatStep = TWOPI / (fLineDivider * 4);
|
||||
lLonStep = PI / (fLineDivider * 2 * fPointDivider);
|
||||
for(double lLat = -HALFPI; lLat <= HALFPI; lLat += lLatStep)
|
||||
{
|
||||
for(double lLon = -PI; lLon <= PI; lLon += lLonStep)
|
||||
{
|
||||
transformAndAddDot(new Coordinate(lLat, lLon));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void transformAndAddDot(Coordinate pPos)
|
||||
{
|
||||
final Point3D lPointRotated = fProjection.rotate(pPos.getPoint3DRads());
|
||||
if(fProjection.isVisible(lPointRotated))
|
||||
{
|
||||
Point2D lPoint = fProjection.finalize(fProjection.project2D(lPointRotated));
|
||||
if(fProjection.isWithinImage(lPoint))
|
||||
{
|
||||
fDots.add(new ScanDot(ScanDot.DotTypeGrid, lPoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
src/com/ctreber/acearth/scandot/DotGeneratorStars.java
Normal file
51
src/com/ctreber/acearth/scandot/DotGeneratorStars.java
Normal file
@ -0,0 +1,51 @@
|
||||
package com.ctreber.acearth.scandot;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* <p>Generate random stars as dots.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class DotGeneratorStars extends ScanDotGenerator
|
||||
{
|
||||
private final int fImageWidth;
|
||||
private final int fImageHeight;
|
||||
private int fBigStars;
|
||||
private double fStarFrequency;
|
||||
private final Random lRandom;
|
||||
|
||||
public DotGeneratorStars(int pWidth, int pHeight,
|
||||
double pStarFrequency, int pBigStars, Random rnd)
|
||||
{
|
||||
lRandom = rnd;
|
||||
fImageWidth = pWidth;
|
||||
fImageHeight = pHeight;
|
||||
fStarFrequency = pStarFrequency;
|
||||
fBigStars = pBigStars;
|
||||
}
|
||||
|
||||
public void generateScanDots()
|
||||
{
|
||||
// Make sure stars don't jump around between updates.
|
||||
// final Random lRandom = new Random(ACearth.getStartTime());
|
||||
|
||||
final int lStarsMax = (int)(fImageWidth * fImageHeight * fStarFrequency);
|
||||
for(int i = 0; i < lStarsMax; i++)
|
||||
{
|
||||
// "-1" to leave space for big stars.
|
||||
int x = (int)(lRandom.nextDouble() * (fImageWidth - 1));
|
||||
int y = (int)(lRandom.nextDouble() * fImageHeight);
|
||||
|
||||
fDots.add(new ScanDot(ScanDot.DotTypeStar, x, y));
|
||||
|
||||
// A big star is just two pixels wide.
|
||||
if((fBigStars != 0) && (Math.random() * 100 < fBigStars))
|
||||
{
|
||||
fDots.add(new ScanDot(ScanDot.DotTypeStar, x + 1, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
67
src/com/ctreber/acearth/scandot/ScanDot.java
Normal file
67
src/com/ctreber/acearth/scandot/ScanDot.java
Normal file
@ -0,0 +1,67 @@
|
||||
package com.ctreber.acearth.scandot;
|
||||
|
||||
import com.ctreber.acearth.util.Point2D;
|
||||
|
||||
/**
|
||||
* <p>A single scandot (opposed to a Polygon).
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ScanDot implements Comparable
|
||||
{
|
||||
// types of dots
|
||||
public static final int DotTypeStar = 0;
|
||||
public static final int DotTypeGrid = 1;
|
||||
|
||||
private int fX;
|
||||
private int fY;
|
||||
private int fType;
|
||||
|
||||
public ScanDot(int pType, int pX, int pY)
|
||||
{
|
||||
fType = pType;
|
||||
fX = pX;
|
||||
fY = pY;
|
||||
}
|
||||
|
||||
public ScanDot(int pType, Point2D pPoint)
|
||||
{
|
||||
fType = pType;
|
||||
fX = (int)pPoint.getX();
|
||||
fY = (int)pPoint.getY();
|
||||
}
|
||||
|
||||
public int compareTo(Object o)
|
||||
{
|
||||
if(o instanceof ScanDot)
|
||||
{
|
||||
ScanDot lOther = (ScanDot)o;
|
||||
|
||||
return fY > lOther.fY ? 1 : (fY < lOther.fY ? -1 : 0);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Can't compare to " + o.getClass());
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
public int getX()
|
||||
{
|
||||
return fX;
|
||||
}
|
||||
|
||||
public int getY()
|
||||
{
|
||||
return fY;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return fX + ", " + fY + ": " + fType;
|
||||
}
|
||||
}
|
27
src/com/ctreber/acearth/scandot/ScanDotGenerator.java
Normal file
27
src/com/ctreber/acearth/scandot/ScanDotGenerator.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.ctreber.acearth.scandot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A ScanDotGenerator produces ScanDots.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
abstract public class ScanDotGenerator
|
||||
{
|
||||
List fDots = new ArrayList();
|
||||
|
||||
/**
|
||||
* <p>Generate whatever dots are generated.
|
||||
*/
|
||||
abstract public void generateScanDots();
|
||||
|
||||
public List getScanDots()
|
||||
{
|
||||
return fDots;
|
||||
}
|
||||
}
|
131
src/com/ctreber/acearth/shader/Shader.java
Normal file
131
src/com/ctreber/acearth/shader/Shader.java
Normal file
@ -0,0 +1,131 @@
|
||||
package com.ctreber.acearth.shader;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
import com.ctreber.acearth.projection.Projection;
|
||||
import com.ctreber.acearth.scanbit.BitGeneratorMap;
|
||||
import com.ctreber.acearth.util.Coordinate;
|
||||
import com.ctreber.acearth.util.Point3D;
|
||||
|
||||
/**
|
||||
* <p>A shader computes Colors for a row of pixel types, depending
|
||||
* on lighting parameters.</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
abstract public class Shader
|
||||
{
|
||||
private static final Color COLOR_SPACE = Color.black;
|
||||
private static final Color COLOR_STAR = Color.white;
|
||||
private static final Color COLOR_WATER = Color.blue;
|
||||
private static final Color COLOR_LAND = Color.green;
|
||||
// Brown
|
||||
//static final Color COLOR_LAND = new Color(255, 136, 25);
|
||||
private static final Color COLOR_GRID_LAND = Color.white;
|
||||
// Bright blue
|
||||
private static final Color COLOR_GRID_WATER = new Color(128, 128, 255);
|
||||
|
||||
/** <p>Needed to calculate lighting vectors. */
|
||||
Projection fProjection;
|
||||
|
||||
// Stuff below only needed when shading.
|
||||
private Coordinate fSunPos;
|
||||
private double fNightSideBrightness;
|
||||
private double fDaySideBrightness;
|
||||
private double fTerminatorDiscontinuity;
|
||||
|
||||
private double fDaySideValueBase;
|
||||
private double fDaySideValueRange;
|
||||
Point3D fLightVector;
|
||||
|
||||
abstract public Color[] getShadedColors(int pRowNo, int[] pRowTypes);
|
||||
|
||||
public void init()
|
||||
{
|
||||
// Precompute shading parameters. I personally find the terminator
|
||||
// stuff is obscure and might as well be left out.
|
||||
final double tmp = fTerminatorDiscontinuity / 100;
|
||||
// 100%: day, 0%: night
|
||||
fDaySideValueBase = (int)(tmp * fDaySideBrightness +
|
||||
(1 - tmp) * fNightSideBrightness);
|
||||
fDaySideValueRange = fDaySideBrightness - fDaySideValueBase;
|
||||
fLightVector = fProjection.rotate(fSunPos.getPoint3D());
|
||||
}
|
||||
|
||||
Color getShadedColorForType(int pType, double pSunValue)
|
||||
{
|
||||
double lBrightness;
|
||||
|
||||
if(pSunValue < 0)
|
||||
{
|
||||
// The sun is below the horizon.
|
||||
lBrightness = fNightSideBrightness / 100;
|
||||
} else
|
||||
{
|
||||
// The sun is above the horizon. The brightness will range from
|
||||
// the base to the maximum value.
|
||||
lBrightness = (fDaySideValueBase + pSunValue * fDaySideValueRange) / 100;
|
||||
}
|
||||
if(lBrightness > 1.0)
|
||||
{
|
||||
lBrightness = 1.0;
|
||||
}
|
||||
|
||||
switch(pType)
|
||||
{
|
||||
case BitGeneratorMap.PixTypeSpace:
|
||||
return COLOR_SPACE;
|
||||
|
||||
case BitGeneratorMap.PixTypeStar:
|
||||
return COLOR_STAR;
|
||||
|
||||
case BitGeneratorMap.PixTypeGridLand:
|
||||
return shade(COLOR_GRID_LAND, lBrightness);
|
||||
|
||||
case BitGeneratorMap.PixTypeGridWater:
|
||||
return shade(COLOR_GRID_WATER, lBrightness);
|
||||
|
||||
case BitGeneratorMap.PixTypeLand:
|
||||
return shade(COLOR_LAND, lBrightness);
|
||||
|
||||
case BitGeneratorMap.PixTypeWater:
|
||||
return shade(COLOR_WATER, lBrightness);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Color shade(Color pColor, double pBrightness)
|
||||
{
|
||||
return new Color((int)(pColor.getRed() * pBrightness),
|
||||
(int)(pColor.getGreen() * pBrightness),
|
||||
(int)(pColor.getBlue() * pBrightness));
|
||||
}
|
||||
|
||||
public void setProjection(Projection pProjection)
|
||||
{
|
||||
fProjection = pProjection;
|
||||
}
|
||||
|
||||
public void setSunPos(Coordinate pSunPos)
|
||||
{
|
||||
fSunPos = pSunPos;
|
||||
}
|
||||
|
||||
public void setDaySideBrightness(double pDaySideBrightness)
|
||||
{
|
||||
fDaySideBrightness = pDaySideBrightness;
|
||||
}
|
||||
|
||||
public void setNightSideBrightness(double pNightSideBrightness)
|
||||
{
|
||||
fNightSideBrightness = pNightSideBrightness;
|
||||
}
|
||||
|
||||
public void setTerminatorDiscontinuity(double pTerminatorDiscontinuity)
|
||||
{
|
||||
fTerminatorDiscontinuity = pTerminatorDiscontinuity;
|
||||
}
|
||||
}
|
59
src/com/ctreber/acearth/shader/ShaderDefault.java
Normal file
59
src/com/ctreber/acearth/shader/ShaderDefault.java
Normal file
@ -0,0 +1,59 @@
|
||||
package com.ctreber.acearth.shader;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* <p>Shader for projections which display the whole surface.</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ShaderDefault extends Shader
|
||||
{
|
||||
public Color[] getShadedColors(int pRowNo, int[] pRowTypes)
|
||||
{
|
||||
final double y = fProjection.inverseProjectY(fProjection.inverseFinalizeY(pRowNo));
|
||||
|
||||
// conceptually, on each iteration of the i loop, we want:
|
||||
//
|
||||
// x = Math.sin(INV_XPROJECT(i)) * sqrt(1 - (y*y));
|
||||
// z = cos(INV_XPROJECT(i)) * sqrt(1 - (y*y));
|
||||
//
|
||||
// computing this directly is rather expensive, however, so we only
|
||||
// compute the first (i=0) pair of values directly; all other pairs
|
||||
// (i>0) are obtained through successive rotations of the original
|
||||
// pair (by inv_proj_scale radians).
|
||||
//
|
||||
|
||||
// compute initial (x, z) values
|
||||
double tmp = Math.sqrt(1 - (y * y));
|
||||
double x = Math.sin(fProjection.inverseFinalizeX(0)) * tmp;
|
||||
double z = Math.cos(fProjection.inverseFinalizeX(0)) * tmp;
|
||||
|
||||
// compute rotation coefficients used
|
||||
// to find subsequent (x, z) values
|
||||
tmp = 1 / fProjection.getScale();
|
||||
final double sin_theta = Math.sin(tmp);
|
||||
final double cos_theta = Math.cos(tmp);
|
||||
|
||||
// save a little computation in the inner loop
|
||||
final double lYBySunVectorY = y * fLightVector.getY();
|
||||
|
||||
// use i_lim to encourage compilers to register loop limit
|
||||
final Color[] lColors = new Color[pRowTypes.length];
|
||||
for(int lColNo = 0; lColNo < pRowTypes.length; lColNo++)
|
||||
{
|
||||
double lSunValue = (x * fLightVector.getX()) + lYBySunVectorY +
|
||||
(z * fLightVector.getZ());
|
||||
lColors[lColNo] = getShadedColorForType(pRowTypes[lColNo], lSunValue);
|
||||
|
||||
// compute next (x, z) values via 2-d rotation
|
||||
tmp = (cos_theta * z) - (sin_theta * x);
|
||||
x = (sin_theta * z) + (cos_theta * x);
|
||||
z = tmp;
|
||||
}
|
||||
|
||||
return lColors;
|
||||
}
|
||||
}
|
24
src/com/ctreber/acearth/shader/ShaderFlat.java
Normal file
24
src/com/ctreber/acearth/shader/ShaderFlat.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.ctreber.acearth.shader;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* <p>Flat shader (does not care for Projection).</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ShaderFlat extends Shader
|
||||
{
|
||||
public Color[] getShadedColors(int pRowNo, int[] pRowTypes)
|
||||
{
|
||||
final Color[] lColors = new Color[pRowTypes.length];
|
||||
for(int i = 0; i < pRowTypes.length; i++)
|
||||
{
|
||||
lColors[i] = getShadedColorForType(pRowTypes[i], 1.0);
|
||||
}
|
||||
|
||||
return lColors;
|
||||
}
|
||||
}
|
55
src/com/ctreber/acearth/shader/ShaderOrtho.java
Normal file
55
src/com/ctreber/acearth/shader/ShaderOrtho.java
Normal file
@ -0,0 +1,55 @@
|
||||
package com.ctreber.acearth.shader;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* <p>Shader for the orthographic projection.</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class ShaderOrtho extends Shader
|
||||
{
|
||||
private static double[] fXValues;
|
||||
|
||||
public Color[] getShadedColors(int pRowNo, int[] pRowTypes)
|
||||
{
|
||||
if(pRowNo == 0)
|
||||
{
|
||||
fXValues = computeXValues(pRowTypes.length);
|
||||
}
|
||||
|
||||
final double y = fProjection.inverseProjectY(fProjection.inverseFinalizeY(pRowNo));
|
||||
final double tmp = 1 - (y * y);
|
||||
final double lYBySunVectorY = y * fLightVector.getY();
|
||||
|
||||
final Color[] lColors = new Color[pRowTypes.length];
|
||||
for(int lColNo = 0; lColNo < pRowTypes.length; lColNo++)
|
||||
{
|
||||
double x = fXValues[lColNo];
|
||||
double z = Math.sqrt(tmp - (x * x));
|
||||
|
||||
double lSunValue = (x * fLightVector.getX()) + lYBySunVectorY + (z * fLightVector.getZ());
|
||||
lColors[lColNo] = getShadedColorForType(pRowTypes[lColNo], lSunValue);
|
||||
}
|
||||
|
||||
return lColors;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return X value for each column in image.
|
||||
*/
|
||||
private double[] computeXValues(int pWidth)
|
||||
{
|
||||
final double[] lTable = new double[pWidth];
|
||||
|
||||
for(int lColNo = 0; lColNo < pWidth; lColNo++)
|
||||
{
|
||||
lTable[lColNo] = fProjection.inverseProjectX(fProjection.inverseFinalizeX(lColNo));
|
||||
}
|
||||
|
||||
return lTable;
|
||||
}
|
||||
}
|
153
src/com/ctreber/acearth/util/Coordinate.java
Normal file
153
src/com/ctreber/acearth/util/Coordinate.java
Normal file
@ -0,0 +1,153 @@
|
||||
package com.ctreber.acearth.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Latitude and longitude coordinate. Can be used as declination and right
|
||||
* ascension as well.
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class Coordinate {
|
||||
/*
|
||||
* MeanObliquity gives the mean obliquity of the earth's axis at epoch
|
||||
* 1990.0 (computed as 23.440592 degrees according to the method given in
|
||||
* duffett-smith, section 27)
|
||||
*/
|
||||
private static final double MEAN_OBLIQUITY = 23.440592 * Toolkit.TWOPI / 360;
|
||||
|
||||
// Or DE
|
||||
private double fLat;
|
||||
// Or RA
|
||||
private double fLong;
|
||||
|
||||
public Coordinate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Construct a location specfied by two angles. Your choice if in degrees or
|
||||
* rads, but keep track!
|
||||
*
|
||||
* @param pLong
|
||||
* Longitude or RA
|
||||
* @param pLat
|
||||
* Latitude or DE
|
||||
*/
|
||||
public Coordinate(double pLat, double pLong) {
|
||||
fLat = pLat;
|
||||
fLong = pLong;
|
||||
}
|
||||
|
||||
public void renderAsXML(Writer writer) throws IOException {
|
||||
writer.write("<Coordinate>\n");
|
||||
writer.write(" <latitude>" + fLat + "</latitude>\n");
|
||||
writer.write(" <longitude>" + fLong + "</longitude>\n");
|
||||
writer.write("</Coordinate>\n");
|
||||
}
|
||||
|
||||
public Point3D getPoint3D() {
|
||||
final double lLatRad = Toolkit.degsToRads(fLat);
|
||||
final double lLongRad = Toolkit.degsToRads(fLong);
|
||||
|
||||
final double lX = Math.cos(lLatRad) * Math.sin(lLongRad);
|
||||
final double lY = Math.sin(lLatRad);
|
||||
final double lZ = Math.cos(lLatRad) * Math.cos(lLongRad);
|
||||
|
||||
return new Point3D(lX, lY, lZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Assumes coordinate is not in degrees but rads.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Point3D getPoint3DRads() {
|
||||
final double lX = Math.cos(fLat) * Math.sin(fLong);
|
||||
final double lY = Math.sin(fLat);
|
||||
final double lZ = Math.cos(fLat) * Math.cos(fLong);
|
||||
|
||||
return new Point3D(lX, lY, lZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Convert from ecliptic to equatorial coordinates (after duffett-smith,
|
||||
* section 27)
|
||||
*/
|
||||
public Coordinate eclipticToEquatorial() {
|
||||
final double sin_e = Math.sin(MEAN_OBLIQUITY);
|
||||
final double cos_e = Math.cos(MEAN_OBLIQUITY);
|
||||
|
||||
final double lRA = Math.atan2(Math.sin(fLong) * cos_e - Math.tan(fLat) * sin_e, Math.cos(fLong));
|
||||
final double lDE = Math.asin(Math.sin(fLat) * cos_e + Math.cos(fLat) * sin_e * Math.sin(fLong));
|
||||
|
||||
return new Coordinate(lDE, lRA);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Add position to this position, make sure coordinates are valid.
|
||||
*/
|
||||
public void add(Coordinate lOther) {
|
||||
fLat += lOther.fLat;
|
||||
fLong += lOther.fLong;
|
||||
wrap();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Warp coordinates exceeding valid values. Happens when latitudes and
|
||||
* longitudes are added or substracted.
|
||||
*/
|
||||
public void wrap() {
|
||||
if (fLat > 90) {
|
||||
fLat = 180 - fLat;
|
||||
fLong += 180;
|
||||
} else if (fLat < -90) {
|
||||
fLat = -180 - fLat;
|
||||
fLong += 180;
|
||||
}
|
||||
|
||||
if (fLong > 180) {
|
||||
do {
|
||||
fLong -= 360;
|
||||
} while (fLong > 180);
|
||||
} else if (fLong < -180) {
|
||||
do {
|
||||
fLong += 360;
|
||||
} while (fLong < -180);
|
||||
}
|
||||
}
|
||||
|
||||
public double getLat() {
|
||||
return fLat;
|
||||
}
|
||||
|
||||
public double getDE() {
|
||||
return fLat;
|
||||
}
|
||||
|
||||
public double getLong() {
|
||||
return fLong;
|
||||
}
|
||||
|
||||
public double getRA() {
|
||||
return fLong;
|
||||
}
|
||||
|
||||
public boolean check() {
|
||||
return (-90 <= fLat) && (fLat <= 90) && (-180 <= fLong) && (fLong <= 180);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "lat: " + fLat + ", long: " + fLong;
|
||||
}
|
||||
}
|
59
src/com/ctreber/acearth/util/EdgeCrossing.java
Normal file
59
src/com/ctreber/acearth/util/EdgeCrossing.java
Normal file
@ -0,0 +1,59 @@
|
||||
package com.ctreber.acearth.util;
|
||||
|
||||
/**
|
||||
* <p>Holds information about a line crossing "the edge of Earth".
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class EdgeCrossing
|
||||
{
|
||||
public static final int XingTypeEntry = 0;
|
||||
public static final int XingTypeExit = 1;
|
||||
|
||||
private int fType;
|
||||
private int fIndex;
|
||||
private double fX;
|
||||
private double fY;
|
||||
private double fAngle;
|
||||
|
||||
public EdgeCrossing(int pType, int pIndex, double pX, double pY, double pAngle)
|
||||
{
|
||||
fType = pType;
|
||||
fX = pX;
|
||||
fY = pY;
|
||||
fAngle = pAngle;
|
||||
fIndex = pIndex;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return fType + ": " + fX + ", " + fY + ", " + fAngle + " (" + fIndex + ")";
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
public double getX()
|
||||
{
|
||||
return fX;
|
||||
}
|
||||
|
||||
public double getY()
|
||||
{
|
||||
return fY;
|
||||
}
|
||||
|
||||
public double getAngle()
|
||||
{
|
||||
return fAngle;
|
||||
}
|
||||
|
||||
public int getIndex()
|
||||
{
|
||||
return fIndex;
|
||||
}
|
||||
}
|
35
src/com/ctreber/acearth/util/Point2D.java
Normal file
35
src/com/ctreber/acearth/util/Point2D.java
Normal file
@ -0,0 +1,35 @@
|
||||
package com.ctreber.acearth.util;
|
||||
|
||||
/**
|
||||
* <p>A point in a 2 axis space.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class Point2D
|
||||
{
|
||||
private double fX;
|
||||
private double fY;
|
||||
|
||||
public Point2D(double pX, double pY)
|
||||
{
|
||||
fX = pX;
|
||||
fY = pY;
|
||||
}
|
||||
|
||||
public double getX()
|
||||
{
|
||||
return fX;
|
||||
}
|
||||
|
||||
public double getY()
|
||||
{
|
||||
return fY;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "x: " + fX + ", y: " + fY;
|
||||
}
|
||||
}
|
48
src/com/ctreber/acearth/util/Point3D.java
Normal file
48
src/com/ctreber/acearth/util/Point3D.java
Normal file
@ -0,0 +1,48 @@
|
||||
package com.ctreber.acearth.util;
|
||||
|
||||
/**
|
||||
* <p>A point in a 2 axis space.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class Point3D
|
||||
{
|
||||
private double fX;
|
||||
private double fY;
|
||||
private double fZ;
|
||||
|
||||
public Point3D(double pX, double pY, double pZ)
|
||||
{
|
||||
fX = pX;
|
||||
fY = pY;
|
||||
fZ = pZ;
|
||||
}
|
||||
|
||||
public double getX()
|
||||
{
|
||||
return fX;
|
||||
}
|
||||
|
||||
public double getY()
|
||||
{
|
||||
return fY;
|
||||
}
|
||||
|
||||
public double getZ()
|
||||
{
|
||||
return fZ;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "x: " + fX + ", y: " + fY + ", z: " + fZ;
|
||||
}
|
||||
|
||||
public Coordinate getCoordinate()
|
||||
{
|
||||
return new Coordinate(Toolkit.radsToDegs(Math.asin(fY)),
|
||||
Toolkit.radsToDegs(Math.atan2(fX, fZ)));
|
||||
}
|
||||
}
|
49
src/com/ctreber/acearth/util/Polygon.java
Normal file
49
src/com/ctreber/acearth/util/Polygon.java
Normal file
@ -0,0 +1,49 @@
|
||||
package com.ctreber.acearth.util;
|
||||
|
||||
|
||||
/**
|
||||
* <p>A polygon in a 3 axis space.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class Polygon
|
||||
{
|
||||
public static final int LAND = 1;
|
||||
public static final int WATER = -1;
|
||||
|
||||
private int fType;
|
||||
private Point3D[] fPoints;
|
||||
|
||||
public Polygon(int pType, Point3D[] pPoints)
|
||||
{
|
||||
fType = pType;
|
||||
fPoints = pPoints;
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
public Point3D[] getPoints()
|
||||
{
|
||||
return fPoints;
|
||||
}
|
||||
|
||||
public Point3D getPoint(int pIndex)
|
||||
{
|
||||
return fPoints[pIndex];
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
return fPoints.length;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "Type " + fType + ", " + fPoints.length + " points";
|
||||
}
|
||||
}
|
99
src/com/ctreber/acearth/util/StringParser.java
Normal file
99
src/com/ctreber/acearth/util/StringParser.java
Normal file
@ -0,0 +1,99 @@
|
||||
package com.ctreber.acearth.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Cuts a string in words separated by white space. Quotes and square
|
||||
* brackets are recognized (that is, white space within is ignored).
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class StringParser
|
||||
{
|
||||
public static List parse(String pLine)
|
||||
{
|
||||
final List lSections = new ArrayList();
|
||||
|
||||
// True if within word.
|
||||
boolean lInSectionP = false;
|
||||
// Current char
|
||||
char lChar;
|
||||
// Wait for this character before switching back to normal parsing.
|
||||
char lSeparator = ' ';
|
||||
// Part count.
|
||||
int lSectionNo = 0;
|
||||
// Part start position
|
||||
int lSectionStart = 0;
|
||||
// Part end position
|
||||
int lSectionEnd = 0;
|
||||
|
||||
final int lLen = pLine.length();
|
||||
for(int lCharNo = 0; lCharNo <= lLen; lCharNo++)
|
||||
{
|
||||
if(lCharNo < lLen)
|
||||
{
|
||||
lChar = pLine.charAt(lCharNo);
|
||||
} else
|
||||
{
|
||||
// This is a fictional last character.
|
||||
lChar = ' ';
|
||||
}
|
||||
|
||||
if(lInSectionP)
|
||||
{
|
||||
// In section. Termination is by space or specific separator.
|
||||
if((lChar != ' ') || (lSeparator != ' '))
|
||||
{
|
||||
// It's not a space, or it is a space, but we wait for a special separator.
|
||||
if(lChar == lSeparator)
|
||||
{
|
||||
// We waited for this separator. Switch back to normal parsing.
|
||||
lSeparator = ' ';
|
||||
lSectionEnd = lCharNo - 1;
|
||||
} else
|
||||
{
|
||||
lSectionEnd = lCharNo;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// Section has ended (with a space).
|
||||
lSections.add(pLine.substring(lSectionStart, lSectionEnd + 1));
|
||||
lSectionNo++;
|
||||
lInSectionP = false;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// Not in a section, skipping white space.
|
||||
if(lChar != ' ')
|
||||
{
|
||||
// No white space: a section has started.
|
||||
if(lChar == '"')
|
||||
{
|
||||
// Special parsing "string"
|
||||
lSeparator = '"';
|
||||
lSectionStart = lCharNo + 1;
|
||||
} else if(lChar == '[')
|
||||
{
|
||||
// Special parsing "square brackets"
|
||||
lSeparator = ']';
|
||||
lSectionStart = lCharNo + 1;
|
||||
} else
|
||||
{
|
||||
// Use normal parsing.
|
||||
lSeparator = ' ';
|
||||
lSectionEnd = lSectionStart = lCharNo;
|
||||
}
|
||||
lInSectionP = true;
|
||||
} else
|
||||
{
|
||||
// More void...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lSections;
|
||||
}
|
||||
}
|
258
src/com/ctreber/acearth/util/SunPositionCalculator.java
Normal file
258
src/com/ctreber/acearth/util/SunPositionCalculator.java
Normal file
@ -0,0 +1,258 @@
|
||||
package com.ctreber.acearth.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <p>Calculates the position of the point on Earth which is directly
|
||||
* below the sun or the moon.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class SunPositionCalculator
|
||||
{
|
||||
/*
|
||||
* the epoch upon which these astronomical calculations are based is
|
||||
* 1990 january 0.0, 631065600 seconds since the beginning of the
|
||||
* "unix epoch" (00:00:00 GMT, Jan. 1, 1970)
|
||||
*
|
||||
* given a number of seconds since the start of the unix epoch,
|
||||
* daysSinceEpoch() computes the number of days since the start of the
|
||||
* astronomical epoch (1990 january 0.0)
|
||||
*/
|
||||
|
||||
private static final long EPOCH_START = 631065600000l;
|
||||
|
||||
/*
|
||||
* assuming the apparent orbit of the sun about the earth is circular,
|
||||
* the rate at which the orbit progresses is given by RadsPerDay --
|
||||
* TWOPI radians per orbit divided by 365.242191 days per year:
|
||||
*/
|
||||
|
||||
private static final double RADS_PER_DAY = Toolkit.TWOPI / 365.242191;
|
||||
|
||||
/*
|
||||
* details of sun's apparent orbit at epoch 1990.0 (after
|
||||
* duffett-smith, table 6, section 46)
|
||||
*
|
||||
* Epsilon_g (ecliptic longitude at epoch 1990.0) 279.403303 degrees
|
||||
* OmegaBar_g (ecliptic longitude of perigee) 282.768422 degrees
|
||||
* Eccentricity (eccentricity of orbit) 0.016713
|
||||
*/
|
||||
|
||||
private static final double EPSILON_G = Toolkit.degsToRads(279.403303);
|
||||
private static final double OMEGA_BAR_G = Toolkit.degsToRads(282.768422);
|
||||
private static final double ECCENTRICITY = 0.016713;
|
||||
|
||||
/*
|
||||
* Lunar parameters, epoch January 0, 1990.0
|
||||
*/
|
||||
private static final double MOON_MEAN_LONGITUDE = Toolkit.degsToRads(318.351648);
|
||||
private static final double MOON_MEAN_LONGITUDE_PERIGEE = Toolkit.degsToRads(36.340410);
|
||||
private static final double MOON_MEAN_LONGITUDE_NODE = Toolkit.degsToRads(318.510107);
|
||||
private static final double MOON_INCLINATION = Toolkit.degsToRads(5.145396);
|
||||
|
||||
private static final double SIDERAL_MONTH = 27.3217;
|
||||
|
||||
/**
|
||||
* <p>Calculate the position of the mean sun: where the sun would
|
||||
* be if the earth's orbit were circular instead of ellipictal.
|
||||
*
|
||||
* <p>Verified.
|
||||
*
|
||||
* @param pDays days since ephemeris epoch
|
||||
*/
|
||||
private static double getMeanSunLongitude(double pDays)
|
||||
{
|
||||
double N, M;
|
||||
|
||||
N = RADS_PER_DAY * pDays;
|
||||
N = Toolkit.fmod(N, 0, Toolkit.TWOPI);
|
||||
if(N < 0)
|
||||
{
|
||||
N += Toolkit.TWOPI;
|
||||
}
|
||||
|
||||
M = N + EPSILON_G - OMEGA_BAR_G;
|
||||
if(M < 0)
|
||||
{
|
||||
M += Toolkit.TWOPI;
|
||||
}
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Compute ecliptic longitude of sun (in radians)
|
||||
* (after duffett-smith, section 47)
|
||||
*
|
||||
* <p>Verified.
|
||||
*
|
||||
* @param pMillis Milliseconds since unix epoch
|
||||
*/
|
||||
private static double getSunEclipticLongitude(long pMillis)
|
||||
{
|
||||
final double lDays = daysSinceEpoch(pMillis);
|
||||
final double M_sun = getMeanSunLongitude(lDays);
|
||||
|
||||
final double E = doKepler(M_sun);
|
||||
final double v = 2 * Math.atan(Math.sqrt((1 + ECCENTRICITY) / (1 - ECCENTRICITY)) * Math.tan(E / 2));
|
||||
|
||||
return (v + OMEGA_BAR_G);
|
||||
}
|
||||
|
||||
static double daysSinceEpoch(long pMillis)
|
||||
{
|
||||
return (double)(pMillis - EPOCH_START) / 24 / 3600 / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* solve Kepler's equation via Newton's method
|
||||
* (after duffett-smith, section 47)
|
||||
*
|
||||
* <p>Verified.
|
||||
*/
|
||||
private static double doKepler(double M)
|
||||
{
|
||||
double E;
|
||||
double lDelta;
|
||||
|
||||
E = M;
|
||||
while(true)
|
||||
{
|
||||
lDelta = E - ECCENTRICITY * Math.sin(E) - M;
|
||||
if(Math.abs(lDelta) <= 1e-10)
|
||||
{
|
||||
break;
|
||||
}
|
||||
E -= lDelta / (1 - ECCENTRICITY * Math.cos(E));
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>computing julian dates (assuming gregorian calendar, thus this is
|
||||
* only valid for dates of 1582 oct 15 or later)
|
||||
* (after duffett-smith, section 4)
|
||||
*
|
||||
* <p>Verified.
|
||||
*
|
||||
* @param pYear year (e.g. 19xx)
|
||||
* @param pMonth month (jan=1, feb=2, ...)
|
||||
* @param pDay day of month
|
||||
*/
|
||||
private static double getJulianDate(int pYear, int pMonth, int pDay)
|
||||
{
|
||||
if((pMonth == 1) || (pMonth == 2))
|
||||
{
|
||||
pYear -= 1;
|
||||
pMonth += 12;
|
||||
}
|
||||
|
||||
final int A = pYear / 100;
|
||||
final int B = 2 - A + (A / 4);
|
||||
final int C = (int)(365.25 * pYear);
|
||||
final int D = (int)(30.6001 * (pMonth + 1));
|
||||
|
||||
return B + C + D + pDay + 1720994.5;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>compute greenwich mean sidereal time (getGST) corresponding to a given
|
||||
* number of milliseconds since the unix epoch
|
||||
* (after duffett-smith, section 12)
|
||||
*
|
||||
* <p>Verified.
|
||||
*/
|
||||
private static double getGST(long pMillis)
|
||||
{
|
||||
final Calendar lCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||
lCal.setTime(new Date(pMillis));
|
||||
|
||||
final double lJulianDate = getJulianDate(lCal.get(Calendar.YEAR), lCal.get(Calendar.MONTH) + 1,
|
||||
lCal.get(Calendar.DAY_OF_MONTH));
|
||||
final double T = (lJulianDate - 2451545) / 36525;
|
||||
double T0 = ((T + 2.5862e-5) * T + 2400.051336) * T + 6.697374558;
|
||||
|
||||
T0 = Toolkit.fmod(T0, 0, 24.0);
|
||||
if(T0 < 0)
|
||||
{
|
||||
T0 += 24;
|
||||
}
|
||||
|
||||
final double UT = lCal.get(Calendar.HOUR_OF_DAY) +
|
||||
(lCal.get(Calendar.MINUTE) + lCal.get(Calendar.SECOND) / 60.0) / 60.0;
|
||||
|
||||
T0 += UT * 1.002737909;
|
||||
T0 = Toolkit.fmod(T0, 0, 24.0);
|
||||
if(T0 < 0)
|
||||
{
|
||||
T0 += 24;
|
||||
}
|
||||
|
||||
return T0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Given a particular time (expressed in milliseconds since the unix
|
||||
* epoch), compute position on the earth (lat, lon) such that sun is
|
||||
* directly overhead.
|
||||
*
|
||||
* <p>Verified.
|
||||
*
|
||||
* @param pMillis seconds since unix epoch
|
||||
*
|
||||
*/
|
||||
public static Coordinate getSunPositionOnEarth(long pMillis)
|
||||
{
|
||||
final Coordinate lSunPosEc = new Coordinate(0.0, getSunEclipticLongitude(pMillis));
|
||||
final Coordinate lSunPosEq = lSunPosEc.eclipticToEquatorial();
|
||||
|
||||
final double lRA = Toolkit.limitRads(lSunPosEq.getRA() - (Toolkit.TWOPI / 24) * getGST(pMillis));
|
||||
|
||||
return new Coordinate(Toolkit.radsToDegs(lSunPosEq.getDE()), Toolkit.radsToDegs(lRA));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Given a particular time (expressed in milliseconds since the unix
|
||||
* epoch), compute position on the earth (lat, lon) such that the
|
||||
* moon is directly overhead.
|
||||
*
|
||||
* Based on duffett-smith **2nd ed** section 61; combines some steps
|
||||
* into single expressions to reduce the number of extra variables.
|
||||
*
|
||||
* <p>Verified.
|
||||
*/
|
||||
public static Coordinate getMoonPositionOnEarth(long pMillis)
|
||||
{
|
||||
final double lDays = daysSinceEpoch(pMillis);
|
||||
double lSunLongEc = getSunEclipticLongitude(pMillis);
|
||||
final double Ms = getMeanSunLongitude(lDays);
|
||||
|
||||
double L = Toolkit.limitRads(Toolkit.fmod(lDays / SIDERAL_MONTH, 0, 1.0) * Toolkit.TWOPI + MOON_MEAN_LONGITUDE);
|
||||
double Mm = Toolkit.limitRads(L - Toolkit.degsToRads(0.1114041 * lDays) - MOON_MEAN_LONGITUDE_PERIGEE);
|
||||
double N = Toolkit.limitRads(MOON_MEAN_LONGITUDE_NODE - Toolkit.degsToRads(0.0529539 * lDays));
|
||||
final double Ev = Toolkit.degsToRads(1.2739) * Math.sin(2.0 * (L - lSunLongEc) - Mm);
|
||||
final double Ae = Toolkit.degsToRads(0.1858) * Math.sin(Ms);
|
||||
Mm += Ev - Ae - Toolkit.degsToRads(0.37) * Math.sin(Ms);
|
||||
final double Ec = Toolkit.degsToRads(6.2886) * Math.sin(Mm);
|
||||
L += Ev + Ec - Ae + Toolkit.degsToRads(0.214) * Math.sin(2.0 * Mm);
|
||||
L += Toolkit.degsToRads(0.6583) * Math.sin(2.0 * (L - lSunLongEc));
|
||||
N -= Toolkit.degsToRads(0.16) * Math.sin(Ms);
|
||||
|
||||
L -= N;
|
||||
lSunLongEc = Toolkit.limitRads((Math.abs(Math.cos(L)) < 1e-12) ?
|
||||
(N + Math.sin(L) * Math.cos(MOON_INCLINATION) * Math.PI / 2) :
|
||||
(N + Math.atan2(Math.sin(L) * Math.cos(MOON_INCLINATION), Math.cos(L))));
|
||||
final double lSunLatEc = Math.asin(Math.sin(L) * Math.sin(MOON_INCLINATION));
|
||||
|
||||
final Coordinate lSunPosEq = new Coordinate(lSunLatEc, lSunLongEc).eclipticToEquatorial();
|
||||
final double lRA = Toolkit.limitRads(lSunPosEq.getRA() - (Toolkit.TWOPI / 24) * getGST(pMillis));
|
||||
|
||||
return new Coordinate(Toolkit.radsToDegs(lSunPosEq.getDE()), Toolkit.radsToDegs(lRA));
|
||||
}
|
||||
}
|
135
src/com/ctreber/acearth/util/Toolkit.java
Normal file
135
src/com/ctreber/acearth/util/Toolkit.java
Normal file
@ -0,0 +1,135 @@
|
||||
package com.ctreber.acearth.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* <p>Some tools.
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class Toolkit
|
||||
{
|
||||
public static final double TWOPI = Math.PI * 2;
|
||||
public static final double PI = Math.PI;
|
||||
public static final double HALFPI = Math.PI / 2;
|
||||
private static final HashSet fsNoCap;
|
||||
|
||||
static
|
||||
{
|
||||
fsNoCap = new HashSet();
|
||||
fsNoCap.add("a");
|
||||
fsNoCap.add("as");
|
||||
fsNoCap.add("to");
|
||||
fsNoCap.add("of");
|
||||
fsNoCap.add("the");
|
||||
fsNoCap.add("off");
|
||||
fsNoCap.add("and");
|
||||
fsNoCap.add("mid");
|
||||
}
|
||||
|
||||
public static double degsToRads(double pDegrees)
|
||||
{
|
||||
return pDegrees * TWOPI / 360;
|
||||
}
|
||||
|
||||
public static double radsToDegs(double pRadians)
|
||||
{
|
||||
return pRadians * 360 / TWOPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force an angular value into the range [-PI, +PI]
|
||||
*/
|
||||
public static double limitRads(double x)
|
||||
{
|
||||
return fmod(x, -Math.PI, Math.PI);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Verified.
|
||||
*/
|
||||
public static double fmod(double pValue, double pMod)
|
||||
{
|
||||
while(pValue < 0)
|
||||
{
|
||||
pValue += pMod;
|
||||
}
|
||||
while(pValue > pMod)
|
||||
{
|
||||
pValue -= pMod;
|
||||
}
|
||||
|
||||
return pValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Examples: min -2, max 2: range 4
|
||||
*
|
||||
* <ul>
|
||||
* <li> value 1: lFact = 0
|
||||
* <li> value 3: lFact = 1, value -1
|
||||
* <li> value 9: lFact = 2, value 1
|
||||
* <li> value -3: lFact = -1, value 1
|
||||
* </ul>
|
||||
*/
|
||||
public static double fmod(double pValue, double pMinValue, double pMaxValue)
|
||||
{
|
||||
final double lRange = pMaxValue - pMinValue;
|
||||
int lFact = (int)((pValue - pMinValue) / lRange);
|
||||
if(pValue < pMinValue)
|
||||
{
|
||||
lFact--;
|
||||
}
|
||||
|
||||
return pValue - lFact * lRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Capitalize String. Uppercase words smaller/equal than 3 chars,
|
||||
* lowercase defined exceptions. Capitalize within word after '.' and '-'.
|
||||
* Capitalize all others.
|
||||
*/
|
||||
public static String intelligentCapitalize(String pText)
|
||||
{
|
||||
boolean lDoCap = false;
|
||||
final StringTokenizer lST = new StringTokenizer(pText, ".- ", true);
|
||||
final StringBuffer lSB = new StringBuffer(50);
|
||||
while(lST.hasMoreTokens())
|
||||
{
|
||||
String lWord = lST.nextToken();
|
||||
|
||||
if(lWord.equals(".") || lWord.equals("-"))
|
||||
{
|
||||
lDoCap = true;
|
||||
lSB.append(lWord);
|
||||
continue;
|
||||
}
|
||||
if(lWord.equals(" "))
|
||||
{
|
||||
lDoCap = false;
|
||||
lSB.append(lWord);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(lDoCap || (lWord.length() > 3))
|
||||
{
|
||||
lSB.append(Character.toUpperCase(lWord.charAt(0)));
|
||||
lSB.append(lWord.substring(1).toLowerCase());
|
||||
} else
|
||||
{
|
||||
if(fsNoCap.contains(lWord.toLowerCase()))
|
||||
{
|
||||
lSB.append(lWord.toLowerCase());
|
||||
} else
|
||||
{
|
||||
lSB.append(lWord.toUpperCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lSB.toString();
|
||||
}
|
||||
}
|
38
src/com/ctreber/aclib/gui/MOBoolean.java
Normal file
38
src/com/ctreber/aclib/gui/MOBoolean.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.ctreber.aclib.gui;
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class MOBoolean extends MonitoredObject
|
||||
{
|
||||
private boolean fBoolean;
|
||||
|
||||
public MOBoolean()
|
||||
{
|
||||
}
|
||||
|
||||
public MOBoolean(boolean pBoolean)
|
||||
{
|
||||
fBoolean = pBoolean;
|
||||
}
|
||||
|
||||
public void set(boolean pValue)
|
||||
{
|
||||
fBoolean = pValue;
|
||||
fireValueChanged();
|
||||
}
|
||||
|
||||
public boolean get()
|
||||
{
|
||||
return fBoolean;
|
||||
}
|
||||
|
||||
public boolean checkRange()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
13
src/com/ctreber/aclib/gui/MOChangeListener.java
Normal file
13
src/com/ctreber/aclib/gui/MOChangeListener.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.ctreber.aclib.gui;
|
||||
|
||||
/**
|
||||
* <p>Implemented by classes interetested in MonitoredObject values changes.</p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public interface MOChangeListener
|
||||
{
|
||||
public void valueChanged(MonitoredObject pObject);
|
||||
}
|
74
src/com/ctreber/aclib/gui/MODouble.java
Normal file
74
src/com/ctreber/aclib/gui/MODouble.java
Normal file
@ -0,0 +1,74 @@
|
||||
package com.ctreber.aclib.gui;
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class MODouble extends MonitoredObject
|
||||
{
|
||||
private double fDouble;
|
||||
private boolean fCheckRange = false;
|
||||
private double fMin;
|
||||
private double fMax;
|
||||
|
||||
public MODouble()
|
||||
{
|
||||
}
|
||||
|
||||
public MODouble(double pDouble)
|
||||
{
|
||||
fDouble = pDouble;
|
||||
}
|
||||
|
||||
public MODouble(double pDouble, double pMin, double pMax)
|
||||
{
|
||||
fMin = pMin;
|
||||
fMax = pMax;
|
||||
fCheckRange = true;
|
||||
set(pDouble);
|
||||
}
|
||||
|
||||
public void set(double pDouble)
|
||||
{
|
||||
if(!checkRange(pDouble))
|
||||
{
|
||||
throw new IllegalArgumentException("Argument '" + pDouble +
|
||||
"' out of range [" + niceFormat(fMin) + "; " + niceFormat(fMax) + "]");
|
||||
}
|
||||
fDouble = pDouble;
|
||||
fireValueChanged();
|
||||
}
|
||||
|
||||
private static String niceFormat(double pDouble)
|
||||
{
|
||||
if(pDouble == Double.MAX_VALUE)
|
||||
{
|
||||
return "Infinity";
|
||||
}
|
||||
|
||||
if(pDouble == Double.MIN_VALUE)
|
||||
{
|
||||
return "-Infinity";
|
||||
}
|
||||
|
||||
return Double.toString(pDouble);
|
||||
}
|
||||
|
||||
public double get()
|
||||
{
|
||||
return fDouble;
|
||||
}
|
||||
|
||||
private boolean checkRange(double pDouble)
|
||||
{
|
||||
return !fCheckRange || (fMin <= pDouble) && (pDouble <= fMax);
|
||||
}
|
||||
|
||||
public boolean checkRange()
|
||||
{
|
||||
return checkRange(fDouble);
|
||||
}
|
||||
}
|
86
src/com/ctreber/aclib/gui/MOEnum.java
Normal file
86
src/com/ctreber/aclib/gui/MOEnum.java
Normal file
@ -0,0 +1,86 @@
|
||||
package com.ctreber.aclib.gui;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Monitored enumeration value.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
* </p>
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class MOEnum extends MonitoredObject {
|
||||
private HashSet fValidValues = new HashSet();
|
||||
/**
|
||||
* <p>
|
||||
* null if no value selected
|
||||
*/
|
||||
private Object fValue;
|
||||
|
||||
public void addValidValue(Object pValue) {
|
||||
fValidValues.add(pValue);
|
||||
}
|
||||
|
||||
public void set(Object pValue) {
|
||||
if (pValue != null) {
|
||||
checkValue(pValue);
|
||||
}
|
||||
|
||||
fValue = pValue;
|
||||
fireValueChanged();
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return fValue;
|
||||
}
|
||||
|
||||
public boolean is(Object pObject) {
|
||||
checkValue(pObject);
|
||||
|
||||
return this.equals(pObject);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
if (fValue == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fValue.hashCode();
|
||||
}
|
||||
|
||||
private void checkValue(Object pValue) {
|
||||
if (!fValidValues.contains(pValue)) {
|
||||
throw new IllegalArgumentException("Illegal enum value '" + pValue + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof MOEnum) {
|
||||
MOEnum lOther = (MOEnum) obj;
|
||||
if (fValue == null) {
|
||||
return lOther.fValue == null;
|
||||
}
|
||||
|
||||
return fValue.equals(lOther.fValue);
|
||||
}
|
||||
|
||||
if (fValue == null) {
|
||||
return obj.equals(null);
|
||||
}
|
||||
|
||||
return fValue.equals(obj);
|
||||
}
|
||||
|
||||
public HashSet getValidValues() {
|
||||
return fValidValues;
|
||||
}
|
||||
|
||||
public boolean checkRange() {
|
||||
return true;
|
||||
}
|
||||
}
|
74
src/com/ctreber/aclib/gui/MOInteger.java
Normal file
74
src/com/ctreber/aclib/gui/MOInteger.java
Normal file
@ -0,0 +1,74 @@
|
||||
package com.ctreber.aclib.gui;
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class MOInteger extends MonitoredObject
|
||||
{
|
||||
private int fInteger;
|
||||
private boolean fCheckRange = false;
|
||||
private int fMin;
|
||||
private int fMax;
|
||||
|
||||
public MOInteger()
|
||||
{
|
||||
}
|
||||
|
||||
public MOInteger(int pInteger)
|
||||
{
|
||||
fInteger = pInteger;
|
||||
}
|
||||
|
||||
public MOInteger(int pInteger, int pMin, int pMax)
|
||||
{
|
||||
fMin = pMin;
|
||||
fMax = pMax;
|
||||
fCheckRange = true;
|
||||
set(pInteger);
|
||||
}
|
||||
|
||||
public void set(int pInteger)
|
||||
{
|
||||
if(!checkRange(pInteger))
|
||||
{
|
||||
throw new IllegalArgumentException("Argument '" + pInteger +
|
||||
"' out of range [" + niceFormat(fMin) + "; " + niceFormat(fMax) + "]");
|
||||
}
|
||||
fInteger = pInteger;
|
||||
fireValueChanged();
|
||||
}
|
||||
|
||||
private static String niceFormat(int pInteger)
|
||||
{
|
||||
if(pInteger == Integer.MAX_VALUE)
|
||||
{
|
||||
return "Infinity";
|
||||
}
|
||||
|
||||
if(pInteger == Integer.MIN_VALUE)
|
||||
{
|
||||
return "-Infinity";
|
||||
}
|
||||
|
||||
return Integer.toString(pInteger);
|
||||
}
|
||||
|
||||
public int get()
|
||||
{
|
||||
return fInteger;
|
||||
}
|
||||
|
||||
private boolean checkRange(int pInteger)
|
||||
{
|
||||
return !fCheckRange || (fMin <= pInteger) && (pInteger <= fMax);
|
||||
}
|
||||
|
||||
public boolean checkRange()
|
||||
{
|
||||
return checkRange(fInteger);
|
||||
}
|
||||
}
|
36
src/com/ctreber/aclib/gui/MOString.java
Normal file
36
src/com/ctreber/aclib/gui/MOString.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.ctreber.aclib.gui;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* <p>© 2002 Christian Treber, ct@ctreber.com</p>
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class MOString extends MonitoredObject
|
||||
{
|
||||
private String fString;
|
||||
|
||||
public MOString(String pString)
|
||||
{
|
||||
fString = pString;
|
||||
}
|
||||
|
||||
public void set(String pString)
|
||||
{
|
||||
fString = pString;
|
||||
fireValueChanged();
|
||||
}
|
||||
|
||||
public String get()
|
||||
{
|
||||
return fString;
|
||||
}
|
||||
|
||||
public boolean checkRange()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
44
src/com/ctreber/aclib/gui/MonitoredObject.java
Normal file
44
src/com/ctreber/aclib/gui/MonitoredObject.java
Normal file
@ -0,0 +1,44 @@
|
||||
package com.ctreber.aclib.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
* </p>
|
||||
*
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
abstract public class MonitoredObject {
|
||||
private List fListeners = new ArrayList();
|
||||
|
||||
public void addChangeListener(MOChangeListener pListener) {
|
||||
fListeners.add(pListener);
|
||||
}
|
||||
|
||||
public void removeChangeListener(MOChangeListener pListener) {
|
||||
fListeners.remove(pListener);
|
||||
}
|
||||
|
||||
void fireValueChanged() {
|
||||
final Iterator lIt = fListeners.iterator();
|
||||
while (lIt.hasNext()) {
|
||||
MOChangeListener lListener = (MOChangeListener) lIt.next();
|
||||
lListener.valueChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Check value agains (possibly defined) constraints.
|
||||
*
|
||||
* @return True if value is within range or range is not checked.
|
||||
*/
|
||||
abstract public boolean checkRange();
|
||||
}
|
20
src/com/ctreber/aclib/sort/CTSort.java
Normal file
20
src/com/ctreber/aclib/sort/CTSort.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.ctreber.aclib.sort;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* <p>Teehee - found that Comparator allready exists.
|
||||
*
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
abstract public class CTSort
|
||||
{
|
||||
public void sort(Object[] items)
|
||||
{
|
||||
sort(items, new DefaultComparator());
|
||||
}
|
||||
|
||||
abstract public void sort(Object[] items, Comparator comparator);
|
||||
}
|
19
src/com/ctreber/aclib/sort/DefaultComparator.java
Normal file
19
src/com/ctreber/aclib/sort/DefaultComparator.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.ctreber.aclib.sort;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* <p>Implements a default Comparator based on Comparable and a ascending
|
||||
* sort order. Requires that the two objects are Comparable.
|
||||
*
|
||||
* © 2002 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*
|
||||
*/
|
||||
public class DefaultComparator implements Comparator
|
||||
{
|
||||
public int compare(Object o1, Object o2)
|
||||
{
|
||||
return ((Comparable)o1).compareTo(o2);
|
||||
}
|
||||
}
|
96
src/com/ctreber/aclib/sort/QuickSort.java
Normal file
96
src/com/ctreber/aclib/sort/QuickSort.java
Normal file
@ -0,0 +1,96 @@
|
||||
package com.ctreber.aclib.sort;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* © 2001 Christian Treber, ct@ctreber.com
|
||||
* @author Christian Treber, ct@ctreber.com
|
||||
*/
|
||||
public class QuickSort extends CTSort
|
||||
{
|
||||
public void sort(Object[] items, Comparator comparator)
|
||||
{
|
||||
if(items.length <= 1)
|
||||
{
|
||||
// Nothing to sort t all or only one element.
|
||||
return;
|
||||
}
|
||||
|
||||
qsort(items, comparator, 0, items.length - 1);
|
||||
insertionSort(items, comparator, 0, items.length - 1);
|
||||
}
|
||||
|
||||
private void qsort(Object[] items, Comparator comparator, int l, int r)
|
||||
{
|
||||
final int M = 4;
|
||||
int i;
|
||||
int j;
|
||||
Object v;
|
||||
|
||||
if((r - l) > M)
|
||||
{
|
||||
i = (r + l) / 2;
|
||||
if(comparator.compare(items[l], items[i]) > 0)
|
||||
{
|
||||
swap(items, l, i);
|
||||
}
|
||||
if(comparator.compare(items[l], items[r]) > 0)
|
||||
{
|
||||
swap(items, l, r);
|
||||
}
|
||||
if(comparator.compare(items[i], items[r]) > 0)
|
||||
{
|
||||
swap(items, i, r);
|
||||
}
|
||||
|
||||
j = r - 1;
|
||||
swap(items, i, j);
|
||||
i = l;
|
||||
v = items[j];
|
||||
while(true)
|
||||
{
|
||||
while(comparator.compare(items[++i], v) < 0)
|
||||
{
|
||||
}
|
||||
while(comparator.compare(items[--j], v) > 0)
|
||||
{
|
||||
}
|
||||
if(j < i)
|
||||
{
|
||||
break;
|
||||
}
|
||||
swap(items, i, j);
|
||||
}
|
||||
swap(items, i, r - 1);
|
||||
qsort(items, comparator, l, j);
|
||||
qsort(items, comparator, i + 1, r);
|
||||
}
|
||||
}
|
||||
|
||||
private static void swap(Object[] items, int i, int j)
|
||||
{
|
||||
final Object tmp;
|
||||
tmp = items[i];
|
||||
items[i] = items[j];
|
||||
items[j] = tmp;
|
||||
}
|
||||
|
||||
private static void insertionSort(Object[] items, Comparator comparator, int lo0, int hi0)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
Object v;
|
||||
|
||||
for(i = lo0 + 1; i <= hi0; i++)
|
||||
{
|
||||
v = items[i];
|
||||
j = i;
|
||||
while((j > lo0) && (comparator.compare(items[j - 1], v) > 0))
|
||||
{
|
||||
items[j] = items[j - 1];
|
||||
j--;
|
||||
}
|
||||
items[j] = v;
|
||||
}
|
||||
}
|
||||
}
|
228
src/jcckit/GraphicsPlotCanvas.java
Normal file
228
src/jcckit/GraphicsPlotCanvas.java
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.graphic.Renderer;
|
||||
import jcckit.plot.Plot;
|
||||
import jcckit.plot.PlotCanvas;
|
||||
import jcckit.renderer.Graphics2DRenderer;
|
||||
import jcckit.renderer.Transformation;
|
||||
import jcckit.util.ConfigParameters;
|
||||
import jcckit.util.Factory;
|
||||
|
||||
/**
|
||||
* Class which handles plotting into a <tt>Graphics</tt> context based on the
|
||||
* {@link jcckit.renderer.GraphicsRenderer}. This class is not a subclass of
|
||||
* <tt>java.awt.Component</tt>. The actual AWT component presenting the plot
|
||||
* is an innerclass. Its instance wrapped by <tt>GraphicsPlotCanvas</tt> can
|
||||
* be obtained with {@link #getGraphicsCanvas}.
|
||||
* <p>
|
||||
* The plot is painted by using double-buffering and pre-rendered view of the
|
||||
* coordinate system. That is, the coordinate system is drawn into an off-screen
|
||||
* image. It will be redrawn only if the size of the embedding AWT component is
|
||||
* changed.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class GraphicsPlotCanvas extends PlotCanvas {
|
||||
/** Key of a configuration parameter. */
|
||||
public static final String BACKGROUND_KEY = "background";
|
||||
public static final String FOREGROUND_KEY = "foreground";
|
||||
public static final String DOUBLE_BUFFERING_KEY = "doubleBuffering";
|
||||
|
||||
/**
|
||||
* Class which does the actual painting. Needs the <tt>Component</tt> into
|
||||
* which the plot is painted for some resources like size, background color,
|
||||
* etc.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
private final BufferedImage img3;
|
||||
|
||||
private final Graphics2D g3;
|
||||
|
||||
private Transformation _transformation;
|
||||
private String _renderer = "jcckit.renderer.GraphicsRenderer";
|
||||
|
||||
private GraphicalElement _marker;
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters. <table
|
||||
* border=1 cellpadding=5>
|
||||
* <tr>
|
||||
* <th>Key & Default Value</th>
|
||||
* <th>Type</th>
|
||||
* <th>Mandatory</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><tt>background = </tt><i>default background color of the wrapped
|
||||
* AWT component</i></td>
|
||||
* <td><tt>Color</tt></td>
|
||||
* <td>no</td>
|
||||
* <td>Background color of the wrapped AWT component.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><tt>foreground = </tt><i>default foreground color of the wrapped
|
||||
* AWT component</i></td>
|
||||
* <td><tt>Color</tt></td>
|
||||
* <td>no</td>
|
||||
* <td>Foreground color of the wrapped AWT component.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><tt>doubleBuffering = true</td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>If <tt>true</tt> the plot will be painted by using
|
||||
* double-buffering and pre-rendered view of the coordinate system.
|
||||
* </td></tr>
|
||||
* </table>
|
||||
* In addition the configuration parameters of the
|
||||
* <a href="plot/PlotCanvas.html#PlotCanvas(jcckit.util.ConfigParameters)">
|
||||
* constructor</a> of the superclass {@link jcckit.plot.PlotCanvas} apply.
|
||||
*/
|
||||
public GraphicsPlotCanvas(ConfigParameters config, BufferedImage img3) {
|
||||
super(config);
|
||||
this.img3 = img3;
|
||||
setRenderer("jcckit.renderer.Graphics2DRenderer");
|
||||
|
||||
g3 = img3.createGraphics();
|
||||
g3.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// _doubleBuffering = config.getBoolean(DOUBLE_BUFFERING_KEY, true);
|
||||
background = config.getColor(BACKGROUND_KEY, Color.WHITE);
|
||||
foreground = config.getColor(FOREGROUND_KEY, Color.BLACK);
|
||||
}
|
||||
|
||||
private final Color background;
|
||||
private final Color foreground;
|
||||
|
||||
/**
|
||||
* Paints the plot. If {@link GraphicsPlotCanvas#_doubleBuffering} is set
|
||||
* double-buffering and pre-rendered view of the coordinate system is used.
|
||||
*/
|
||||
public void paint() {
|
||||
Dimension size = new Dimension(img3.getWidth(), img3.getHeight());
|
||||
g3.setColor(background);
|
||||
g3.fillRect(0, 0, size.width + 1, size.height + 1);
|
||||
|
||||
init(size);
|
||||
|
||||
_transformation.apply(g3);
|
||||
Plot plot = getPlot();
|
||||
drawCoordinateSystem(size, plot);
|
||||
drawPlot(plot);
|
||||
if (_marker != null) {
|
||||
_marker.renderWith(createRenderer());
|
||||
}
|
||||
}
|
||||
|
||||
private void drawPlot(Plot plot) {
|
||||
prepare();
|
||||
Renderer renderer = createRenderer();
|
||||
GraphicalElement[] curves = plot.getCurves();
|
||||
for (int i = 0; i < curves.length; i++) {
|
||||
curves[i].renderWith(renderer);
|
||||
}
|
||||
GraphicalElement annotation = plot.getAnnotation();
|
||||
if (annotation != null) {
|
||||
annotation.renderWith(renderer);
|
||||
}
|
||||
if (plot.isLegendVisible()) {
|
||||
plot.getLegend().renderWith(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
private void init(Dimension size) {
|
||||
calculateTransformation(size);
|
||||
}
|
||||
|
||||
private void drawCoordinateSystem(Dimension size, Plot plot) {
|
||||
g3.setColor(foreground);
|
||||
plot.getCoordinateSystem().renderWith(createRenderer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare graphics context before drawing the pre-rendered view of the
|
||||
* coordinate system. Does nothing but will be used in subclasses.
|
||||
*/
|
||||
protected void prepare() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the transformation form device-independent coordinates into
|
||||
* device-dependent coordinates according to the specified canvas size.
|
||||
*/
|
||||
protected void calculateTransformation(Dimension size) {
|
||||
_transformation = new Transformation(size.width, size.height, getPaper(), getHorizontalAnchor(),
|
||||
getVerticalAnchor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an appropriated {@link Renderer} for the specified
|
||||
* <tt>Graphics</tt> context.
|
||||
*/
|
||||
protected Renderer createRenderer() {
|
||||
return ((Graphics2DRenderer) Factory.create(_renderer)).init(g3);
|
||||
// return ((GraphicsRenderer) Factory.create(_renderer)).init(g, null,
|
||||
// _transformation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the renderer used to render the plot. The default value is
|
||||
* {@link GraphicsRenderer}.
|
||||
*
|
||||
* @param className
|
||||
* Fully qualified name of the renderer class.
|
||||
*/
|
||||
public void setRenderer(String className) {
|
||||
_renderer = className;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Maps the cursor position onto a point in device-independent
|
||||
// coordinates.
|
||||
// *
|
||||
// * @param x
|
||||
// * X-coordinate of the cursor.
|
||||
// * @param y
|
||||
// * Y-coordinate of the cursor.
|
||||
// */
|
||||
// public GraphPoint mapCursorPosition(int x, int y) {
|
||||
// return _transformation.transformBack(x, y);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Defines a graphical marker which will be drawn on top of the plot. To
|
||||
* remove the marker call this method with argument <tt>null</tt>.
|
||||
*
|
||||
* @param marker
|
||||
* Marker element. Can be <tt>null</tt>.
|
||||
*/
|
||||
public void setMarker(GraphicalElement marker) {
|
||||
_marker = marker;
|
||||
}
|
||||
|
||||
}
|
182
src/jcckit/data/DataContainer.java
Normal file
182
src/jcckit/data/DataContainer.java
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.data;
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Abstract superclass of all data containers. A data container holds an
|
||||
* ordered list of {@link DataElement DataElements} of the same type.
|
||||
* <p>
|
||||
* Data elements can be added, inserted, removed, or replaced.
|
||||
* Such an action leads to a {@link DataEvent} which will be delivered to
|
||||
* all {@link DataListener DataListeners} observing this
|
||||
* <code>DataContainer</code>. If this data container also implements
|
||||
* {@link DataEvent} (as {@link DataCurve} does) also the listeners
|
||||
* registrated at the data container containg this container will be notified.
|
||||
* As a consequence a <tt>DataListener</tt> must only be registered at the
|
||||
* {@link DataPlot} instance and it will automatically also received events
|
||||
* caused by manipulating one of its <tt>DataCurves</tt>.
|
||||
* <p>
|
||||
* Concrete subclasses have to implement {@link #isValid} which
|
||||
* checks whether the added or inserted <tt>DataElement</tt> is of the right
|
||||
* type. This is an application of the Template Method Design Pattern.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public abstract class DataContainer {
|
||||
private final static String TEMPLATE
|
||||
= "Invalid operation: {0}, Element: {1}, Container: {2}";
|
||||
final static String ADD = "add",
|
||||
REPLACE = "replace",
|
||||
INSERT = "insert";
|
||||
|
||||
private final Vector _listeners = new Vector();
|
||||
private final Vector _container = new Vector();
|
||||
|
||||
/** Adds a {@link DataListener}. Does nothing if already added. */
|
||||
public void addDataListener(DataListener listener) {
|
||||
if (!_listeners.contains(listener)) {
|
||||
_listeners.addElement(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes a {@link DataListener}. Does nothing if already removed. */
|
||||
public void removeDataListener(DataListener listener) {
|
||||
_listeners.removeElement(listener);
|
||||
}
|
||||
|
||||
private void notifyListeners(DataEvent event) {
|
||||
for (int i = 0, n = _listeners.size(); i < n; i++) {
|
||||
((DataListener) _listeners.elementAt(i)).dataChanged(event);
|
||||
}
|
||||
// Notifies also parent container
|
||||
if (this instanceof DataElement) {
|
||||
DataContainer container = ((DataElement) this).getContainer();
|
||||
if (container != null) {
|
||||
container.notifyListeners(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the number of elements of this container. */
|
||||
public int getNumberOfElements() {
|
||||
return _container.size();
|
||||
}
|
||||
|
||||
/** Returns the element for the specified index. */
|
||||
public DataElement getElement(int index) {
|
||||
return (DataElement) _container.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the specified element.
|
||||
* @param element Element to be looked for.
|
||||
* @return -1 if not found.
|
||||
*/
|
||||
public int getIndexOf(DataElement element) {
|
||||
return _container.indexOf(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link DataElement}. After the element has been successfully
|
||||
* added all {@link DataListener DataListeners} will be informed.
|
||||
* @param element DataElement to be added.
|
||||
* @throws IllegalArgumentException if <tt>element</tt> is not of the correct
|
||||
* type which will be checked by the method {@link #isValid}.
|
||||
*/
|
||||
public void addElement(DataElement element) {
|
||||
if (isValid(element)) {
|
||||
_container.addElement(element);
|
||||
element.setContainer(this);
|
||||
notifyListeners(DataEvent.createAddEvent(this));
|
||||
} else {
|
||||
throwException(ADD, element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a {@link DataElement} at the specified index.
|
||||
* After the element has been successfully inserted
|
||||
* all {@link DataListener DataListeners} will be informed.
|
||||
* @param index Index at which <tt>element</tt> will be inserted.
|
||||
* All elements with an index >= <tt>index</tt> will be shifted.
|
||||
* @param element DataElement to be added.
|
||||
* @throws IllegalArgumentException if <tt>element</tt> is not of the correct
|
||||
* type which will be checked by the method {@link #isValid}.
|
||||
*/
|
||||
public void insertElementAt(int index, DataElement element) {
|
||||
if (isValid(element)) {
|
||||
_container.insertElementAt(element, index);
|
||||
element.setContainer(this);
|
||||
notifyListeners(DataEvent.createInsertEvent(this, index));
|
||||
} else {
|
||||
throwException(INSERT, element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a {@link DataElement} at the specified index.
|
||||
* After the element has been successfully removed
|
||||
* all {@link DataListener DataListeners} will be informed.
|
||||
* @param index Index of the element which will be removed.
|
||||
* All elements with an index > <tt>index</tt> will be shifted.
|
||||
*/
|
||||
public void removeElementAt(int index) {
|
||||
DataElement element = (DataElement) _container.elementAt(index);
|
||||
element.setContainer(null);
|
||||
_container.removeElementAt(index);
|
||||
notifyListeners(DataEvent.createRemoveEvent(this, index, element));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the {@link DataElement} at the specified index.
|
||||
* After the element has been successfully replaced
|
||||
* all {@link DataListener DataListeners} will be informed.
|
||||
* @param index Index of the element which will be replaced by
|
||||
* <tt>element</tt>.
|
||||
* @param element The new <tt>DataElement</tt>.
|
||||
* @throws IllegalArgumentException if <tt>element</tt> is not of the correct
|
||||
* type which will be checked by the method {@link #isValid}.
|
||||
*/
|
||||
public void replaceElementAt(int index, DataElement element) {
|
||||
if (isValid(element)) {
|
||||
DataElement oldElement = (DataElement) _container.elementAt(index);
|
||||
oldElement.setContainer(null);
|
||||
_container.setElementAt(element, index);
|
||||
element.setContainer(this);
|
||||
notifyListeners(DataEvent.createReplaceEvent(this, index, oldElement));
|
||||
} else {
|
||||
throwException(REPLACE, element);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwException(String operation, DataElement element) {
|
||||
throw new IllegalArgumentException(MessageFormat.format(TEMPLATE,
|
||||
new Object[] {operation, element, this.getClass().getName()}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the specified {@link DataElement} has the
|
||||
* correct type. Concrete subclasses have to implement this method.
|
||||
* @param element <tt>DataElement</tt> to be checked.
|
||||
*/
|
||||
protected abstract boolean isValid(DataElement element);
|
||||
}
|
93
src/jcckit/data/DataCurve.java
Normal file
93
src/jcckit/data/DataCurve.java
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.data;
|
||||
|
||||
import jcckit.util.ConfigParameters;
|
||||
|
||||
/**
|
||||
* A curve is a {@link DataContainer} of {@link DataPoint DataPoints}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class DataCurve extends DataContainer implements DataElement {
|
||||
/** Config parameter key. */
|
||||
public static final String X_KEY = "x",
|
||||
Y_KEY = "y",
|
||||
TITLE_KEY = "title";
|
||||
|
||||
private final String _title;
|
||||
private DataContainer _container;
|
||||
|
||||
/** Creates an empty instance with the specified title. */
|
||||
public DataCurve(String title) {
|
||||
_title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified config parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>title = </tt><i>empty string</i></td>
|
||||
* <td><tt>String</tt></td><td>no</td>
|
||||
* <td>Curve title.</td></tr>
|
||||
* <tr><td><tt>x</tt></td><td><tt>double[]</tt></td><td>yes</td>
|
||||
* <td>x-coordinates of the curve points.</td></tr>
|
||||
* <tr><td><tt>y</tt></td><td><tt>double[]</tt></td><td>yes</td>
|
||||
* <td>y-coordinates of the curve points.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public DataCurve(ConfigParameters config) {
|
||||
this(config.get(TITLE_KEY, ""));
|
||||
double[] xPoints = config.getDoubleArray(X_KEY);
|
||||
double[] yPoints = config.getDoubleArray(Y_KEY);
|
||||
int n = Math.min(xPoints.length, yPoints.length);
|
||||
for (int i = 0; i < n; i++) {
|
||||
addElement(new DataPoint(xPoints[i], yPoints[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DataPlot} containing this curve.
|
||||
*/
|
||||
public DataContainer getContainer() {
|
||||
return _container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the {@link DataPlot} where this is a curve of.
|
||||
*/
|
||||
public void setContainer(DataContainer container) {
|
||||
_container = container;
|
||||
}
|
||||
|
||||
/** Returns the title of this curve. */
|
||||
public String getTitle() {
|
||||
return _title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if <tt>element</tt> is an instance of
|
||||
* {@link DataPoint}.
|
||||
*/
|
||||
protected boolean isValid(DataElement element) {
|
||||
return element instanceof DataPoint;
|
||||
}
|
||||
}
|
40
src/jcckit/data/DataElement.java
Normal file
40
src/jcckit/data/DataElement.java
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.data;
|
||||
|
||||
/**
|
||||
* Interface for all kinds of data elements.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface DataElement {
|
||||
/**
|
||||
* Returns the container containing this element.
|
||||
* @return <tt>null</tt> if this element is not an element of a container.
|
||||
*/
|
||||
public DataContainer getContainer();
|
||||
|
||||
/**
|
||||
* Sets the container which should contain this element.
|
||||
* This method should <b>not</b> used outside {@link DataContainer}..
|
||||
* @param container Container which should contains this element. Cann be
|
||||
* <tt>null</tt> if this element does not belong to a container.
|
||||
*/
|
||||
public void setContainer(DataContainer container);
|
||||
}
|
128
src/jcckit/data/DataEvent.java
Normal file
128
src/jcckit/data/DataEvent.java
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.data;
|
||||
|
||||
/**
|
||||
* Event to be sent to a {@link DataListener}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class DataEvent {
|
||||
private final DataContainer _container;
|
||||
private final DataEventType _type;
|
||||
private final int _index;
|
||||
private final DataElement _deletedElement;
|
||||
|
||||
/**
|
||||
* Creates an instance for the specified parameters.
|
||||
* @param container The container which has been changed.
|
||||
* @param type Type of change.
|
||||
* @param index Index of the element which has been added, inserted,
|
||||
* replaced, or removed.
|
||||
* @param deletedElement Element which has been replaced or removed.
|
||||
*/
|
||||
private DataEvent(DataContainer container, DataEventType type, int index,
|
||||
DataElement deletedElement) {
|
||||
_container = container;
|
||||
_type = type;
|
||||
_index = index;
|
||||
_deletedElement = deletedElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event of type {@link DataEventType#ELEMENT_ADDED} for the
|
||||
* specified container.
|
||||
* @param container Container where an element has been added.
|
||||
* @return <tt>ELEMENT_ADDED</tt> event.
|
||||
*/
|
||||
public static final DataEvent createAddEvent(DataContainer container) {
|
||||
return new DataEvent(container, DataEventType.ELEMENT_ADDED,
|
||||
container.getNumberOfElements() - 1, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event of type {@link DataEventType#ELEMENT_INSERTED} for the
|
||||
* specified container.
|
||||
* @param container Container where an element has been inserted.
|
||||
* @param index Index at which an element has been inserted.
|
||||
* @return <tt>ELEMENT_INSERTED</tt> event.
|
||||
*/
|
||||
public static final DataEvent createInsertEvent(DataContainer container,
|
||||
int index) {
|
||||
return new DataEvent(container, DataEventType.ELEMENT_INSERTED, index,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event of type {@link DataEventType#ELEMENT_REPLACED} for the
|
||||
* specified container.
|
||||
* @param container Container where an element has been replaced.
|
||||
* @param index Index of the replaced element.
|
||||
* @param replacedElement The previous element at <tt>index</tt>.
|
||||
* @return <tt>ELEMENT_REPLACED</tt> event.
|
||||
*/
|
||||
public static final DataEvent createReplaceEvent(DataContainer container,
|
||||
int index, DataElement replacedElement) {
|
||||
return new DataEvent(container, DataEventType.ELEMENT_REPLACED, index,
|
||||
replacedElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event of type {@link DataEventType#ELEMENT_REMOVED} for the
|
||||
* specified container.
|
||||
* @param container Container where an element has been removed.
|
||||
* @param index Index of the removed element.
|
||||
* @param removedElement The previous element at <tt>index</tt>.
|
||||
* @return <tt>ELEMENT_REMOVED</tt> event.
|
||||
*/
|
||||
public static final DataEvent createRemoveEvent(DataContainer container,
|
||||
int index, DataElement removedElement) {
|
||||
return new DataEvent(container, DataEventType.ELEMENT_REMOVED, index,
|
||||
removedElement);
|
||||
}
|
||||
|
||||
/** Returns the container. */
|
||||
public DataContainer getContainer() {
|
||||
return _container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event type. Will be one of the constants
|
||||
* {@link DataEventType#ELEMENT_ADDED},
|
||||
* {@link DataEventType#ELEMENT_INSERTED},
|
||||
* {@link DataEventType#ELEMENT_REMOVED}, or
|
||||
* {@link DataEventType#ELEMENT_REPLACED}.
|
||||
*/
|
||||
public DataEventType getType() {
|
||||
return _type;
|
||||
}
|
||||
|
||||
/** Returns the index. */
|
||||
public int getIndex() {
|
||||
return _index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the deleted element.
|
||||
* @return <tt>null</tt> if either an element has been added or inserted.
|
||||
*/
|
||||
public DataElement getDeletedElement() {
|
||||
return _deletedElement;
|
||||
}
|
||||
}
|
35
src/jcckit/data/DataEventType.java
Normal file
35
src/jcckit/data/DataEventType.java
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.data;
|
||||
|
||||
/**
|
||||
* Type of a {@link DataEvent}. Implements the typesafe enumeration pattern.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class DataEventType {
|
||||
private DataEventType() {}
|
||||
|
||||
/** Event type. */
|
||||
public static final DataEventType ELEMENT_ADDED = new DataEventType(),
|
||||
ELEMENT_INSERTED = new DataEventType(),
|
||||
ELEMENT_REPLACED = new DataEventType(),
|
||||
ELEMENT_REMOVED = new DataEventType();
|
||||
|
||||
}
|
33
src/jcckit/data/DataListener.java
Normal file
33
src/jcckit/data/DataListener.java
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.data;
|
||||
|
||||
/**
|
||||
* An interface all observers of {@link DataEvent DataEvents}
|
||||
* have to implement.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface DataListener {
|
||||
/**
|
||||
* Sends the specified data event to this object.
|
||||
* @param event Data event informing where and what happened.
|
||||
*/
|
||||
public void dataChanged(DataEvent event);
|
||||
}
|
74
src/jcckit/data/DataPlot.java
Normal file
74
src/jcckit/data/DataPlot.java
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.data;
|
||||
|
||||
import jcckit.util.ConfigParameters;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* A plot is a {@link DataContainer} of {@link DataCurve DataCurves}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class DataPlot extends DataContainer {
|
||||
/** Config parameter key. */
|
||||
public static final String CURVES_KEY = "curves",
|
||||
DATA_KEY = "data";
|
||||
|
||||
/** Creates an empty instance. */
|
||||
public DataPlot() {}
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified config parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>curves</tt></td><td><tt>String[]</tt></td><td>yes</td>
|
||||
* <td>List of keys denoting data curves. Each key refers to
|
||||
* config parameters used in the
|
||||
* <a href="DataCurve.html#DataCurve(jcckit.util.ConfigParameters)">
|
||||
* constructor</a> of {@link DataCurve}.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public DataPlot(ConfigParameters config) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(config.get(CURVES_KEY));
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
addElement(new DataCurve(config.getNode(tokenizer.nextToken())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to create a <tt>DataPlot</tt> based on the specified
|
||||
* config parameters. It is a short-cut of
|
||||
* <tt>new DataPlot(config.getNode("data"))</tt>.
|
||||
*/
|
||||
public static DataPlot create(ConfigParameters config) {
|
||||
return new DataPlot(config.getNode(DATA_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if <tt>element</tt> is an instance of
|
||||
* {@link DataCurve}.
|
||||
*/
|
||||
protected boolean isValid(DataElement element) {
|
||||
return element instanceof DataCurve;
|
||||
}
|
||||
}
|
||||
|
40
src/jcckit/data/DataPoint.java
Normal file
40
src/jcckit/data/DataPoint.java
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.data;
|
||||
|
||||
import jcckit.util.Point;
|
||||
|
||||
/**
|
||||
* Immutable two-dimensional point in data coordinates.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class DataPoint extends Point implements DataElement {
|
||||
public DataPoint(double x, double y) {
|
||||
super(x, y);
|
||||
}
|
||||
|
||||
/** Returns always <tt>null</tt>. */
|
||||
public DataContainer getContainer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Does nothing. */
|
||||
public void setContainer(DataContainer container) {}
|
||||
}
|
129
src/jcckit/graphic/Anchor.java
Normal file
129
src/jcckit/graphic/Anchor.java
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import jcckit.util.ConfigParameters;
|
||||
import jcckit.util.FactoryException;
|
||||
|
||||
/**
|
||||
* Anchor of a graphical element. There exist only the three
|
||||
* instances {@link #LEFT_BOTTOM}, {@link #CENTER}, and
|
||||
* {@link #RIGHT_TOP}.
|
||||
* <p>
|
||||
* The anchor factor can be used in a position formular. Its value
|
||||
* for the three instances reads:
|
||||
* <p>
|
||||
* <center>
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Instance</th><th>Factor</th></tr>
|
||||
* <tr><td><tt>LEFT_BOTTOM</tt></td><td>0</td></tr>
|
||||
* <tr><td><tt>CENTER</tt></td><td>1</td></tr>
|
||||
* <tr><td><tt>RIGHT_TOP</tt></td><td>2</td></tr>
|
||||
* </table>
|
||||
* </center>
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class Anchor {
|
||||
/** Anchor constant. */
|
||||
public static final Anchor LEFT_BOTTOM = new Anchor(0),
|
||||
CENTER = new Anchor(1),
|
||||
RIGHT_TOP = new Anchor(2);
|
||||
private static final String LEFT_VALUE = "left",
|
||||
RIGHT_VALUE = "right",
|
||||
CENTER_VALUE = "center",
|
||||
TOP_VALUE = "top",
|
||||
BOTTOM_VALUE = "bottom";
|
||||
|
||||
/**
|
||||
* Returns form the specified configuration parameters the
|
||||
* horizontal anchor defined by the specified key or the
|
||||
* specified default value.
|
||||
* @param config Configuration parameters.
|
||||
* @param key The key of the anchor. <tt>null</tt> is not allowed.
|
||||
* @param defaultValue The default value.
|
||||
* @return one of the three instances of <tt>Anchor</tt>.
|
||||
* @throws FactoryException if the value of <tt>key</tt> is
|
||||
* neither <tt>left</tt>, <tt>center</tt>,
|
||||
* nor <tt>right</tt>.
|
||||
* Note, that {@link FactoryException#getClassName()}
|
||||
* returns the invalid value.
|
||||
*/
|
||||
public static Anchor getHorizontalAnchor(ConfigParameters config, String key,
|
||||
Anchor defaultValue) {
|
||||
Anchor result = defaultValue;
|
||||
String anchor = config.get(key, null);
|
||||
if (anchor != null) {
|
||||
if (anchor.equals(LEFT_VALUE)) {
|
||||
result = Anchor.LEFT_BOTTOM;
|
||||
} else if (anchor.equals(CENTER_VALUE)) {
|
||||
result = Anchor.CENTER;
|
||||
} else if (anchor.equals(RIGHT_VALUE)) {
|
||||
result = Anchor.RIGHT_TOP;
|
||||
} else {
|
||||
throw new FactoryException(config, key, "Invalid horizontal anchor.");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns form the specified configuration parameters the
|
||||
* vertical anchor defined by the specified key or the
|
||||
* specified default value.
|
||||
* @param config Configuration parameters.
|
||||
* @param key The key of the anchor. <tt>null</tt> is not allowed.
|
||||
* @param defaultValue The default value.
|
||||
* @return one of the three instances of <tt>Anchor</tt>.
|
||||
* @throws FactoryException if the value of <tt>key</tt> is
|
||||
* neither <tt>top</tt>, <tt>center</tt>,
|
||||
* nor <tt>bottom</tt>.
|
||||
* Note, that {@link FactoryException#getClassName()}
|
||||
* returns the invalid value.
|
||||
*/
|
||||
public static Anchor getVerticalAnchor(ConfigParameters config, String key,
|
||||
Anchor defaultValue) {
|
||||
Anchor result = defaultValue;
|
||||
String anchor = config.get(key, null);
|
||||
if (anchor != null) {
|
||||
if (anchor.equals(BOTTOM_VALUE)) {
|
||||
result = Anchor.LEFT_BOTTOM;
|
||||
} else if (anchor.equals(CENTER_VALUE)) {
|
||||
result = Anchor.CENTER;
|
||||
} else if (anchor.equals(TOP_VALUE)) {
|
||||
result = Anchor.RIGHT_TOP;
|
||||
} else {
|
||||
throw new FactoryException(config, key, "Invalid vertcal anchor.");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private final int _factor;
|
||||
|
||||
private Anchor(int factor) {
|
||||
_factor = factor;
|
||||
}
|
||||
|
||||
/** Returns the factor. */
|
||||
public int getFactor() {
|
||||
return _factor;
|
||||
}
|
||||
}
|
||||
|
202
src/jcckit/graphic/BasicGraphicAttributes.java
Normal file
202
src/jcckit/graphic/BasicGraphicAttributes.java
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import jcckit.util.ConfigParameters;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* The basic attributes of any {@link BasicGraphicalElement}. This is an
|
||||
* extension of {@link ShapeAttributes} implementing {@link TextAttributes}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class BasicGraphicAttributes extends ShapeAttributes
|
||||
implements TextAttributes {
|
||||
/** Configuration parameter key. */
|
||||
public static final String TEXT_COLOR_KEY = "textColor",
|
||||
FONT_NAME_KEY = "fontName",
|
||||
FONT_STYLE_KEY = "fontStyle",
|
||||
FONT_SIZE_KEY = "fontSize",
|
||||
HORIZONTAL_ANCHOR_KEY = "horizontalAnchor",
|
||||
VERTICAL_ANCHOR_KEY = "verticalAnchor",
|
||||
ORIENTATION_ANGLE_KEY = "orientationAngle";
|
||||
|
||||
private final Color _textColor;
|
||||
private final String _fontName;
|
||||
private final FontStyle _fontStyle;
|
||||
private final double _fontSize;
|
||||
private final double _orientationAngle;
|
||||
private final Anchor _horizontalAnchor;
|
||||
private final Anchor _verticalAnchor;
|
||||
|
||||
/**
|
||||
* Creates a new instance based on the specified configuration
|
||||
* parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>textColor = </tt><i>default foreground color of the
|
||||
* renderer</i></td><td><tt>Color</tt></td><td>no</td>
|
||||
* <td>The text color.</td></tr>
|
||||
* <tr><td><tt>fontName = </tt><i>default font name of the
|
||||
* renderer</i></td><td><tt>String</tt></td><td>no</td>
|
||||
* <td>The name of the text font. The standard Java font name
|
||||
* "Serif", "SansSerif", and "Monospaced" can be used.
|
||||
* Other font names depend on the actual {@link Renderer}
|
||||
* rendering the corresponding {@link BasicGraphicalElement}.
|
||||
* </td></tr>
|
||||
* <tr><td><tt>fontStyle = normal</tt></td><td><tt>String</tt>
|
||||
* </td><td>no</td>
|
||||
* <td>The font style. Possible values are:
|
||||
* <ul><li><tt>normal</tt><li><tt>bold</tt><li><tt>italic</tt>
|
||||
* <li><tt>bold italic</tt></ul>
|
||||
* </td></tr>
|
||||
* <tr><td><tt>fontSize = </tt><i>default font size of the
|
||||
* renderer</i></td><td><tt>double</tt></td><td>no</td>
|
||||
* <td>The font size in units of the device-independent
|
||||
* coordinates.</td></tr>
|
||||
* <tr><td><tt>orientationAngle = 0</tt></td><td><tt>double</tt></td>
|
||||
* <td>no</td>
|
||||
* <td>The orientation angle of the text (in degree).
|
||||
* Zero means normal orientation whereas a positive value means
|
||||
* a rotation in counter-clockweise direction.</td></tr>
|
||||
* <tr><td><tt>horizontalAnchor = left</tt></td><td><tt>String</tt>
|
||||
* </td><td>no</td>
|
||||
* <td>Anchor for horizontal text position. Possible values are
|
||||
* <tt>left</tt>, <tt>center</tt>, and <tt>right</tt>.</td></tr>
|
||||
* <tr><td><tt>verticalAnchor = center</tt></td><td><tt>String</tt>
|
||||
* </td><td>no</td>
|
||||
* <td>Anchor for vertical text position. Possible values are
|
||||
* <tt>top</tt>, <tt>center</tt>, and <tt>bottom</tt>.</td></tr>
|
||||
* </table>
|
||||
* Additional configuration parameters are explained in the
|
||||
* {@link ShapeAttributes#ShapeAttributes constructor}
|
||||
* of the superclass {@link ShapeAttributes}.
|
||||
*/
|
||||
public BasicGraphicAttributes(ConfigParameters config) {
|
||||
super(config);
|
||||
_textColor = config.getColor(TEXT_COLOR_KEY, null);
|
||||
_fontName = config.get(FONT_NAME_KEY, null);
|
||||
_fontStyle = FontStyle.getFontStyle(config, FONT_STYLE_KEY,
|
||||
FontStyle.NORMAL);
|
||||
_fontSize = config.getDouble(FONT_SIZE_KEY, 0);
|
||||
_orientationAngle = config.getDouble(ORIENTATION_ANGLE_KEY, 0);
|
||||
|
||||
_horizontalAnchor = Anchor.getHorizontalAnchor(config,
|
||||
HORIZONTAL_ANCHOR_KEY, Anchor.LEFT_BOTTOM);
|
||||
_verticalAnchor = Anchor.getVerticalAnchor(config,
|
||||
VERTICAL_ANCHOR_KEY, Anchor.CENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param fillColor The fill color. May be <tt>null</tt>.
|
||||
* @param lineColor The line color. May be <tt>null</tt>.
|
||||
* @param lineThickness Thickness of the line.
|
||||
* Negative numbers will be trimmed to zero.
|
||||
* @param linePattern Line pattern. May be <tt>null</tt>.
|
||||
* @param textColor The text color. May be <tt>null</tt>.
|
||||
* @param fontName The font name. May be <tt>null</tt>.
|
||||
* @param fontStyle The font style. May be <tt>null</tt>.
|
||||
* @param fontSize The font size in units of the device-independent
|
||||
* coordinates. May be <tt>null</tt>.
|
||||
* @param orientationAngle Orientation angle of the text.
|
||||
* @param horizontalAnchor Horizontal text anchor.
|
||||
* @param verticalAnchor Vertical text anchor.
|
||||
*/
|
||||
public BasicGraphicAttributes(Color fillColor, Color lineColor,
|
||||
double lineThickness,
|
||||
double[] linePattern, Color textColor,
|
||||
String fontName, FontStyle fontStyle,
|
||||
double fontSize, double orientationAngle,
|
||||
Anchor horizontalAnchor,
|
||||
Anchor verticalAnchor) {
|
||||
super(fillColor, lineColor, lineThickness, linePattern);
|
||||
_textColor = textColor;
|
||||
_fontName = fontName;
|
||||
_fontStyle = fontStyle;
|
||||
_fontSize = fontSize;
|
||||
_orientationAngle = orientationAngle;
|
||||
_horizontalAnchor = horizontalAnchor;
|
||||
_verticalAnchor = verticalAnchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text color.
|
||||
* @return <tt>null</tt> means default color of the renderer.
|
||||
*/
|
||||
public Color getTextColor() {
|
||||
return _textColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font name.
|
||||
* @return <tt>null</tt> means default font name of the renderer.
|
||||
*/
|
||||
public String getFontName() {
|
||||
return _fontName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font style.
|
||||
* @return <tt>null</tt> means default font style of the renderer.
|
||||
*/
|
||||
public FontStyle getFontStyle() {
|
||||
return _fontStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font size in units of the device-independent coordinates.
|
||||
*/
|
||||
public double getFontSize() {
|
||||
return _fontSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the orientation angle in degree. Zero means
|
||||
* normal text orientation. Any positive angle means a
|
||||
* counter-clockwise rotation of the text.
|
||||
*/
|
||||
public double getOrientationAngle() {
|
||||
return _orientationAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the anchor for horizontal position of the text.
|
||||
* Note, that the anchor is related to the text <em>before</em>
|
||||
* it is rotated by the orientation angle.
|
||||
* @return one of the three instances of <tt>Anchor</tt>.
|
||||
*/
|
||||
public Anchor getHorizontalAnchor() {
|
||||
return _horizontalAnchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the anchor for vertical position of the text.
|
||||
* Note, that the anchor is related to the text <em>before</em>
|
||||
* it is rotated by the orientation angle.
|
||||
* @return one of the three instances of <tt>Anchor</tt>.
|
||||
*/
|
||||
public Anchor getVerticalAnchor() {
|
||||
return _verticalAnchor;
|
||||
}
|
||||
}
|
||||
|
58
src/jcckit/graphic/BasicGraphicalElement.java
Normal file
58
src/jcckit/graphic/BasicGraphicalElement.java
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Abstract superclass of all basic {@link GraphicalElement
|
||||
* GraphicalElements}. Concrete subclasses have to implement
|
||||
* the method {@link GraphicalElement#renderWith}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public abstract class BasicGraphicalElement implements GraphicalElement {
|
||||
private final GraphicAttributes _attributes;
|
||||
|
||||
/**
|
||||
* Creates an instance with the specified drawing attributes.
|
||||
* Note, that a {@link Renderer} should use default attributes
|
||||
* in the case no attributes are defined.
|
||||
* @param attributes Drawing attributes or <tt>null</tt> if undefined.
|
||||
*/
|
||||
public BasicGraphicalElement(GraphicAttributes attributes) {
|
||||
_attributes = attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the drawing attributes.
|
||||
* @return <tt>null</tt> if undefined.
|
||||
*/
|
||||
public GraphicAttributes getGraphicAttributes() {
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this basic graphical element has a closed shape
|
||||
* or not. By default always <tt>true</tt>. Subclasses may override
|
||||
* this behaviour.
|
||||
* @return <tt>true</tt> if the shape is closed.
|
||||
*/
|
||||
public boolean isClosed() {
|
||||
return true;
|
||||
}
|
||||
}
|
81
src/jcckit/graphic/ClippingRectangle.java
Normal file
81
src/jcckit/graphic/ClippingRectangle.java
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Immutable class of a rectangular clipping area.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class ClippingRectangle implements ClippingShape {
|
||||
private final double _minX, _minY, _maxX, _maxY;
|
||||
|
||||
/**
|
||||
* Creates an instance for the specified coordinates of
|
||||
* two opposite corner points.
|
||||
*/
|
||||
public ClippingRectangle(double x1, double y1, double x2, double y2) {
|
||||
_minX = Math.min(x1, x2);
|
||||
_minY = Math.min(y1, y2);
|
||||
_maxX = Math.max(x1, x2);
|
||||
_maxY = Math.max(y1, y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the specified point is inside this
|
||||
* rectangle.
|
||||
*/
|
||||
public boolean isInside(GraphPoint point) {
|
||||
double x = point.getX();
|
||||
double y = point.getY();
|
||||
return _minX <= x && x <= _maxX && _minY <= y && y <= _maxY;
|
||||
}
|
||||
|
||||
/** Returns the minimum x value. */
|
||||
public double getMinX() {
|
||||
return _minX;
|
||||
}
|
||||
|
||||
/** Returns the maximum x value. */
|
||||
public double getMaxX() {
|
||||
return _maxX;
|
||||
}
|
||||
|
||||
/** Returns the minimum y value. */
|
||||
public double getMinY() {
|
||||
return _minY;
|
||||
}
|
||||
|
||||
/** Returns the maximum y value. */
|
||||
public double getMaxY() {
|
||||
return _maxY;
|
||||
}
|
||||
|
||||
/** Returns this instance. */
|
||||
public ClippingRectangle getBoundingBox() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns a {@link Rectangle}. */
|
||||
public BasicGraphicalElement getGraphicalElement() {
|
||||
return new Rectangle(new GraphPoint(0.5 * (_minX + _maxX),
|
||||
0.5 * (_minY + _maxY)),
|
||||
_maxX - _minX, _maxY - _minY, null);
|
||||
}
|
||||
}
|
47
src/jcckit/graphic/ClippingShape.java
Normal file
47
src/jcckit/graphic/ClippingShape.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Defining a clipping shape applied to all {@link GraphicalElement
|
||||
* GraphicalElements} of a {@link GraphicalComposite}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface ClippingShape {
|
||||
/**
|
||||
* Returns <tt>true</tt> if the specified point is inside this
|
||||
* clipping shape.
|
||||
*/
|
||||
public boolean isInside(GraphPoint point);
|
||||
|
||||
/**
|
||||
* Returns the bounding box of this clipping shape.
|
||||
* This method will be used by renderers who supports only
|
||||
* rectangular clipping shapes.
|
||||
*/
|
||||
public ClippingRectangle getBoundingBox();
|
||||
|
||||
/**
|
||||
* Returns a basic graphical element (such as {@link Rectangle}
|
||||
* or {@link Polygon}) which may be used by renderers to
|
||||
* define the clipping shape for the output device.
|
||||
*/
|
||||
public BasicGraphicalElement getGraphicalElement();
|
||||
}
|
35
src/jcckit/graphic/FillAttributes.java
Normal file
35
src/jcckit/graphic/FillAttributes.java
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Interface for fill attributes.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface FillAttributes extends GraphicAttributes {
|
||||
/**
|
||||
* Returns the fill color.
|
||||
* @return <tt>null</tt> means no filling.
|
||||
*/
|
||||
public Color getFillColor();
|
||||
}
|
||||
|
82
src/jcckit/graphic/FontStyle.java
Normal file
82
src/jcckit/graphic/FontStyle.java
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import jcckit.util.ConfigParameters;
|
||||
import jcckit.util.FactoryException;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* Font style constants.
|
||||
* This class is based on the typesafe enumeration pattern.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class FontStyle {
|
||||
private static final Hashtable REPOSITORY = new Hashtable();
|
||||
static final String NORMAL_TXT = "normal",
|
||||
BOLD_TXT = "bold",
|
||||
ITALIC_TXT = "italic",
|
||||
BOLD_ITALIC_TXT = "bold italic";
|
||||
/** Font style constant. */
|
||||
public static final FontStyle NORMAL = new FontStyle(NORMAL_TXT),
|
||||
BOLD = new FontStyle(BOLD_TXT),
|
||||
ITALIC = new FontStyle(ITALIC_TXT),
|
||||
BOLD_ITALIC = new FontStyle(BOLD_ITALIC_TXT);
|
||||
|
||||
private final String _description;
|
||||
|
||||
/** Non-public constructor to control the number of instances. */
|
||||
private FontStyle(String description) {
|
||||
_description = description;
|
||||
REPOSITORY.put(description, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns from the specified configuration parameters the font style
|
||||
* defined by the specified key or the specified default value.
|
||||
* @param config Configuration parameters.
|
||||
* @param key The key of the font style.
|
||||
* @param defaultValue The default value.
|
||||
* @return one of the four instances of <tt>FontStyle</tt>.
|
||||
* @throws FactoryException if the value of the key-value pair denoted
|
||||
* by <tt>key</tt> is neither <tt>normal</tt>, <tt>bold</tt>,
|
||||
* <tt>italic</tt>, nor <tt>bold italic</tt>,
|
||||
* Note, that {@link FactoryException#getClassName()}
|
||||
* returns the invalid value.
|
||||
*/
|
||||
public static FontStyle getFontStyle(ConfigParameters config, String key,
|
||||
FontStyle defaultValue) {
|
||||
FontStyle result = defaultValue;
|
||||
String value = config.get(key, null);
|
||||
if (value != null) {
|
||||
result = (FontStyle) REPOSITORY.get(value);
|
||||
if (result == null) {
|
||||
throw new FactoryException(config, key, "Invalid font style.");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns a human readable description for pretty printing. */
|
||||
public String toString() {
|
||||
return _description;
|
||||
}
|
||||
}
|
43
src/jcckit/graphic/GraphPoint.java
Normal file
43
src/jcckit/graphic/GraphPoint.java
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import jcckit.util.Point;
|
||||
|
||||
/**
|
||||
* Immutable class of a two-dimensional point in the device-independent
|
||||
* coordinate system.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class GraphPoint extends Point {
|
||||
/**
|
||||
* Creates an instance for the specified vector.
|
||||
* If <tt>vector</tt> is <tt>null</tt> or not long enough the
|
||||
* default value 0 will be used instead.
|
||||
*/
|
||||
public GraphPoint(double[] vector) {
|
||||
super(vector);
|
||||
}
|
||||
|
||||
/** Creates an instance for the specified coordinates. */
|
||||
public GraphPoint(double x, double y) {
|
||||
super(x, y);
|
||||
}
|
||||
}
|
36
src/jcckit/graphic/GraphicAttributes.java
Normal file
36
src/jcckit/graphic/GraphicAttributes.java
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Marker interface for all types of graphic attributes
|
||||
* of a {@link BasicGraphicalElement}. Graphic attributes are only
|
||||
* hints for {@link Renderer Renderers} how to render a
|
||||
* <tt>BasicGraphicalElement</tt>. Whether they are used and how
|
||||
* they are interpreted depends on the concrete <tt>Renderer</tt>.
|
||||
* <p>
|
||||
* This is only a marker interface. There are several subinterfaces
|
||||
* specifying various attributes grouped by the type of element to
|
||||
* be rendered.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface GraphicAttributes {
|
||||
}
|
||||
|
106
src/jcckit/graphic/GraphicalComposite.java
Normal file
106
src/jcckit/graphic/GraphicalComposite.java
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Container for {@link GraphicalElement GraphicalElements}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class GraphicalComposite implements GraphicalElement {
|
||||
private final Vector _elements = new Vector();
|
||||
private final ClippingShape _clippingShape;
|
||||
|
||||
/**
|
||||
* Creates an instance with the specified clipping shape.
|
||||
* @param clippingShape Clipping shape or <tt>null</tt> if no clipping.
|
||||
*/
|
||||
public GraphicalComposite(ClippingShape clippingShape) {
|
||||
_clippingShape = clippingShape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the clipping shape.
|
||||
* @return <tt>null</tt> if no clipping should be applied.
|
||||
*/
|
||||
public ClippingShape getClippingShape() {
|
||||
return _clippingShape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified element at the end of the list of elements.
|
||||
* @param element Element to be added. <tt>null</tt> is not allowed.
|
||||
* @throws NullPointerException if <tt>element == null</tt>
|
||||
*/
|
||||
public void addElement(GraphicalElement element) {
|
||||
if (element == null) {
|
||||
throwNullPointerException();
|
||||
} else {
|
||||
_elements.addElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove all elements. */
|
||||
public void removeAllElements() {
|
||||
_elements.removeAllElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the specified element at the specified index of
|
||||
* the list of elements.
|
||||
* @param element New element. <tt>null</tt> is not allowed.
|
||||
* @throws NullPointerException if <tt>element == null</tt>
|
||||
*/
|
||||
public void replaceElementAt(int index, GraphicalElement element) {
|
||||
if (element == null) {
|
||||
throwNullPointerException();
|
||||
} else {
|
||||
_elements.setElementAt(element, index);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwNullPointerException() {
|
||||
throw new NullPointerException(
|
||||
"A null as an GraphicalElement is not allowed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders all {@link GraphicalElement GraphicalElements} in the sequence
|
||||
* they have been added.
|
||||
* @param renderer Renderer which implements all renderer interfaces
|
||||
* necessary to render the child elements.
|
||||
* @throws IllegalArgumentException if <tt>renderer</tt> is not
|
||||
* an instance of <tt>GraphicalCompositeRenderer</tt>.
|
||||
*/
|
||||
public void renderWith(Renderer renderer) {
|
||||
if (renderer instanceof GraphicalCompositeRenderer) {
|
||||
GraphicalCompositeRenderer r = (GraphicalCompositeRenderer) renderer;
|
||||
r.startRendering(this);
|
||||
for (int i = 0, n = _elements.size(); i < n; i++) {
|
||||
((GraphicalElement) _elements.elementAt(i)).renderWith(r);
|
||||
}
|
||||
r.finishRendering(this);
|
||||
} else {
|
||||
throw new IllegalArgumentException(renderer
|
||||
+ " does not implements GraphicalCompositeRenderer.");
|
||||
}
|
||||
}
|
||||
}
|
40
src/jcckit/graphic/GraphicalCompositeRenderer.java
Normal file
40
src/jcckit/graphic/GraphicalCompositeRenderer.java
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Interface of all {@link Renderer Renderers} who render a
|
||||
* {@link GraphicalComposite}. Note, that a
|
||||
* <tt>GraphicalCompositeRenderer</tt> does <em>not</em>
|
||||
* render the element of a <tt>GraphicalComposite</tt>
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface GraphicalCompositeRenderer extends Renderer {
|
||||
/**
|
||||
* Starts rendering of the specified composite before its
|
||||
* elements are rendererd. Implementations of this method
|
||||
* usually obtain the {@link ClippingShape} from
|
||||
* <tt>composite</tt>.
|
||||
*/
|
||||
public void startRendering(GraphicalComposite composite);
|
||||
|
||||
/** Finishes rendering of the specified composite. */
|
||||
public void finishRendering(GraphicalComposite composite);
|
||||
}
|
41
src/jcckit/graphic/GraphicalElement.java
Normal file
41
src/jcckit/graphic/GraphicalElement.java
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Interface all graphical elements have to implement.
|
||||
* Together with the marker interface {@link Renderer} it
|
||||
* realizes the Anticyclic Visitor Pattern, a variant of the
|
||||
* GoF Visitor Pattern. This allows not only to extend JCCKit with
|
||||
* new renderers but also with new types of <tt>GraphicalElements</tt>
|
||||
* without touching existing code.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface GraphicalElement {
|
||||
/**
|
||||
* Renders this element according to the type of renderer.
|
||||
* Concrete <tt>GraphicalElements</tt> who are not instances of
|
||||
* {@link GraphicalComposite} dynamically cast <tt>renderer</tt>.
|
||||
* If it does not implement the type of renderer specific for
|
||||
* the concrete <tt>GraphicalElement</tt> it should throw an
|
||||
* <tt>IllegalArgumentException</tt>.
|
||||
*/
|
||||
public abstract void renderWith(Renderer renderer);
|
||||
}
|
52
src/jcckit/graphic/LineAttributes.java
Normal file
52
src/jcckit/graphic/LineAttributes.java
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Interface for line attributes.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface LineAttributes extends GraphicAttributes {
|
||||
/**
|
||||
* Returns the line color.
|
||||
* @return <tt>null</tt> means default color of the renderer.
|
||||
*/
|
||||
public Color getLineColor();
|
||||
|
||||
/**
|
||||
* Returns the line tickness. 0 means that the line thickness is
|
||||
* chosen as thin as possible.
|
||||
* Implementations have to guarantee that the returned value is
|
||||
* never negative.
|
||||
*/
|
||||
public double getLineThickness();
|
||||
|
||||
/**
|
||||
* Returns the line pattern. This is a sequence of length where the
|
||||
* pen is down or up. The first element is the length where the
|
||||
* pen is down. The next element is the length where the pen is up.
|
||||
* The pattern is cyclically repeated.
|
||||
* @return <tt>null</tt> means solid line.
|
||||
*/
|
||||
public double[] getLinePattern();
|
||||
}
|
||||
|
54
src/jcckit/graphic/Oval.java
Normal file
54
src/jcckit/graphic/Oval.java
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* An oval (i.e. an ellipse).
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class Oval extends Rectangle {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param center The position of the center of this element.
|
||||
* @param width The width.
|
||||
* @param height The height.
|
||||
* @param attributes Drawing attributes. Can be <tt>null</tt>.
|
||||
*/
|
||||
public Oval(GraphPoint center, double width, double height,
|
||||
GraphicAttributes attributes) {
|
||||
super(center, width, height, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this oval with the specified {@link Renderer}.
|
||||
* @param renderer An instance of {@link OvalRenderer}.
|
||||
* @throws IllegalArgumentException if <tt>renderer</tt> is not
|
||||
* an instance of <tt>OvalRenderer</tt>.
|
||||
*/
|
||||
public void renderWith(Renderer renderer) {
|
||||
if (renderer instanceof OvalRenderer) {
|
||||
((OvalRenderer) renderer).render(this);
|
||||
} else {
|
||||
throw new IllegalArgumentException(renderer
|
||||
+ " does not implements OvalRenderer.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
src/jcckit/graphic/OvalRenderer.java
Normal file
30
src/jcckit/graphic/OvalRenderer.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Interface of all {@link Renderer Renderers} who render a
|
||||
* {@link Oval}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface OvalRenderer extends Renderer {
|
||||
/** Renders the specified oval. */
|
||||
public void render(Oval oval);
|
||||
}
|
85
src/jcckit/graphic/Polygon.java
Normal file
85
src/jcckit/graphic/Polygon.java
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* A polygon or polyline.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class Polygon extends BasicGraphicalElement {
|
||||
private final Vector _points = new Vector();
|
||||
private final boolean _closed;
|
||||
|
||||
/**
|
||||
* Creates an instance of the specified graphic attributes.
|
||||
* @param closed <tt>true</tt> if this polygon is closed.
|
||||
*/
|
||||
public Polygon(GraphicAttributes attributes, boolean closed) {
|
||||
super(attributes);
|
||||
_closed = closed;
|
||||
}
|
||||
|
||||
/** Returns <tt>true</tt> if this polygon is closed. */
|
||||
public boolean isClosed() {
|
||||
return _closed;
|
||||
}
|
||||
|
||||
/** Returns the number points. */
|
||||
public int getNumberOfPoints() {
|
||||
return _points.size();
|
||||
}
|
||||
|
||||
/** Returns the point for the specified index. */
|
||||
public GraphPoint getPoint(int index) {
|
||||
return (GraphPoint) _points.elementAt(index);
|
||||
}
|
||||
|
||||
/** Adds a new point to the end of the list of points. */
|
||||
public void addPoint(GraphPoint point) {
|
||||
_points.addElement(point);
|
||||
}
|
||||
|
||||
/** Removes all points. */
|
||||
public void removeAllPoints() {
|
||||
_points.removeAllElements();
|
||||
}
|
||||
|
||||
/** Replaces the point at the specified index by a new one. */
|
||||
public void replacePointAt(int index, GraphPoint point) {
|
||||
_points.setElementAt(point, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this line with the specified {@link Renderer}.
|
||||
* @param renderer An instance of {@link PolygonRenderer}.
|
||||
* @throws IllegalArgumentException if <tt>renderer</tt> is not
|
||||
* an instance of <tt>PolygonRenderer</tt>.
|
||||
*/
|
||||
public void renderWith(Renderer renderer) {
|
||||
if (renderer instanceof PolygonRenderer) {
|
||||
((PolygonRenderer) renderer).render(this);
|
||||
} else {
|
||||
throw new IllegalArgumentException(renderer
|
||||
+ " does not implements PolygonRenderer.");
|
||||
}
|
||||
}
|
||||
}
|
30
src/jcckit/graphic/PolygonRenderer.java
Normal file
30
src/jcckit/graphic/PolygonRenderer.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Interface of all {@link Renderer Renderers} who render an
|
||||
* instance of {@link Polygon}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface PolygonRenderer extends Renderer {
|
||||
/** Renders the specified <tt>Polygon</tt> instance. */
|
||||
public void render(Polygon polygon);
|
||||
}
|
76
src/jcckit/graphic/Rectangle.java
Normal file
76
src/jcckit/graphic/Rectangle.java
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* A rectangle.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class Rectangle extends BasicGraphicalElement {
|
||||
private final GraphPoint _center;
|
||||
private final double _width;
|
||||
private final double _height;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param center The position of the center of this element.
|
||||
* @param width The width.
|
||||
* @param height The height.
|
||||
* @param attributes Drawing attributes. Can be <tt>null</tt>.
|
||||
*/
|
||||
public Rectangle(GraphPoint center, double width, double height,
|
||||
GraphicAttributes attributes) {
|
||||
super(attributes);
|
||||
_center = center;
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
/** Returns the center of this element. */
|
||||
public GraphPoint getCenter() {
|
||||
return _center;
|
||||
}
|
||||
|
||||
/** Returns the width of this element. */
|
||||
public double getWidth() {
|
||||
return _width;
|
||||
}
|
||||
|
||||
/** Returns the height of this element. */
|
||||
public double getHeight() {
|
||||
return _height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this rectangle with the specified {@link Renderer}.
|
||||
* @param renderer An instance of {@link RectangleRenderer}.
|
||||
* @throws IllegalArgumentException if <tt>renderer</tt> is not
|
||||
* an instance of <tt>RectangleRenderer</tt>.
|
||||
*/
|
||||
public void renderWith(Renderer renderer) {
|
||||
if (renderer instanceof RectangleRenderer) {
|
||||
((RectangleRenderer) renderer).render(this);
|
||||
} else {
|
||||
throw new IllegalArgumentException(renderer
|
||||
+ " does not implements RectangleRenderer.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
src/jcckit/graphic/RectangleRenderer.java
Normal file
30
src/jcckit/graphic/RectangleRenderer.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Interface of all {@link Renderer Renderers} who render a
|
||||
* {@link Rectangle}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface RectangleRenderer extends Renderer {
|
||||
/** Renders the specified rectangle. */
|
||||
public void render(Rectangle rectangle);
|
||||
}
|
27
src/jcckit/graphic/Renderer.java
Normal file
27
src/jcckit/graphic/Renderer.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Marker interface. Each subclass is an interface for a specific
|
||||
* type of {@link GraphicalElement}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface Renderer {}
|
104
src/jcckit/graphic/ShapeAttributes.java
Normal file
104
src/jcckit/graphic/ShapeAttributes.java
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import jcckit.util.ConfigParameters;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Basic attributes for shapes.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class ShapeAttributes implements LineAttributes, FillAttributes {
|
||||
/** Configuration parameter key. */
|
||||
public static final String FILL_COLOR_KEY = "fillColor",
|
||||
LINE_COLOR_KEY = "lineColor",
|
||||
LINE_THICKNESS_KEY = "lineThickness",
|
||||
LINE_PATTERN_KEY = "linePattern";
|
||||
|
||||
private final Color _fillColor;
|
||||
private final Color _lineColor;
|
||||
private final double _lineThickness;
|
||||
private final double[] _linePattern;
|
||||
|
||||
/**
|
||||
* Creates a new instance based on the specified configuration
|
||||
* parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>fillColor = <i>no filling</i></tt></td><td><tt>Color</tt></td>
|
||||
* <td>no</td><td>The fill color of the shape.</td></tr>
|
||||
* <tr><td><tt>lineColor = <i>no line<i></tt></td><td><tt>Color</tt></td>
|
||||
* <td>no</td><td>The color of a line, a polygon, or the border of a shape.</td></tr>
|
||||
* <tr><td><tt>lineThickness = 0</tt></td><td><tt>double</tt></td>
|
||||
* <td>no</td>
|
||||
* <td>The thickness of a line. A thickness of zero means that
|
||||
* the renderer will draw the thinest line possible.</td></tr>
|
||||
* <tr><td><tt>linePattern = </tt><i>solid line</i></td>
|
||||
* <td><tt>double[]</tt></td><td>no</td>
|
||||
* <td>A sequence of lengths where the pen is alternatively
|
||||
* down or up. For example, <tt>0.1 0.1</tt> will lead to a dashed
|
||||
* line whereas <tt>0.02 0.02</tt> is the pattern of a dotted
|
||||
* line and <tt>0.02 0.02 0.1 0.02</tt> of a dashed-dotted
|
||||
* line.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public ShapeAttributes(ConfigParameters config) {
|
||||
this(config.getColor(FILL_COLOR_KEY, null),
|
||||
config.getColor(LINE_COLOR_KEY, null),
|
||||
config.getDouble(LINE_THICKNESS_KEY, 0),
|
||||
config.getDoubleArray(LINE_PATTERN_KEY, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param fillColor The fill color. May be <tt>null</tt>.
|
||||
* @param lineColor The line color. May be <tt>null</tt>.
|
||||
* @param lineThickness Thickness of the line.
|
||||
* Negative numbers will be trimmed to zero.
|
||||
* @param linePattern Line pattern. May be <tt>null</tt>.
|
||||
*/
|
||||
public ShapeAttributes(Color fillColor, Color lineColor,
|
||||
double lineThickness, double[] linePattern) {
|
||||
_fillColor = fillColor;
|
||||
_lineColor = lineColor;
|
||||
_lineThickness = Math.max(0, lineThickness);
|
||||
_linePattern = linePattern;
|
||||
}
|
||||
|
||||
public Color getFillColor() {
|
||||
return _fillColor;
|
||||
}
|
||||
|
||||
public Color getLineColor() {
|
||||
return _lineColor;
|
||||
}
|
||||
|
||||
public double getLineThickness() {
|
||||
return _lineThickness;
|
||||
}
|
||||
|
||||
public double[] getLinePattern() {
|
||||
return _linePattern;
|
||||
}
|
||||
}
|
||||
|
67
src/jcckit/graphic/Text.java
Normal file
67
src/jcckit/graphic/Text.java
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* A single line of text.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class Text extends BasicGraphicalElement {
|
||||
private final GraphPoint _position;
|
||||
private final String _text;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance with the specified parameters.
|
||||
* @param position Position of the text.
|
||||
* @param text Text.
|
||||
* @param attributes Drawing attributes. Can be <tt>null</tt>.
|
||||
*/
|
||||
public Text(GraphPoint position, String text, GraphicAttributes attributes) {
|
||||
super(attributes);
|
||||
_position = position;
|
||||
_text = text;
|
||||
}
|
||||
|
||||
/** Returns the position. */
|
||||
public GraphPoint getPosition() {
|
||||
return _position;
|
||||
}
|
||||
|
||||
/** Returns the text string. */
|
||||
public String getText() {
|
||||
return _text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this line with the specified {@link Renderer}.
|
||||
* @param renderer An instance of {@link TextRenderer}.
|
||||
* @throws IllegalArgumentException if <tt>renderer</tt> is not
|
||||
* an instance of <tt>TextRenderer</tt>.
|
||||
*/
|
||||
public void renderWith(Renderer renderer) {
|
||||
if (renderer instanceof TextRenderer) {
|
||||
((TextRenderer) renderer).render(this);
|
||||
} else {
|
||||
throw new IllegalArgumentException(renderer
|
||||
+ " does not implements TextRenderer.");
|
||||
}
|
||||
}
|
||||
}
|
75
src/jcckit/graphic/TextAttributes.java
Normal file
75
src/jcckit/graphic/TextAttributes.java
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Interface for text attributes.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface TextAttributes extends GraphicAttributes {
|
||||
/**
|
||||
* Returns the text color.
|
||||
* @return <tt>null</tt> means default color of the renderer.
|
||||
*/
|
||||
public Color getTextColor();
|
||||
|
||||
/**
|
||||
* Returns the font name.
|
||||
* @return <tt>null</tt> means default font name of the renderer.
|
||||
*/
|
||||
public String getFontName();
|
||||
|
||||
/**
|
||||
* Returns the font style.
|
||||
* @return <tt>null</tt> means default font style of the renderer.
|
||||
*/
|
||||
public FontStyle getFontStyle();
|
||||
|
||||
/**
|
||||
* Returns the font size in units of the device-independent coordinates.
|
||||
*/
|
||||
public double getFontSize();
|
||||
|
||||
/**
|
||||
* Returns the orientation angle in degree. Zero means
|
||||
* normal text orientation. Any positive angle means a
|
||||
* counter-clockwise rotation of the text.
|
||||
*/
|
||||
public double getOrientationAngle();
|
||||
|
||||
/**
|
||||
* Returns the anchor for horizontal position of the text.
|
||||
* Note, that the anchor is related to the text <em>before</em>
|
||||
* it is rotated by the orientation angle.
|
||||
* @return one of the three instances of <tt>Anchor</tt>.
|
||||
*/
|
||||
public Anchor getHorizontalAnchor();
|
||||
|
||||
/**
|
||||
* Returns the anchor for vertical position of the text.
|
||||
* Note, that the anchor is related to the text <em>before</em>
|
||||
* it is rotated by the orientation angle.
|
||||
* @return one of the three instances of <tt>Anchor</tt>.
|
||||
*/
|
||||
public Anchor getVerticalAnchor();
|
||||
}
|
||||
|
30
src/jcckit/graphic/TextRenderer.java
Normal file
30
src/jcckit/graphic/TextRenderer.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.graphic;
|
||||
|
||||
/**
|
||||
* Interface of all {@link Renderer Renderers} who render an
|
||||
* instance of {@link Text}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface TextRenderer extends Renderer {
|
||||
/** Renders the specified <tt>Text</tt> instance. */
|
||||
public void render(Text text);
|
||||
}
|
120
src/jcckit/plot/AbstractSymbolFactory.java
Normal file
120
src/jcckit/plot/AbstractSymbolFactory.java
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.GraphPoint;
|
||||
import jcckit.graphic.GraphicAttributes;
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.util.ConfigParameters;
|
||||
import jcckit.util.Factory;
|
||||
|
||||
/**
|
||||
* Abstract superclass of all {@link SymbolFactory SymbolFactories}.
|
||||
* Subclasses have to implement {@link #createPlainSymbol createPlainSymbol()}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public abstract class AbstractSymbolFactory implements SymbolFactory {
|
||||
/** Size of all symbols. */
|
||||
protected final double _size;
|
||||
|
||||
/** Attributes of all symbols. */
|
||||
protected final GraphicAttributes _attributes;
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>size = </tt>0.01</td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Size of the symbol in device-independent units.</td></tr>
|
||||
* <tr><td><tt>attributes</tt></td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Configuration parameters for the attributes of the symbol.
|
||||
* <tt>className</tt> has to be a class which is an instance of
|
||||
* {@link GraphicAttributes}.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public AbstractSymbolFactory(ConfigParameters config) {
|
||||
_size = config.getDouble(SIZE_KEY, DEFAULT_SIZE);
|
||||
_attributes = (GraphicAttributes) Factory.createOrGet(
|
||||
config.getNode(ATTRIBUTES_KEY), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a symbol.
|
||||
* Evaluate <tt>hintFromPreviousPoint</tt> if it is a {@link AttributesHint}.
|
||||
* Calls {@link #createSymbol(GraphPoint, GraphicAttributes, Hint, Hint)}.
|
||||
* @param point Symbol position.
|
||||
* @param hintFromPreviousPoint Hint from the previous point.
|
||||
* @param hintFromPreviousCurve Hint from the previous curve.
|
||||
*/
|
||||
public Symbol createSymbol(GraphPoint point, Hint hintFromPreviousPoint,
|
||||
Hint hintFromPreviousCurve) {
|
||||
GraphicAttributes attributes = _attributes;
|
||||
Hint hintForNextPoint = hintFromPreviousPoint;
|
||||
if (hintFromPreviousPoint instanceof AttributesHint) {
|
||||
attributes = ((AttributesHint) hintFromPreviousPoint).getAttributes();
|
||||
hintForNextPoint
|
||||
= ((AttributesHint) hintFromPreviousPoint).getNextHint();
|
||||
}
|
||||
return createSymbol(point, attributes, hintForNextPoint,
|
||||
hintFromPreviousCurve);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a symbol.
|
||||
* Uses {@link #createPlainSymbol createPlainSymbol()}.
|
||||
* @param point Symbol position.
|
||||
* @param attributes Symbol attributes.
|
||||
* @param hintForNextPoint Hint for the next point. Will be delivered
|
||||
* unchanged in the return <tt>Symbol</tt> object.
|
||||
* @param hintFromPreviousCurve Hint from the previous curve.
|
||||
* Will be delivered unchanged in the return <tt>Symbol</tt> object.
|
||||
* Subclasses may override this behavior.
|
||||
*/
|
||||
protected Symbol createSymbol(GraphPoint point, GraphicAttributes attributes,
|
||||
Hint hintForNextPoint,
|
||||
Hint hintFromPreviousCurve) {
|
||||
return new Symbol(createPlainSymbol(point, _size, attributes),
|
||||
hintForNextPoint, hintFromPreviousCurve);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a symbol for the legend at the specified position.
|
||||
* Uses {@link #createPlainSymbol createPlainSymbol()}
|
||||
* @param centerPosition Center position of the symbol.
|
||||
* @param size The size of the symbol. Will be ignored because the value
|
||||
* given in the constructor will be used.
|
||||
*/
|
||||
public GraphicalElement createLegendSymbol(GraphPoint centerPosition,
|
||||
double size) {
|
||||
return createPlainSymbol(centerPosition, _size, _attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the graphical element of the plain symbol.
|
||||
* @param centerPosition Center position of the symbol.
|
||||
* @param size The size of the symbol.
|
||||
* @param attributes The attributes of the symbol.
|
||||
*/
|
||||
protected abstract GraphicalElement createPlainSymbol(
|
||||
GraphPoint centerPosition, double size, GraphicAttributes attributes);
|
||||
}
|
39
src/jcckit/plot/AttributesHint.java
Normal file
39
src/jcckit/plot/AttributesHint.java
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.GraphicAttributes;
|
||||
|
||||
/**
|
||||
* A {@link Hint} which wraps a {@link GraphicAttributes} instance.
|
||||
* In addition the method {@link #getNextHint()} creates a new instance
|
||||
* with different attributes derivated from the wrapped attributes.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface AttributesHint extends Hint {
|
||||
/**
|
||||
* Returns the hint for the next {@link Symbol} of a {@link Curve}.
|
||||
* The new hint has a different {@link GraphicAttributes}.
|
||||
*/
|
||||
public AttributesHint getNextHint();
|
||||
|
||||
/** Returns the attributes value. */
|
||||
public GraphicAttributes getAttributes();
|
||||
}
|
496
src/jcckit/plot/AxisParameters.java
Normal file
496
src/jcckit/plot/AxisParameters.java
Normal file
@ -0,0 +1,496 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import jcckit.graphic.BasicGraphicAttributes;
|
||||
import jcckit.graphic.GraphPoint;
|
||||
import jcckit.graphic.LineAttributes;
|
||||
import jcckit.graphic.ShapeAttributes;
|
||||
import jcckit.graphic.TextAttributes;
|
||||
import jcckit.util.ConfigData;
|
||||
import jcckit.util.ConfigParameters;
|
||||
import jcckit.util.ConfigParametersBasedConfigData;
|
||||
import jcckit.util.Factory;
|
||||
import jcckit.util.Format;
|
||||
import jcckit.util.PropertiesBasedConfigData;
|
||||
import jcckit.util.TicLabelFormat;
|
||||
import jcckit.util.Util;
|
||||
|
||||
/**
|
||||
* Helper class with various parameters defining an axis.
|
||||
* This helper class is used by {@link CartesianCoordinateSystem}
|
||||
* to set up a coordinate systems.
|
||||
* <p>
|
||||
* This class holds more than a dozen parameters. There are two factory
|
||||
* methods creating instances for x- and y-axis based on
|
||||
* {@link ConfigParameters}. They differ in their default parameters for
|
||||
* those axes.
|
||||
* <p>
|
||||
* Note, that there is a direct access of these parameters without getters
|
||||
* and setters but only for classes in the package <tt>jcckit.plot</tt>.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class AxisParameters {
|
||||
/** Configuration parameter key. */
|
||||
public static final String LOG_SCALE_KEY = "logScale",
|
||||
MINIMUM_KEY = "minimum",
|
||||
MAXIMUM_KEY = "maximum",
|
||||
AXIS_LENGTH_KEY = "axisLength",
|
||||
AXIS_ATTRIBUTES_KEY = "axisAttributes",
|
||||
AXIS_LABEL_KEY = "axisLabel",
|
||||
AXIS_LABEL_POSITION_KEY = "axisLabelPosition",
|
||||
AXIS_LABEL_ATTRIBUTES_KEY = "axisLabelAttributes",
|
||||
AUTOMATIC_TIC_CALCULATION_KEY
|
||||
= "automaticTicCalculation",
|
||||
MINIMUM_TIC_KEY = "minimumTic",
|
||||
MAXIMUM_TIC_KEY = "maximumTic",
|
||||
NUMBER_OF_TICS_KEY = "numberOfTics",
|
||||
TIC_LENGTH_KEY = "ticLength",
|
||||
TIC_ATTRIBUTES_KEY = "ticAttributes",
|
||||
TIC_LABEL_FORMAT_KEY = "ticLabelFormat",
|
||||
TIC_LABEL_POSITION_KEY = "ticLabelPosition",
|
||||
TIC_LABEL_ATTRIBUTES_KEY = "ticLabelAttributes",
|
||||
GRID_KEY = "grid",
|
||||
GRID_ATTRIBUTES_KEY = "gridAttributes";
|
||||
|
||||
private static final double LN10 = Math.log(10);
|
||||
|
||||
/** If <tt>true</tt> the scale is logarithmic otherwise linear. */
|
||||
boolean logScale;
|
||||
/** Minimum data value represented by the axis. */
|
||||
double minimum;
|
||||
/** Maximum data value represented by the axis. */
|
||||
double maximum;
|
||||
/** Length of the axis in device-independent graphical units. */
|
||||
double axisLength;
|
||||
/**
|
||||
* Line attributes of the axis.
|
||||
* Can be <tt>null</tt> which means default attributes.
|
||||
*/
|
||||
LineAttributes axisAttributes;
|
||||
|
||||
boolean automaticTicCalculation;
|
||||
double minimumTic;
|
||||
double maximumTic;
|
||||
int numberOfTics;
|
||||
/**
|
||||
* Length of the tics in device-independent graphical units.
|
||||
* If 0 no tics and tics label will be drawn.
|
||||
*/
|
||||
double ticLength;
|
||||
/**
|
||||
* Attributes of the tics.
|
||||
* Can be <tt>null</tt> which means default attributes.
|
||||
*/
|
||||
LineAttributes ticAttributes;
|
||||
/** Tic label formatter. */
|
||||
TicLabelFormat ticLabelFormat;
|
||||
/** Position of the tic label relative to the tic. */
|
||||
GraphPoint ticLabelPosition;
|
||||
/** Text attributes of the tic labels. */
|
||||
TextAttributes ticLabelAttributes;
|
||||
|
||||
/** If <tt>true</tt> grid lines are drawn. */
|
||||
boolean grid;
|
||||
/**
|
||||
* Attributes of the grid lines.
|
||||
* Can be <tt>null</tt> which means default attributes.
|
||||
*/
|
||||
LineAttributes gridAttributes;
|
||||
|
||||
/** Axis label. */
|
||||
String axisLabel;
|
||||
/** Position of the axis label relative to the center of the axis. */
|
||||
GraphPoint axisLabelPosition;
|
||||
/** Text attributes of the axis label. */
|
||||
TextAttributes axisLabelAttributes;
|
||||
|
||||
/**
|
||||
* Calculate the tics based on <tt>minimumTic</tt>, <tt>maximumTic</tt>,
|
||||
* and <tt>numberOfTics</tt>. If <tt>automaticTicCalculation == true</tt>
|
||||
* appropriated values for these fields are calculated.
|
||||
*/
|
||||
double[] calculateTics() {
|
||||
if (automaticTicCalculation) {
|
||||
calculateTicsParameters();
|
||||
}
|
||||
double[] result = new double[numberOfTics];
|
||||
if (numberOfTics > 0) {
|
||||
double b = Util.log(minimumTic, logScale);
|
||||
double a = Util.log(maximumTic, logScale);
|
||||
a = numberOfTics > 1 ? (a - b) / (numberOfTics - 1) : 0;
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = Util.exp(a * i + b, logScale);
|
||||
}
|
||||
result[0] = adjust(minimum, result[0]);
|
||||
result[numberOfTics - 1] = adjust(maximum, result[numberOfTics - 1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void calculateTicsParameters() {
|
||||
double min = Math.min(minimum, maximum);
|
||||
double max = Math.max(minimum, maximum);
|
||||
if (logScale) {
|
||||
int minExponent = (int) (199.9999 + Math.log(min) / LN10) - 199;
|
||||
int maxExponent = (int) (200.0001 + Math.log(max) / LN10) - 200;
|
||||
minimumTic = Math.exp(LN10 * minExponent);
|
||||
maximumTic = Math.exp(LN10 * maxExponent);
|
||||
numberOfTics = maxExponent - minExponent + 1;
|
||||
} else {
|
||||
int baseExponent = (int) (199.69 + Math.log(max - min) / LN10) - 200;
|
||||
double base = 0.2 * Math.exp(LN10 * baseExponent);
|
||||
do
|
||||
{
|
||||
base *= 5;
|
||||
int minInt = (int) (999999.999999 + min / base) - 999999;
|
||||
int maxInt = (int) (1000000.000001 + max / base) - 1000000;
|
||||
minimumTic = minInt * base;
|
||||
maximumTic = maxInt * base;
|
||||
numberOfTics = maxInt - minInt + 1;
|
||||
} while (numberOfTics > 11);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>adjustingValue</tt> if <tt>value</tt> is very close
|
||||
* to <tt>adjustingValue</tt>. Otherwise <tt>value</tt> is returned.
|
||||
*/
|
||||
private static double adjust(double adjustingValue, double value) {
|
||||
return value != 0 && Math.abs(adjustingValue / value - 1) < 1e-11
|
||||
? adjustingValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <tt>Properties</tt> object with those default parameters
|
||||
* which are common for x- and y-axis.
|
||||
*/
|
||||
private static Properties createDefaultAxisProperties() {
|
||||
Properties p = new Properties();
|
||||
p.put(LOG_SCALE_KEY, "false");
|
||||
p.put(MINIMUM_KEY, "0");
|
||||
p.put(MAXIMUM_KEY, "1");
|
||||
p.put(AXIS_LENGTH_KEY, "0.8");
|
||||
p.put(AXIS_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
|
||||
ShapeAttributes.class.getName());
|
||||
p.put(AXIS_LABEL_KEY, "x");
|
||||
p.put(AXIS_LABEL_POSITION_KEY, "0 -0.05");
|
||||
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
|
||||
BasicGraphicAttributes.class.getName());
|
||||
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "center");
|
||||
p.put(AUTOMATIC_TIC_CALCULATION_KEY, "true");
|
||||
p.put(TIC_LENGTH_KEY, "0.01");
|
||||
p.put(TIC_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
|
||||
ShapeAttributes.class.getName());
|
||||
p.put(TIC_LABEL_POSITION_KEY, "0 -0.01");
|
||||
p.put(TIC_LABEL_FORMAT_KEY, "%1.1f");
|
||||
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
|
||||
BasicGraphicAttributes.class.getName());
|
||||
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "center");
|
||||
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "top");
|
||||
p.put(GRID_KEY, "false");
|
||||
p.put(GRID_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
|
||||
ShapeAttributes.class.getName());
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <tt>Properties</tt> object of the default parameters for
|
||||
* an x-axis.
|
||||
*/
|
||||
private static Properties createDefaultXAxisProperties() {
|
||||
Properties p = createDefaultAxisProperties();
|
||||
p.put(AXIS_LABEL_KEY, "x");
|
||||
p.put(AXIS_LABEL_POSITION_KEY, "0 -0.05");
|
||||
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "top");
|
||||
p.put(TIC_LABEL_POSITION_KEY, "0 -0.01");
|
||||
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "center");
|
||||
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "top");
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an x axis based on the specified configuration parameters.
|
||||
* All numbers (lengths, fontsizes, linethicknesses, etc.) are in
|
||||
* device-independent units.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>automaticTicCalculation = true</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>Has to be <tt>true</tt> if the tics should be calculated
|
||||
* automatically.</td></tr>
|
||||
* <tr><td><tt>axisAttributes = </tt>default values of
|
||||
* {@link ShapeAttributes}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Attributes of the axis box.</td></tr>
|
||||
* <tr><td><tt>axisLabel = x</tt></td>
|
||||
* <td><tt>String</tt></td><td>no</td>
|
||||
* <td>Axis label.</td></tr>
|
||||
* <tr><td><tt>axisLabelAttributes = </tt>default values of
|
||||
* {@link BasicGraphicAttributes} with a text anchor CENTER
|
||||
* TOP.</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Text attributes of axis label.</td></tr>
|
||||
* <tr><td><tt>axisLabelPosition = 0 -0.05</tt></td>
|
||||
* <td><tt>double[]</tt></td><td>no</td>
|
||||
* <td>Position of the anchor of the axis
|
||||
* label relative to the center of the x-axis line.</td></tr>
|
||||
* <tr><td><tt>axisLength = 0.8</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Length of the x-axis.</td></tr>
|
||||
* <tr><td><tt>grid = false</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>If <tt>true</tt> grid lines will be drawn through the axis
|
||||
* tics.</td></tr>
|
||||
* <tr><td><tt>gridAttributes = </tt>default values of
|
||||
* {@link ShapeAttributes}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Attributes of the grid lines.</td></tr>
|
||||
* <tr><td><tt>logScale = false</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>If <tt>true</tt> the axis will be logarithmic. Otherwise
|
||||
* the axis is linear.</td></tr>
|
||||
* <tr><td><tt>maximum = 1</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>The corresponding data value of one end of the axis.</td></tr>
|
||||
* <tr><td><tt>maximumTic = </tt>result from automatic calculation</td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>The corresponding data value of the tic nearest the maximum end
|
||||
* of the axis.</td></tr>
|
||||
* <tr><td><tt>minimum = 0</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>The corresponding data value of one end of the axis.</td></tr>
|
||||
* <tr><td><tt>minimumTic = </tt>result from automatic calculation</td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>The corresponding data value of the tic nearest the minimum end
|
||||
* of the axis.</td></tr>
|
||||
* <tr><td><tt>numberOfTics = </tt>result from automatic calculation</td>
|
||||
* <td><tt>int</tt></td><td>no</td>
|
||||
* <td>Number of tics. The tics between the minimum and maximum tic
|
||||
* are spaced equidistantly.</td></tr>
|
||||
* <tr><td><tt>ticAttributes = </tt>default values of
|
||||
* {@link ShapeAttributes}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Attributes of the tics.</td></tr>
|
||||
* <tr><td><tt>ticLabelAttributes = </tt>default values of
|
||||
* {@link BasicGraphicAttributes} with a text anchor CENTER
|
||||
* TOP.</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Text attributes of tic labels.</td></tr>
|
||||
* <tr><td><tt>ticLabelFormat = %1.1f</tt></td>
|
||||
* <td><tt>String</tt> or <tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Defines rendering of the tic label. By default a
|
||||
* <tt>printf</tt>-like format string is given (see {@link Format}).
|
||||
* Note, that an empty string means that tic labels are dropped.
|
||||
* <p>
|
||||
* For non-numerical rendering an implementation of a
|
||||
* {@link TicLabelFormat} can be specified (e.g.
|
||||
* {@link TicLabelMap}). Note, that a configuration sub tree with
|
||||
* a <tt>className</tt> key-value pair overwrites any string
|
||||
* definition.</td></tr>
|
||||
* <tr><td><tt>ticLabelPosition = 0 -0.01</tt></td>
|
||||
* <td><tt>double[]</tt></td><td>no</td>
|
||||
* <td>Position of the anchor of the tic label relative to the
|
||||
* tic position on the axis.</td></tr>
|
||||
* <tr><td><tt>ticLength = 0.01</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Length of the tics. Negative/positive values mean tics
|
||||
* inside/outside the box.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public static AxisParameters createXAxis(ConfigParameters config) {
|
||||
return createAxis(config, createDefaultXAxisProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <tt>Properties</tt> object of the default parameters for
|
||||
* an x-axis.
|
||||
*/
|
||||
private static Properties createDefaultYAxisProperties() {
|
||||
Properties p = createDefaultAxisProperties();
|
||||
p.put(AXIS_LENGTH_KEY, "0.45");
|
||||
p.put(AXIS_LABEL_KEY, "y");
|
||||
p.put(AXIS_LABEL_POSITION_KEY, "-0.1 0");
|
||||
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "bottom");
|
||||
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.ORIENTATION_ANGLE_KEY, "90");
|
||||
p.put(TIC_LABEL_POSITION_KEY, "-0.01 0");
|
||||
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "right");
|
||||
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "center");
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an y axis based on the specified configuration parameters.
|
||||
* All numbers (lengths, fontsizes, linethicknesses, etc.) are in
|
||||
* device-independent units.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>automaticTicCalculation = true</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>Has to be <tt>true</tt> if the tics should be calculated
|
||||
* automatically.</td></tr>
|
||||
* <tr><td><tt>axisAttributes = </tt>default values of
|
||||
* {@link ShapeAttributes}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Attributes of the axis box.</td></tr>
|
||||
* <tr><td><tt>axisLabel = y</tt></td>
|
||||
* <td><tt>String</tt></td><td>no</td>
|
||||
* <td>Axis label.</td></tr>
|
||||
* <tr><td><tt>axisLabelAttributes = </tt>default values of
|
||||
* {@link BasicGraphicAttributes} with a text anchor CENTER
|
||||
* BOTTOM and the text rotated by 90 degree.</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Text attributes of axis label.</td></tr>
|
||||
* <tr><td><tt>axisLabelPosition = -0.1 0</tt></td>
|
||||
* <td><tt>double[]</tt></td><td>no</td>
|
||||
* <td>Position of the anchor of the axis
|
||||
* label relative to the center of the y-axis line.</td></tr>
|
||||
* <tr><td><tt>axisLength = 0.45</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Length of the y-axis.</td></tr>
|
||||
* <tr><td><tt>grid = false</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>If <tt>true</tt> grid lines will be drawn through the axis
|
||||
* tics.</td></tr>
|
||||
* <tr><td><tt>gridAttributes = </tt>default values of
|
||||
* {@link ShapeAttributes}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Attributes of the grid lines.</td></tr>
|
||||
* <tr><td><tt>logScale = false</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>If <tt>true</tt> the axis will be logarithmic. Otherwise
|
||||
* the axis is linear.</td></tr>
|
||||
* <tr><td><tt>maximum = 1</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>The corresponding data value of one end of the axis.</td></tr>
|
||||
* <tr><td><tt>maximumTic = </tt>result from automatic calculation</td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>The corresponding data value of the tic nearest the maximum end
|
||||
* of the axis.</td></tr>
|
||||
* <tr><td><tt>minimum = 0</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>The corresponding data value of one end of the axis.</td></tr>
|
||||
* <tr><td><tt>minimumTic = </tt>result from automatic calculation</td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>The corresponding data value of the tic nearest the minimum end
|
||||
* of the axis.</td></tr>
|
||||
* <tr><td><tt>numberOfTics = </tt>result from automatic calculation</td>
|
||||
* <td><tt>int</tt></td><td>no</td>
|
||||
* <td>Number of tics. The tics between the minimum and maximum tic
|
||||
* are spaced equidistantly.</td></tr>
|
||||
* <tr><td><tt>ticAttributes = </tt>default values of
|
||||
* {@link ShapeAttributes}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Attributes of the tics.</td></tr>
|
||||
* <tr><td><tt>ticLabelAttributes = </tt>default values of
|
||||
* {@link BasicGraphicAttributes} with a text anchor RIGHT CENTER.
|
||||
* </td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Text attributes of tic labels.</td></tr>
|
||||
* <tr><td><tt>ticLabelFormat = %1.1f</tt></td>
|
||||
* <td><tt>String</tt></td><td>no</td>
|
||||
* <td>Defines rendering of the tic label. By default a
|
||||
* <tt>printf</tt>-like format string is given (see {@link Format}).
|
||||
* Note, that an empty string means that tic labels are dropped.
|
||||
* <p>
|
||||
* For non-numerical rendering an implementation of a
|
||||
* {@link TicLabelFormat} can be specified (e.g.
|
||||
* {@link TicLabelMap}). Note, that a configuration sub tree with
|
||||
* a <tt>className</tt> key-value pair overwrites any string
|
||||
* definition.</td></tr>
|
||||
* <tr><td><tt>ticLabelPosition = -0.01 0</tt></td>
|
||||
* <td><tt>double[]</tt></td><td>no</td>
|
||||
* <td>Position of the anchor of the tic label relative to the
|
||||
* tic position on the axis.</td></tr>
|
||||
* <tr><td><tt>ticLength = 0.01</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Length of the tics. Negative/positive values mean tics
|
||||
* inside/outside the box.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public static AxisParameters createYAxis(ConfigParameters config) {
|
||||
return createAxis(config, createDefaultYAxisProperties());
|
||||
}
|
||||
|
||||
private static AxisParameters createAxis(ConfigParameters config,
|
||||
Properties p) {
|
||||
ConfigData cd = new PropertiesBasedConfigData(p);
|
||||
ConfigParameters c = new ConfigParameters(cd);
|
||||
cd = new ConfigParametersBasedConfigData(config, c);
|
||||
c = new ConfigParameters(cd);
|
||||
|
||||
AxisParameters a = new AxisParameters();
|
||||
a.logScale = c.getBoolean(LOG_SCALE_KEY);
|
||||
a.minimum = c.getDouble(MINIMUM_KEY);
|
||||
a.maximum = c.getDouble(MAXIMUM_KEY);
|
||||
a.axisLength = c.getDouble(AXIS_LENGTH_KEY);
|
||||
a.axisAttributes
|
||||
= (LineAttributes) Factory.create(c.getNode(AXIS_ATTRIBUTES_KEY));
|
||||
a.axisLabel = c.get(AXIS_LABEL_KEY);
|
||||
a.axisLabelPosition
|
||||
= new GraphPoint(c.getDoubleArray(AXIS_LABEL_POSITION_KEY));
|
||||
a.axisLabelAttributes = (TextAttributes) Factory.create(
|
||||
c.getNode(AXIS_LABEL_ATTRIBUTES_KEY));
|
||||
a.ticLength = c.getDouble(TIC_LENGTH_KEY);
|
||||
a.automaticTicCalculation
|
||||
= c.getBoolean(AUTOMATIC_TIC_CALCULATION_KEY);
|
||||
if (!a.automaticTicCalculation) {
|
||||
a.calculateTicsParameters(); // calculate default parameters
|
||||
a.minimumTic = c.getDouble(MINIMUM_TIC_KEY, a.minimumTic);
|
||||
a.maximumTic = c.getDouble(MAXIMUM_TIC_KEY, a.maximumTic);
|
||||
a.numberOfTics = c.getInt(NUMBER_OF_TICS_KEY, a.numberOfTics);
|
||||
}
|
||||
a.ticAttributes
|
||||
= (LineAttributes) Factory.create(c.getNode(TIC_ATTRIBUTES_KEY));
|
||||
a.ticLabelFormat = createTicLabelFormat(c);
|
||||
a.ticLabelPosition
|
||||
= new GraphPoint(c.getDoubleArray(TIC_LABEL_POSITION_KEY));
|
||||
a.ticLabelAttributes = (TextAttributes) Factory.create(
|
||||
c.getNode(TIC_LABEL_ATTRIBUTES_KEY));
|
||||
a.grid = c.getBoolean(GRID_KEY);
|
||||
a.gridAttributes
|
||||
= (LineAttributes) Factory.create(c.getNode(GRID_ATTRIBUTES_KEY));
|
||||
return a;
|
||||
}
|
||||
|
||||
private static TicLabelFormat createTicLabelFormat(ConfigParameters c)
|
||||
{
|
||||
TicLabelFormat result = Format.create(c, TIC_LABEL_FORMAT_KEY);
|
||||
ConfigParameters node = c.getNode(TIC_LABEL_FORMAT_KEY);
|
||||
if (node.get(Factory.CLASS_NAME_KEY, null) != null) {
|
||||
result = (TicLabelFormat) Factory.create(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
130
src/jcckit/plot/BarFactory.java
Normal file
130
src/jcckit/plot/BarFactory.java
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.GraphPoint;
|
||||
import jcckit.graphic.GraphicAttributes;
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.graphic.Rectangle;
|
||||
import jcckit.util.ConfigParameters;
|
||||
|
||||
/**
|
||||
* A factory of bars. The bars are {@link Rectangle Rectangles}.
|
||||
* Depending on the configuration parameters the bars can be
|
||||
* horizontal or vertical. Bars of several curves can be side by side or
|
||||
* stacked. The bar length is determined by the x or y value of the
|
||||
* curve point in device-independent coordinates. If the value is negative
|
||||
* the bar goes into the negative direction. For stacked bars the values
|
||||
* should always be positive.
|
||||
* <p>
|
||||
* When used inside a {@link SimpleCurve} soft clipping should always be
|
||||
* switched off (see
|
||||
* {@link SimpleCurve#SimpleCurve(ConfigParameters, int, int, ClippingShape, Legend)}).
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class BarFactory extends AbstractSymbolFactory {
|
||||
/** Configuration parameter key. */
|
||||
public static final String STACKED_KEY = "stacked",
|
||||
HORIZONTAL_BARS_KEY = "horizontalBars";
|
||||
|
||||
private final boolean _stacked;
|
||||
private final boolean _horizontalBars;
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>horizontalBars = false</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>If <tt>true</tt> horizontal bars will be drawn. Otherwise
|
||||
* vertical bars are drawn.</td></tr>
|
||||
* <tr><td><tt>stacked = false</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>If <tt>true</tt> the bars of several curves will be
|
||||
* stacked.</td></tr>
|
||||
* </table>
|
||||
* In addition the configuration parameters of the
|
||||
* <a href="AbstractSymbolFactory.html#AbstractSymbolFactory(jcckit.util.ConfigParameters)">
|
||||
* constructor</a> of the superclass {@link AbstractSymbolFactory} apply.
|
||||
*/
|
||||
public BarFactory(ConfigParameters config) {
|
||||
super(config);
|
||||
_horizontalBars = config.getBoolean(HORIZONTAL_BARS_KEY, false);
|
||||
_stacked = config.getBoolean(STACKED_KEY, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a bar at the specified point.
|
||||
* If <tt>hintFromPreviousCurve</tt>
|
||||
* is not an instance of {@link PositionHint} the values of
|
||||
* origin and position will be (0,0).
|
||||
* @param hintFromPreviousCurve Hint from previous curve. Will be used
|
||||
* to calculate symbol shape and hint for the next curve.
|
||||
*/
|
||||
protected Symbol createSymbol(GraphPoint point, GraphicAttributes attributes,
|
||||
Hint hintForNextPoint,
|
||||
Hint hintFromPreviousCurve) {
|
||||
GraphPoint origin = new GraphPoint(null);
|
||||
GraphPoint position = origin;
|
||||
if (hintFromPreviousCurve instanceof PositionHint) {
|
||||
origin = ((PositionHint) hintFromPreviousCurve).getOrigin();
|
||||
position = ((PositionHint) hintFromPreviousCurve).getPosition();
|
||||
}
|
||||
double px = position.getX();
|
||||
double py = position.getY();
|
||||
double x = point.getX() - origin.getX();
|
||||
double y = point.getY() - origin.getY();
|
||||
if (_horizontalBars) {
|
||||
y = _size;
|
||||
position = new GraphPoint(px + 0.5 * x, point.getY() + py);
|
||||
px += _stacked ? x : 0;
|
||||
py += _stacked ? 0 : _size;
|
||||
} else {
|
||||
x = _size;
|
||||
position = new GraphPoint(point.getX() + px, py + 0.5 * y);
|
||||
px += _stacked ? 0 : _size;
|
||||
py += _stacked ? y : 0;
|
||||
}
|
||||
Hint hintForNextCurve = new PositionHint(origin, new GraphPoint(px, py));
|
||||
return new Symbol(new Rectangle(position, Math.abs(x), Math.abs(y),
|
||||
attributes),
|
||||
hintForNextPoint, hintForNextCurve);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a symbol for the legend at the specified position.
|
||||
* @param centerPosition Center position of the symbol.
|
||||
* @param size The size of the symbol.
|
||||
*/
|
||||
public GraphicalElement createLegendSymbol(GraphPoint centerPosition,
|
||||
double size) {
|
||||
return new Rectangle(centerPosition, size, size, _attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>null</tt> because this method isn't needed but has to be
|
||||
* implemented.
|
||||
*/
|
||||
protected GraphicalElement createPlainSymbol(
|
||||
GraphPoint centerPosition, double size, GraphicAttributes attributes) {
|
||||
return null;
|
||||
}
|
||||
}
|
206
src/jcckit/plot/CartesianCoordinateSystem.java
Normal file
206
src/jcckit/plot/CartesianCoordinateSystem.java
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.data.DataPoint;
|
||||
import jcckit.graphic.ClippingRectangle;
|
||||
import jcckit.graphic.ClippingShape;
|
||||
import jcckit.graphic.GraphicalComposite;
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.graphic.GraphicAttributes;
|
||||
import jcckit.graphic.GraphPoint;
|
||||
import jcckit.graphic.LineAttributes;
|
||||
import jcckit.graphic.Polygon;
|
||||
import jcckit.graphic.Text;
|
||||
import jcckit.transformation.CartesianTransformation;
|
||||
import jcckit.transformation.Transformation;
|
||||
import jcckit.util.ConfigParameters;
|
||||
|
||||
/**
|
||||
* A Cartesian coordinate system. One or both axes can be logarithmic.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class CartesianCoordinateSystem implements CoordinateSystem {
|
||||
/** Configuration parameter key. */
|
||||
public static final String ORIGIN_KEY = "origin",
|
||||
X_AXIS_KEY = "xAxis",
|
||||
Y_AXIS_KEY = "yAxis";
|
||||
|
||||
private final CartesianTransformation _transformation;
|
||||
private final GraphicalComposite _view;
|
||||
private final ClippingRectangle _clippingRectangle;
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>origin = 0.15, 0.1</tt></td>
|
||||
* <td><tt>double[]</tt></td><td>no</td>
|
||||
* <td>Position (in device-independent coordinates) of the lower-left
|
||||
* corner of the axis box.</td></tr>
|
||||
* <tr><td><tt>xAxis</tt></td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Parameters defining the x-axis. For definitions and default
|
||||
* values see {@link AxisParameters#createXAxis
|
||||
* AxisParameters.createXAxis()}.</td></tr>
|
||||
* <tr><td><tt>yAxis</tt></td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Parameters defining the y-axis. For definitions and default
|
||||
* values see {@link AxisParameters#createYAxis
|
||||
* AxisParameters.createYAxis()}.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public CartesianCoordinateSystem(ConfigParameters config) {
|
||||
this(new GraphPoint(config.getDoubleArray(ORIGIN_KEY,
|
||||
new double[] {0.15, 0.1})),
|
||||
AxisParameters.createXAxis(config.getNode(X_AXIS_KEY)),
|
||||
AxisParameters.createYAxis(config.getNode(Y_AXIS_KEY)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance for the specified origin and parameters
|
||||
* of both axes.
|
||||
* @param origin Position (in device-independent coordinates) of the
|
||||
* lower-left corner of the axis box.
|
||||
* @param xAxisParameters Parameters of the x-axis.
|
||||
* @param yAxisParameters Parameters of the y-axis.
|
||||
*/
|
||||
public CartesianCoordinateSystem(GraphPoint origin,
|
||||
AxisParameters xAxisParameters,
|
||||
AxisParameters yAxisParameters) {
|
||||
double x = origin.getX();
|
||||
double y = origin.getY();
|
||||
_transformation = new CartesianTransformation(xAxisParameters.logScale,
|
||||
yAxisParameters.logScale,
|
||||
new DataPoint(xAxisParameters.minimum, yAxisParameters.minimum),
|
||||
new GraphPoint(x, y),
|
||||
new DataPoint(xAxisParameters.maximum, yAxisParameters.maximum),
|
||||
new GraphPoint(x + xAxisParameters.axisLength,
|
||||
y + yAxisParameters.axisLength));
|
||||
_clippingRectangle = new ClippingRectangle(x, y,
|
||||
x + xAxisParameters.axisLength,
|
||||
y + yAxisParameters.axisLength);
|
||||
_view = new GraphicalComposite(null);
|
||||
createView(origin, xAxisParameters, yAxisParameters);
|
||||
}
|
||||
|
||||
/** Creates the graphical representation of this coordinate system. */
|
||||
private void createView(GraphPoint origin,
|
||||
AxisParameters xAxisParameters,
|
||||
AxisParameters yAxisParameters) {
|
||||
double x0 = origin.getX();
|
||||
double x1 = x0 + xAxisParameters.axisLength;
|
||||
double y0 = origin.getY();
|
||||
double y1 = y0 + yAxisParameters.axisLength;
|
||||
GraphPoint lowerLeftCorner = new GraphPoint(x0, y0);
|
||||
GraphPoint upperLeftCorner = new GraphPoint(x0, y1);
|
||||
GraphPoint lowerRightCorner = new GraphPoint(x1, y0);
|
||||
GraphPoint upperRightCorner = new GraphPoint(x1, y1);
|
||||
LineAttributes xLineAttributes = xAxisParameters.axisAttributes;
|
||||
LineAttributes yLineAttributes = yAxisParameters.axisAttributes;
|
||||
createTicsAndGrid(true, y0, y1, xAxisParameters);
|
||||
createTicsAndGrid(false, x0, x1, yAxisParameters);
|
||||
addLine(lowerLeftCorner, lowerRightCorner, xLineAttributes);
|
||||
addLine(lowerLeftCorner, upperLeftCorner, yLineAttributes);
|
||||
addLine(upperLeftCorner, upperRightCorner, xLineAttributes);
|
||||
addLine(lowerRightCorner, upperRightCorner, yLineAttributes);
|
||||
createLabel(0.5 * (x0 + x1), y0, xAxisParameters);
|
||||
createLabel(x0, 0.5 * (y0 + y1), yAxisParameters);
|
||||
}
|
||||
|
||||
private void createLabel(double x, double y, AxisParameters parameters) {
|
||||
if (parameters.axisLabel.length() > 0) {
|
||||
_view.addElement(new Text(
|
||||
new GraphPoint(x + parameters.axisLabelPosition.getX(),
|
||||
y + parameters.axisLabelPosition.getY()),
|
||||
parameters.axisLabel, parameters.axisLabelAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
private void createTicsAndGrid(boolean isXAxis, double low, double high,
|
||||
AxisParameters parameters) {
|
||||
double[] tics = parameters.calculateTics();
|
||||
int offIndex = isXAxis ? 1 : 0;
|
||||
double[] point = new double[2]; // helper array
|
||||
for (int i = 0; i < tics.length; i++) {
|
||||
point[1 - offIndex] = tics[i];
|
||||
point[offIndex] = 1;
|
||||
GraphPoint gPoint1 =
|
||||
_transformation.transformToGraph(new DataPoint(point[0], point[1]));
|
||||
point[0] = gPoint1.getX();
|
||||
point[1] = gPoint1.getY();
|
||||
point[offIndex] = high;
|
||||
gPoint1 = new GraphPoint(point[0], point[1]);
|
||||
point[offIndex] += parameters.ticLength;
|
||||
addLine(gPoint1, new GraphPoint(point[0], point[1]),
|
||||
parameters.ticAttributes);
|
||||
point[offIndex] = low;
|
||||
GraphPoint gPoint2 = new GraphPoint(point[0], point[1]);
|
||||
if (parameters.grid) {
|
||||
addLine(gPoint1, gPoint2, parameters.gridAttributes);
|
||||
}
|
||||
point[offIndex] -= parameters.ticLength;
|
||||
addLine(gPoint2, new GraphPoint(point[0], point[1]),
|
||||
parameters.ticAttributes);
|
||||
if (parameters.ticLabelFormat != null) {
|
||||
point[offIndex] += parameters.ticLength;
|
||||
point[0] += parameters.ticLabelPosition.getX();
|
||||
point[1] += parameters.ticLabelPosition.getY();
|
||||
_view.addElement(new Text(new GraphPoint(point[0], point[1]),
|
||||
parameters.ticLabelFormat.form(tics[i]),
|
||||
parameters.ticLabelAttributes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addLine(GraphPoint point1, GraphPoint point2,
|
||||
GraphicAttributes attributes) {
|
||||
Polygon line = new Polygon(attributes, false);
|
||||
line.addPoint(point1);
|
||||
line.addPoint(point2);
|
||||
_view.addElement(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the graphical representation of the coordinate system.
|
||||
* In each call the same instance is returned.
|
||||
*/
|
||||
public GraphicalElement getView() {
|
||||
return _view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the clipping rectangle of specified by the axis.
|
||||
* In each call the same instance is returned.
|
||||
*/
|
||||
public ClippingShape getClippingShape() {
|
||||
return _clippingRectangle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transformation of data coordinates into the device-independent
|
||||
* coordinates of the axis box.
|
||||
* In each call the same instance is returned.
|
||||
*/
|
||||
public Transformation getTransformation() {
|
||||
return _transformation;
|
||||
}
|
||||
}
|
54
src/jcckit/plot/CircleSymbolFactory.java
Normal file
54
src/jcckit/plot/CircleSymbolFactory.java
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.GraphicAttributes;
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.graphic.GraphPoint;
|
||||
import jcckit.graphic.Oval;
|
||||
import jcckit.util.ConfigParameters;
|
||||
|
||||
/**
|
||||
* A factory of circle symbols.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class CircleSymbolFactory extends AbstractSymbolFactory {
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters.
|
||||
* For the configuration parameters see the
|
||||
* <a href="AbstractSymbolFactory.html#AbstractSymbolFactory(jcckit.util.ConfigParameters)">
|
||||
* constructor</a> of the superclass {@link AbstractSymbolFactory}.
|
||||
*/
|
||||
public CircleSymbolFactory(ConfigParameters config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a circle.
|
||||
* @param centerPosition Position of the center of the circle.
|
||||
* @param size Diameter of the circle.
|
||||
* @param attributes Circle attributes.
|
||||
*/
|
||||
protected GraphicalElement createPlainSymbol(GraphPoint centerPosition,
|
||||
double size,
|
||||
GraphicAttributes attributes) {
|
||||
return new Oval(centerPosition, size, size, attributes);
|
||||
}
|
||||
}
|
55
src/jcckit/plot/CoordinateSystem.java
Normal file
55
src/jcckit/plot/CoordinateSystem.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.graphic.ClippingShape;
|
||||
import jcckit.transformation.Transformation;
|
||||
|
||||
/**
|
||||
* Interface for all generators of coordinate systems. A
|
||||
* <tt>CoordinateSystem</tt> creates a
|
||||
* {@link jcckit.graphic.GraphicalComposite} which contains all the
|
||||
* {@link GraphicalElement GraphicalElements} defining axes, labels, grid, etc.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface CoordinateSystem {
|
||||
/**
|
||||
* Returns the graphical representation of a coordinate
|
||||
* system. Different invocations of this method may return
|
||||
* different coordinate systems, e.g., due to changes in the
|
||||
* transformation or clipping shapes.
|
||||
*/
|
||||
public GraphicalElement getView();
|
||||
|
||||
/**
|
||||
* Returns the clipping chape of {@link Curve Curves} drawn on top
|
||||
* of the coordinates system. Different invocations of
|
||||
* this method may return different clipping shapes.
|
||||
*/
|
||||
public ClippingShape getClippingShape();
|
||||
|
||||
/**
|
||||
* Returns the transformation between data coordinates and
|
||||
* device-independent graphcial coordinates. Different invocations
|
||||
* of this method may return different transformations.
|
||||
*/
|
||||
public Transformation getTransformation();
|
||||
}
|
64
src/jcckit/plot/Curve.java
Normal file
64
src/jcckit/plot/Curve.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.graphic.GraphPoint;
|
||||
|
||||
/**
|
||||
* A curve is defined by a sequence of points in device-independent
|
||||
* coordinates. The points can be decorated by symbols and/or
|
||||
* connected by lines.{@link Hint Hints} are used to determine additional
|
||||
* properties of the symbol. This is especially important for
|
||||
* charts with bars.
|
||||
* <p>
|
||||
* In accordance with the Factory Method Pattern
|
||||
* the symbols are created by a {@link SymbolFactory}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface Curve {
|
||||
/**
|
||||
* Returns the graphical representation of a curve.
|
||||
* Different invocations of this method might return
|
||||
* different instances.
|
||||
* This is especially true after adding, inserting, removing, or
|
||||
* repplacing a point of the curve.
|
||||
*/
|
||||
public GraphicalElement getView();
|
||||
|
||||
/**
|
||||
* Returns a symbol which can be used to create the legend for the curve.
|
||||
* For example, it should return a horizontal line with the symbol
|
||||
* in the middle if the curve is a line with points decorated by symbols.
|
||||
*/
|
||||
public GraphicalElement getLegendSymbol();
|
||||
|
||||
/**
|
||||
* Appends a new point to the curve.
|
||||
* @param point Position in device-independent coordinates.
|
||||
* @param hintFromPreviousCurve Hint which may be used to calculate
|
||||
* the corresponding {@link GraphicalElement}.
|
||||
* @return hint for next curve.
|
||||
*/
|
||||
public Hint addPoint(GraphPoint point, Hint hintFromPreviousCurve);
|
||||
|
||||
/** Removes all points from the curve. */
|
||||
public void removeAllPoints();
|
||||
}
|
42
src/jcckit/plot/CurveFactory.java
Normal file
42
src/jcckit/plot/CurveFactory.java
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.ClippingShape;
|
||||
|
||||
/**
|
||||
* Interface of a curve factory. A curve factory creates a new instance
|
||||
* of a {@link Curve}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface CurveFactory {
|
||||
/**
|
||||
* Creates a new curve instance.
|
||||
* @param curveIndex The index of the curve in the {@link Plot} to which
|
||||
* it should belong.
|
||||
* @param numberOfCurves Number of curves. Will be needed to calculate the
|
||||
* y-coordinate of the legend symbol.
|
||||
* @param clippingShape Clipping shape applied to the curve.
|
||||
* @param legend The legend which will show the curve symbol.
|
||||
* @return an empty instance.
|
||||
*/
|
||||
public Curve create(int curveIndex, int numberOfCurves,
|
||||
ClippingShape clippingShape, Legend legend);
|
||||
}
|
136
src/jcckit/plot/ErrorBarFactory.java
Normal file
136
src/jcckit/plot/ErrorBarFactory.java
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.GraphPoint;
|
||||
import jcckit.graphic.GraphicAttributes;
|
||||
import jcckit.graphic.GraphicalComposite;
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.graphic.Rectangle;
|
||||
import jcckit.util.ConfigParameters;
|
||||
import jcckit.util.Factory;
|
||||
|
||||
/**
|
||||
* Symbol factory for creating symbols with error bars. It wraps
|
||||
* a {@link SymbolFactory} for creating the symbol. The error bars
|
||||
* are {@link Rectangle Rectangles}.
|
||||
* <p>
|
||||
* Curves with error bars are based on <em>two</em>
|
||||
* {@link jcckit.data.DataCurve DataCurves}:
|
||||
* <ol><li>The plain curve.
|
||||
* <li>An instance which stores the errors in <i>x</i> and <i>y</i>.
|
||||
* It is assumed that the errors are positive values defining
|
||||
* the error symmetrically around the curve points.
|
||||
* </ol>
|
||||
* <p>
|
||||
* The <tt>ErrorBarFactory</tt> needs an instance of {@link PositionHint}
|
||||
* as initial {@link Hint} for the next curve. Its origin must be
|
||||
* the origin of the data coordinate system in device-independent coordinates.
|
||||
* The position of <tt>PositionHint</tt> must be undefined.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class ErrorBarFactory implements SymbolFactory {
|
||||
/** Configuration parameter key. */
|
||||
public static final String SYMBOL_FACTORY_KEY = "symbolFactory";
|
||||
|
||||
private final SymbolFactory _symbolFactory;
|
||||
private final GraphicAttributes _attributes;
|
||||
private final double _size;
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>symbolFactory = null</tt></td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Definition of the wrapped {@link SymbolFactory} which generates
|
||||
* the curve symbol without bars. By default an empty
|
||||
* {@link GraphicalComposite} will be created.</td></tr>
|
||||
* <tr><td><tt>size = 0</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Width of the error bars.</td></tr>
|
||||
* <tr><td><tt>attributes = null</tt></td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Definition of the {@link GraphicAttributes} of the error
|
||||
* bars.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public ErrorBarFactory(ConfigParameters config) {
|
||||
_symbolFactory = (SymbolFactory) Factory.createOrGet(
|
||||
config.getNode(SYMBOL_FACTORY_KEY), null);
|
||||
_size = config.getDouble(SIZE_KEY, 0);
|
||||
_attributes = (GraphicAttributes) Factory.createOrGet(
|
||||
config.getNode(ATTRIBUTES_KEY), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the legend symbol. Calls the wrapped {@link SymbolFactory}
|
||||
* or returns an empty instance of {@link GraphicalComposite} if undefined.
|
||||
*/
|
||||
public GraphicalElement createLegendSymbol(GraphPoint centerPosition,
|
||||
double size) {
|
||||
return _symbolFactory == null ? new GraphicalComposite(null)
|
||||
: _symbolFactory.createLegendSymbol(centerPosition, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates either the curve symbol or the error bars. Error bars are
|
||||
* created when <tt>hintFromPreviousCurve</tt> is an instance of
|
||||
* {@link PositionHint} and its position attribute is not <tt>null</tt>.
|
||||
* Otherwise the curve symbol is created. The position attributes stores
|
||||
* the curve point (in device-independent coordinates). The origin is
|
||||
* always as set in the initial <tt>PositionHint</tt>. The hint for
|
||||
* the next curve wrapped by the returned <tt>Symbol</tt> is always
|
||||
* a <tt>PositionHint</tt>.
|
||||
*/
|
||||
public Symbol createSymbol(GraphPoint point, Hint hintFromPreviousPoint,
|
||||
Hint hintFromPreviousCurve) {
|
||||
GraphPoint origin = new GraphPoint(null);
|
||||
GraphPoint position = null;
|
||||
if (hintFromPreviousCurve instanceof PositionHint) {
|
||||
origin = ((PositionHint) hintFromPreviousCurve).getOrigin();
|
||||
position = ((PositionHint) hintFromPreviousCurve).getPosition();
|
||||
}
|
||||
if (position == null) {
|
||||
if (_symbolFactory == null) {
|
||||
return new Symbol(new GraphicalComposite(null), hintFromPreviousPoint,
|
||||
new PositionHint(origin, point));
|
||||
} else {
|
||||
return _symbolFactory.createSymbol(point, hintFromPreviousPoint,
|
||||
new PositionHint(origin, point));
|
||||
}
|
||||
} else {
|
||||
double xError = point.getX() - origin.getX();
|
||||
double yError = point.getY() - origin.getY();
|
||||
GraphicalComposite errorBars = new GraphicalComposite(null);
|
||||
if (xError > 0) {
|
||||
errorBars.addElement(new Rectangle(position, 2 * xError, _size,
|
||||
_attributes));
|
||||
}
|
||||
if (yError > 0) {
|
||||
errorBars.addElement(new Rectangle(position, _size, 2 * yError,
|
||||
_attributes));
|
||||
}
|
||||
return new Symbol(errorBars, hintFromPreviousPoint,
|
||||
new PositionHint(origin, null));
|
||||
}
|
||||
}
|
||||
}
|
32
src/jcckit/plot/Hint.java
Normal file
32
src/jcckit/plot/Hint.java
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
|
||||
/**
|
||||
* Marker interface of all types of hints. Hints are used to calculate
|
||||
* {@link jcckit.graphic.GraphicalElement} representing a point in a {@link
|
||||
* Curve}. For example, in a chart with stacked
|
||||
* bars the data determines the height of a bar but the foot of
|
||||
* a bar is determined by the height of the bar below. Its value will be
|
||||
* stored in a {@link PositionHint}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public interface Hint {}
|
250
src/jcckit/plot/Legend.java
Normal file
250
src/jcckit/plot/Legend.java
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.graphic.BasicGraphicAttributes;
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.graphic.GraphicalComposite;
|
||||
import jcckit.graphic.GraphicAttributes;
|
||||
import jcckit.graphic.GraphPoint;
|
||||
import jcckit.graphic.Polygon;
|
||||
import jcckit.graphic.Rectangle;
|
||||
import jcckit.graphic.ShapeAttributes;
|
||||
import jcckit.graphic.Text;
|
||||
import jcckit.graphic.TextAttributes;
|
||||
import jcckit.util.ConfigData;
|
||||
import jcckit.util.ConfigParameters;
|
||||
import jcckit.util.ConfigParametersBasedConfigData;
|
||||
import jcckit.util.Factory;
|
||||
import jcckit.util.PropertiesBasedConfigData;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for creating the legend of a {@link Plot}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class Legend {
|
||||
/** Configuration parameter key. */
|
||||
public static final String UPPER_RIGHT_CORNER_KEY = "upperRightCorner",
|
||||
BOX_WIDTH_KEY = "boxWidth",
|
||||
BOX_HEIGHT_KEY = "boxHeight",
|
||||
BOX_ATTRIBUTES_KEY = "boxAttributes",
|
||||
TITLE_KEY = "title",
|
||||
TITLE_DISTANCE_KEY = "titleDistance",
|
||||
TITLE_ATTRIBUTES_KEY = "titleAttributes",
|
||||
LEFT_DISTANCE_KEY = "leftDistance",
|
||||
BOTTOM_DISTANCE_KEY = "bottomDistance",
|
||||
TOP_DISTANCE_KEY = "topDistance",
|
||||
LINE_LENGTH_KEY = "lineLength",
|
||||
SYMBOL_SIZE_KEY = "symbolSize",
|
||||
CURVE_TITLE_DISTANCE_KEY = "curveTitleDistance",
|
||||
CURVE_TITLE_ATTRIBUTES_KEY
|
||||
= "curveTitleAttributes";
|
||||
|
||||
private final GraphicalComposite _box;
|
||||
private final TextAttributes _curveTitleAttributes;
|
||||
private final double _xSymbol;
|
||||
private final double _xText;
|
||||
private final double _yBase;
|
||||
private final double _yLastRow;
|
||||
private final double _length;
|
||||
private final double _size;
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters.
|
||||
* All numbers (lengths, fontsizes, linethicknesses, etc.) are in
|
||||
* device-independent units.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>bottomDistance = 0.02</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Distance between the last row and the bottom of the legend box.
|
||||
* </td></tr>
|
||||
* <tr><td><tt>boxAttributes = </tt>default values of
|
||||
* {@link ShapeAttributes} with a white fill color.</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Attributes of the legend box.</td></tr>
|
||||
* <tr><td><tt>boxHeight = 0.1</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Height of the legend box.</td></tr>
|
||||
* <tr><td><tt>boxWidth = 0.2</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Width of the legend box.</td></tr>
|
||||
* <tr><td><tt>curveTitleAttributes = </tt>default values of
|
||||
* {@link BasicGraphicAttributes}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Text attributes of curve titles printed in the legend.</td></tr>
|
||||
* <tr><td><tt>curveTitleDistance = 0.005</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Horizontal distance between the line part of the legend symbol
|
||||
* and the curve title.</td></tr>
|
||||
* <tr><td><tt>leftDistance = 0.01</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Horizontal distance between the line part of the legend symbol
|
||||
* and the left border of the legend box.</td></tr>
|
||||
* <tr><td><tt>lineLength = 0.035</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Length of the line part of the legend symbol.</td></tr>
|
||||
* <tr><td><tt>symbolSize = 0.01</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Size of the symbol part of the legend symbol. Will be the
|
||||
* <tt>size</tt> argument of {@link SymbolFactory#createLegendSymbol
|
||||
* createLegendSymbol} in a {@link SymbolFactory}.</td></tr>
|
||||
* <tr><td><tt>titleAttributes = </tt>default values of
|
||||
* {@link BasicGraphicAttributes} with a text anchor CENTER
|
||||
* TOP.</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Text attributes of the title of the legend box.</td></tr>
|
||||
* <tr><td><tt>title = Legend</tt></td>
|
||||
* <td><tt>String</tt></td><td>no</td>
|
||||
* <td>Title of the legend box.</td></tr>
|
||||
* <tr><td><tt>titleDistance = 0.005</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Distance between the center of the upper line of the legend box
|
||||
* and the anchor of the legend title.</td></tr>
|
||||
* <tr><td><tt>topDistance = 0.04</tt></td>
|
||||
* <td><tt>double</tt></td><td>no</td>
|
||||
* <td>Distance between the first row and the top of the legend box.
|
||||
* </td></tr>
|
||||
* <tr><td><tt>upperRightCorner = 0.94, 0.54</tt></td>
|
||||
* <td><tt>double[]</tt></td><td>no</td>
|
||||
* <td>Position of the upper-right corner of the legend box.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public Legend(ConfigParameters config) {
|
||||
config = mergeWithDefaultConfig(config);
|
||||
GraphPoint corner
|
||||
= new GraphPoint(config.getDoubleArray(UPPER_RIGHT_CORNER_KEY,
|
||||
new double[] {0.94, 0.54}));
|
||||
double width = config.getDouble(BOX_WIDTH_KEY, 0.2);
|
||||
double height = config.getDouble(BOX_HEIGHT_KEY, 0.1);
|
||||
_curveTitleAttributes = (TextAttributes) Factory.create(
|
||||
config.getNode(CURVE_TITLE_ATTRIBUTES_KEY));
|
||||
_xSymbol = corner.getX() - width
|
||||
+ config.getDouble(LEFT_DISTANCE_KEY, 0.01);
|
||||
_yBase = corner.getY() - config.getDouble(TOP_DISTANCE_KEY, 0.04);
|
||||
_yLastRow = corner.getY() - height
|
||||
+ config.getDouble(BOTTOM_DISTANCE_KEY, 0.02);
|
||||
_length = config.getDouble(LINE_LENGTH_KEY, 0.035);
|
||||
_size = config.getDouble(SYMBOL_SIZE_KEY, 0.01);
|
||||
_xText = _xSymbol + _length
|
||||
+ config.getDouble(CURVE_TITLE_DISTANCE_KEY, 0.005);
|
||||
|
||||
_box = new GraphicalComposite(null);
|
||||
double xCenter = corner.getX() - width / 2;
|
||||
_box.addElement(new Rectangle(
|
||||
new GraphPoint(xCenter, corner.getY() - height / 2), width, height,
|
||||
(GraphicAttributes) Factory.create(
|
||||
config.getNode(BOX_ATTRIBUTES_KEY))));
|
||||
_box.addElement(new Text(
|
||||
new GraphPoint(xCenter, corner.getY()
|
||||
- config.getDouble(TITLE_DISTANCE_KEY, 0.005)),
|
||||
config.get(TITLE_KEY, "Legend"),
|
||||
(TextAttributes) Factory.create(
|
||||
config.getNode(TITLE_ATTRIBUTES_KEY))));
|
||||
}
|
||||
|
||||
private ConfigParameters mergeWithDefaultConfig(ConfigParameters config) {
|
||||
Properties p = new Properties();
|
||||
p.put(BOX_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
|
||||
ShapeAttributes.class.getName());
|
||||
p.put(BOX_ATTRIBUTES_KEY + '/'
|
||||
+ ShapeAttributes.FILL_COLOR_KEY, "0xffffff");
|
||||
p.put(BOX_ATTRIBUTES_KEY + '/'
|
||||
+ ShapeAttributes.LINE_COLOR_KEY, "0");
|
||||
p.put(TITLE_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
|
||||
BasicGraphicAttributes.class.getName());
|
||||
p.put(TITLE_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "center");
|
||||
p.put(TITLE_ATTRIBUTES_KEY + '/'
|
||||
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "top");
|
||||
p.put(CURVE_TITLE_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
|
||||
BasicGraphicAttributes.class.getName());
|
||||
ConfigData cd = new PropertiesBasedConfigData(p);
|
||||
cd = new ConfigParametersBasedConfigData(config, new ConfigParameters(cd));
|
||||
return new ConfigParameters(cd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the legend box with title but without legend symbols and curve
|
||||
* titles.
|
||||
*/
|
||||
public GraphicalElement getBox() {
|
||||
return _box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the symbol part of a legend symbol.
|
||||
* @param curveIndex Index of the curve. Will be needed to calculate the
|
||||
* y-coordinate of the symbol.
|
||||
* @param numberOfCurves Number of curves. Will be needed to calculate the
|
||||
* y-coordinate of the symbol.
|
||||
* @param factory Factory for the symbol part of the legend symbol.
|
||||
* Can be <tt>null</tt>.
|
||||
* @param withLine <tt>true</tt> if the line part of the legend symbol
|
||||
* should be created.
|
||||
* @param lineAttributes Attributes of the line part.
|
||||
*/
|
||||
public GraphicalElement createSymbol(int curveIndex, int numberOfCurves,
|
||||
SymbolFactory factory,
|
||||
boolean withLine,
|
||||
GraphicAttributes lineAttributes) {
|
||||
GraphicalComposite result = new GraphicalComposite(null);
|
||||
double y = calculateBaseLine(curveIndex, numberOfCurves);
|
||||
if (withLine) {
|
||||
Polygon line = new Polygon(lineAttributes, false);
|
||||
line.addPoint(new GraphPoint(_xSymbol, y));
|
||||
line.addPoint(new GraphPoint(_xSymbol + _length, y));
|
||||
result.addElement(line);
|
||||
}
|
||||
if (factory != null) {
|
||||
result.addElement(factory.createLegendSymbol(
|
||||
new GraphPoint(_xSymbol + _length / 2, y), _size));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private double calculateBaseLine(int curveIndex, int numberOfCurves) {
|
||||
if (numberOfCurves > 1) {
|
||||
return _yBase + ((_yLastRow - _yBase) / (numberOfCurves - 1))
|
||||
* curveIndex;
|
||||
} else {
|
||||
return 0.5 * (_yBase + _yLastRow);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the title part of a legend symbol.
|
||||
* @param curveIndex Index of the curve. Will be needed to calculate the
|
||||
* y-coordinate of the title.
|
||||
* @param numberOfCurves Number of curves. Will be needed to calculate the
|
||||
* y-coordinate of the symbol.
|
||||
* @param title Title text.
|
||||
*/
|
||||
public GraphicalElement createCurveTitle(int curveIndex, int numberOfCurves,
|
||||
String title) {
|
||||
return new Text(new GraphPoint(_xText, calculateBaseLine(curveIndex,
|
||||
numberOfCurves)),
|
||||
title, _curveTitleAttributes);
|
||||
}
|
||||
}
|
377
src/jcckit/plot/Plot.java
Normal file
377
src/jcckit/plot/Plot.java
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import jcckit.data.DataCurve;
|
||||
import jcckit.data.DataEvent;
|
||||
import jcckit.data.DataListener;
|
||||
import jcckit.data.DataPlot;
|
||||
import jcckit.data.DataPoint;
|
||||
import jcckit.graphic.ClippingShape;
|
||||
import jcckit.graphic.GraphPoint;
|
||||
import jcckit.graphic.GraphicalComposite;
|
||||
import jcckit.graphic.GraphicalElement;
|
||||
import jcckit.transformation.Transformation;
|
||||
import jcckit.util.ConfigParameters;
|
||||
import jcckit.util.Factory;
|
||||
|
||||
/**
|
||||
* A plot is determined by a {@link CoordinateSystem}, {@link Curve Curves},
|
||||
* an optional annotation layer and an optional {@link Legend}. When rendered
|
||||
* these components are draw in this order.
|
||||
* <p>
|
||||
* Registrated {@link PlotListener PlotListeners} will be informed
|
||||
* when the plot changes.
|
||||
* <p>
|
||||
* A {@link DataPlot} can be connected with a <tt>Plot</tt> instance.
|
||||
* This is done with the method {@link #connect connect()} which registrates
|
||||
* this <tt>Plot</tt> instance as
|
||||
* a {@link DataListener} at the connected <tt>DataPlot</tt>.
|
||||
* After an received {@link DataEvent DataEvents} has been handled
|
||||
* the registrated <tt>PlotListeners</tt> will receive a
|
||||
* {@link PlotEvent} of the type {@link PlotEventType#DATA_PLOT_CHANGED}.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class Plot implements DataListener {
|
||||
/** Configuration parameter key. */
|
||||
public static final String COORDINATE_SYSTEM_KEY = "coordinateSystem",
|
||||
CURVE_FACTORY_KEY = "curveFactory",
|
||||
LEGEND_VISIBLE_KEY = "legendVisible",
|
||||
LEGEND_KEY = "legend",
|
||||
INITIAL_HINT_FOR_NEXT_CURVE_KEY
|
||||
= "initialHintForNextCurve";
|
||||
private final Vector _plotListeners = new Vector();
|
||||
private DataPlot _dataPlot;
|
||||
private final CurveFactory _curveFactory;
|
||||
private final Vector _curves = new Vector();
|
||||
private final Vector _nextCurveHints = new Vector();
|
||||
private final Hint _initialHintForNextCurve;
|
||||
private final Legend _legend;
|
||||
private final boolean _legendVisibility;
|
||||
|
||||
private GraphicalElement _coordinateSystemView;
|
||||
private ClippingShape _clippingShape;
|
||||
private Transformation _transformation;
|
||||
private GraphicalElement _annotation;
|
||||
private GraphicalComposite _legendView = new GraphicalComposite(null);
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters.
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Key & Default Value</th><th>Type</th><th>Mandatory</th>
|
||||
* <th>Description</th></tr>
|
||||
* <tr><td><tt>coordinateSystem = </tt>{@link CartesianCoordinateSystem}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Definition of the {@link CoordinateSystem}.</td></tr>
|
||||
* <tr><td><tt>curveFactory = </tt>{@link SimpleCurveFactory}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Definition of the {@link CurveFactory}.</td></tr>
|
||||
* <tr><td><tt>initialHintForNextCurve = null</tt></td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Definition of the initial {@link Hint} which is needed by some
|
||||
* {@link SymbolFactory SymbolFactories} like {@link BarFactory}.
|
||||
* </td></tr>
|
||||
* <tr><td><tt>legend = </tt>default values of {@link Legend}</td>
|
||||
* <td><tt>ConfigParameters</tt></td><td>no</td>
|
||||
* <td>Configuration parameters of a {@link Legend}.</td></tr>
|
||||
* <tr><td><tt>legendVisible = true</tt></td>
|
||||
* <td><tt>boolean</tt></td><td>no</td>
|
||||
* <td>If <tt>true</tt> the {@link Legend} will be created.</td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public Plot(ConfigParameters config) {
|
||||
CoordinateSystem coordinateSystem = (CoordinateSystem) Factory.create(
|
||||
config.getNode(COORDINATE_SYSTEM_KEY),
|
||||
CartesianCoordinateSystem.class.getName());
|
||||
setCoordinateSystem(coordinateSystem);
|
||||
_curveFactory = (CurveFactory) Factory.create(
|
||||
config.getNode(CURVE_FACTORY_KEY),
|
||||
SimpleCurveFactory.class.getName());
|
||||
_initialHintForNextCurve = (Hint) Factory.createOrGet(
|
||||
config.getNode(INITIAL_HINT_FOR_NEXT_CURVE_KEY), null);
|
||||
_legend = new Legend(config.getNode(LEGEND_KEY));
|
||||
_legendVisibility = config.getBoolean(LEGEND_VISIBLE_KEY, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the coordinate system. All curves will be regenerated and a
|
||||
* {@link PlotEvent} of type {@link PlotEventType#COODINATE_SYSTEM_CHANGED}
|
||||
* will be fired.
|
||||
*
|
||||
* @param coordinateSystem New coordinate system.
|
||||
*/
|
||||
public void setCoordinateSystem(CoordinateSystem coordinateSystem)
|
||||
{
|
||||
_coordinateSystemView = coordinateSystem.getView();
|
||||
_clippingShape = coordinateSystem.getClippingShape();
|
||||
_transformation = coordinateSystem.getTransformation();
|
||||
if (_dataPlot != null)
|
||||
{
|
||||
generateCurves(_dataPlot);
|
||||
}
|
||||
notifyListeners(
|
||||
new PlotEvent(this, PlotEventType.COODINATE_SYSTEM_CHANGED, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified {@link PlotListener}. Does nothing if
|
||||
* already added.
|
||||
*/
|
||||
public void addPlotListener(PlotListener listener) {
|
||||
if (!_plotListeners.contains(listener)) {
|
||||
_plotListeners.addElement(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specfied {@link PlotListener}. Does nothing if
|
||||
* already removed.
|
||||
*/
|
||||
public void removePlotListener(PlotListener listener) {
|
||||
_plotListeners.removeElement(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends all registrated {@link PlotListener PlotListeners}
|
||||
* the specified event.
|
||||
*/
|
||||
protected void notifyListeners(PlotEvent event) {
|
||||
for (int i = 0, n = _plotListeners.size(); i < n; i++) {
|
||||
((PlotListener) _plotListeners.elementAt(i)).plotChanged(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect the specified {@link DataPlot} with this instance.
|
||||
* <p>
|
||||
* If this <tt>Plot</tt> instance is already connected with a
|
||||
* <tt>DataPlot</tt> the connection will be released and a
|
||||
* {@link PlotEvent} of the type {@link PlotEventType#DATA_PLOT_DISCONNECTED}
|
||||
* will be sent to all registrated {@link PlotListener PlotListeners}.
|
||||
* <p>
|
||||
* It registers itself at <tt>dataPlot</tt> and
|
||||
* all its {@link DataCurve DataCurves}.
|
||||
* <p>
|
||||
* Finally all curves will be generated and a <tt>PlotEvent</tt>
|
||||
* of the type {@link PlotEventType#DATA_PLOT_CONNECTED} will be transmitted.
|
||||
* @param dataPlot Data to be connected with this plot instance.
|
||||
* Can be <tt>null</tt> in order to disconnect this instance from
|
||||
* any <tt>DataPlot</tt>.
|
||||
*/
|
||||
public void connect(DataPlot dataPlot) {
|
||||
if (_dataPlot != null) {
|
||||
_dataPlot.removeDataListener(this);
|
||||
notifyListeners(new PlotEvent(this, PlotEventType.DATA_PLOT_DISCONNECTED,
|
||||
_dataPlot));
|
||||
}
|
||||
_dataPlot = dataPlot;
|
||||
if (_dataPlot != null)
|
||||
{
|
||||
_dataPlot.addDataListener(this);
|
||||
generateCurves(_dataPlot);
|
||||
notifyListeners(new PlotEvent(this, PlotEventType.DATA_PLOT_CONNECTED,
|
||||
_dataPlot));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a point from device-independent coordinates into
|
||||
* data coordinates.
|
||||
* @param point Point in device-independent coordinates.
|
||||
* @return transform <tt>point</tt>.
|
||||
*/
|
||||
public DataPoint transform(GraphPoint point) {
|
||||
return _transformation.transformToData(point);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a graphical representation of the complete plot.
|
||||
* @return <tt>GraphicalComposite</tt> containing the views of the
|
||||
* coordinate system, the curves, and optionally the legend (in this order).
|
||||
*/
|
||||
public GraphicalComposite getCompletePlot() {
|
||||
GraphicalComposite result = new GraphicalComposite(null);
|
||||
result.addElement(_coordinateSystemView);
|
||||
GraphicalElement[] curves = getCurves();
|
||||
for (int i = 0; i < curves.length; i++) {
|
||||
result.addElement(curves[i]);
|
||||
}
|
||||
if (_annotation != null) {
|
||||
result.addElement(_annotation);
|
||||
}
|
||||
if (_legendVisibility) {
|
||||
result.addElement(getLegend());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns the view of the coordinate system. */
|
||||
public GraphicalElement getCoordinateSystem() {
|
||||
return _coordinateSystemView;
|
||||
}
|
||||
|
||||
/** Returns the graphical representations of all curves. */
|
||||
public GraphicalElement[] getCurves() {
|
||||
synchronized (_curves) {
|
||||
GraphicalElement[] curves = new GraphicalElement[_curves.size()];
|
||||
for (int i = 0; i < curves.length; i++) {
|
||||
curves[i] = ((Curve) _curves.elementAt(i)).getView();
|
||||
}
|
||||
return curves;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the annotation layer.
|
||||
* @return <tt>null</tt> if no annotation layer.
|
||||
*/
|
||||
public GraphicalElement getAnnotation()
|
||||
{
|
||||
return _annotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the annotation layer.
|
||||
* @param annotation Any kind of graphics which will be drawn on the
|
||||
* top of the curves but may be covered by the legend.
|
||||
* Can be <tt>null</tt>.
|
||||
*/
|
||||
public void setAnnotation(GraphicalElement annotation)
|
||||
{
|
||||
_annotation = annotation;
|
||||
}
|
||||
|
||||
/** Returns <tt>true</tt> if the legend is visible. */
|
||||
public boolean isLegendVisible() {
|
||||
return _legendVisibility;
|
||||
}
|
||||
|
||||
/** Returns the graphical representations of the legend. */
|
||||
public GraphicalElement getLegend() {
|
||||
return _legendView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the received {@link DataEvent} and notifies
|
||||
* {@link PlotListener PlotListeners} by an event of the type
|
||||
* {@link PlotEventType#DATA_CURVE_CHANGED} or
|
||||
* {@link PlotEventType#DATA_PLOT_CHANGED}. The following table shows what
|
||||
* this method does:
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Source of <tt>event</tt></th>
|
||||
* <th>All hints for the next curve are <tt>null</tt>?</th>
|
||||
* <th>Action</th><th>Type of sent {@link PlotEvent}</th></tr>
|
||||
* <tr><td>{@link DataCurve}</td><td>Yes</td><td>Recreate changed curve.<td>
|
||||
* <td><tt>DATA_CURVE_CHANGED</tt></td></tr>
|
||||
* <tr><td>{@link DataCurve}</td><td>No</td><td>Recreate changed curve
|
||||
* and all curves with large curve index.<td>
|
||||
* <td><tt>DATA_PLOT_CHANGED</tt></td></tr>
|
||||
* <tr><td>{@link DataPlot}</td><td>-</td><td>Recreate all curves
|
||||
* and {@link Legend} view.<td>
|
||||
* <td><tt>DATA_PLOT_CHANGED</tt></td></tr>
|
||||
* </table>
|
||||
*/
|
||||
public void dataChanged(DataEvent event) {
|
||||
Integer index = new Integer(0);
|
||||
PlotEventType type = PlotEventType.DATA_PLOT_CHANGED;
|
||||
synchronized (_curves) {
|
||||
int numberOfCurves = _curves.size();
|
||||
if (event.getContainer() instanceof DataCurve
|
||||
&& numberOfCurves == _dataPlot.getNumberOfElements()) {
|
||||
DataCurve curve = (DataCurve) event.getContainer();
|
||||
index = new Integer(curve.getContainer().getIndexOf(curve));
|
||||
type = PlotEventType.DATA_CURVE_CHANGED;
|
||||
fillCurve(index.intValue(), curve);
|
||||
if (index.intValue() < numberOfCurves - 1) {
|
||||
Vector curveHints
|
||||
= (Vector) _nextCurveHints.elementAt(index.intValue());
|
||||
for (int i = 0, n = curveHints.size(); i < n; i++) {
|
||||
if (curveHints.elementAt(i) != null) {
|
||||
type = PlotEventType.DATA_PLOT_CHANGED;
|
||||
for (int j = index.intValue()+1; j < numberOfCurves; j++) {
|
||||
fillCurve(j, (DataCurve) _dataPlot.getElement(j));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
generateCurves(_dataPlot);
|
||||
}
|
||||
}
|
||||
notifyListeners(new PlotEvent(Plot.this, type, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates all curves based on the specified data.
|
||||
* In addition the legend view is created.
|
||||
*/
|
||||
private void generateCurves(DataPlot dataPlot) {
|
||||
synchronized (_curves) {
|
||||
_legendView = new GraphicalComposite(null);
|
||||
_legendView.addElement(_legend.getBox());
|
||||
_curves.setSize(0);
|
||||
_nextCurveHints.setSize(0);
|
||||
for (int i = 0, n = dataPlot.getNumberOfElements(); i < n; i++) {
|
||||
Curve curve = _curveFactory.create(i, n, _clippingShape, _legend);
|
||||
_curves.addElement(curve);
|
||||
_nextCurveHints.addElement(new Vector());
|
||||
DataCurve dataCurve = (DataCurve) dataPlot.getElement(i);
|
||||
_legendView.addElement(curve.getLegendSymbol());
|
||||
_legendView.addElement(
|
||||
_legend.createCurveTitle(i, n, dataCurve.getTitle()));
|
||||
fillCurve(i, dataCurve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillCurve(int curveIndex, DataCurve dataCurve) {
|
||||
Vector curveHints = (Vector) _nextCurveHints.elementAt(curveIndex);
|
||||
Curve curve = (Curve) _curves.elementAt(curveIndex);
|
||||
curve.removeAllPoints();
|
||||
for (int i = 0, n = dataCurve.getNumberOfElements(); i < n; i++) {
|
||||
setHintForNextCurve(curveHints, i,
|
||||
curve.addPoint(_transformation.transformToGraph(
|
||||
(DataPoint) dataCurve.getElement(i)),
|
||||
getHintForNextCurve(curveIndex - 1, i)));
|
||||
}
|
||||
}
|
||||
|
||||
private Hint getHintForNextCurve(int curveIndex, int pointIndex) {
|
||||
Hint result = _initialHintForNextCurve;
|
||||
if (curveIndex >= 0) {
|
||||
Vector curveHints = (Vector) _nextCurveHints.elementAt(curveIndex);
|
||||
result = pointIndex < curveHints.size() ?
|
||||
(Hint) curveHints.elementAt(pointIndex)
|
||||
: getHintForNextCurve(curveIndex - 1, pointIndex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void setHintForNextCurve(Vector curveHints, int pointIndex,
|
||||
Hint hint) {
|
||||
while (curveHints.size() <= pointIndex) {
|
||||
curveHints.addElement(_initialHintForNextCurve);
|
||||
}
|
||||
curveHints.setElementAt(hint, pointIndex);
|
||||
}
|
||||
}
|
135
src/jcckit/plot/PlotCanvas.java
Normal file
135
src/jcckit/plot/PlotCanvas.java
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
import jcckit.data.DataPlot;
|
||||
import jcckit.graphic.Anchor;
|
||||
import jcckit.graphic.ClippingRectangle;
|
||||
import jcckit.util.ConfigParameters;
|
||||
|
||||
/**
|
||||
* An abstract canvas containg a single {@link Plot}. The canvas is specified
|
||||
* by a {@link ClippingRectangle}, called <em>paper</em>. A horizontal and
|
||||
* vertical {@link Anchor} determine the position of the paper on the actual
|
||||
* device.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class PlotCanvas implements PlotListener {
|
||||
/** Configuration parameter key. */
|
||||
public static final String PAPER_KEY = "paper", HORIZONTAL_ANCHOR_KEY = "horizontalAnchor",
|
||||
VERTICAL_ANCHOR_KEY = "verticalAnchor", PLOT_KEY = "plot";
|
||||
private final ClippingRectangle _paper;
|
||||
private final Anchor _horizontalAnchor;
|
||||
private final Anchor _verticalAnchor;
|
||||
private final Plot _plot;
|
||||
|
||||
/**
|
||||
* Creates an instance from the specified configuration parameters. <table
|
||||
* border=1 cellpadding=5>
|
||||
* <tr>
|
||||
* <th>Key & Default Value</th>
|
||||
* <th>Type</th>
|
||||
* <th>Mandatory</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><tt>horizontalAnchor = center</tt></td>
|
||||
* <td><tt>String</tt></td>
|
||||
* <td>no</td>
|
||||
* <td>Horizontal position of the paper relative to the device border.
|
||||
* Possible values are <tt>left</tt>, <tt>center</tt>, and
|
||||
* <tt>right</tt>.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><tt>paper = 0, 0, 1, 0.6</tt></td>
|
||||
* <td><tt>double[]</tt></td>
|
||||
* <td>no</td>
|
||||
* <td>Rectangle defining the paper. The first two values determine the x-
|
||||
* and y- coordinates (in device-independent units) of the lower-left
|
||||
* corner. The last two values determine the upper-right corner.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><tt>plot = </tt>default values of {@link Plot}</td>
|
||||
* <td><tt>ConfigParameters</tt></td>
|
||||
* <td>no</td>
|
||||
* <td>Definition of the {@link Plot}.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><tt>verticalAnchor = center</tt></td>
|
||||
* <td><tt>String</tt></td>
|
||||
* <td>no</td>
|
||||
* <td>Vertical position of the paper relative to the device border.
|
||||
* Possible values are <tt>top</tt>, <tt>center</tt>, and
|
||||
* <tt>bottom</tt>.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* Note, that this instance registers itself at the wrapped {@link Plot}
|
||||
* instance.
|
||||
*/
|
||||
public PlotCanvas(ConfigParameters config) {
|
||||
double[] paper = config.getDoubleArray(PAPER_KEY, new double[] { 0, 0, 1, 0.6 });
|
||||
_paper = new ClippingRectangle(paper[0], paper[1], paper[2], paper[3]);
|
||||
_horizontalAnchor = Anchor.getHorizontalAnchor(config, HORIZONTAL_ANCHOR_KEY, Anchor.CENTER);
|
||||
_verticalAnchor = Anchor.getVerticalAnchor(config, VERTICAL_ANCHOR_KEY, Anchor.CENTER);
|
||||
_plot = new Plot(config.getNode(PLOT_KEY));
|
||||
_plot.addPlotListener(this);
|
||||
}
|
||||
|
||||
/** Returns the paper definition. */
|
||||
public ClippingRectangle getPaper() {
|
||||
return _paper;
|
||||
}
|
||||
|
||||
/** Returns the horizontal anchor. */
|
||||
public Anchor getHorizontalAnchor() {
|
||||
return _horizontalAnchor;
|
||||
}
|
||||
|
||||
/** Returns the vertical anchor. */
|
||||
public Anchor getVerticalAnchor() {
|
||||
return _verticalAnchor;
|
||||
}
|
||||
|
||||
/** Returns the plot. */
|
||||
public Plot getPlot() {
|
||||
return _plot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects the wrapped {@link Plot} instance with the specified
|
||||
* {@link DataPlot}.
|
||||
*
|
||||
* @param dataPlot
|
||||
* Data to be connected with this plot canvas. Can be
|
||||
* <tt>null</tt> in order to disconnect this instance from a
|
||||
* <tt>DataPlot</tt>.
|
||||
*/
|
||||
public void connect(DataPlot dataPlot) {
|
||||
_plot.connect(dataPlot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the spcified event. Here nothing is done. But subclass may
|
||||
* override this method.
|
||||
*/
|
||||
public void plotChanged(PlotEvent event) {
|
||||
}
|
||||
}
|
88
src/jcckit/plot/PlotEvent.java
Normal file
88
src/jcckit/plot/PlotEvent.java
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
/**
|
||||
* A plot event signales some changes of a {@link Plot}.
|
||||
* It has three attributes:
|
||||
* <ul><li><b>source</b>: Indicates the <tt>Plot</tt> instance responsible
|
||||
* for this event.
|
||||
* <li><b>type</b>: The type of event.
|
||||
* <li><b>message</b>: The message object. Its meaning depends on the
|
||||
* type of event:
|
||||
* <table border=1 cellpadding=5>
|
||||
* <tr><th>Type</th><th>Meaning of the message object</th></tr>
|
||||
* <tr><td>{@link PlotEventType#DATA_PLOT_CONNECTED},
|
||||
* {@link PlotEventType#DATA_PLOT_DISCONNECTED}</td>
|
||||
* <td>The {@link jcckit.data.DataPlot} (dis)connected with the
|
||||
* {@link Plot} instance specified by the source.</td>
|
||||
* <tr><td>{@link PlotEventType#DATA_PLOT_CHANGED}</td>
|
||||
* <td>An <tt>Integer</tt> indicating the lowest index of
|
||||
* those curves which have been changed.</td>
|
||||
* <tr><td>{@link PlotEventType#DATA_CURVE_CHANGED}</td>
|
||||
* <td>An <tt>Integer</tt> indicating the index of the curve
|
||||
* which has been changed.</td>
|
||||
* </table>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class PlotEvent {
|
||||
private final Plot _source;
|
||||
private final PlotEventType _type;
|
||||
private final Object _message;
|
||||
|
||||
/**
|
||||
* Creates a new event for the specified source, type, and message.
|
||||
* @param source Plot causing this event.
|
||||
* @param type Type of the event. Possible values are
|
||||
* {@link PlotEventType#DATA_PLOT_CHANGED},
|
||||
* {@link PlotEventType#DATA_CURVE_CHANGED},
|
||||
* {@link PlotEventType#DATA_PLOT_CONNECTED}, and
|
||||
* {@link PlotEventType#DATA_PLOT_DISCONNECTED}.
|
||||
* @param message Message object. Can be <tt>null</tt>
|
||||
*/
|
||||
public PlotEvent(Plot source, PlotEventType type, Object message) {
|
||||
_source = source;
|
||||
_type = type;
|
||||
_message = message;
|
||||
}
|
||||
|
||||
/** Returns the source of this event. */
|
||||
public Plot getSource() {
|
||||
return _source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event type.
|
||||
* @return either {@link PlotEventType#DATA_PLOT_CHANGED},
|
||||
* {@link PlotEventType#DATA_CURVE_CHANGED},
|
||||
* {@link PlotEventType#DATA_PLOT_CONNECTED}, or
|
||||
* {@link PlotEventType#DATA_PLOT_DISCONNECTED}.
|
||||
*/
|
||||
public PlotEventType getType() {
|
||||
return _type;
|
||||
}
|
||||
|
||||
/** Returns the message object. */
|
||||
public Object getMessage() {
|
||||
return _message;
|
||||
}
|
||||
}
|
36
src/jcckit/plot/PlotEventType.java
Normal file
36
src/jcckit/plot/PlotEventType.java
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details
|
||||
* (http://www.gnu.org/copyleft/lesser.html).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package jcckit.plot;
|
||||
|
||||
/**
|
||||
* Types of {@link PlotEvent PlotEvents}. Using the typesafe enumeration
|
||||
* pattern.
|
||||
*
|
||||
* @author Franz-Josef Elmer
|
||||
*/
|
||||
public class PlotEventType {
|
||||
/** Event type. */
|
||||
public static final PlotEventType DATA_PLOT_CONNECTED = new PlotEventType(),
|
||||
DATA_PLOT_DISCONNECTED = new PlotEventType(),
|
||||
COODINATE_SYSTEM_CHANGED = new PlotEventType(),
|
||||
DATA_CURVE_CHANGED = new PlotEventType(),
|
||||
DATA_PLOT_CHANGED = new PlotEventType();
|
||||
|
||||
private PlotEventType() {}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user