diff --git a/src/com/ctreber/acearth/ACearth.java b/src/com/ctreber/acearth/ACearth.java new file mode 100644 index 000000000..64e7ad7f0 --- /dev/null +++ b/src/com/ctreber/acearth/ACearth.java @@ -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; + +/** + *

AC.earth - XEarth for Java + *

+ * + *

+ * 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! + * + *

+ * I wanted to extend the program, but not in C. So I created this Java version, + * and found the process quite painfull interesting. The + * biggest effort went into resolving references between C files and + * eliminatiing pointers. + * + *

License

+ * + *

+ * AC.earth Copyright (c) 2002 Christian Treber, ct@ctreber.com + * + *

+ * AC.earth is based on XEarth by Kirk Johnson + * + *

+ * To comply with the XEarth license I include the following text: + * + *

+ * 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.
+ * 
+ * + *

+ * 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 + * + *

+ * © 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; + + /** + *

+ * Well, the main class. + * @param markers + */ + public ACearth(List 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(); + } + + } + + /** + *

+ * 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"); + } + } + + /** + *

+ * 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))); + } + + /** + *

+ * 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; + } + +} \ No newline at end of file diff --git a/src/com/ctreber/acearth/Configuration.java b/src/com/ctreber/acearth/Configuration.java new file mode 100644 index 000000000..95295d34f --- /dev/null +++ b/src/com/ctreber/acearth/Configuration.java @@ -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; + +/** + *

+ *

+ * + *

+ * © 2002 Christian Treber, ct@ctreber.com (06.10.2002) + *

+ * + * @author Christian Treber, ct@ctreber.com + * + */ +public class Configuration { + private Map fValues = new HashMap(); + + /** + *

+ * 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; + } +} diff --git a/src/com/ctreber/acearth/ConfigurationACearth.java b/src/com/ctreber/acearth/ConfigurationACearth.java new file mode 100644 index 000000000..d441e508b --- /dev/null +++ b/src/com/ctreber/acearth/ConfigurationACearth.java @@ -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; + +/** + *

+ * How to avoid writing all the accessors? Code generator that creates derived + * class from template class? Configuration items in data structure? + *

+ * + *

+ * © 2002 Christian Treber, ct@ctreber.com (06.10.2002) + *

+ * + * @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()); + } +} diff --git a/src/com/ctreber/acearth/MapData.java b/src/com/ctreber/acearth/MapData.java new file mode 100644 index 000000000..3bd79a3c9 --- /dev/null +++ b/src/com/ctreber/acearth/MapData.java @@ -0,0 +1,6835 @@ +package com.ctreber.acearth; + +import java.util.ArrayList; +import java.util.List; + +/** + *

AC.earth - XEarth for Java + *

+ * + *

+ * 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! + * + *

+ * I wanted to extend the program, but not in C. So I created this Java version, + * and found the process quite painfull interesting. The + * biggest effort went into resolving references between C files and + * eliminatiing pointers. + * + *

License

+ * + *

+ * AC.earth Copyright (c) 2002 Christian Treber, ct@ctreber.com + * + *

+ * AC.earth is based on XEarth by Kirk Johnson + * + *

+ * To comply with the XEarth license I include the following text: + * + *

+ * 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, d 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.
+ * 
+ * + *

+ * 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 d and time, not seconds since epoch todo + * Phase 2: Compact map d into binary file + * + *

+ * © 2002 Christian Treber, ct@ctreber.com + * + * @author Christian Treber, ct@ctreber.com + */ +public class MapData { + + private final List d = new ArrayList(); + + public MapData() { + //add("/*0*/"); + add("3903,1,13663,15523,21733,"); + add("-138,74,34,69,29,-64,-38,19,10,-93,24,41,"); + add("-123,2,74,-139,23,68,-93,-54,94,-46,17,16,"); + add("33,33,-44,-145,-37,113,-59,-82,92,-117,-44,99,"); + add("-83,-79,101,-98,-59,97,-129,1,70,-132,62,30,"); + add("-136,30,54,-146,22,63,-120,37,38,-137,40,44,"); + add("-132,50,34,-137,27,51,-140,23,54,-141,32,48,"); + add("-133,4,62,-123,-34,82,-124,44,28,-95,124,-40,"); + add("-134,50,28,-136,-5,65,-143,24,48,-135,51,25,"); + add("-151,13,57,-116,80,-5,-70,114,-49,-151,52,28,"); + add("-141,44,27,-137,28,36,-151,0,61,-115,-55,84,"); + add("-137,-19,66,-113,-59,83,-106,-67,85,-83,-88,91,"); + add("-56,-106,92,4,-127,82,57,-127,62,81,-117,47,"); + add("4,-126,79,-56,-109,89,-81,-94,88,-111,-65,80,"); + add("-137,-19,60,-140,50,16,-129,77,-4,-125,84,-11,"); + add("-140,59,9,-141,51,13,-141,46,16,-146,36,22,"); + add("-145,24,28,-147,4,41,-146,30,23,-136,66,-3,"); + add("-101,105,-39,-69,120,-58,-46,125,-69,-119,79,-19,"); + add("-150,23,25,-143,45,7,-135,65,-9,-147,32,16,"); + add("-145,29,16,-142,15,24,-138,-36,55,-149,6,29,"); + add("-142,46,1,-154,71,-14,-125,38,0,-122,43,-4,"); + add("-131,126,-59,-138,25,9,-148,44,-2,-111,93,-43,"); + add("-32,122,-79,97,86,-77,111,74,-72,87,91,-80,"); + add("55,110,-89,20,109,-83,-52,128,-82,-122,81,-36,"); + add("-105,100,-54,-10,122,-89,103,79,-78,66,104,-92,"); + add("-18,101,-74,-145,-63,76,-125,-11,32,-59,130,-89,"); + add("-132,44,-11,-122,31,-2,-140,-37,51,-116,-63,67,"); + add("-123,-52,59,-148,-9,28,-165,-12,33,-130,47,-18,"); + add("-137,6,13,-141,-43,50,-141,43,-15,-120,-13,23,"); + add("-120,-62,60,-141,-30,36,-134,-48,49,-126,58,-32,"); + add("-147,39,-17,-152,5,8,-152,-1,12,-138,-34,35,"); + add("-152,-18,23,-141,-6,11,-140,-63,54,-146,-2,7,"); + add("-148,-18,19,-152,-10,12,-146,-17,16,-134,-51,40,"); + add("-137,-51,39,-122,-67,50,-94,-101,74,-153,-3,1,"); + add("-142,-45,31,-141,-36,24,-96,-91,63,-113,-76,51,"); + add("-131,-64,42,-148,-12,3,-148,11,-14,-140,28,-26,"); + add("-91,63,-49,-167,-51,26,-149,14,-19,-148,-15,0,"); + add("-147,-15,0,-141,43,-42,-112,79,-66,-79,97,-77,"); + add("-61,80,-64,-177,-45,16,-75,-108,69,-60,-116,77,"); + add("-58,-117,76,-67,-115,73,-74,-111,69,-82,-109,65,"); + add("-94,-100,58,-130,-71,31,-136,-61,24,-140,-54,17,"); + add("-142,-49,13,-136,-61,21,-108,-86,40,-109,-96,47,"); + add("-114,-89,40,-67,-108,58,-32,-126,76,-92,-106,52,"); + add("-95,-106,50,-65,-120,64,-22,-130,76,-16,-131,77,"); + add("18,-106,67,52,-115,78,-47,-130,68,-87,-111,50,"); + add("-97,-107,45,-92,-108,45,-107,-102,39,-124,-81,22,"); + add("-137,-67,11,-117,-90,27,-110,-101,34,-137,-63,6,"); + add("-142,-53,-1,-148,-33,-13,-149,-22,-22,-131,-55,1,"); + add("-102,-108,34,-70,-128,52,-73,-122,47,-62,-129,53,"); + add("-110,-97,23,-136,-69,2,-130,-68,2,-97,-100,27,"); + add("-63,-128,47,-72,-127,45,-68,-126,43,-24,-137,61,"); + add("-48,-134,51,-105,-101,20,-115,-97,14,-113,-102,17,"); + add("-124,-85,4,-45,-85,27,-86,-166,50,-81,-132,36,"); + add("-63,-120,34,-64,-131,39,-91,-126,28,-120,-81,-2,"); + add("-82,-125,28,-39,-135,45,-41,-142,46,-36,-139,45,"); + add("11,-63,29,88,49,7,55,-128,68,94,-66,54,"); + add("72,-129,71,25,-129,57,-35,-131,40,-72,-140,30,"); + add("-12,-75,25,57,-175,80,29,-137,57,23,-139,56,"); + add("5,-143,51,-9,-144,46,-25,-144,40,-51,-140,32,"); + add("-67,-134,24,-71,-130,20,-54,-138,27,-39,-142,32,"); + add("-15,-146,40,-39,-140,30,-86,-127,11,-87,-123,9,"); + add("-101,-113,1,-125,-80,-16,-35,-55,4,131,-79,62,"); + add("79,-115,55,55,-132,52,48,-37,24,80,37,14,"); + add("-24,-130,27,5,-132,35,86,-97,49,143,40,32,"); + add("151,15,39,139,11,37,23,-12,9,-165,-14,-43,"); + add("-150,-15,-39,-124,-71,-18,-137,66,-57,-95,-40,-19,"); + add("4,-145,37,-10,-150,33,68,-38,29,109,-29,39,"); + add("169,19,45,140,-28,46,108,53,18,32,16,5,"); + add("-131,-86,-16,-144,20,-46,-145,-14,-39,-139,0,-41,"); + add("-63,-98,4,132,-84,59,105,-1,30,30,-154,43,"); + add("141,35,33,23,-19,11,-4,-74,15,145,44,31,"); + add("138,22,33,85,-33,31,-198,-69,-40,68,-43,28,"); + add("74,-18,24,-111,-109,-7,57,-133,43,67,-24,23,"); + add("37,-29,16,51,-69,28,93,5,23,42,-89,29,"); + add("50,7,12,-20,-138,21,87,-128,47,146,-64,49,"); + add("100,-103,43,114,-63,40,40,-145,35,105,-106,43,"); + add("55,-111,32,51,-127,32,3,-125,20,49,-47,19,"); + add("-112,-70,-15,99,-97,37,66,-128,34,69,-98,30,"); + add("130,-47,35,64,-103,28,124,-117,43,137,-54,36,"); + add("123,-81,35,103,-103,34,110,-85,32,132,-68,34,"); + add("80,-100,27,164,-73,38,115,-81,30,105,-101,29,"); + add("109,-105,30,109,-98,28,107,-112,28,118,-87,27,"); + add("130,-70,27,131,-69,26,132,-73,26,140,-50,24,"); + add("136,-62,24,144,-33,22,137,60,13,138,61,12,"); + add("135,58,12,141,51,12,143,53,11,140,57,10,"); + add("154,36,13,144,15,12,80,34,4,221,-11,21,"); + add("150,21,10,153,12,10,31,26,0,-186,-21,-12,"); + add("-70,16,-7,216,24,15,145,2,10,70,-27,7,"); + add("241,-37,18,88,41,1,74,-80,12,215,-66,16,"); + add("148,-42,10,139,-66,11,145,61,0,127,75,-3,"); + add("152,42,0,142,47,-2,142,46,-2,131,71,-5,"); + add("138,62,-5,135,65,-7,139,51,-5,127,55,-7,"); + add("-86,84,-8,179,-137,12,126,67,-9,101,104,-12,"); + add("145,45,-9,147,33,-7,150,23,-8,151,18,-8,"); + add("151,15,-8,152,14,-9,152,2,-8,118,66,-15,"); + add("96,-12,-4,194,-39,-9,150,-20,-8,138,-57,-5,"); + add("119,-93,1,116,-123,3,104,-60,-4,93,-111,3,"); + add("72,-52,-2,-60,-116,16,22,-115,9,66,-152,6,"); + add("111,-118,-1,127,-59,-9,123,10,-14,172,14,-20,"); + add("81,57,-14,16,106,-11,97,-87,-4,83,20,-12,"); + add("13,34,-5,114,-41,-11,107,4,-14,144,-25,-18,"); + add("172,14,-25,57,94,-16,10,60,-7,117,-110,-8,"); + add("125,-37,-16,93,-200,1,128,-95,-14,128,-3,-20,"); + add("103,-40,-15,18,-169,8,77,-131,-5,50,-132,-1,"); + add("-31,-147,13,-24,-149,11,-20,-146,10,0,-155,5,"); + add("-58,-164,16,-80,-104,16,-38,-144,10,131,-77,-21,"); + add("-34,-206,9,-55,-13,9,-78,-47,14,106,-119,-17,"); + add("145,-47,-25,-5,-38,1,-148,11,26,-107,24,17,"); + add("-17,-219,3,-58,-133,9,-72,-120,10,-86,-22,13,"); + add("-68,14,11,81,-166,-15,78,-129,-15,131,-79,-23,"); + add("25,-86,-7,-143,111,26,-24,16,5,89,-154,-19,"); + add("76,-104,-16,30,-67,-7,110,-201,-26,122,-55,-23,"); + add("48,-37,-10,-95,-2,16,116,-113,-26,116,-93,-25,"); + add("108,-103,-25,91,-120,-24,103,-106,-26,89,-118,-25,"); + add("104,-105,-28,95,-110,-27,110,-104,-30,78,-131,-27,"); + add("57,-122,-23,82,-96,-26,50,-176,-27,-13,-142,-11,"); + add("102,-132,-36,104,-28,-26,127,73,-21,93,-26,-24,"); + add("-201,-68,38,-145,-55,26,65,-176,-34,77,-125,-32,"); + add("81,-121,-33,28,-149,-25,49,-142,-31,54,-139,-31,"); + add("63,-136,-34,66,-131,-35,13,-141,-25,-66,-116,-2,"); + add("-103,-102,7,18,-151,-29,41,-143,-34,36,-135,-32,"); + add("49,-132,-35,63,-140,-41,80,-124,-43,39,-130,-35,"); + add("20,-148,-34,-29,-145,-23,-11,-149,-29,-32,-147,-24,"); + add("-72,-145,-14,-85,-112,-5,-122,-66,14,-122,-104,4,"); + add("-63,-130,-16,-105,-105,-2,-74,-124,-13,-34,-157,-32,"); + add("-69,-133,-19,-16,-143,-33,-36,-147,-32,-55,-134,-24,"); + add("-50,-135,-26,-44,-152,-34,-93,-118,-14,-41,-114,-24,"); + add("0,-144,-43,2,-144,-43,-19,-144,-41,-27,-148,-40,"); + add("-22,-140,-40,-12,-144,-44,14,-143,-49,61,-126,-55,"); + add("56,-127,-56,98,-104,-56,78,-117,-58,64,-122,-58,"); + add("51,-130,-58,58,-125,-59,57,-126,-59,67,-119,-60,"); + add("36,-136,-61,39,-134,-61,51,-126,-61,67,-120,-64,"); + add("69,-117,-64,50,-128,-65,77,-111,-65,74,-113,-66,"); + add("50,-126,-66,16,-135,-62,-51,-115,-38,-7,-166,-71,"); + add("-8,-132,-57,-15,-140,-60,-13,-136,-59,33,-133,-71,"); + add("44,-122,-69,31,-129,-70,-17,-137,-62,0,-135,-66,"); + add("-2,-133,-66,18,-132,-71,21,-122,-68,21,-125,-70,"); + add("12,-128,-71,19,-130,-74,41,-121,-76,52,-119,-79,"); + add("58,-116,-80,84,-100,-79,88,-94,-78,98,-93,-81,"); + add("61,-104,-78,59,-112,-82,37,-121,-82,30,-125,-83,"); + add("16,-127,-81,24,-125,-83,31,-121,-83,45,-116,-86,"); + add("41,-117,-86,51,-113,-88,57,-108,-87,61,-107,-90,"); + add("21,-123,-87,-4,-129,-84,-31,-128,-75,-113,-90,-23,"); + add("-98,-49,-2,35,-95,-76,20,-75,-58,78,-152,-131,"); + add("6,-123,-89,-60,-113,-60,47,-37,-42,134,23,-29,"); + add("68,-84,-84,108,-67,-86,80,-84,-90,125,-33,-69,"); + add("120,35,-18,134,79,9,151,38,-29,129,19,-35,"); + add("138,-2,-56,150,15,-49,131,79,6,134,50,-18,"); + add("145,18,-47,117,-26,-69,139,5,-55,142,26,-43,"); + add("131,-22,-74,122,-33,-80,139,-17,-76,122,77,1,"); + add("139,-10,-74,110,29,-30,112,94,16,135,-5,-70,"); + add("135,4,-64,138,53,-30,135,59,-24,131,75,-13,"); + add("131,75,-12,129,77,-12,124,90,-1,128,79,-11,"); + add("122,91,-1,118,93,2,113,99,8,113,99,7,"); + add("126,83,-13,126,80,-15,115,101,4,108,105,10,"); + add("101,112,18,98,113,19,95,118,24,103,110,12,"); + add("87,122,29,106,111,9,112,98,-4,119,92,-13,"); + add("122,70,-31,127,93,-20,85,115,20,83,127,29,"); + add("55,132,47,65,130,40,76,128,29,70,131,35,"); + add("48,133,49,45,135,51,-9,92,60,-74,102,107,"); + add("104,114,-1,117,120,-7,131,81,-40,122,53,-51,"); + add("130,55,-55,130,46,-62,131,49,-61,130,49,-63,"); + add("128,60,-55,110,95,-25,103,114,-9,70,138,25,"); + add("-30,65,57,76,199,53,59,134,28,32,109,34,"); + add("26,155,61,42,142,42,-38,14,34,-44,-59,2,"); + add("31,186,71,10,140,62,-18,132,76,3,115,53,"); + add("15,152,60,-54,105,86,-37,109,76,49,147,32,"); + add("20,140,48,3,59,24,117,-35,-97,114,87,-42,"); + add("108,102,-32,96,108,-23,120,104,-41,123,58,-66,"); + add("95,68,-40,108,117,-32,117,122,-36,72,132,-1,"); + add("115,90,-50,109,78,-51,120,74,-63,119,65,-67,"); + add("99,59,-54,147,55,-94,106,38,-70,135,57,-87,"); + add("102,89,-48,115,73,-66,102,97,-48,86,104,-32,"); + add("85,115,-28,98,117,-40,99,115,-41,60,144,0,"); + add("42,99,0,42,96,-3,30,174,35,-10,83,36,"); + add("-10,101,43,18,182,45,13,138,32,22,135,24,"); + add("6,161,44,47,139,1,-9,159,54,25,141,20,"); + add("4,141,35,10,153,33,10,126,25,63,149,-15,"); + add("25,140,13,-29,151,62,-84,79,90,-85,64,86,"); + add("-73,102,85,-2,156,37,-21,134,47,-19,149,47,"); + add("-19,119,39,-35,164,61,14,142,16,54,146,-17,"); + add("-35,114,49,11,161,18,59,120,-28,44,119,-17,"); + add("-78,96,80,-61,118,67,-77,87,75,-36,161,52,"); + add("23,148,1,52,143,-24,50,144,-23,41,151,-15,"); + add("49,140,-25,92,92,-66,62,139,-37,37,138,-18,"); + add("72,152,-47,26,97,-13,71,122,-50,52,152,-33,"); + add("18,145,-6,101,86,-81,107,41,-89,71,113,-55,"); + add("34,134,-23,127,38,-109,89,107,-74,72,119,-59,"); + add("65,140,-53,52,131,-44,71,99,-62,80,121,-71,"); + add("70,106,-63,82,114,-75,76,109,-70,75,111,-70,"); + add("75,110,-71,75,109,-74,81,101,-79,85,91,-84,"); + add("78,102,-78,80,99,-82,85,91,-87,87,85,-89,"); + add("91,74,-94,92,69,-97,90,77,-95,89,76,-96,"); + add("78,96,-87,69,108,-80,73,103,-84,71,105,-82,"); + add("66,112,-80,64,112,-79,66,109,-81,64,110,-82,"); + add("61,115,-78,62,112,-81,49,125,-69,40,132,-62,"); + add("51,123,-73,53,119,-77,47,126,-71,43,128,-69,"); + add("38,132,-64,12,144,-39,20,142,-48,32,134,-61,"); + add("42,124,-73,44,123,-75,31,137,-65,11,140,-43,"); + add("58,113,-94,38,127,-74,30,129,-66,24,138,-63,"); + add("42,119,-80,33,131,-74,-10,152,-29,-2,147,-38,"); + add("-10,152,-31,69,73,-106,24,26,-38,-53,40,54,"); + add("-13,145,-27,-24,153,-18,-28,142,-10,15,138,-62,"); + add("-35,100,10,-105,49,113,-83,-34,112,-46,-113,93,"); + add("-75,-66,111,-89,-32,116,-91,-28,117,-82,-53,112,"); + add("-93,-32,117,-101,25,108,-98,-13,116,-83,-61,110,"); + add("-98,-19,115,-101,15,106,-96,-14,108,-74,-80,104,"); + add("-79,-74,105,-87,-57,108,-101,22,101,-113,29,108,"); + add("-91,-1,94,-84,-72,105,-85,-65,103,-86,-55,101,"); + add("-112,-5,112,-109,12,104,-102,86,77,-96,96,67,"); + add("-86,113,52,-74,136,34,-89,95,57,-99,63,75,"); + add("-117,-24,116,-43,19,34,87,98,-107,88,66,-102,"); + add("77,82,-96,-35,155,-13,-75,117,35,-92,112,52,"); + add("-100,62,73,-97,117,53,-86,83,52,-79,138,26,"); + add("-97,97,57,-109,73,73,-94,111,46,-86,117,37,"); + add("-94,110,44,-121,46,89,-92,89,49,-102,50,70,"); + add("-112,33,83,-66,134,8,-86,29,62,-21,-93,50,"); + add("-96,161,23,-64,103,15,-85,138,19,-56,143,-7,"); + add("-44,144,-19,-46,136,-16,-62,143,-5,-64,135,-2,"); + add("-76,133,7,-83,129,14,-79,109,17,-110,64,60,"); + add("-100,91,41,-122,107,49,-110,57,61,-78,129,4,"); + add("-59,140,-16,-63,146,-17,-32,132,-35,-52,137,-23,"); + add("-33,149,-44,-47,136,-28,-56,143,-27,10,76,-44,"); + add("-128,195,1,-63,134,-19,-57,131,-24,-120,83,47,"); + add("-108,96,31,-111,87,37,-134,73,59,-73,102,0,"); + add("-93,125,0,-48,134,-37,-20,153,-68,43,57,-62,"); + add("-128,103,35,-123,123,19,-84,121,-9,-82,124,-13,"); + add("-91,123,-7,-86,122,-10,-91,122,-9,-96,117,-3,"); + add("-91,122,-10,-92,124,-13,-67,126,-30,-68,124,-31,"); + add("-88,115,-12,-105,134,-13,-42,105,-39,-113,113,2,"); + add("-110,104,6,-106,108,-1,-95,114,-12,-85,119,-24,"); + add("-61,127,-45,-109,113,-7,-5,135,-88,49,1,-32,"); + add("86,-151,47,88,-107,16,114,-104,-5,80,-117,25,"); + add("65,-125,39,116,-100,-12,110,-101,-7,115,-93,-18,"); + add("134,-51,-58,42,108,-98,-38,135,-61,8,122,-86,"); + add("-7,130,-82,-17,126,-74,10,119,-87,50,-2,-33,"); + add("14,-138,84,20,-130,74,25,-132,70,-1,-137,90,"); + add("43,-69,16,141,-10,-92,115,-95,-20,98,-116,6,"); + add("97,-116,4,94,-115,6,104,-108,-7,100,-114,-2,"); + add("94,-115,2,99,-119,1,85,-103,-1,86,-96,-7,"); + add("104,-120,-6,97,-117,-3,58,-142,39,51,-108,23,"); + add("104,-121,-9,102,-81,-32,121,-53,-64,122,-83,-49,"); + add("111,-96,-33,94,-121,-7,87,-129,1,76,-122,6,"); + add("68,-99,0,98,-169,11,16,-130,55,19,-142,59,"); + add("68,-123,8,49,-139,31,60,-134,18,101,-119,-23,"); + add("83,-108,-17,97,-113,-24,110,-56,-65,124,-71,-71,"); + add("111,-91,-51,98,-97,-38,86,-115,-20,88,-136,-13,"); + add("80,-130,-9,64,-143,8,90,-117,-27,73,-128,-7,"); + add("90,-126,-26,106,-94,-54,103,-93,-53,82,-118,-25,"); + add("58,-121,-2,102,-128,-40,72,-124,-16,53,-141,8,"); + add("41,-148,20,-12,-138,64,40,-140,17,12,-117,33,"); + add("97,-176,-26,53,-134,-1,28,-110,13,65,-183,2,"); + add("74,-127,-25,29,-144,20,24,-145,25,74,-136,-27,"); + add("75,-114,-35,127,-42,-108,105,-7,-100,93,42,-104,"); + add("94,34,-103,92,9,-95,64,101,-96,81,71,-105,"); + add("62,98,-97,96,35,-111,104,10,-111,104,4,-111,"); + add("93,36,-111,90,45,-112,89,46,-113,65,93,-104,"); + add("76,71,-111,96,5,-108,94,6,-109,90,45,-118,"); + add("46,110,-96,44,108,-93,76,66,-115,80,52,-115,"); + add("89,32,-118,84,36,-116,73,67,-115,87,32,-120,"); + add("85,34,-121,80,47,-119,70,61,-116,65,68,-113,"); + add("63,83,-118,-38,151,-21,3,138,-69,50,93,-110,"); + add("72,53,-121,73,52,-121,76,43,-124,78,34,-123,"); + add("68,63,-125,69,47,-119,86,6,-123,92,-28,-116,"); + add("73,43,-127,10,133,-87,-30,138,-32,27,112,-102,"); + add("75,35,-129,79,18,-128,73,30,-126,22,110,-100,"); + add("-19,144,-57,15,115,-93,54,64,-124,69,33,-128,"); + add("80,10,-133,2,92,-61,-55,140,-5,-51,141,-14,"); + add("-17,137,-65,-21,139,-62,8,116,-95,56,-22,-73,"); + add("66,-9,-102,-3,146,-99,-3,110,-77,9,114,-100,"); + add("31,90,-120,15,102,-103,-7,124,-86,-6,121,-87,"); + add("-19,131,-74,-69,85,49,-92,72,98,-86,113,51,"); + add("-88,108,57,-85,116,46,-84,92,60,-86,26,120,"); + add("-94,38,120,-88,27,117,-94,42,114,-95,53,104,"); + add("-96,94,71,-91,110,48,-89,112,42,-81,127,16,"); + add("-63,134,-18,-55,135,-33,-63,129,-17,-35,140,-71,"); + add("-52,93,-3,-22,-178,188,-23,-89,111,-31,-81,115,"); + add("-14,-111,114,-22,-100,113,-38,-91,128,-14,-93,94,"); + add("-5,-92,80,-19,-114,115,-59,-61,127,-80,-22,127,"); + add("-96,21,114,-89,18,106,-100,6,127,-65,-24,103,"); + add("-64,-60,127,-97,15,113,-96,115,39,-70,26,69,"); + add("-65,57,41,-26,95,-37,3,161,-123,-50,136,-40,"); + add("-70,137,-16,-27,111,-52,-102,122,33,-82,23,85,"); + add("-7,-115,97,20,-126,72,18,-129,75,64,-135,22,"); + add("9,-77,45,-113,146,31,-93,140,8,-98,105,39,"); + add("-90,132,9,-23,84,-37,-31,122,-57,-81,129,-4,"); + add("-84,90,30,-110,86,63,-92,67,55,-105,120,27,"); + add("-124,79,80,-67,94,2,-102,129,12,-94,130,1,"); + add("-90,122,1,-88,113,7,-90,119,1,-95,94,26,"); + add("-62,54,23,42,90,-122,-74,158,-54,147,-35,-134,"); + add("67,37,-108,6,90,-87,-19,107,-73,55,-45,-23,"); + add("112,-93,-47,102,-43,-82,82,50,-141,100,-108,-22,"); + add("108,-111,-30,108,-99,-43,85,-130,11,92,-103,-22,"); + add("97,-111,-22,82,-131,12,93,-121,-12,100,-103,-37,"); + add("101,-51,-85,102,-25,-107,108,-63,-87,106,-94,-58,"); + add("89,-88,-41,105,-72,-78,110,-54,-100,100,-94,-55,"); + add("94,-33,-101,91,-5,-120,100,-57,-91,92,-32,-103,"); + add("48,68,-126,57,50,-127,39,69,-119,56,56,-132,"); + add("49,61,-129,83,0,-125,98,-44,-108,79,-89,-38,"); + add("83,-141,4,68,-132,15,71,-127,4,94,-116,-41,"); + add("101,-37,-127,84,-36,-101,86,-23,-117,79,-2,-127,"); + add("89,-42,-109,82,-30,-108,72,8,-130,86,-24,-124,"); + add("84,-14,-132,73,-2,-126,91,-52,-112,86,-30,-126,"); + add("85,-25,-130,53,13,-111,73,-23,-115,51,29,-124,"); + add("37,18,-89,69,19,-152,70,-4,-133,68,5,-141,"); + add("32,59,-126,66,6,-143,86,-53,-119,67,-15,-125,"); + add("51,34,-146,51,22,-136,61,1,-135,50,25,-140,"); + add("53,20,-141,20,17,-67,132,-165,-108,64,-132,8,"); + add("78,-36,-142,59,-87,-36,69,-126,-17,82,-136,-38,"); + add("70,-92,-62,67,-7,-154,61,-60,-82,52,-32,-93,"); + add("17,75,-133,9,-7,-15,4,-112,125,62,-112,-24,"); + add("74,-107,-64,77,-73,-112,72,-61,-117,65,-33,-136,"); + add("30,42,-131,32,47,-146,39,-4,-103,24,-180,155,"); + add("-30,-54,148,-31,-37,130,-49,-18,149,-33,-6,93,"); + add("89,-158,-53,73,-92,-89,77,-102,-89,74,-102,-84,"); + add("74,-110,-77,72,-96,-92,71,-77,-110,65,-51,-127,"); + add("38,23,-139,27,56,-143,17,60,-125,22,64,-145,"); + add("-8,94,-95,-34,140,-75,-74,137,55,-40,161,-91,"); + add("18,29,-95,54,-38,-120,36,-139,72,52,-115,-11,"); + add("41,-10,-118,11,-135,145,66,-140,-30,66,-125,-54,"); + add("51,-142,20,31,-133,66,38,-139,50,47,-133,11,"); + add("54,-123,-26,54,-119,-33,48,-125,-8,43,-134,15,"); + add("53,-149,-4,47,-129,-8,60,-158,-19,53,-138,-25,"); + add("50,-137,-17,51,-145,-13,54,-159,-12,35,-108,-4,"); + add("59,-160,-35,51,-123,-49,60,-131,-71,47,-113,-50,"); + add("54,-157,-34,58,-129,-77,53,-122,-70,39,-100,-44,"); + add("44,-137,-28,54,-154,-52,41,-124,-33,36,-139,-4,"); + add("48,-169,-26,36,-109,-40,52,-167,-50,45,-130,-56,"); + add("48,-119,-81,46,-117,-82,44,-128,-66,41,-123,-60,"); + add("41,-147,-44,37,-137,-39,41,-140,-55,36,-126,-51,"); + add("28,-99,-42,30,-135,-22,34,-195,-1,29,-109,-48,"); + add("35,-111,-67,47,-161,-94,39,-116,-90,40,-98,-112,"); + add("39,-50,-139,23,51,-139,15,82,-129,-5,131,-67,"); + add("-13,127,-37,4,120,-113,21,47,-142,22,41,-143,"); + add("30,-9,-149,5,5,-30,-40,53,161,-26,128,22,"); + add("-6,125,-84,-9,129,-72,-2,108,-91,25,-3,-132,"); + add("5,62,-91,-29,150,1,-28,148,-7,-38,164,28,"); + add("-23,115,1,-29,160,-28,-21,155,-68,-10,107,-78,"); + add("-19,133,-65,-27,145,-36,-29,146,-33,-32,122,17,"); + add("-28,89,40,-35,149,-13,-45,151,39,-32,147,-39,"); + add("-38,128,24,-43,146,21,-34,145,-30,-27,134,-66,"); + add("-14,110,-99,16,30,-147,14,-6,-75,1,34,-72,"); + add("-26,154,-116,-3,70,-117,24,-12,-144,7,49,-146,"); + add("-8,83,-127,-38,140,-30,-32,120,-35,-12,88,-121,"); + add("-3,64,-137,-7,76,-139,-18,89,-88,-25,114,-107,"); + add("-13,87,-134,-9,70,-133,-26,108,-106,-25,104,-102,"); + add("-30,113,-95,-28,101,-68,-28,113,-137,-21,87,-122,"); + add("-9,29,-19,-4,-10,94,-34,124,-122,27,-56,-83,"); + add("-1,45,-207,-23,87,-134,-13,53,-105,-35,116,-129,"); + add("-37,110,-67,-31,89,-47,-61,153,48,-49,129,-38,"); + add("-29,92,-116,-9,39,-146,-12,44,-145,-34,95,-113,"); + add("-49,127,-48,-29,67,32,62,-145,-77,57,-142,-11,"); + add("8,-13,-68,-14,40,-98,-52,133,-70,75,-182,-57,"); + add("-12,35,-112,-44,109,-9,33,-76,-139,-48,120,-77,"); + add("-21,54,-26,65,-162,-49,-42,106,-96,-59,144,-14,"); + add("-1,4,-21,61,-150,-42,33,-82,-72,-48,117,-129,"); + add("-48,115,-84,-57,138,37,-53,128,7,-57,134,0,"); + add("-44,104,54,-21,49,122,-39,88,132,-26,59,139,"); + add("-22,48,48,3,-3,-138,47,-107,-105,34,-78,-126,"); + add("4,-12,-148,72,-167,-24,44,-106,-87,15,-43,-144,"); + add("-5,4,-156,46,-116,-110,54,-137,-75,48,-121,-40,"); + add("56,-142,-41,52,-133,-24,53,-139,-34,45,-123,-74,"); + add("9,-27,-38,-22,59,8,54,-149,-71,38,-114,-94,"); + add("9,-30,-61,-24,61,-13,48,-135,-53,3,-16,-54,"); + add("-16,36,-44,62,-169,-7,0,-8,-58,-17,26,-129,"); + add("27,-95,-117,32,-103,-77,45,-136,-47,24,-40,146,"); + add("33,-125,-154,-37,96,-55,58,-178,-50,28,-93,-52,"); + add("48,-161,-73,39,-130,-51,43,-142,-32,38,-126,-30,"); + add("48,-147,26,49,-146,40,47,-148,37,40,-122,44,"); + add("44,-147,15,2,-29,-76,-42,117,-105,-17,42,-53,"); + add("50,-175,-19,-23,51,-92,33,-122,-32,-32,84,-84,"); + add("15,-70,-58,-15,39,-41,26,-110,-54,-39,103,-107,"); + add("-43,117,-85,-33,69,-124,-36,88,-93,-24,83,4,"); + add("-3,-54,-168,-48,120,-98,-41,123,-30,-44,128,-30,"); + add("31,-151,-129,40,-155,-57,14,-85,-92,-2,-35,-92,"); + add("56,-180,20,30,-130,-54,37,-146,-32,38,-142,-12,"); + add("37,-146,-21,27,-134,-67,33,-147,-32,30,-143,-55,"); + add("37,-155,-14,11,-70,-40,-28,99,-27,29,-160,-70,"); + add("21,-130,-68,26,-144,-58,29,-148,-37,31,-141,-4,"); + add("31,-141,3,33,-158,-10,6,-71,-55,13,-72,-15,"); + add("33,-145,19,33,-156,14,36,-130,69,29,-134,26,"); + add("26,-148,-14,2,-59,-53,-15,50,-44,39,-168,63,"); + add("27,-129,31,34,-153,54,26,-142,18,30,-145,45,"); + add("22,-137,11,7,-139,-93,-24,27,-135,5,-134,-93,"); + add("-1,-104,-102,-2,-95,-95,3,-152,-107,-7,-70,-96,"); + add("7,-124,-52,1,-114,-73,-5,-112,-101,1,-126,-77,"); + add("1,-132,-75,11,-156,-28,14,-142,-6,10,-151,-22,"); + add("7,-139,-30,-4,-115,-74,12,-146,0,3,-140,-38,"); + add("-2,-122,-58,-9,-132,-95,-10,-122,-90,-10,-121,-86,"); + add("5,-156,-18,-14,-115,-96,-23,-76,-131,-18,-93,-106,"); + add("-24,-88,-128,-27,-66,-136,-22,-98,-112,-27,-72,-129,"); + add("-28,-72,-129,-22,-96,-106,-20,-35,-86,-40,49,-157,"); + add("-22,21,-88,-26,2,-102,8,154,50,10,136,59,"); + add("11,135,65,13,138,78,24,89,116,8,136,63,"); + add("-8,153,2,-6,142,11,-5,153,23,-15,144,-22,"); + add("-16,146,-19,-9,152,15,1,137,55,5,133,70,"); + add("9,123,90,20,85,124,15,100,112,6,121,87,"); + add("16,85,115,19,71,126,11,103,109,3,127,88,"); + add("19,58,133,31,-16,146,18,68,134,12,80,121,"); + add("8,86,105,-2,133,85,-15,41,-55,3,-124,-72,"); + add("0,-49,-38,-16,196,57,-14,146,35,-16,147,32,"); + add("-2,103,72,-2,124,97,-20,150,21,-12,142,64,"); + add("29,-19,151,12,45,117,-18,149,43,-22,146,25,"); + add("-28,150,-11,-27,123,-22,-36,141,-59,-35,128,-61,"); + add("-34,150,-27,-37,143,-45,-40,134,-67,-38,133,-56,"); + add("-36,134,-38,-30,149,21,-36,144,-20,-34,137,-9,"); + add("-28,122,7,-37,54,-137,-33,23,-144,-16,-59,-160,"); + add("39,-162,-1,37,-146,12,9,-83,-52,-31,-7,-164,"); + add("-30,8,-140,-27,-21,-151,-7,-56,-96,-5,-88,-112,"); + add("-10,-97,-145,-5,-87,-105,13,-135,-73,-4,-53,-63,"); + add("29,-193,-50,21,-154,-43,-36,34,-123,-30,51,-83,"); + add("19,-149,-42,27,-125,12,-38,23,-137,-34,-36,-164,"); + add("-18,-78,-129,-9,-95,-104,-27,-58,-142,7,-100,-41,"); + add("46,-128,86,27,-147,6,26,-152,2,17,-163,-35,"); + add("12,-82,-2,-52,57,-162,-42,111,-88,-42,110,-85,"); + add("-46,58,-132,-51,62,-140,-25,121,-13,4,123,89,"); + add("-1,39,21,-18,-128,-141,-39,-14,-140,-9,147,56,"); + add("3,81,64,-30,-77,-152,4,97,73,-40,11,-127,"); + add("-6,92,40,-42,114,-68,-40,10,-127,-32,-63,-142,"); + add("-59,75,-141,-54,62,-131,-50,90,-97,-53,60,-123,"); + add("-58,91,-120,-54,71,-114,-46,100,-72,-41,93,-60,"); + add("-37,148,-13,-31,158,14,-30,109,-13,-50,117,-63,"); + add("-30,153,20,-15,138,55,-25,124,17,-34,152,15,"); + add("-28,158,39,-20,136,50,-22,134,43,-15,136,65,"); + add("-26,140,40,0,105,90,3,119,114,-8,120,83,"); + add("-7,106,75,14,94,131,14,90,130,7,80,101,"); + add("10,118,149,-10,109,83,7,95,122,-2,105,108,"); + add("-3,106,110,-15,45,-3,-38,137,29,4,83,113,"); + add("1,91,112,-17,130,97,-20,110,68,-57,138,-24,"); + add("-54,137,-16,-55,130,-24,-66,120,-76,-58,70,-105,"); + add("-72,109,-102,-57,131,-21,-57,108,-48,-36,71,-26,"); + add("-45,12,-132,-61,63,-114,-59,95,-65,-72,78,-126,"); + add("-46,24,-111,-62,43,-134,-41,48,-62,-34,60,-27,"); + add("-14,-62,-118,-10,-97,-149,-36,-22,-129,-64,65,-103,"); + add("2,-104,-116,77,-141,52,45,-140,-33,24,-120,-67,"); + add("17,-115,-77,-58,-12,-173,-57,124,-22,-18,111,74,"); + add("-26,121,63,-73,123,-61,-16,13,-28,-46,17,-105,"); + add("-78,58,-139,-50,16,-113,-62,28,-127,-75,77,-107,"); + add("-63,51,-103,-62,6,-144,-29,49,-18,-32,-36,-116,"); + add("-70,53,-111,-73,78,-93,-56,79,-47,-13,65,38,"); + add("-30,-67,-139,-58,161,33,-19,119,82,-75,112,-55,"); + add("-2,-33,-39,34,-104,-32,5,-131,-123,-1,-80,-85,"); + add("-55,26,-96,-54,54,-65,-40,45,-43,-53,30,-85,"); + add("-32,-3,-73,-87,63,-122,-50,-9,-116,-65,19,-116,"); + add("-71,17,-130,-80,46,-117,-98,116,-87,-28,51,-6,"); + add("-14,31,1,-91,99,-85,-74,32,-114,-103,87,-115,"); + add("-79,73,-82,-82,82,-76,-50,91,-8,-13,71,46,"); + add("-78,49,-99,-77,5,-139,-82,111,-44,-83,71,-82,"); + add("-64,95,-23,-62,48,-66,-44,102,22,-40,-15,-85,"); + add("-28,-6,-56,-58,141,35,-39,101,30,46,34,115,"); + add("-127,87,-137,-54,85,-10,-56,143,46,-47,-20,-103,"); + add("15,-44,-16,-73,105,-22,-90,112,-42,-64,95,-13,"); + add("-115,119,-74,-79,122,-6,-41,102,36,-5,21,13,"); + add("-83,22,-116,-94,84,-69,-101,50,-113,-20,139,110,"); + add("1,35,40,-102,57,-106,-29,101,59,-77,74,-46,"); + add("-58,12,-81,-32,114,70,67,-11,98,-159,133,-114,"); + add("-20,42,13,50,52,138,8,96,119,63,18,124,"); + add("116,-69,116,31,53,113,29,28,82,-126,35,-174,"); + add("-93,81,-63,-105,73,-90,-99,59,-93,-86,56,-77,"); + add("-34,133,99,25,76,128,10,90,123,40,56,135,"); + add("4,74,95,73,9,136,76,5,137,5,99,132,"); + add("-36,38,-15,11,-124,-136,-72,8,-113,-84,29,-107,"); + add("-24,-78,-135,-62,-21,-130,-51,-42,-133,-70,17,-93,"); + add("-12,121,124,7,78,105,-13,101,103,33,74,145,"); + add("-62,121,49,-41,121,84,-33,114,91,-36,114,88,"); + add("-44,117,81,-44,121,87,19,71,130,38,52,136,"); + add("15,79,139,1,59,85,-94,108,-13,-104,105,-34,"); + add("-115,101,-56,-91,70,-58,-105,97,-40,-64,75,-3,"); + add("-66,-10,-127,-103,105,-21,-82,81,-20,-136,62,-137,"); + add("-76,32,-78,-125,58,-119,-47,-24,-109,-91,71,-42,"); + add("-94,124,27,58,52,166,74,-12,100,64,25,141,"); + add("39,56,147,23,65,135,97,-31,118,88,-61,57,"); + add("129,-98,73,102,-82,52,80,-6,131,25,59,137,"); + add("-74,118,55,-84,108,19,-38,109,106,59,10,125,"); + add("65,14,144,24,51,131,-22,92,115,-74,112,52,"); + add("-105,109,-13,-101,67,-74,-37,-43,-143,-102,33,-130,"); + add("-65,19,-86,-133,124,-31,-106,97,-22,-106,68,-72,"); + add("-105,53,-95,-110,54,-98,-106,87,-34,-134,101,-57,"); + add("-102,77,-41,-78,4,-122,-71,-5,-122,0,-91,-149,"); + add("60,-97,-60,113,-96,28,108,-82,42,123,-93,52,"); + add("88,-91,0,-19,-77,-152,136,-111,47,93,-79,32,"); + add("-144,58,-147,-113,62,-85,-115,90,-44,-111,61,-81,"); + add("-113,56,-91,-106,46,-91,-97,31,-101,-93,3,-134,"); + add("-105,44,-89,-1,-105,-155,-62,-37,-142,-27,-60,-125,"); + add("94,-121,-38,106,-109,-4,-1,-61,-85,-7,-28,-51,"); + add("120,-40,116,118,-122,0,52,-66,-17,-29,-65,-130,"); + add("-35,-59,-128,-109,51,-83,-59,-48,-147,-101,-1,-137,"); + add("24,-67,-55,65,-148,-103,37,-87,-62,39,-74,-39,"); + add("87,11,130,88,-84,13,26,-142,-142,57,-118,-69,"); + add("16,-93,-91,119,-132,1,112,-116,12,74,-115,-36,"); + add("25,-109,-94,66,-86,-11,-7,-85,-108,-97,52,-70,"); + add("-111,45,-94,-37,-21,-73,-70,78,-3,-81,57,-40,"); + add("-112,37,-103,-90,-7,-121,-106,68,-57,-97,-5,-126,"); + add("-126,95,-48,-86,98,4,-101,132,28,-28,89,67,"); + add("-63,130,74,-78,121,47,-64,123,66,-43,115,85,"); + add("-18,107,106,-15,103,109,-2,97,117,-18,104,107,"); + add("-29,108,102,-13,98,110,27,76,134,18,79,126,"); + add("-3,85,110,-93,116,36,-98,88,-8,-119,65,-63,"); + add("-108,31,-97,-125,72,-58,-123,70,-58,-122,86,-33,"); + add("-120,63,-62,-97,76,-14,-88,121,59,-57,107,81,"); + add("-116,101,0,-118,89,-16,-123,77,-37,-113,40,-77,"); + add("-117,100,6,-124,41,-85,-107,85,-3,-127,95,-8,"); + add("-61,9,-56,-24,-24,-61,-64,8,-58,50,-110,-99,"); + add("-88,-27,-132,-63,-35,-115,-145,38,-102,-118,38,-73,"); + add("-132,67,-45,-131,59,-55,-129,67,-41,-130,83,-18,"); + add("-121,80,-12,-106,90,18,-121,90,6,-129,72,-29,"); + add("-123,89,5,-125,84,-4,-126,85,-1,-132,74,-20,"); + add("-129,82,-5,-128,80,-6,-125,85,6,-114,92,27,"); + add("-114,91,26,-109,100,45,-119,88,21,-131,79,0,"); + add("-116,93,34,-120,89,25,-134,76,-3,-132,74,-3,"); + add("-118,84,25,-97,100,66,-71,79,59,-102,100,66,"); + add("-105,106,75,-63,93,90,-75,74,54,-61,108,117,"); + add("-79,93,83,-110,89,51,-105,100,74,-107,80,43,"); + add("-132,75,15,-109,82,47,-36,61,73,-24,76,107,"); + add("-79,91,89,19,67,129,-18,21,21,-106,11,-66,"); + add("-41,73,92,32,53,118,48,67,155,-14,78,128,"); + add("23,66,140,68,17,87,116,-7,88,92,-13,56,"); + add("94,-97,-96,121,-86,-49,36,8,46,-84,73,57,"); + add("198,-81,31,88,15,107,-139,99,55,-15,57,95,"); + add("-48,44,39,132,-65,-1,101,-71,-41,56,19,90,"); + add("-109,95,76,-84,83,80,0,44,86,127,-10,101,"); + add("86,14,110,30,54,137,-139,80,23,-137,46,-42,"); + add("-135,61,-7,-136,58,-12,-136,51,-26,-136,54,-17,"); + add("-142,64,0,-143,71,15,-119,71,38,-139,69,17,"); + add("-130,52,-6,-149,58,-10,-141,57,-1,-142,57,-2,"); + add("-125,55,9,-115,77,66,-138,60,13,-145,46,-19,"); + add("-135,63,25,-131,63,30,-145,46,-15,-144,29,-48,"); + add("-126,9,-75,-131,2,-89,-103,-2,-78,-145,8,-85,"); + add("-73,-25,-101,-59,-25,-91,-125,51,20,-111,-21,-115,"); + add("-110,-10,-90,-144,20,-50,-93,-27,-111,-87,54,54,"); + add("-145,67,47,-122,0,-72,-96,-31,-117,-70,-24,-85,"); + add("-163,1,-89,-50,-59,-140,-12,-32,-67,158,-11,64,"); + add("80,-49,-49,-105,-24,-102,-154,32,-21,-130,-6,-79,"); + add("-155,53,20,-111,-1,-57,-135,-2,-70,-150,10,-52,"); + add("-53,63,93,122,17,89,33,27,67,-87,73,97,"); + add("-111,65,72,-127,62,59,-142,49,30,-136,52,41,"); + add("-111,67,81,-142,54,45,-96,68,93,-145,51,42,"); + add("-138,21,-15,-134,3,-48,-143,18,-19,-112,-14,-72,"); + add("-69,-19,-64,-127,17,-11,106,-88,-136,73,-56,-82,"); + add("-17,-66,-133,-14,-67,-133,-156,43,26,-129,56,62,"); + add("-127,53,61,-121,47,50,-165,41,27,-100,5,-21,"); + add("-39,83,150,-67,73,125,-70,56,90,-158,25,6,"); + add("-138,1,-37,-115,-32,-97,-19,-22,-49,170,0,48,"); + add("129,-52,-68,49,-72,-127,69,-67,-110,37,-63,-111,"); + add("81,-63,-95,66,-61,-96,131,-36,-28,169,-43,-28,"); + add("150,-47,-39,90,-65,-90,128,-53,-54,120,-61,-71,"); + add("138,-48,-39,123,-61,-65,132,-58,-56,91,-73,-96,"); + add("134,-71,-75,115,-51,-44,139,-53,-37,119,-52,-43,"); + add("159,-20,30,145,-37,-3,85,-30,-17,36,-84,-128,"); + add("117,-79,-83,122,-58,-44,106,-49,-36,109,-94,-106,"); + add("82,-82,-98,75,-82,-101,65,-85,-107,62,-85,-108,"); + add("41,-87,-117,33,-86,-120,30,-89,-123,20,-86,-123,"); + add("25,-88,-120,33,-89,-119,32,-90,-118,34,-90,-117,"); + add("22,-90,-119,-12,-73,-110,29,-103,-133,32,-93,-116,"); + add("50,-95,-109,14,-91,-119,-30,-84,-125,-195,88,36,"); + add("-121,70,44,-137,65,33,-119,79,60,-98,87,82,"); + add("-56,82,91,-57,83,96,-59,73,80,-205,54,-2,"); + add("-151,27,-18,-78,5,-23,-22,101,138,-37,90,117,"); + add("-88,84,91,-127,63,47,-135,56,35,-139,6,-38,"); + add("-140,1,-47,-134,70,61,5,81,122,17,78,125,"); + add("-41,86,117,-89,79,93,-98,75,85,-119,64,62,"); + add("-100,19,-1,17,-95,-143,-132,50,38,-20,87,131,"); + add("47,56,102,18,68,116,-29,86,130,-106,66,74,"); + add("-66,73,102,130,32,94,103,-30,-19,47,77,145,"); + add("-70,79,111,-99,71,90,-128,63,68,-114,62,73,"); + add("-87,70,95,-55,78,123,-97,68,93,-121,24,7,"); + add("-147,9,-24,-105,-31,-85,-80,65,96,-168,46,39,"); + add("-100,19,9,53,-101,-168,-37,-29,-61,-127,65,85,"); + add("-121,58,77,-134,29,22,-156,25,12,-144,-2,-33,"); + add("-137,-3,-32,-103,-67,-138,-35,-62,-117,-94,-9,-32,"); + add("-79,89,144,-103,42,58,-147,52,71,-131,39,52,"); + add("-94,50,77,-110,45,69,-88,41,63,-145,58,91,"); + add("-135,28,39,-149,33,45,-154,42,67,-110,29,47,"); + add("-142,33,52,-122,43,75,-88,36,65,-48,26,48,"); + add("-79,-44,-90,-151,-18,-40,-139,-29,-58,-91,10,17,"); + add("-85,59,112,37,70,137,32,61,121,79,42,84,"); + add("57,43,89,16,96,195,36,62,129,70,9,19,"); + add("137,40,90,51,50,108,169,-17,-27,36,11,26,"); + add("61,36,80,155,-21,-32,83,-6,-5,-231,34,53,"); + add("-136,-5,-19,-97,17,29,72,29,68,-155,-33,-80,"); + add("-91,-42,-93,-163,-15,-36,-124,23,46,-123,34,71,"); + add("-112,47,100,-74,53,114,-24,59,131,77,57,126,"); + add("-49,54,121,-99,29,69,-108,-6,-12,54,-64,-146,"); + add("-67,-63,-139,-79,-39,-84,-150,6,20,-139,16,41,"); + add("-148,-25,-46,-76,-52,-109,-43,-62,-131,-129,-32,-58,"); + add("-159,-30,-48,-105,-46,-87,-124,-6,0,-30,8,22,"); + add("-73,-24,-43,-57,44,101,39,66,136,-102,62,146,"); + add("30,32,67,11,49,105,29,27,57,-151,-27,-39,"); + add("-117,24,70,16,27,60,-138,-5,10,-65,55,136,"); + add("-33,35,84,122,35,61,121,49,94,115,44,86,"); + add("113,41,79,158,6,-6,124,3,-8,183,20,27,"); + add("23,-15,-38,-80,-60,-133,-18,-46,-105,10,-32,-75,"); + add("86,19,35,82,53,115,21,61,141,16,64,151,"); + add("76,33,75,102,59,134,129,33,73,138,35,80,"); + add("111,28,63,105,29,69,121,41,101,115,40,102,"); + add("82,18,44,870,23,91,110,40,114,77,23,70,"); + add("168,28,91,133,20,70,114,30,98,147,9,46,"); + add("-90,27,62,141,13,57,73,-15,-30,53,-51,-132,"); + add("-19,-34,-96,-41,-51,-145,15,-49,-127,95,-34,-73,"); + add("169,5,42,52,49,140,124,28,99,17,53,147,"); + add("69,28,93,171,-33,-53,144,4,48,140,8,58,"); + add("131,12,67,113,11,64,150,-6,27,138,-14,5,"); + add("138,-42,-71,49,-51,-127,60,-54,-127,76,-29,-53,"); + add("-71,79,190,-14,52,140,1,50,144,110,25,109,"); + add("-28,52,141,-81,43,99,-8,49,144,48,39,136,"); + add("93,26,116,113,17,100,135,5,72,150,-3,56,"); + add("113,-7,29,162,-13,33,146,-15,25,140,-3,62,"); + add("52,28,120,-7,49,156,114,7,87,44,10,60,"); + add("14,38,140,41,25,111,-150,31,21,30,35,144,"); + add("94,17,120,126,4,94,139,-28,-16,135,-41,-62,"); + add("151,-29,-4,25,19,88,-141,35,31,-58,13,9,"); + add("14,-26,-86,-127,49,98,155,0,104,71,5,70,"); + add("-208,7,-117,-46,10,7,91,20,141,98,13,115,"); + add("101,9,110,114,4,102,96,10,117,95,1,79,"); + add("109,-40,-76,133,-7,81,117,-41,-68,-35,-14,-89,"); + add("120,-42,-66,96,-58,-148,89,0,74,65,10,99,"); + add("130,-44,-61,71,-13,15,25,41,188,42,22,129,"); + add("122,-11,72,140,-30,16,82,17,155,-11,36,147,"); + add("11,19,96,183,-61,-70,112,-43,-66,155,-51,-47,"); + add("84,-4,77,16,27,138,-14,31,125,-75,53,155,"); + add("-80,36,74,-32,23,74,-15,35,154,-25,35,141,"); + add("72,0,99,109,-54,-133,105,-45,-94,50,-21,-34,"); + add("-128,64,153,-73,48,147,30,17,135,-15,32,149,"); + add("18,21,148,53,10,136,28,19,158,37,11,129,"); + add("65,4,136,47,-2,67,-5,36,232,-126,44,76,"); + add("38,14,176,36,11,147,59,2,141,104,-14,111,"); + add("123,-27,48,138,-42,-32,187,-62,-75,-42,18,54,"); + add("-141,44,29,-118,42,81,-131,41,52,-47,24,99,"); + add("100,-12,127,-67,31,125,69,-3,154,111,-34,-29,"); + add("-3,-9,-99,147,-28,121,100,-20,81,90,-18,85,"); + add("77,-8,160,91,-20,75,130,-34,57,-12,7,30,"); + add("-147,40,-39,-126,31,-55,-140,35,-59,-92,16,-109,"); + add("-133,32,-52,-138,31,-73,-128,32,-25,-139,29,-69,"); + add("-131,24,-93,-135,29,-56,-140,29,-51,-155,38,9,"); + add("-68,29,120,-52,14,26,-2,-10,-105,-127,37,72,"); + add("-73,28,119,-80,32,142,-82,30,140,29,5,136,"); + add("51,1,149,91,-14,95,46,-1,124,-187,43,23,"); + add("2,10,158,-32,14,112,-177,35,-56,-60,23,186,"); + add("83,-11,131,135,-25,77,148,-30,61,135,-30,13,"); + add("142,-36,-57,44,-12,-44,21,3,184,63,-11,92,"); + add("147,-40,-107,144,-35,15,202,-54,-65,-73,21,54,"); + add("-123,32,26,-149,37,6,-32,13,130,106,-21,127,"); + add("51,-9,130,-27,8,64,-59,17,91,33,-5,135,"); + add("77,-18,95,108,-26,130,55,-13,135,48,-11,147,"); + add("66,-18,128,103,-27,104,85,-24,134,147,-41,64,"); + add("19,-6,68,15,-5,55,129,-34,-105,26,-8,31,"); + add("25,-8,70,136,-36,-112,129,-37,-45,103,-32,103,"); + add("80,-25,120,132,-38,-81,21,-7,3,-143,41,91,"); + add("-118,37,-84,-104,31,-37,37,-15,193,1,-4,148,"); + add("12,-8,152,-17,-1,153,3,-8,154,55,-21,114,"); + add("136,-42,33,138,-40,-30,143,-45,34,130,-38,-51,"); + add("84,-20,-134,141,-43,-46,99,-28,-115,139,-44,-30,"); + add("133,-47,62,126,-43,4,155,-52,-32,141,-50,9,"); + add("67,-29,129,-217,78,-48,-91,30,49,147,-56,97,"); + add("75,-27,24,-208,74,-46,-143,50,-14,-108,40,-86,"); + add("-122,44,-87,-69,19,95,-20,-1,153,-144,42,95,"); + add("-91,26,69,-105,27,110,-56,9,142,31,-19,141,"); + add("84,-28,24,106,-34,10,-98,21,131,30,-19,134,"); + add("148,-48,3,117,-31,-89,78,-17,-117,122,-36,-74,"); + add("69,-22,-14,-138,31,215,-60,10,119,-78,16,122,"); + add("-115,38,-4,-151,50,-18,-124,44,-71,-124,43,-54,"); + add("-144,45,-14,-64,14,67,179,-57,30,125,-44,67,"); + add("52,-28,137,63,-31,126,126,-49,95,144,-44,-27,"); + add("145,-47,-12,144,-46,-26,122,-48,68,107,-46,95,"); + add("131,-53,64,136,-49,11,136,-52,28,89,-28,-48,"); + add("36,2,-152,-16,20,-148,86,-19,-130,104,-30,-102,"); + add("111,-37,-68,140,-53,-1,120,-48,13,104,-50,107,"); + add("129,-49,-15,73,-19,-133,41,-13,-37,-39,1,179,"); + add("-129,44,82,-136,57,-40,-129,53,-27,-126,47,10,"); + add("-142,50,53,-63,13,112,8,-18,149,45,-31,143,"); + add("136,-57,59,142,-53,-20,138,-57,23,102,-50,93,"); + add("82,-46,121,126,-59,66,78,-45,115,43,-35,140,"); + add("57,-39,119,74,-46,108,-89,19,130,-46,-2,147,"); + add("-88,19,119,-113,31,99,-93,46,-59,72,-8,-137,"); + add("102,-28,-92,11,18,-161,-96,49,-74,-84,51,-134,"); + add("-94,51,-104,-79,46,-124,-107,51,-78,-132,56,-46,"); + add("-104,51,-100,-143,47,58,-132,44,48,-138,54,-39,"); + add("-127,51,-45,-138,54,-54,-142,53,-26,-121,47,-58,"); + add("-126,49,-59,-139,50,-36,-135,41,25,-146,45,24,"); + add("-107,44,-100,-115,44,-86,-124,45,-74,-148,49,-40,"); + add("-125,31,66,-83,14,108,-48,-1,147,-42,-1,123,"); + add("116,-48,130,127,-47,76,124,-46,79,112,-45,93,"); + add("74,-39,124,41,-31,146,95,-43,99,120,-41,17,"); + add("125,-39,-7,123,-50,70,110,-45,58,111,-53,108,"); + add("78,-23,-21,122,-24,-128,143,-52,19,146,-46,-48,"); + add("73,-19,-46,128,-61,101,66,-43,127,-160,48,75,"); + add("-148,45,55,-120,29,88,-120,29,81,-122,25,107,"); + add("-140,42,39,-122,26,88,-106,18,107,-87,7,124,"); + add("-101,13,115,-20,-16,122,55,-38,110,148,-51,18,"); + add("124,-43,8,82,-56,149,10,-26,114,62,-41,104,"); + add("-119,33,37,-113,55,-90,-93,27,22,4,-32,149,"); + add("-4,-32,163,-60,-8,131,-85,3,112,-35,-21,147,"); + add("41,-47,149,-77,-2,113,-87,20,38,-90,56,-120,"); + add("-88,48,-90,-8,17,-64,-53,-20,162,-10,-31,147,"); + add("55,-34,69,-14,-15,81,-74,-7,122,-44,-22,144,"); + add("-2,-43,171,-14,-29,128,-19,-34,149,-41,-25,138,"); + add("26,-38,109,85,-58,111,53,-51,120,-70,-19,143,"); + add("-68,2,64,-159,44,17,-135,42,-6,-111,47,-48,"); + add("-14,46,-145,77,18,-141,3,26,-96,-128,49,-44,"); + add("-150,49,-21,-141,24,57,-100,-4,114,-90,-3,96,"); + add("222,-83,76,62,-44,91,74,-55,118,90,-69,142,"); + add("142,-41,0,117,-61,82,66,-54,112,64,-59,127,"); + add("39,-38,80,-114,24,35,-160,55,-21,-116,7,85,"); + add("-21,-50,172,-30,-38,141,-44,-33,136,-18,-44,143,"); + add("15,-50,132,125,-58,61,134,-55,39,87,-65,108,"); + add("-108,-7,111,-171,30,57,-122,8,76,-161,52,-16,"); + add("-157,32,34,-14,-54,156,100,-54,67,150,-56,35,"); + add("136,-17,-59,121,-76,104,-62,-35,139,-143,18,62,"); + add("-138,38,4,-140,47,-18,-139,20,48,-134,64,-69,"); + add("-83,61,-101,-108,57,-75,-77,52,-85,-35,66,-152,"); + add("-97,53,-78,-153,45,-17,-139,35,-4,-122,43,-38,"); + add("-145,48,-39,-131,50,-55,-35,17,-25,137,-22,-26,"); + add("172,-52,33,120,-16,-36,126,-23,-20,163,-31,-28,"); + add("144,-22,-41,137,-12,-66,138,-19,-52,141,-23,-41,"); + add("122,-3,-88,89,17,-123,62,29,-135,27,39,-143,"); + add("-8,50,-143,-36,54,-137,-97,54,-86,-118,58,-80,"); + add("-129,45,-36,-124,35,-5,-133,33,4,-164,34,26,"); + add("-107,20,20,-188,54,-27,-146,34,0,-150,34,3,"); + add("-145,30,10,-127,8,63,-145,14,55,-85,-11,92,"); + add("-32,-14,67,-106,45,-73,-137,20,24,-42,26,-57,"); + add("73,11,-81,-168,22,37,-53,-27,118,-158,15,48,"); + add("-68,-6,58,-88,16,1,-103,34,-50,-68,18,-19,"); + add("189,-4,-93,63,34,-146,-88,35,-63,-131,25,-8,"); + add("-159,26,8,-61,-27,121,26,-41,118,15,-28,81,"); + add("-100,59,-136,-39,43,-117,-48,35,-90,-92,-13,92,"); + add("24,-50,148,-47,-22,93,-103,51,-111,-30,-54,187,"); + add("-4,-45,141,-43,-10,52,-44,57,-156,-3,55,-172,"); + add("-113,9,23,-46,-29,115,-20,-42,140,-51,-43,155,"); + add("-8,-37,114,-142,27,-21,-138,10,25,3,-21,63,"); + add("99,-27,38,1,-24,71,-133,8,28,-51,-34,119,"); + add("20,-39,105,-49,-14,57,-19,63,-172,-63,18,-30,"); + add("3,-52,148,-27,-6,29,-81,38,-80,-1,-47,132,"); + add("41,-28,66,-100,12,0,-57,-14,60,-78,-50,161,"); + add("19,-50,132,-110,-31,118,37,-32,72,121,-13,-3,"); + add("-55,-17,61,-119,-5,51,22,-32,75,-8,-30,81,"); + add("-128,34,-51,-13,-34,92,-68,-38,115,104,-25,35,"); + add("-22,-38,101,-97,-8,46,10,-31,75,96,-15,11,"); + add("-150,-26,102,-89,-41,122,-29,-49,124,-5,-59,142,"); + add("102,-25,34,-142,-35,113,-11,-42,101,-17,-61,141,"); + add("32,-65,140,-65,-49,121,-116,-25,80,-12,-22,49,"); + add("74,4,-24,-32,-65,149,-87,-22,64,-107,-19,61,"); + add("-74,-53,125,-30,-54,117,-20,-47,102,103,-40,63,"); + add("121,38,-100,11,45,-95,83,15,-48,-5,-52,109,"); + add("-74,-49,115,-125,-37,99,-78,21,-28,-105,24,-32,"); + add("-65,-36,84,-117,-54,126,-12,-43,88,3,-20,39,"); + add("-93,17,-21,40,-36,67,-187,32,-38,-68,-35,77,"); + add("142,-19,19,44,-6,7,-107,-31,73,-170,5,11,"); + add("-38,-29,61,138,-35,51,19,-30,56,-139,30,-41,"); + add("-26,-22,45,-79,-18,43,-10,-20,39,-119,5,2,"); + add("-73,-15,35,51,-34,60,135,-9,4,88,-13,15,"); + add("-204,6,8,-58,-54,107,41,-62,111,-12,-60,111,"); + add("165,3,-22,141,9,-30,81,9,-26,121,5,-25,"); + add("46,10,-23,-65,-71,137,-113,15,-13,-165,6,8,"); + add("-137,-10,31,-71,-39,77,44,-55,96,56,-52,87,"); + add("-60,-51,95,76,-8,8,32,-7,9,58,-30,46,"); + add("91,74,-140,133,14,-40,-101,-58,115,-116,-74,141,"); + add("22,-36,61,36,-9,12,-128,-39,79,-45,-62,111,"); + add("96,-4,-3,89,24,-50,69,16,-36,-27,-68,119,"); + add("-8,-73,125,52,-14,17,-163,-5,26,-11,-80,133,"); + add("113,-56,81,164,-41,48,93,-44,62,120,-27,28,"); + add("139,12,-38,114,32,-68,113,56,-108,91,75,-138,"); + add("71,50,-95,85,48,-96,129,23,-62,16,79,-137,"); + add("-21,60,-100,45,39,-76,43,-102,168,100,-60,85,"); + add("86,-42,54,22,-91,149,77,-82,121,102,-39,44,"); + add("30,-102,160,52,-68,100,79,-76,105,81,-75,101,"); + add("100,-72,92,107,-82,103,-20,-80,129,43,-77,108,"); + add("97,-78,95,31,-91,130,152,-23,-2,139,15,-55,"); + add("85,37,-78,-46,84,-116,82,66,-121,93,34,-76,"); + add("140,2,-42,120,7,-44,27,94,-155,33,71,-122,"); + add("-10,85,-133,-17,82,-129,-22,77,-118,-36,75,-113,"); + add("0,71,-119,-42,78,-120,-84,51,-62,-18,8,-8,"); + add("158,11,-67,92,44,-104,59,43,-94,109,50,-124,"); + add("-4,43,-75,-166,-24,98,-135,18,11,-144,30,-10,"); + add("-87,17,-4,167,12,-72,119,0,-37,2,31,-55,"); + add("149,-74,84,81,29,-78,74,63,-140,-30,63,-103,"); + add("-137,64,-72,-118,56,-65,-130,36,-23,-116,42,-42,"); + add("-64,75,-122,-41,74,-128,-29,75,-135,10,49,-99,"); + add("-15,80,-154,-40,69,-124,76,46,-118,-7,57,-113,"); + add("69,41,-108,71,47,-122,85,54,-144,93,36,-111,"); + add("75,31,-94,48,61,-151,27,60,-142,7,54,-123,"); + add("-98,55,-87,11,62,-146,-33,63,-135,49,45,-126,"); + add("-1,19,-44,43,11,-45,45,31,-92,136,-8,-38,"); + add("142,2,-68,121,-7,-38,168,-56,59,69,-63,119,"); + add("54,-65,129,-102,-29,116,-19,-59,146,-32,-54,138,"); + add("-35,-54,138,-50,-50,131,-57,-41,114,-34,-55,135,"); + add("-52,-49,125,-61,-30,89,-21,-65,145,24,-66,128,"); + add("78,-59,90,58,-76,131,98,-70,104,39,-58,98,"); + add("35,-86,155,29,-67,119,95,-70,98,126,-32,10,"); + add("161,-43,16,118,-28,2,88,-64,85,11,-26,43,"); + add("80,38,-106,156,9,-87,89,28,-93,101,21,-88,"); + add("125,31,-120,87,26,-94,91,14,-71,143,6,-86,"); + add("115,7,-74,136,12,-97,132,-76,79,140,-29,-19,"); + add("134,-20,-36,62,-45,55,-190,9,90,-75,-38,116,"); + add("-100,-25,103,-13,-67,136,-131,-8,83,-145,16,45,"); + add("-146,21,32,-137,6,55,-107,-24,97,-117,-9,71,"); + add("-105,-33,110,-98,-41,117,21,-66,111,73,-68,92,"); + add("97,-88,114,158,-25,-26,66,-81,113,35,-79,122,"); + add("68,-81,109,16,-74,121,-89,-48,120,-143,29,13,"); + add("-109,73,-77,-134,61,-47,-107,36,-17,-124,-37,114,"); + add("-48,-64,126,16,-80,128,-34,-71,129,31,-93,141,"); + add("30,-73,105,61,-83,110,66,-83,105,74,-87,106,"); + add("34,-78,107,-27,-60,104,-107,38,-18,47,87,-152,"); + add("-16,52,-75,-34,-119,198,-91,-45,103,-86,-36,85,"); + add("-11,-86,133,-87,-52,109,-140,-7,59,-122,57,-43,"); + add("-29,57,-75,-218,21,39,-130,-21,74,-112,-40,93,"); + add("-111,-38,89,-63,-56,100,-148,-32,88,-129,-25,72,"); + add("-126,-32,78,-132,-15,55,-87,9,10,190,-58,34,"); + add("-36,-31,53,-140,41,-22,-103,81,-90,-133,38,-21,"); + add("-139,51,-42,-94,-4,27,-136,-64,122,-128,-38,80,"); + add("-91,-22,48,-108,37,-30,-13,81,-112,-199,13,18,"); + add("-104,55,-58,-90,68,-83,-50,40,-48,-25,89,-125,"); + add("1,91,-135,42,64,-102,84,60,-105,60,68,-113,"); + add("96,51,-97,-95,45,-50,-102,33,-33,-46,108,-159,"); + add("68,72,-125,-33,84,-128,-29,28,-39,-132,-44,93,"); + add("-66,-71,124,-120,-33,72,-139,-21,54,-71,-78,132,"); + add("72,-25,27,91,85,-145,98,9,-30,90,-10,1,"); + add("-70,-93,155,-18,-17,29,-92,29,-29,-109,-42,80,"); + add("-76,-38,70,13,-54,79,32,-90,131,5,-98,145,"); + add("84,-39,46,72,-99,134,40,-83,114,75,-76,97,"); + add("-8,-64,92,19,-48,65,63,-79,100,137,-58,59,"); + add("59,-44,51,-210,58,-47,-104,-26,52,-25,-83,118,"); + add("-102,23,-17,-129,39,-35,-146,-27,55,4,-80,109,"); + add("-47,-11,21,-127,39,-37,-147,-12,32,-140,-28,53,"); + add("-93,-63,94,-127,-54,83,-74,-49,71,-18,-91,121,"); + add("-46,-85,114,-90,-78,108,-68,-65,87,16,-45,57,"); + add("47,-36,41,-117,-21,35,128,-38,39,-230,4,9,"); + add("-135,-41,59,-128,-49,67,-143,-27,39,-139,-41,56,"); + add("-32,-93,115,6,-98,119,-35,-60,72,-123,-64,80,"); + add("-144,-29,37,-135,-47,56,-12,-90,106,-152,-52,60,"); + add("-149,15,-18,-155,15,-20,-86,84,-100,-162,-7,4,"); + add("52,-114,135,32,-91,106,9,-114,130,-161,-25,24,"); + add("-133,4,-10,-139,-10,5,-111,74,-90,-151,-18,12,"); + add("-136,-26,20,-161,-16,8,-72,-73,77,57,-63,75,"); + add("-53,-87,93,137,-50,67,137,-19,29,162,-32,46,"); + add("100,-45,55,119,-19,27,91,-75,85,133,-37,45,"); + add("-30,-117,125,67,-94,103,85,-65,71,146,-61,67,"); + add("44,-104,109,-9,-94,97,103,-89,93,52,-99,101,"); + add("23,-57,57,-115,142,-145,-71,-3,2,-22,-109,110,"); + add("-19,-107,106,14,-78,78,-40,-136,133,-28,-107,103,"); + add("-32,-106,101,-74,-99,92,-138,-42,35,-146,0,-5,"); + add("-143,33,-37,-142,-16,8,-151,34,-42,-139,-3,-6,"); + add("-172,-22,9,-145,9,-21,-145,24,-35,-138,23,-34,"); + add("-148,23,-37,-159,-13,-4,-147,-4,-14,-148,-5,-12,"); + add("-141,50,-67,-128,15,-31,-139,-42,21,-62,-79,67,"); + add("-211,-45,10,-123,-56,35,-32,-88,78,77,-89,95,"); + add("53,-76,79,-2,-93,86,-45,-126,108,-2,-102,92,"); + add("2,-115,103,22,-108,99,-27,-115,98,-8,-54,45,"); + add("-83,-186,148,-46,-98,76,-66,-108,81,-83,-102,72,"); + add("-64,-84,59,-44,-119,91,19,-93,79,126,53,-22,"); + add("61,39,-23,-122,-131,87,47,-63,58,109,-10,26,"); + add("-38,-152,115,-1,-121,95,-19,-114,86,-49,-117,83,"); + add("18,-67,55,169,15,14,153,-25,40,133,6,14,"); + add("142,54,-22,157,13,10,84,-19,25,121,-86,80,"); + add("70,-67,58,30,-135,104,79,-114,93,127,-64,60,"); + add("128,33,-12,92,101,-65,140,50,-25,138,39,-17,"); + add("123,56,-33,151,11,3,151,-8,16,148,11,0,"); + add("152,-13,18,134,36,-21,159,-4,9,106,95,-67,"); + add("69,112,-83,114,78,-56,141,35,-24,133,37,-26,"); + add("39,115,-89,58,119,-92,90,88,-69,131,65,-52,"); + add("61,86,-69,-122,102,-82,-43,111,-91,13,111,-91,"); + add("73,102,-84,87,93,-79,93,91,-77,81,100,-86,"); + add("77,60,-52,88,121,-106,134,42,-40,147,33,-32,"); + add("144,32,-34,110,76,-70,132,56,-56,124,59,-59,"); + add("73,90,-85,0,111,-100,-56,113,-101,-23,112,-102,"); + add("34,91,-87,120,73,-76,120,69,-72,103,22,-29,"); + add("168,-48,33,114,8,-17,115,-6,-4,128,-73,57,"); + add("153,-46,29,141,-6,-10,144,54,-67,82,80,-86,"); + add("112,69,-80,121,50,-63,145,31,-49,99,69,-81,"); + add("80,84,-95,121,57,-75,149,-25,2,134,-51,28,"); + add("136,-50,26,130,-60,35,52,-105,93,70,-99,83,"); + add("55,-106,91,69,-75,59,122,-75,47,102,-99,73,"); + add("141,-44,13,116,-90,59,127,-69,37,105,-88,57,"); + add("126,-83,47,135,-58,22,123,-28,-3,147,-15,-22,"); + add("126,-70,33,105,-88,52,132,-70,28,155,-24,-19,"); + add("74,-117,83,113,-80,41,135,-26,-15,107,-79,39,"); + add("69,-110,75,82,-106,67,60,-114,80,26,-104,80,"); + add("-78,-77,86,-23,-114,101,-26,-99,88,115,-56,13,"); + add("83,65,-77,68,93,-96,53,91,-91,-1,112,-93,"); + add("128,48,-79,49,65,-70,-51,122,-89,-128,78,-28,"); + add("-125,71,-24,8,117,-104,39,103,-103,86,76,-94,"); + add("104,-33,-2,164,-45,-12,114,-71,26,89,-93,54,"); + add("97,12,-43,-10,118,-102,-113,94,-46,-123,78,-31,"); + add("-144,57,-5,-133,65,-17,-139,59,-10,-143,42,4,"); + add("-142,49,-3,-141,79,-31,14,125,-120,-172,27,24,"); + add("-145,1,39,-142,41,0,-124,69,-32,-127,77,-40,"); + add("-115,84,-50,-80,101,-77,-62,107,-87,-76,104,-82,"); + add("-102,74,-48,-137,65,-31,-133,63,-32,-126,69,-40,"); + add("-81,97,-79,-38,109,-101,34,91,-101,-89,117,-101,"); + add("60,86,-102,128,30,-60,109,51,-79,144,-3,-31,"); + add("37,-68,62,12,-104,106,70,-91,77,105,-36,12,"); + add("54,87,-104,82,59,-82,137,-74,40,56,-99,89,"); + add("72,-97,79,123,-77,46,1,-51,51,118,-122,90,"); + add("134,-72,34,107,-73,41,151,-4,-39,153,-49,1,"); + add("130,-72,32,136,-74,30,31,-32,22,-122,21,18,"); + add("213,-65,-5,139,-55,9,144,-73,23,103,-35,-1,"); + add("148,-91,37,112,-86,43,138,-77,24,-10,-96,95,"); + add("35,-112,91,22,-110,94,18,-133,116,33,-91,71,"); + add("140,-97,36,114,-81,32,83,-104,62,88,-88,45,"); + add("129,-94,34,135,-66,6,69,-40,8,-23,-79,78,"); + add("115,-110,50,89,-38,-3,126,-18,-34,159,17,-78,"); + add("142,-3,-56,130,-29,-28,119,-85,22,-228,24,75,"); + add("-138,50,14,-119,-8,55,-120,-49,88,-42,-110,108,"); + add("111,-102,42,122,-103,37,19,-127,96,120,-89,24,"); + add("113,33,-72,102,-109,47,63,-49,12,89,76,-98,"); + add("119,-92,24,37,13,-26,-57,117,-70,-80,121,-65,"); + add("-91,110,-52,25,58,-59,134,-63,-5,47,72,-80,"); + add("-121,89,-23,-21,73,-53,144,21,-80,128,-70,4,"); + add("87,-9,-31,-51,146,-103,-119,77,-13,-136,65,3,"); + add("-121,63,-2,-151,55,16,-61,42,-11,63,83,-100,"); + add("-9,85,-71,85,-38,-2,-133,153,-80,-101,103,-51,"); + add("-106,100,-46,-27,125,-104,68,49,-73,134,-93,29,"); + add("112,-92,36,75,-17,-16,-36,90,-68,134,-79,14,"); + add("41,11,-28,-67,96,-59,113,-7,-44,-169,116,-33,"); + add("11,66,-66,125,23,-78,96,39,-80,125,5,-63,"); + add("105,13,-62,149,-35,-38,149,-29,-43,116,-76,15,"); + add("140,11,-79,28,-41,24,-103,-68,116,35,-72,52,"); + add("96,112,-154,98,57,-105,75,70,-106,56,82,-109,"); + add("128,13,-81,127,12,-79,112,-18,-44,95,62,-113,"); + add("-145,71,8,-141,52,25,-122,78,-13,-72,105,-68,"); + add("-105,106,-53,-118,86,-27,-5,75,-75,43,77,-102,"); + add("-37,120,-108,39,89,-115,102,41,-100,-33,122,-114,"); + add("-32,111,-104,-30,100,-95,3,95,-108,22,84,-107,"); + add("160,5,-96,-13,108,-117,-43,104,-96,-38,95,-89,"); + add("72,25,-71,82,100,-168,27,90,-125,11,88,-114,"); + add("111,33,-107,76,31,-85,88,25,-87,-59,90,-76,"); + add("-21,26,-20,98,-112,81,108,-71,21,69,-16,-24,"); + add("-180,-4,118,-23,-14,31,114,-65,10,158,-67,-16,"); + add("132,-5,-78,125,10,-94,134,-33,-47,47,-66,51,"); + add("-99,-45,120,-80,-55,119,-12,-79,103,182,-57,-48,"); + add("134,-44,-36,78,-102,70,37,-104,100,148,-59,-29,"); + add("89,44,-113,40,79,-121,101,33,-110,79,41,-105,"); + add("65,56,-115,144,-23,-75,92,32,-108,-42,108,-105,"); + add("-159,7,107,-90,-33,108,-132,55,25,-118,90,-29,"); + add("-103,98,-51,-28,90,-95,70,20,-75,80,89,-172,"); + add("92,41,-119,84,19,-87,107,13,-98,85,61,-144,"); + add("62,52,-118,125,7,-107,86,30,-108,72,14,-78,"); + add("154,-9,-111,-4,-62,89,-80,-44,124,-41,-57,111,"); + add("-114,-27,126,-13,-39,63,115,-63,-7,145,-69,-22,"); + add("8,-33,38,-49,-42,94,-32,-19,49,-4,-135,179,"); + add("30,-76,74,-119,-11,106,-110,8,72,26,-75,74,"); + add("162,-54,-53,120,-86,15,134,-31,-63,127,-64,-19,"); + add("133,-52,-41,132,-45,-49,131,-71,-18,131,-76,-11,"); + add("128,-82,-5,130,-75,-16,137,-72,-27,125,-50,-44,"); + add("131,-43,-60,125,-75,-16,123,-73,-18,94,-109,49,"); + add("99,-108,43,72,-113,72,-6,-94,117,-37,-74,120,"); + add("-73,-52,124,-70,-54,122,-89,-43,125,-122,14,87,"); + add("-132,33,71,-112,-8,101,-98,-33,116,-106,-14,99,"); + add("-136,29,75,-115,31,55,-132,22,76,-126,63,27,"); + add("-119,4,84,-114,25,57,-133,114,-27,-108,-4,81,"); + add("-131,31,60,-111,101,-33,-88,5,57,-112,-20,99,"); + add("-128,7,80,-130,7,80,-127,2,81,-101,-39,109,"); + add("-106,-35,104,-82,-52,107,-80,-62,115,-85,-56,112,"); + add("-46,-79,108,-112,-35,103,-136,22,59,-130,13,63,"); + add("-131,-5,82,-136,18,59,-107,-21,81,65,-99,62,"); + add("120,-47,-21,86,-22,-27,-177,-28,128,-37,-77,95,"); + add("-126,-30,99,-132,3,68,-125,14,53,-140,-26,99,"); + add("-120,26,36,-121,-25,86,-74,-77,110,-52,-90,110,"); + add("18,-115,97,63,-74,37,134,27,-91,87,-35,-12,"); + add("-6,-95,91,120,-127,55,1,-112,100,34,-86,60,"); + add("-158,38,45,42,-116,82,178,-55,-41,144,-64,-17,"); + add("24,-119,91,90,-110,49,95,-87,25,-4,-78,69,"); + add("140,2,-75,128,11,-77,27,-34,14,-66,-60,87,"); + add("-90,-34,75,184,-9,-90,135,38,-104,151,-52,-39,"); + add("91,-55,-3,109,-105,27,139,-47,-38,111,10,-72,"); + add("124,27,-95,56,55,-80,-20,119,-91,42,74,-89,"); + add("136,-10,-73,133,-37,-48,139,-57,-36,133,-59,-31,"); + add("117,-98,11,130,-69,-22,125,1,-82,110,25,-93,"); + add("116,15,-90,91,52,-107,48,96,-119,61,81,-114,"); + add("103,26,-94,133,-55,-43,129,-24,-70,42,57,-82,"); + add("118,50,-132,58,-114,63,-48,-95,121,81,-123,53,"); + add("13,-114,92,40,-113,72,91,-122,41,36,-120,78,"); + add("75,-122,50,-4,-99,87,-24,-99,101,12,-122,93,"); + add("-4,-114,97,-9,-114,98,1,-113,91,2,-125,97,"); + add("1,-114,89,20,-125,83,9,-123,88,-6,-117,93,"); + add("-27,-109,100,-52,-94,105,-86,-64,105,-114,-26,95,"); + add("-130,-8,92,-97,-4,66,-89,-7,62,-155,22,83,"); + add("50,-167,88,34,-111,55,"); + add(""); + //add("/*1*/"); + add("2737,1,-14284,23878,-11217,"); + add("-82,-105,-117,-15,25,72,-60,-31,10,-79,-19,62,"); + add("9,110,225,-46,-61,-72,-154,-85,22,40,7,-38,"); + add("54,-36,-148,1,-47,-99,-122,-119,-90,-97,31,190,"); + add("25,-21,-77,-3,-73,-146,-91,-31,55,11,-36,-89,"); + add("-159,-97,12,-70,-4,82,-94,2,131,-118,-56,45,"); + add("-43,51,167,-40,-46,-43,34,-54,-159,-75,-37,27,"); + add("-59,19,122,-93,-16,98,60,99,126,-21,-11,5,"); + add("-93,-116,-113,-75,5,120,-18,-24,-28,-75,-101,-104,"); + add("-108,-75,1,-89,-3,123,55,85,101,-32,-19,6,"); + add("-123,-105,-42,-7,-27,-46,-43,-47,-35,-81,17,159,"); + add("-116,-60,49,-40,-57,-60,-105,-66,22,-127,-79,29,"); + add("-105,-95,-35,-124,-106,-28,-98,-74,1,-88,-112,-92,"); + add("-92,-106,-71,18,-79,-186,29,58,71,40,78,93,"); + add("80,93,65,18,-7,-42,-45,-114,-161,40,41,20,"); + add("30,80,115,96,95,47,95,26,-94,91,7,-122,"); + add("101,19,-114,137,43,-116,-52,-83,-87,-118,-92,-9,"); + add("-117,-93,-10,-108,-96,-29,-143,-117,-12,-135,-130,-48,"); + add("-50,-79,-75,-157,-56,130,47,-16,-100,-29,-66,-80,"); + add("-93,-105,-58,-83,-98,-54,-84,-112,-77,-75,-105,-78,"); + add("-91,-115,-68,-70,-99,-70,-81,-109,-68,-79,-107,-67,"); + add("-72,-119,-97,-41,-94,-95,-65,-112,-90,-101,-106,-26,"); + add("-87,-112,-55,-110,-104,-6,-98,-108,-29,-104,-110,-19,"); + add("-75,-117,-75,-84,-126,-70,-25,-76,-80,-75,-126,-82,"); + add("-115,-95,27,-115,-90,35,-103,-111,-12,-80,-119,-56,"); + add("-97,-117,-25,-103,-98,10,-115,-91,43,-161,-129,59,"); + add("-58,-77,-21,-114,-71,74,-7,56,92,-67,27,148,"); + add("-90,-7,134,1,-10,-18,84,0,-134,22,-52,-112,"); + add("-131,-135,12,72,27,-74,-56,-101,-58,-97,-115,-11,"); + add("-110,-72,74,-100,-74,55,-42,-104,-80,-100,-122,-9,"); + add("-113,-93,54,-106,-102,31,-103,-87,50,-115,-98,55,"); + add("-100,-98,32,-86,-121,-19,-91,-125,-18,-92,-40,104,"); + add("-84,-16,124,-85,-18,123,-114,-81,90,-91,-59,81,"); + add("-80,-14,125,-100,-90,58,-75,-40,83,-109,-75,98,"); + add("-100,-79,80,-101,-100,50,-88,-122,-1,-77,-103,4,"); + add("-104,-135,15,-99,-113,37,-104,-118,43,-74,-117,-13,"); + add("-98,-106,51,-92,-124,16,-93,-102,52,-101,-150,3,"); + add("-74,-80,45,-85,-138,-7,-88,-117,27,-92,-81,86,"); + add("-90,-67,101,-91,-76,95,-94,-102,67,-88,-91,72,"); + add("-88,-94,70,-71,-130,-14,-61,-137,-44,-62,-124,-21,"); + add("22,-4,-54,54,10,-108,83,17,-158,-35,-68,-8,"); + add("-90,-85,87,-88,-108,61,-83,-64,101,-84,-69,103,"); + add("-95,-84,110,-62,13,159,-81,-98,64,-88,-89,95,"); + add("-79,-62,109,-79,-94,70,-115,-182,49,-40,-70,8,"); + add("-56,-132,-30,-56,-147,-45,-58,-85,38,-92,-109,97,"); + add("-89,-97,105,-69,-68,91,-77,-78,102,-78,-94,87,"); + add("-77,-89,95,-74,-86,91,-73,-123,44,-75,-139,31,"); + add("-41,7,123,-3,91,124,38,129,60,75,109,-70,"); + add("75,120,-54,66,92,-61,83,66,-140,48,13,-114,"); + add("74,106,-59,56,136,28,68,124,-18,78,115,-53,"); + add("78,123,-40,83,113,-65,70,128,-8,74,133,-10,"); + add("74,120,-22,75,71,-94,55,56,-62,78,120,-30,"); + add("84,100,-69,88,119,-51,85,86,-87,76,126,-10,"); + add("83,133,-13,79,83,-72,96,128,-46,82,80,-79,"); + add("92,121,-43,91,103,-61,91,88,-82,90,83,-87,"); + add("94,102,-64,81,122,-5,74,130,21,83,131,7,"); + add("86,113,-25,72,131,35,103,170,26,-42,-12,72,"); + add("-90,-65,101,-91,-42,139,-45,4,109,-93,-93,68,"); + add("-88,-49,130,-71,-79,43,-66,-126,-37,-88,-117,29,"); + add("-87,-114,34,-86,-133,7,-87,-114,37,-89,-115,45,"); + add("-78,-97,45,-90,-131,29,-89,-101,72,-91,-113,60,"); + add("-85,-83,93,-88,-111,61,-89,-78,117,-60,-23,123,"); + add("-62,-104,9,-85,-141,17,-80,-87,88,-82,-66,126,"); + add("-85,-125,47,-58,-24,127,-98,-125,90,-43,-84,-3,"); + add("-31,-134,-109,-78,-137,23,-52,0,150,-18,-42,-12,"); + add("-34,-42,39,-63,-65,90,-117,-117,174,-58,-89,46,"); + add("-45,-70,33,-105,-136,122,-37,-55,33,-72,-83,102,"); + add("-71,-86,103,-73,-100,85,-72,-113,67,-73,-107,82,"); + add("-68,-107,68,-78,-110,101,-63,-90,83,-67,-112,64,"); + add("-64,-137,21,-59,-136,6,-69,-126,60,-67,-105,87,"); + add("-57,-153,-18,-21,-129,-108,-53,-103,46,-5,-91,-114,"); + add("-25,-98,-42,-62,-133,40,-65,-120,71,-63,-107,87,"); + add("-66,-113,89,-52,-66,109,-55,-54,138,-55,-69,119,"); + add("-56,-76,116,-58,-103,90,-59,-114,86,-51,-59,131,"); + add("-48,-48,134,-45,-43,137,-43,-37,139,-32,-3,142,"); + add("-47,-65,124,-54,-103,99,-49,-79,115,-50,-83,118,"); + add("-44,-63,129,-41,-47,137,-41,-53,136,-44,-59,143,"); + add("-42,-72,116,-33,-27,146,-32,-30,145,-35,-40,142,"); + add("-45,-93,116,-43,-58,172,-33,-60,113,-35,-67,116,"); + add("-25,-17,150,-27,-27,146,-35,-66,134,-29,-40,149,"); + add("-14,9,148,0,52,139,1,54,142,0,51,145,"); + add("11,80,128,5,56,134,-7,7,104,-26,-55,123,"); + add("-30,-59,172,25,62,-90,-7,-4,85,-32,-82,117,"); + add("-35,-95,120,-33,-91,116,-33,-94,112,-43,-128,158,"); + add("-22,-72,54,-33,-106,101,-32,-104,104,-30,-96,111,"); + add("-27,-92,117,-24,-81,124,-20,-65,134,-12,-33,146,"); + add("-1,3,152,-6,-14,149,-13,-53,140,-16,-63,136,"); + add("-17,-71,124,-4,-20,157,-8,-44,143,-16,-86,237,"); + add("2,3,72,-4,-32,105,5,-2,175,27,99,105,"); + add("3,-12,139,-35,-165,74,-8,-14,-108,-21,-95,14,"); + add("-16,-90,97,-16,-92,106,-13,-92,128,-18,-108,97,"); + add("-21,-122,85,-15,-103,109,-11,-92,117,-12,-98,114,"); + add("-25,-149,52,-21,-128,50,-23,-111,-36,-27,-130,-35,"); + add("-19,-140,74,-1,-63,128,-5,-97,143,22,71,115,"); + add("17,158,-124,7,2,79,-3,-81,127,-16,-132,72,"); + add("-7,-90,90,6,-49,148,2,-72,134,-2,-92,118,"); + add("-17,-140,51,-24,-136,-28,4,-85,148,17,108,-1,"); + add("10,-4,92,-12,-118,54,-7,-129,92,8,23,39,"); + add("24,62,114,18,5,136,11,-45,124,18,-43,173,"); + add("-3,-104,84,-4,-117,78,30,28,174,-1,-120,95,"); + add("-10,-143,56,23,-13,155,31,74,126,32,74,128,"); + add("6,141,-78,-2,111,-104,18,127,0,33,54,142,"); + add("39,100,135,29,124,58,32,80,105,47,60,198,"); + add("4,-59,69,13,-90,141,5,-141,131,23,-19,127,"); + add("16,-116,158,-24,23,-131,-39,-129,-98,-13,-148,42,"); + add("0,-121,77,6,-115,99,11,-107,115,-4,-121,54,"); + add("10,-111,107,-14,-160,19,-15,-129,-3,2,-130,72,"); + add("-31,-136,-76,-5,-116,28,-12,-155,12,-7,-162,32,"); + add("-14,-141,-11,-15,-186,-2,11,-98,78,-2,-105,25,"); + add("-26,-135,-79,-24,-112,-78,-30,-150,-95,-16,-111,-47,"); + add("-23,-93,-86,-30,-35,-138,-33,-39,-151,-22,-114,-85,"); + add("-4,-170,15,-36,-101,-166,6,-160,53,-17,-111,-74,"); + add("-27,-53,-138,-33,-65,-171,-21,-26,-112,-24,-93,-125,"); + add("1,-170,15,-4,-145,-17,-14,-124,-84,-18,-110,-108,"); + add("4,-151,15,-15,-138,-98,-21,-80,-137,8,-155,32,"); + add("2,-150,-16,10,-154,35,-6,-140,-71,7,-91,21,"); + add("24,-76,129,28,-94,141,22,97,153,13,20,77,"); + add("-5,164,11,3,-13,11,10,-156,22,6,-135,2,"); + add("-1,-144,-50,-6,-131,-75,-20,-69,-134,-14,-89,-119,"); + add("-15,-91,-122,-8,-112,-98,-8,-113,-101,-4,-122,-85,"); + add("10,-152,-16,26,-152,82,12,-139,-4,26,-119,99,"); + add("20,-144,37,-9,-86,-115,19,-129,32,29,-83,126,"); + add("30,-70,132,30,-70,131,31,-83,122,30,-119,87,"); + add("30,-120,86,29,-138,56,30,-135,62,32,-123,80,"); + add("35,-102,104,32,-130,70,34,-129,73,31,-145,41,"); + add("33,-133,55,35,-126,67,35,-143,52,34,-138,43,"); + add("34,-136,49,39,-127,69,40,-127,74,39,-131,62,"); + add("35,-144,26,46,-102,113,43,-120,78,39,-154,26,"); + add("42,-114,73,47,-116,90,44,-128,64,45,-127,64,"); + add("46,-124,66,47,-125,70,32,-162,-34,15,-96,-38,"); + add("48,-136,50,50,-120,77,51,-121,72,52,-85,116,"); + add("53,-104,93,55,-111,91,50,-94,90,54,-68,124,"); + add("54,-71,122,54,-71,118,54,-75,114,59,-82,116,"); + add("53,-47,133,55,-66,118,60,-66,129,57,-55,126,"); + add("58,-60,126,62,-96,97,62,-79,113,62,-62,126,"); + add("61,-93,91,56,-133,35,68,-87,114,65,-89,101,"); + add("68,-87,104,68,-103,91,47,-147,-14,53,-143,3,"); + add("53,-141,2,58,-139,15,55,-139,6,49,-143,-17,"); + add("42,-138,-35,50,-147,-23,58,-138,5,61,-139,10,"); + add("44,-134,-32,44,-140,-45,43,-137,-41,49,-141,-37,"); + add("47,-137,-36,36,-137,-72,4,-78,-87,62,-138,-4,"); + add("62,-111,29,43,-131,-51,56,-141,-31,53,-137,-36,"); + add("62,-135,-10,70,-132,13,55,-134,-36,24,-110,-90,"); + add("60,-137,-28,66,-138,-14,54,-127,-37,51,-134,-57,"); + add("52,-134,-60,44,-117,-56,66,-137,-28,34,-115,-84,"); + add("57,-129,-48,59,-132,-46,44,-120,-73,40,-123,-92,"); + add("76,-129,1,84,-125,28,71,-130,-20,57,-123,-54,"); + add("26,-100,-104,50,-118,-71,75,-131,-20,78,-129,-10,"); + add("82,-129,-3,84,-130,0,76,-123,-14,81,-130,-13,"); + add("78,-119,-7,63,-121,-55,51,-118,-89,76,-125,-31,"); + add("81,-125,-19,43,-108,-100,57,-117,-78,74,-121,-44,"); + add("72,-124,-53,64,-118,-69,46,-103,-94,51,-109,-97,"); + add("72,-117,-50,55,-110,-92,78,-122,-50,65,-122,-96,"); + add("42,-82,-70,87,-130,-52,-11,-41,-145,71,-110,-56,"); + add("88,-116,-17,100,-112,30,85,-119,-42,110,-137,-12,"); + add("83,-92,18,105,-118,19,87,-110,-27,73,-111,-74,"); + add("42,-78,-86,70,-110,-90,89,-116,-50,78,-111,-71,"); + add("81,-108,-55,107,-116,5,98,-91,49,47,-47,10,"); + add("69,-38,112,-33,70,110,20,15,109,40,7,146,"); + add("39,-52,-29,21,-74,-152,88,-69,71,102,-105,9,"); + add("-32,12,-66,53,-66,-33,28,-44,-43,94,-112,-47,"); + add("75,-89,-41,70,-106,-108,126,-123,13,50,-68,-58,"); + add("89,-110,-76,128,-91,118,48,-36,35,74,-96,-84,"); + add("22,-62,-139,38,-66,-102,120,-94,70,-19,-6,-83,"); + add("92,-105,-67,61,-77,-71,103,-112,-62,-4,21,62,"); + add("25,-27,-11,74,-103,-134,-90,77,-19,-51,13,-130,"); + add("-21,37,64,-80,80,25,-44,10,-122,44,-71,-113,"); + add("41,-65,-111,30,-57,-118,108,-124,-107,-26,30,28,"); + add("-11,46,149,33,-26,18,109,-71,111,32,2,123,"); + add("146,-121,40,31,-60,-127,123,-103,21,-19,-7,-94,"); + add("48,-45,-14,52,-14,131,-16,48,132,35,-25,24,"); + add("100,-72,57,2,-6,-18,65,-58,-7,-43,11,-101,"); + add("-43,2,-143,-44,18,-81,26,-28,-22,126,-84,98,"); + add("86,-86,-53,59,-67,-71,102,-98,-55,133,-113,-8,"); + add("-71,88,125,73,-62,-12,133,-103,28,-27,12,-39,"); + add("13,-32,-97,94,-71,26,76,-69,-33,-28,-4,-118,"); + add("59,-52,-18,106,-64,89,107,-88,-18,-26,53,148,"); + add("61,-54,-29,50,-69,-132,110,-78,34,122,-91,11,"); + add("92,-73,-12,130,-91,31,-52,53,65,66,-47,7,"); + add("-52,53,66,23,7,102,-112,74,-45,38,-13,69,"); + add("134,-90,44,89,-78,-45,112,-96,-59,-31,26,10,"); + add("-113,88,22,12,-22,-60,2,-18,-69,-59,11,-148,"); + add("42,-39,-34,135,-106,-30,21,12,126,27,-17,10,"); + add("85,-83,-96,93,-63,20,-42,51,94,-94,85,72,"); + add("7,23,125,76,-8,204,2,-26,-102,5,-42,-169,"); + add("9,-32,-114,115,-92,-38,123,-74,55,-78,77,97,"); + add("-23,34,76,-7,36,136,-20,50,149,82,-53,22,"); + add("44,-63,-128,86,-89,-121,-26,22,12,-49,18,-70,"); + add("6,-27,-100,132,-79,61,88,-39,99,69,-15,139,"); + add("-71,73,99,-116,90,37,-104,92,74,-99,90,83,"); + add("5,32,137,1,38,148,-20,47,123,-14,45,125,"); + add("95,-22,171,-112,84,9,-125,85,-23,-110,50,-111,"); + add("-1,15,51,-48,55,71,-148,108,-12,-55,45,13,"); + add("-91,92,75,-78,87,93,-27,69,159,-102,65,-46,"); + add("-35,39,38,6,7,38,119,-74,59,7,39,145,"); + add("-78,89,88,-121,116,62,-72,75,55,-57,83,110,"); + add("-42,75,123,-14,59,137,-12,60,141,-26,71,141,"); + add("-86,88,46,-35,49,54,-61,88,101,-106,102,32,"); + add("-94,46,-87,-71,11,-132,-100,51,-95,-112,74,-64,"); + add("-114,76,-62,-113,99,-4,-86,99,63,-59,91,102,"); + add("-56,92,108,-33,77,122,13,41,135,13,50,154,"); + add("64,-2,138,-71,86,50,-44,95,131,-71,99,77,"); + add("-89,105,50,-103,109,26,-50,96,109,-34,84,116,"); + add("19,58,165,-54,43,-20,-122,78,-88,-13,80,145,"); + add("91,-47,90,102,-80,41,33,37,145,-76,109,74,"); + add("-106,110,11,-67,-7,-152,51,-78,-57,-81,27,-112,"); + add("-102,62,-85,-106,89,-36,-85,112,55,-97,108,19,"); + add("-104,112,10,-72,119,88,32,6,83,99,-47,112,"); + add("96,-45,110,98,-50,100,70,-3,136,57,13,137,"); + add("25,48,139,-10,97,164,-71,84,20,-106,119,17,"); + add("-69,116,77,-22,75,93,-107,151,65,-80,71,-28,"); + add("-100,134,43,73,-19,108,89,-23,125,71,2,135,"); + add("67,8,133,61,18,139,59,21,137,60,21,139,"); + add("54,30,138,56,27,137,46,40,139,49,38,138,"); + add("37,51,136,27,61,134,-22,95,103,-38,107,95,"); + add("-5,91,122,-23,103,109,-22,103,110,-48,112,79,"); + add("-99,139,38,-86,39,-79,-116,84,-65,-94,116,7,"); + add("-35,112,95,-55,108,58,-109,97,-44,-109,73,-75,"); + add("-105,60,-90,-107,62,-89,-101,101,-33,-41,95,58,"); + add("-75,122,35,-89,122,11,-55,126,71,-28,108,90,"); + add("-10,89,92,-87,138,28,20,-14,15,86,-125,-14,"); + add("12,-97,-99,32,-109,-85,58,-122,-60,84,-122,-19,"); + add("107,-98,46,108,-95,52,83,-34,87,77,5,127,"); + add("98,-51,88,106,-66,79,105,-49,97,89,-24,103,"); + add("62,42,144,98,-20,117,104,-36,107,68,23,123,"); + add("43,86,165,42,31,94,18,89,130,-10,106,107,"); + add("-20,110,97,4,95,113,20,86,122,19,88,121,"); + add("-6,105,106,-26,118,91,-35,122,83,-14,135,121,"); + add("-51,89,26,-45,147,90,-17,105,83,32,78,118,"); + add("16,95,113,-14,129,106,-26,123,83,-61,122,38,"); + add("42,-16,37,134,-47,122,53,-93,-21,27,-119,-79,"); + add("-15,-103,-116,-2,-92,-91,6,-109,-100,-23,-73,-99,"); + add("-55,-129,-200,39,25,75,46,69,127,31,84,122,"); + add("22,92,117,14,99,113,2,108,105,-1,111,102,"); + add("-7,115,97,-24,123,84,-19,123,88,-8,117,95,"); + add("5,111,102,13,106,107,27,95,113,43,82,118,"); + add("21,114,119,4,99,85,-34,135,71,-55,131,42,"); + add("-48,132,50,-33,119,55,-80,153,26,-57,132,36,"); + add("-77,147,23,-26,152,83,18,104,96,-83,84,-33,"); + add("22,52,63,66,23,90,55,87,123,-8,77,44,"); + add("53,100,128,67,63,116,61,84,123,32,97,99,"); + add("66,73,118,83,76,136,58,56,97,94,28,114,"); + add("101,10,109,51,99,114,61,66,101,101,33,121,"); + add("-18,61,19,12,97,70,85,9,89,142,-3,135,"); + add("92,-23,75,109,26,118,4,103,64,53,-40,26,"); + add("106,-50,70,106,13,105,135,-4,121,36,89,83,"); + add("-19,132,57,57,96,104,91,54,110,89,56,108,"); + add("8,109,65,-51,142,30,-6,136,66,15,129,79,"); + add("45,101,90,54,101,97,10,143,78,26,122,80,"); + add("19,122,75,61,99,96,11,134,71,-41,143,31,"); + add("-38,144,32,-18,141,47,7,137,65,45,118,87,"); + add("69,99,99,-24,139,36,-31,146,34,-4,140,52,"); + add("-7,144,50,2,141,56,7,139,57,-12,143,43,"); + add("-50,145,12,-40,145,19,-35,154,24,-35,137,19,"); + add("-3,147,46,-21,153,33,-42,129,7,-23,129,22,"); + add("28,139,65,8,208,68,46,83,61,97,-111,45,"); + add("87,20,76,63,112,81,48,122,72,52,121,74,"); + add("41,130,66,39,174,76,18,127,46,55,111,70,"); + add("62,93,70,67,111,76,94,80,89,88,82,83,"); + add("59,118,70,70,109,75,44,143,63,93,85,84,"); + add("68,113,72,59,123,66,38,135,53,31,139,47,"); + add("24,142,43,19,142,38,-15,166,17,8,111,24,"); + add("-25,186,11,-31,118,-3,-35,149,-4,-55,165,-16,"); + add("-29,123,-4,-40,145,-9,-46,144,-16,-72,130,-36,"); + add("-113,64,-74,-124,19,-87,-121,-17,-90,-123,1,-91,"); + add("-112,45,-78,-117,47,-84,-94,97,-60,-111,64,-79,"); + add("-94,98,-62,-98,95,-68,-86,113,-57,-90,120,-61,"); + add("-99,69,-73,-99,88,-72,-100,83,-74,-103,76,-80,"); + add("-113,73,-87,-98,73,-77,-108,42,-88,-118,12,-99,"); + add("-115,-23,-100,-115,-17,-100,-105,-27,-95,-117,27,-101,"); + add("-118,59,-101,-105,-19,-97,-110,42,-96,-97,69,-86,"); + add("-102,62,-90,-110,46,-100,-99,-47,-97,-101,-35,-98,"); + add("-144,-109,-146,30,126,37,-70,5,-68,-40,-97,-44,"); + add("-29,-148,-39,-81,-122,-89,-4,36,-2,10,141,21,"); + add("23,149,32,47,139,54,-84,-1,-82,4,58,8,"); + add("38,136,43,-76,114,-69,-80,101,-76,-117,-33,-119,"); + add("-63,103,-60,-92,70,-92,-80,35,-80,-91,62,-93,"); + add("-80,22,-83,-107,62,-112,-91,64,-95,-96,57,-102,"); + add("-92,3,-100,-109,-4,-119,-103,-28,-114,-58,-151,-69,"); + add("-40,-110,-48,-31,-140,-40,-71,-3,-80,-78,-95,-94,"); + add("-74,-89,-88,-61,-107,-77,-35,-140,-49,-49,-142,-67,"); + add("-8,45,-6,27,146,41,-11,182,-3,-108,-34,-129,"); + add("-85,58,-97,-100,-67,-124,-82,76,-95,-35,121,-38,"); + add("-39,139,-42,-18,138,-18,-35,60,-41,-75,-100,-96,"); + add("-72,-75,-92,-89,-73,-116,-81,-77,-106,-90,-15,-115,"); + add("-108,19,-141,15,41,22,86,61,114,90,27,116,"); + add("54,124,74,29,135,40,46,136,61,54,108,70,"); + add("44,138,56,79,87,98,81,81,99,66,113,79,"); + add("54,127,64,66,111,77,74,98,87,38,125,41,"); + add("-10,148,-18,-71,91,-89,-95,37,-116,-79,135,-104,"); + add("-8,130,-18,-29,131,-44,-26,148,-43,-27,146,-45,"); + add("-8,150,-25,-12,170,-31,-13,127,-30,-76,142,-112,"); + add("-17,-116,-7,-29,21,-40,-33,100,-52,-62,104,-92,"); + add("-42,110,-68,-74,78,-106,-59,106,-93,-64,99,-98,"); + add("-62,101,-98,-85,40,-118,-83,41,-120,-78,70,-117,"); + add("-92,-113,-107,13,75,6,-27,103,-55,-85,32,-124,"); + add("-84,27,-123,-92,9,-133,5,-52,17,-12,-14,-15,"); + add("-72,37,-110,-84,23,-126,-93,-75,-123,-62,2,-93,"); + add("-78,42,-123,-79,22,-125,-86,9,-132,-73,-172,-81,"); + add("5,71,-6,11,147,-11,-52,116,-104,-49,62,-89,"); + add("-48,105,-98,-54,96,-109,-76,39,-129,-88,-164,-108,"); + add("4,91,-13,40,143,32,24,150,3,-30,139,-84,"); + add("-38,97,-87,-44,104,-101,-49,91,-107,-75,77,-148,"); + add("-49,45,-97,-46,96,-108,-70,41,-135,-72,-32,-118,"); + add("-78,7,-140,-62,-56,-95,-93,37,-181,48,34,77,"); + add("55,90,71,51,161,41,60,100,74,-5,115,-47,"); + add("-58,47,-122,-61,111,-152,-68,-37,-112,-75,67,-165,"); + add("-43,-6,-79,-24,130,-97,-84,-17,-155,39,43,60,"); + add("-32,126,-112,46,78,58,69,-5,135,113,64,189,"); + add("-45,17,-93,-69,17,-138,-69,-5,-131,-72,-8,-139,"); + add("-69,-22,-127,-73,-3,-146,-96,-25,-187,55,-46,133,"); + add("-45,-34,-77,-78,-48,-142,-59,-65,-96,-58,-56,-98,"); + add("-75,-29,-148,-55,34,-134,-65,54,-168,-32,40,-88,"); + add("-19,117,-96,-47,41,-126,-62,-2,-141,-61,-9,-138,"); + add("-62,-27,-135,-61,-16,-139,-63,-22,-142,-52,18,-139,"); + add("-9,126,-86,14,107,-19,-7,131,-88,-34,82,-132,"); + add("-45,40,-138,-47,25,-139,-55,1,-146,-5,123,-88,"); + add("16,145,-43,-25,62,-110,-54,-104,-83,-14,-134,43,"); + add("52,-49,173,-47,-52,-98,-47,-65,-90,-57,-52,-131,"); + add("-57,-30,-142,-56,-64,-123,-64,-68,-148,-41,-115,-55,"); + add("-17,-148,36,2,-128,81,6,-128,89,-7,-136,51,"); + add("-30,-157,-7,-49,-116,-86,-54,-49,-133,-19,85,-101,"); + add("-1,110,-64,-7,78,-63,12,153,-47,46,132,68,"); + add("50,119,81,43,124,58,16,167,-52,6,94,-42,"); + add("-2,123,-85,31,130,12,57,46,143,54,68,114,"); + add("55,123,81,5,134,-75,-47,48,-173,-55,-74,-113,"); + add("-45,-45,-111,-50,-139,-57,-54,-73,-119,-53,-57,-131,"); + add("-53,-86,-113,-53,-88,-111,-47,-29,-139,-41,9,-146,"); + add("-38,13,-143,-42,-130,-52,-56,-133,-106,16,67,9,"); + add("3,32,-10,-31,46,-148,-42,-55,-114,-50,-104,-112,"); + add("-52,-113,-113,-41,-143,-52,-19,-114,8,-35,-159,-27,"); + add("-32,-151,-22,-37,-31,-124,-40,-96,-98,-40,-127,-78,"); + add("-43,-93,-113,-49,-103,-139,-12,-141,39,-22,-159,8,"); + add("-9,38,-65,-2,110,-77,-9,111,-113,-9,99,-111,"); + add("-10,92,-110,-5,113,-106,-13,81,-127,-20,55,-141,"); + add("-23,35,-141,-27,26,-157,-18,35,-127,-27,18,-160,"); + add("-38,-89,-123,-29,-61,-106,-36,-68,-143,-31,-46,-140,"); + add("-33,-79,-124,-30,-56,-136,-25,-11,-150,-11,129,-209,"); + add("-18,-47,-75,-10,63,-142,9,100,-57,9,124,-89,"); + add("-3,84,-129,4,98,-107,6,103,-98,9,118,-105,"); + add("13,124,-83,18,133,-63,13,113,-80,23,146,-59,"); + add("32,130,58,29,134,2,28,135,-4,30,125,26,"); + add("40,177,11,-14,-74,22,3,-8,43,37,164,-3,"); + add("32,145,-17,33,147,-10,38,143,23,39,142,37,"); + add("40,122,78,37,136,18,31,148,-65,21,67,28,"); + add("27,99,5,10,99,-155,-12,15,-146,12,76,-78,"); + add("24,96,-28,9,95,-179,-9,-1,-93,5,66,-146,"); + add("-17,-17,-142,-16,-12,-151,0,38,-139,-11,-10,-126,"); + add("-32,-73,-156,-11,-9,-146,-12,-11,-150,-3,19,-151,"); + add("-2,20,-165,0,19,-147,-25,-71,-125,2,20,-131,"); + add("3,24,-133,15,62,-139,42,140,100,43,133,129,"); + add("22,72,40,43,138,34,42,140,-20,48,151,22,"); + add("43,136,8,46,136,47,44,137,-24,14,50,-76,"); + add("55,155,85,-22,-70,55,-42,-135,73,9,23,49,"); + add("49,140,37,50,141,46,56,160,19,50,140,9,"); + add("50,140,17,30,77,27,51,137,29,47,116,83,"); + add("43,100,105,50,121,77,51,128,19,46,126,-58,"); + add("6,36,-160,-18,-34,-104,4,27,-143,6,31,-179,"); + add("-9,-13,-122,-18,-37,-144,-21,-45,-141,-12,-24,-148,"); + add("-8,-18,-150,-12,-28,-147,-22,-58,-137,-43,-113,-113,"); + add("-43,-114,-41,-53,-142,-13,-54,-145,-2,-43,-119,-51,"); + add("-43,-124,-61,-48,-137,-39,-32,-98,-113,-33,-105,-164,"); + add("-36,-102,24,-32,-103,-95,4,-2,-173,25,67,-69,"); + add("17,31,-155,-13,-58,-173,-7,-37,-107,-6,-41,-144,"); + add("10,-12,-243,-9,-41,-66,0,-27,-131,-2,-39,-146,"); + add("19,28,-134,47,118,-94,34,68,-128,30,53,-132,"); + add("19,9,-162,25,42,-104,57,139,-86,47,106,-93,"); + add("51,128,-54,55,140,-41,52,117,-82,51,108,-91,"); + add("51,106,-95,54,119,-73,57,128,-55,58,131,-52,"); + add("54,117,-60,84,188,-60,-24,-44,43,-84,-179,93,"); + add("32,84,12,55,105,-97,59,126,-61,61,138,-22,"); + add("56,132,-7,48,130,53,66,154,3,74,176,20,"); + add("41,94,3,62,147,27,59,138,27,57,135,40,"); + add("57,134,44,52,127,63,48,122,78,57,131,52,"); + add("62,122,-17,71,128,-61,61,115,-30,76,142,-28,"); + add("57,119,33,60,92,-89,-4,9,63,26,73,95,"); + add("70,131,-8,14,37,42,38,92,91,22,60,88,"); + add("38,100,131,50,107,79,-22,-10,147,-7,13,127,"); + add("16,45,85,19,57,138,46,104,119,52,110,114,"); + add("67,114,-21,31,64,62,-45,-65,87,-29,-52,-1,"); + add("-7,-11,9,23,59,139,15,46,156,47,90,50,"); + add("-19,-29,49,-19,-14,167,-15,-11,148,-36,-51,137,"); + add("-26,-34,144,18,42,151,29,58,109,-35,-56,127,"); + add("-35,-54,123,-47,-82,59,-37,-64,38,-21,-34,138,"); + add("27,52,132,-19,-33,138,59,107,66,-4,-8,122,"); + add("-36,-65,121,-50,-92,117,29,48,103,48,89,-112,"); + add("37,67,-134,50,88,26,57,98,77,19,35,-58,"); + add("15,27,-100,7,12,-104,5,9,-168,62,107,47,"); + add("-17,-29,140,-24,-42,142,36,59,133,25,39,160,"); + add("-5,-14,129,3,-1,151,55,86,135,-59,-104,74,"); + add("-22,-40,38,36,51,147,31,44,116,9,8,77,"); + add("-4,-21,146,15,8,176,-28,-60,109,-19,-57,201,"); + add("-40,-78,59,-56,-108,86,9,-11,173,31,35,121,"); + add("51,67,131,43,55,117,-12,-48,149,-39,-90,112,"); + add("-49,-103,94,-46,-103,105,-29,-79,124,-42,-96,96,"); + add("-58,-113,33,-83,-148,-12,-71,-123,-31,-71,-133,-2,"); + add("14,12,58,12,1,91,-86,-149,-59,-47,-98,37,"); + add("-59,-132,72,-14,-61,125,-49,-123,104,-39,-86,28,"); + add("-61,-140,60,-42,-107,77,-15,-74,144,-44,-116,79,"); + add("-50,-129,75,-10,-53,94,38,26,158,44,67,73,"); + add("69,133,26,64,111,58,72,142,7,72,141,8,"); + add("66,132,-4,58,125,-42,43,109,-75,66,145,-60,"); + add("56,125,-64,53,121,-71,56,124,-68,66,135,-51,"); + add("7,0,40,-46,-102,64,-66,-128,24,-26,-56,23,"); + add("98,190,-32,58,122,-57,51,118,-89,52,114,-78,"); + add("59,122,-68,62,125,-62,65,124,-47,69,129,-43,"); + add("68,125,-44,92,158,-25,60,92,29,77,119,30,"); + add("76,112,42,73,99,67,83,110,86,72,114,-11,"); + add("4,-5,45,24,21,68,50,49,105,78,83,137,"); + add("58,59,108,70,79,99,81,101,73,81,102,63,"); + add("81,95,85,70,68,124,37,11,140,63,60,99,"); + add("81,100,56,91,97,107,61,68,56,48,25,134,"); + add("95,69,193,4,59,-161,23,9,69,72,89,35,"); + add("26,85,-155,10,9,15,30,-9,154,18,-25,150,"); + add("84,79,104,87,109,25,-33,-15,-88,14,31,-36,"); + add("5,41,-103,1,40,-121,5,23,-51,63,28,174,"); + add("40,11,129,42,54,3,60,94,-46,8,-2,39,"); + add("-75,-117,58,-81,-138,88,20,29,-8,66,113,-76,"); + add("75,118,-55,74,121,-75,-19,24,-155,29,76,-125,"); + add("18,79,-187,13,-4,70,-9,-71,196,65,112,-92,"); + add("13,-9,81,59,64,36,32,76,-114,75,146,-180,"); + add("-24,-52,77,-36,-88,143,67,69,48,43,90,-123,"); + add("14,63,-154,21,64,-133,118,139,20,-74,-92,5,"); + add("-31,-74,127,-15,-71,175,81,117,-57,56,69,1,"); + add("106,135,-25,68,85,-11,73,76,39,94,73,131,"); + add("-38,-49,13,-104,-106,-57,-91,-108,-7,-47,-74,60,"); + add("-60,-68,-20,-42,-81,99,-28,-56,70,-62,-95,57,"); + add("-86,-105,-8,-131,-160,-16,64,62,63,78,79,59,"); + add("100,112,37,100,108,51,97,105,43,72,99,-36,"); + add("74,120,-100,77,113,-67,76,113,-78,90,93,38,"); + add("55,46,61,-148,-151,-74,-47,-93,123,-30,-85,157,"); + add("99,85,98,85,80,61,153,155,70,40,40,20,"); + add("97,112,-3,58,86,-66,73,91,-27,159,166,33,"); + add("-81,-96,19,19,6,50,90,69,92,83,50,125,"); + add("70,38,117,60,12,154,52,11,133,60,12,147,"); + add("131,119,60,17,-21,107,62,13,146,43,-7,138,"); + add("91,70,72,40,42,-1,-92,-53,-116,55,100,-113,"); + add("57,110,-139,115,106,35,65,82,-46,115,115,8,"); + add("121,104,49,104,88,41,110,78,84,48,34,38,"); + add("28,8,55,75,30,116,92,65,64,121,108,21,"); + add("-3,-30,74,62,26,88,54,3,128,80,39,94,"); + add("85,37,110,109,74,71,80,94,-52,28,9,44,"); + add("40,-16,131,126,64,129,30,-8,88,93,38,113,"); + add("105,56,94,107,52,103,121,107,-2,-8,-35,69,"); + add("-4,-29,60,-178,-122,-86,32,-15,103,66,1,136,"); + add("72,-9,167,-38,-22,-26,-130,-69,-107,-7,37,-101,"); + add("-67,-14,-107,-103,-53,-97,-159,-94,-120,-65,-45,-35,"); + add("-104,-60,-89,-103,-95,-3,-96,-103,31,-41,-79,93,"); + add("-20,-77,136,82,32,106,95,49,95,108,74,63,"); + add("123,90,55,82,63,30,99,72,40,23,-25,104,"); + add("83,40,80,102,39,117,93,25,125,92,42,89,"); + add("112,46,113,93,39,89,123,44,134,22,57,-80,"); + add("36,85,-115,-20,43,-130,-30,11,-80,-105,-46,-100,"); + add("-28,22,-100,-64,26,-185,-34,27,-132,22,71,-121,"); + add("5,51,-111,-17,47,-147,80,110,-104,68,88,-76,"); + add("40,80,-117,134,108,12,123,104,-5,2,40,-99,"); + add("-108,-42,-127,5,41,-96,1,50,-135,-47,24,-171,"); + add("32,19,19,79,21,123,42,-12,125,33,-26,144,"); + add("110,50,102,112,65,68,120,67,74,82,95,-79,"); + add("61,82,-89,-11,45,-144,-43,18,-144,-67,-4,-134,"); + add("-74,-13,-131,-89,-30,-116,-99,-42,-108,-94,-38,-113,"); + add("-98,-44,-106,-98,-45,-106,-106,-58,-90,-103,-55,-93,"); + add("-115,-73,-74,-112,-73,-67,-116,-83,-49,-113,-78,-60,"); + add("-114,-82,-55,-109,-72,-76,-115,-56,-147,53,45,6,"); + add("104,65,88,121,91,47,108,69,75,117,83,57,"); + add("113,98,-9,16,57,-140,-26,43,-219,24,-2,74,"); + add("16,-31,148,12,-36,152,108,62,91,118,86,38,"); + add("114,76,55,131,77,94,84,41,79,92,39,110,"); + add("86,27,124,120,92,10,113,81,18,139,79,87,"); + add("77,33,78,70,13,120,81,13,143,58,-5,138,"); + add("69,4,136,63,-2,137,60,-6,137,64,-1,130,"); + add("75,7,127,56,-9,131,52,-32,181,44,-3,90,"); + add("99,20,130,74,5,119,76,7,118,108,46,75,"); + add("134,72,56,129,65,61,115,75,12,132,71,48,"); + add("99,24,105,124,40,102,81,4,118,91,21,92,"); + add("132,64,53,120,49,69,144,82,24,74,85,-86,"); + add("-14,53,-143,67,20,52,87,76,-48,80,68,-44,"); + add("97,75,-36,35,76,-132,-21,48,-149,-156,-38,-144,"); + add("95,70,-28,64,77,-97,-12,40,-122,-80,5,-142,"); + add("-12,-31,64,-30,-11,-21,-110,-27,-105,-127,-59,-55,"); + add("-107,-47,-55,-128,-45,-96,-125,-59,-58,19,24,-33,"); + add("54,97,-171,53,-13,131,118,50,66,101,22,112,"); + add("171,62,118,-98,-11,-134,70,22,59,106,27,102,"); + add("107,39,73,154,49,114,21,60,-124,-52,22,-141,"); + add("-43,27,-143,33,72,-146,-152,-58,-96,79,48,0,"); + add("14,40,-88,-94,-11,-134,100,83,-66,71,76,-100,"); + add("-11,39,-135,24,62,-148,29,65,-150,72,74,-101,"); + add("53,75,-145,-13,-19,41,59,2,103,160,82,31,"); + add("37,63,-137,26,63,-161,85,41,23,94,82,-98,"); + add("21,40,-98,-49,12,-135,53,25,16,92,54,-15,"); + add("-52,10,-138,17,20,-37,156,74,39,59,61,-107,"); + add("-28,16,-117,60,38,-23,63,57,-88,69,57,-77,"); + add("102,83,-118,8,24,-79,20,20,-37,74,49,-46,"); + add("-111,-42,-64,-130,-69,5,-146,-88,43,-99,-48,-22,"); + add("-96,-58,25,-49,-28,7,-95,-41,-49,-150,-98,59,"); + add("34,27,-29,17,41,-129,-147,-71,-48,-110,-42,-86,"); + add("-152,-73,-58,50,47,-75,79,60,-67,-57,-21,-49,"); + add("-132,-76,3,-160,-61,-146,61,26,47,109,43,88,"); + add("143,85,-13,94,70,-73,37,50,-133,-63,-7,-132,"); + add("-117,-40,-128,87,51,-3,81,32,66,111,70,-42,"); + add("100,74,-88,118,74,-45,15,33,-126,-36,14,-172,"); + add("9,0,27,45,-2,137,84,29,79,128,82,-65,"); + add("129,69,-4,125,66,-7,-63,-16,-85,20,36,-138,"); + add("-29,12,-144,-2,26,-156,89,63,-95,66,48,-86,"); + add("60,51,-121,40,35,-94,67,52,-111,57,50,-139,"); + add("-47,-6,-120,-118,-44,-117,1,20,-137,-44,-5,-136,"); + add("38,40,-163,14,25,-149,-28,2,-138,-115,-48,-100,"); + add("-134,-70,10,-122,-72,69,-90,-59,99,-141,-75,4,"); + add("-126,-64,-36,-75,-48,63,-110,-70,73,-136,-81,52,"); + add("-81,-55,72,-147,-81,-18,-117,-61,-47,-106,-58,-32,"); + add("-127,-65,-71,-116,-66,-23,-72,-51,68,-61,-54,134,"); + add("-54,-51,138,-72,-60,117,-96,-71,91,-106,-77,75,"); + add("-114,-80,62,-121,-83,40,-123,-83,30,-125,-83,17,"); + add("-126,-79,-24,-132,-77,-69,-106,-62,-54,-111,-61,-90,"); + add("-99,-53,-99,-91,-47,-109,-81,-39,-122,-100,-48,-164,"); + add("-81,-59,24,-107,-89,97,-75,-63,74,-113,-87,43,"); + add("-105,-79,29,-130,-103,48,-103,-85,61,-109,-89,55,"); + add("-102,-90,84,-111,-81,-25,-113,-76,-66,-171,-140,51,"); + add("34,42,-103,-4,11,-101,-114,-81,-55,-149,-133,97,"); + add("41,43,-63,60,64,-122,0,21,-147,-105,-68,-124,"); + add("22,18,1,111,76,92,111,92,-45,79,75,-102,"); + add("54,56,-120,40,49,-163,60,45,13,107,92,-91,"); + add("85,75,-103,103,81,-53,114,83,17,117,88,-23,"); + add("118,88,-25,97,77,-75,128,91,-1,128,88,17,"); + add("117,86,-53,10,22,-157,2,16,-180,1,7,-79,"); + add("-1,10,-152,-23,-6,-149,-67,-37,-156,60,41,10,"); + add("92,69,-93,64,49,-125,36,31,-144,43,35,-143,"); + add("34,29,-159,75,53,-86,104,71,-92,74,51,-124,"); + add("85,58,-119,40,28,-137,36,24,-147,65,42,-134,"); + add("50,31,-135,-11,-8,-147,-44,-31,-140,-40,-31,-200,"); + add("110,72,10,124,78,-12,123,77,-49,127,78,-27,"); + add("121,74,-43,146,88,-45,51,26,-131,-32,-25,-132,"); + add("-139,-87,-39,9,5,-11,128,80,28,67,38,-60,"); + add("112,63,-78,124,75,31,127,75,-3,138,80,10,"); + add("121,72,33,140,80,26,111,66,70,123,71,80,"); + add("121,68,47,114,65,51,111,62,99,85,47,51,"); + add("101,56,71,11,7,65,95,51,27,48,27,106,"); + add("63,33,-10,60,31,34,-13,-4,161,65,34,141,"); + add("106,55,41,105,52,-52,72,35,-130,37,15,-168,"); + add("83,39,-90,46,19,-161,79,36,-75,3,3,49,"); + add("-79,-35,130,-59,-26,161,-35,-15,131,-59,-27,128,"); + add("18,9,136,118,59,92,101,49,32,-31,-15,113,"); + add("-16,-9,126,50,23,132,103,48,78,127,60,65,"); + add("110,50,64,141,65,60,77,38,-96,-2,1,-144,"); + add("15,9,-154,78,37,-114,106,48,-94,68,30,-131,"); + add("19,8,-167,23,11,24,-25,-11,189,7,3,112,"); + add("-100,-45,171,-61,-29,68,-89,-42,116,12,2,157,"); + add("103,45,94,121,53,77,128,54,77,159,73,-115,"); + add("60,22,148,-61,-30,111,-42,-24,145,-3,-7,123,"); + add("39,15,46,131,61,-85,138,64,-138,-35,-19,110,"); + add("-59,-28,68,-116,-54,85,46,14,109,93,34,114,"); + add("115,45,65,101,37,94,152,62,24,119,52,-55,"); + add("96,45,-107,135,57,-57,109,48,-81,56,19,54,"); + add("66,19,122,134,54,-47,120,45,14,79,37,-138,"); + add("77,36,-149,41,13,45,50,19,-23,-6,5,-150,"); + add("45,22,-146,-22,-2,-170,-101,-37,-34,-127,-47,19,"); + add("-127,-52,103,-127,-48,-19,-89,-31,-100,-148,-58,-11,"); + add("-144,-57,-30,-122,-47,-64,-175,-71,-30,-117,-46,-126,"); + add("87,38,-89,112,48,-94,131,54,-56,153,61,26,"); + add("91,35,63,141,56,-31,116,46,-79,111,43,-130,"); + add("-81,-30,-107,-154,-60,-23,-162,-63,-72,76,30,-75,"); + add("143,55,4,196,75,-91,86,33,78,71,26,-98,"); + add("11,3,-102,54,18,-147,88,33,26,157,58,68,"); + add("116,41,-5,120,42,-55,125,42,-76,158,55,8,"); + add("128,42,-55,132,41,-112,70,22,-75,23,5,-78,"); + add("-125,-45,-117,-114,-39,-27,-76,-30,-127,-123,-43,-32,"); + add("-160,-53,55,-110,-42,-70,-136,-49,-22,-142,-49,71,"); + add("-89,-29,108,-55,-16,124,-71,-22,150,-83,-30,38,"); + add("-1,-1,-34,33,11,-33,-107,-42,-58,-131,-52,-69,"); + add("13,8,119,-132,-49,48,-96,-40,-84,-108,-46,-91,"); + add("-57,-27,-143,-83,-37,-88,-125,-51,2,-141,-57,24,"); + add("-144,-61,-14,-41,-22,-92,-95,-41,-26,114,46,-52,"); + add("38,22,135,113,45,-60,128,49,-80,118,50,32,"); + add("181,75,49,-20,-12,-96,69,26,-27,132,44,-152,"); + add("-31,-18,-122,-48,-23,-73,-149,-58,36,-19,0,130,"); + add("-129,-50,41,33,6,-131,146,54,-83,-67,-29,-38,"); + add("-30,-20,-127,59,15,-137,23,-3,-164,-13,-16,-141,"); + add("43,5,-140,94,26,-126,115,37,-94,38,-1,-166,"); + add("125,41,-72,115,37,-70,142,54,6,102,28,-92,"); + add("-15,-22,-149,-12,-22,-150,-12,-22,-146,-138,-61,-71,"); + add("-43,0,128,6,19,144,20,29,187,-75,-34,-47,"); + add("-42,-28,-104,-9,-26,-190,-108,-52,-82,-154,-60,4,"); + add("-152,-59,7,-108,-50,-50,-174,-79,-54,68,23,-40,"); + add("184,68,-58,50,31,85,182,65,-57,38,5,-74,"); + add("139,47,-49,119,35,-77,39,0,-111,-4,-24,-154,"); + add("32,-10,-145,36,-10,-149,68,5,-132,84,9,-131,"); + add("127,25,-132,114,57,88,-14,17,135,47,32,91,"); + add("142,47,-23,132,37,-62,108,14,-139,21,-11,-110,"); + add("87,11,-105,116,20,-113,132,32,-67,113,19,-100,"); + add("112,18,-99,140,36,-44,131,29,-67,98,8,-115,"); + add("38,-12,-122,-82,-53,-131,62,-7,-132,142,57,68,"); + add("135,54,59,40,1,-51,-82,-50,-118,-89,-53,-125,"); + add("79,1,-103,147,43,-6,135,49,40,141,48,36,"); + add("170,45,-16,-69,-36,-77,-55,-47,-138,-9,-37,-150,"); + add("72,-6,-117,20,-29,-143,-66,-60,-170,86,24,-3,"); + add("53,-18,-131,2,-32,-129,-63,-49,-118,24,-19,-101,"); + add("70,46,101,12,39,137,16,42,151,-49,20,136,"); + add("-25,24,126,33,63,227,99,7,-88,13,-32,-147,"); + add("44,-32,-180,30,-15,-95,-5,-39,-151,40,-27,-142,"); + add("-4,-41,-153,-110,-55,-92,45,5,-27,85,-6,-106,"); + add("108,11,-66,125,10,-82,138,21,-55,174,38,-24,"); + add("120,27,-11,156,35,-11,117,9,-67,135,8,-83,"); + add("135,22,-30,145,30,-9,152,26,-26,105,-5,-96,"); + add("100,-12,-111,136,17,-37,146,17,-43,124,1,-78,"); + add("151,20,-27,140,19,-26,147,16,-33,124,-6,-91,"); + add("115,-6,-86,160,20,-20,122,46,82,136,16,-18,"); + add("124,-13,-100,161,35,35,87,-29,-131,55,33,77,"); + add("139,42,76,73,-25,-112,42,-38,-138,104,-20,-104,"); + add("133,-3,-61,49,-34,-123,-41,-40,-104,66,16,23,"); + add("106,-15,-82,140,-26,-125,66,-15,-64,37,-42,-134,"); + add("27,-46,-138,-11,-53,-145,41,-44,-135,89,-34,-116,"); + add("135,-12,-71,148,-3,-46,47,-29,-88,20,-60,-161,"); + add("-50,-23,-49,-136,-35,-57,-140,-33,-47,-120,-35,-57,"); + add("-138,-47,-79,-81,-56,-117,-109,-36,-56,-160,-3,41,"); + add("-158,-18,6,-68,-67,-143,-117,-6,24,-158,-13,25,"); + add("67,-29,-95,140,17,-7,205,63,88,-60,-34,-63,"); + add("-179,-70,-111,42,-48,-129,145,-3,-55,141,6,-29,"); + add("156,23,8,29,73,166,142,5,-28,107,-28,-95,"); + add("87,-40,-119,70,-21,-65,127,-24,-87,96,-37,-107,"); + add("105,-32,-96,-20,-34,-73,-192,-36,-37,-147,-15,0,"); + add("62,-27,-73,-50,-46,-90,-64,-47,-89,-113,-45,-70,"); + add("-151,-17,3,-124,0,32,-127,18,75,-194,-8,39,"); + add("-100,-17,-8,-68,13,51,-91,47,133,-117,28,102,"); + add("-108,-23,-15,39,-62,-152,-86,-54,-89,-79,-64,-112,"); + add("-34,-63,-124,72,-46,-124,159,-3,-57,77,-31,-90,"); + add("67,-50,-124,141,-12,-69,124,38,43,80,-39,-102,"); + add("26,-74,-158,-43,-63,-113,109,-12,-55,55,-60,-133,"); + add("8,-75,-147,46,-53,-112,-48,-53,-89,-123,-74,-110,"); + add("-57,27,66,-61,60,130,-4,-8,-14,37,-64,-132,"); + add("-77,-54,-81,-137,-36,-30,-162,9,65,-61,-42,-61,"); + add("114,-19,-69,160,46,41,86,-61,-135,-67,-54,-82,"); + add("-129,-49,-55,-129,-67,-84,-119,-42,-42,-138,10,60,"); + add("-116,33,95,-4,65,119,-34,91,179,6,-43,-82,"); + add("-48,-58,-91,-90,-77,-112,-97,-71,-96,-11,-72,-125,"); + add("-53,-59,-87,-43,-35,-47,-17,-85,-143,-102,-12,14,"); + add("-72,49,109,-131,44,123,-147,-31,-2,-112,-4,34,"); + add("-197,-92,-87,4,87,151,-95,49,126,19,-17,-38,"); + add("-77,-73,-99,-120,5,56,-104,35,105,-63,53,124,"); + add("-10,-6,-7,-5,-72,-129,51,-64,-135,-57,-80,-116,"); + add("13,-75,-135,-69,-96,-137,-6,-24,-38,106,-35,-103,"); + add("67,-57,-122,33,-94,-169,82,-34,-87,89,-37,-93,"); + add("96,-49,-115,63,-62,-121,-41,-96,-137,86,-23,-66,"); + add("130,44,24,125,-16,-67,99,-44,-102,83,-75,-141,"); + add("42,-58,-101,91,-40,-88,36,-71,-117,-44,19,42,"); + add("-137,27,82,-127,-2,37,-57,52,97,-37,84,141,"); + add("-93,-22,-3,-141,5,56,-90,27,74,-97,52,116,"); + add("-101,-20,6,-32,19,41,-73,40,90,-127,49,126,"); + add("-43,45,90,26,63,92,-86,40,98,-96,48,119,"); + add("-95,41,107,-79,44,109,-10,69,120,-50,62,128,"); + add("-69,42,103,-74,48,118,-71,56,132,-91,31,97,"); + add("-19,54,106,-31,67,136,-69,61,148,75,55,64,"); + add("165,34,-18,13,77,137,-48,65,147,-67,31,93,"); + add("-58,46,119,90,73,96,-41,10,41,-47,57,138,"); + add("-36,64,148,-17,59,129,-75,42,126,-82,38,126,"); + add("-160,31,156,12,-41,-93,-177,-73,-50,89,-3,-57,"); + add("138,10,-58,88,-34,-121,46,-49,-124,-61,-78,-125,"); + add("1,-67,-133,-8,-72,-138,-147,-34,14,-19,-46,-80,"); + add("77,-45,-127,-100,-39,-21,-108,17,91,-81,72,186,"); + add("-63,18,70,-43,51,126,-61,51,138,-149,-7,76,"); + add("-28,56,131,21,67,125,69,16,-9,34,13,6,"); + add("47,46,67,24,56,103,-37,49,128,-27,-27,-40,"); + add("-92,-20,15,-102,4,73,-89,33,130,-12,-27,-52,"); + add("-111,-57,-49,-142,-41,8,-133,-53,-22,-87,46,159,"); + add("-48,-46,-65,-135,-53,-18,-131,-41,5,-130,1,98,"); + add("-109,11,107,-130,-9,78,-177,-14,109,-103,-45,-18,"); + add("-140,-29,51,-106,6,100,-39,52,151,-118,-16,62,"); + add("9,-26,-65,11,-46,-113,-103,-54,-34,-114,-32,27,"); + add("-154,-41,44,-142,-49,18,-163,-73,-16,-109,-48,-5,"); + add("-176,-51,49,-66,10,85,-13,38,99,130,56,2,"); + add("129,43,-24,29,28,35,-139,-21,84,-80,-15,43,"); + add("-154,-101,-82,-135,-44,34,-15,25,71,115,79,68,"); + add("160,107,91,75,63,75,-35,-16,-4,-117,-76,-63,"); + add("-115,-66,-40,-141,-81,-45,-143,-15,110,-116,-71,-46,"); + add("-136,-59,6,-127,-79,-49,-82,-67,-64,-65,-50,-45,"); + add("-143,-56,26,-148,-70,1,-106,-61,-19,-197,-86,23,"); + add("-38,-63,-98,-99,-108,-127,-11,37,93,-37,63,181,"); + add("-104,-51,5,-113,-78,-43,-131,-99,-69,-39,-48,-61,"); + add("-90,-69,-46,-52,22,110,36,78,129,79,77,80,"); + add("94,82,74,23,21,21,-131,-106,-85,-88,-89,-96,"); + add("-22,4,35,76,92,117,-38,-8,26,-83,-108,-141,"); + add("-18,-45,-80,-56,-75,-99,-85,-68,-47,60,12,-44,"); + add("-75,-60,-42,-128,-21,106,-14,-35,-56,-7,-46,-91,"); + add("-126,-71,-1,-154,-77,21,2,45,95,18,77,144,"); + add("-56,-15,36,-91,-90,-80,-163,-46,103,49,9,-42,"); + add("118,28,-87,-8,-31,-56,-136,-78,3,-154,-87,7,"); + add(""); + //add("/*2*/"); + add("855,1,10146,-28113,2593,"); + add("-64,-14,99,-80,-18,106,-94,-21,118,-117,-32,89,"); + add("-142,-49,-9,-125,-42,5,-128,-35,72,-151,-47,23,"); + add("-146,-50,-18,-133,-46,-35,-151,-45,14,-129,-32,74,"); + add("-134,-34,54,-100,-18,108,15,23,153,86,38,101,"); + add("166,53,22,114,38,26,140,39,-36,135,37,-51,"); + add("143,47,6,145,55,58,-124,-32,67,28,23,110,"); + add("85,41,95,148,50,1,46,0,-116,126,38,-40,"); + add("98,45,85,98,27,-54,87,31,0,117,48,45,"); + add("135,50,10,123,45,-4,105,53,98,140,63,69,"); + add("-39,1,110,-64,-4,137,-33,10,148,-42,7,144,"); + add("-39,9,148,-38,12,148,-37,11,146,-28,16,148,"); + add("-87,-10,120,-70,-3,117,-42,15,156,-32,15,133,"); + add("-44,13,141,-80,-2,130,-5,24,117,-7,29,148,"); + add("-32,21,143,-35,21,147,87,40,36,96,40,22,"); + add("-19,30,156,11,38,140,31,47,141,-43,21,144,"); + add("-83,3,129,-86,1,122,-113,-13,102,-111,-11,104,"); + add("-142,-38,40,-137,-36,41,-138,-35,40,-116,-59,-74,"); + add("-56,-54,-130,-62,-27,-26,-49,23,143,-52,19,131,"); + add("-144,-27,65,-26,-48,-141,-89,-34,-22,-138,-28,50,"); + add("-92,-1,101,74,51,99,-49,22,131,-127,-50,-42,"); + add("-141,-33,32,-124,-13,80,-149,-37,17,-130,-15,74,"); + add("-132,-14,77,-147,-42,-9,-144,-26,44,-143,-29,27,"); + add("-147,-33,15,-138,-38,-14,-110,-61,-115,-105,-49,-84,"); + add("-193,-49,-13,38,41,110,-101,-31,-25,-72,23,133,"); + add("127,47,62,-51,10,74,-161,-49,-43,-33,28,117,"); + add("43,40,100,-56,30,138,-19,42,146,36,53,142,"); + add("-86,16,108,-145,-37,-16,-97,-52,-97,-128,-51,-76,"); + add("-146,-38,-26,-149,-29,-1,-148,-30,-2,-141,-7,60,"); + add("-141,-10,48,-149,-24,8,-150,-20,19,-141,-7,49,"); + add("-150,-18,18,-147,-14,28,-149,-16,19,-149,-15,22,"); + add("-142,-3,50,-112,19,105,-133,6,71,-116,18,96,"); + add("-112,20,101,-125,15,86,-121,16,87,-159,-19,-3,"); + add("-150,-19,-10,-151,-12,6,-135,9,64,-132,4,44,"); + add("-156,-14,-3,-118,-35,-73,-114,-37,-85,-153,4,42,"); + add("-88,34,115,-81,37,121,-112,32,108,-35,-26,-68,"); + add("-76,-33,-82,-115,38,126,-117,-31,-73,-110,-34,-83,"); + add("-152,-6,-1,-152,-7,-6,-147,-13,-25,-145,-16,-37,"); + add("-144,-16,-40,-132,-26,-70,-139,-21,-59,-109,-33,-97,"); + add("-99,-36,-108,-90,36,108,-127,-5,-17,-96,20,55,"); + add("-117,5,9,-147,-8,-32,-150,-1,-14,-149,-14,-56,"); + add("-83,28,76,58,42,129,-20,42,118,-126,-13,-49,"); + add("-86,-37,-120,-54,-44,-136,15,-53,-156,-135,-21,-85,"); + add("-82,49,137,-70,46,126,-119,36,88,-81,-19,-70,"); + add("-22,-46,-143,-69,-43,-144,-140,38,89,-43,-33,-110,"); + add("114,-37,-91,71,-44,-122,-30,-42,-140,-71,-35,-129,"); + add("-97,-29,-116,-138,-9,-65,23,-25,-77,-7,-32,-110,"); + add("-136,-7,-58,-104,-24,-113,-14,-51,-183,21,-28,-96,"); + add("58,-21,-58,132,9,68,127,15,86,27,-28,-92,"); + add("-97,-23,-110,-67,-30,-130,-79,-27,-125,-47,-32,-134,"); + add("-5,-37,-148,-31,-33,-141,48,-40,-150,-136,-10,-84,"); + add("-104,-10,-83,-111,-10,-85,-125,-4,-66,-120,-8,-87,"); + add("-117,-10,-97,-90,-20,-132,-69,-16,-107,-93,-15,-121,"); + add("-67,-21,-132,-38,-25,-144,-55,-21,-141,-31,-25,-148,"); + add("-77,-16,-131,-27,-24,-147,3,-27,-149,4,-26,-149,"); + add("22,-28,-148,55,-29,-137,103,-29,-106,150,-18,-6,"); + add("145,-20,-31,134,-7,46,80,13,129,78,14,128,"); + add("132,10,135,16,-14,-76,-32,-21,-147,4,-26,-155,"); + add("162,-21,-42,93,-24,-108,-32,-18,-138,-96,-10,-124,"); + add("-65,-13,-134,-90,-9,-122,-69,-11,-134,-79,-9,-128,"); + add("-44,-14,-146,-57,-11,-139,-22,-15,-147,59,-21,-143,"); + add("-61,-7,-129,-124,4,-86,-90,-3,-120,-57,-6,-139,"); + add("-36,-9,-146,-21,-10,-149,30,-15,-148,71,-17,-133,"); + add("75,-19,-163,-105,10,-3,-134,19,54,-145,14,-43,"); + add("-144,14,-52,-142,14,-50,-140,15,-54,-141,16,-55,"); + add("-136,15,-68,-124,13,-86,-100,9,-114,-115,13,-97,"); + add("-126,16,-86,-144,21,-33,-145,22,-49,-126,14,-211,"); + add("10,2,103,-62,16,132,-128,25,66,-141,24,-30,"); + add("-57,5,-132,-39,2,-151,107,-22,-83,-36,5,-47,"); + add("-142,25,-56,-109,18,-94,-147,29,-31,-156,30,-34,"); + add("-31,9,92,136,-26,79,112,-19,99,54,-6,141,"); + add("-19,9,150,-108,25,85,-133,25,-57,-88,13,-124,"); + add("-107,18,-129,-114,24,14,24,-1,120,84,-12,129,"); + add("60,-7,138,77,-9,129,83,-11,124,-50,19,144,"); + add("-119,31,98,-114,19,-79,-47,1,-148,-123,22,-77,"); + add("-136,28,-54,-143,30,-42,-142,31,-37,-139,32,-11,"); + add("-116,34,108,60,-8,127,139,-31,32,129,-26,64,"); + add("70,-8,134,61,-5,139,61,-3,139,54,-1,147,"); + add("-91,30,115,-36,19,136,-3,14,148,5,14,152,"); + add("-21,19,148,-30,23,145,-30,23,149,-106,31,50,"); + add("-96,33,86,-112,41,116,95,-17,48,-6,13,93,"); + add("-117,39,85,-90,36,105,-94,32,62,-40,17,51,"); + add("-61,31,110,-130,30,-29,-131,37,18,66,-4,97,"); + add("25,9,103,-109,39,70,-156,39,-21,-120,26,-45,"); + add("-54,31,103,-124,41,45,-115,11,-148,-38,20,61,"); + add("29,15,151,-109,31,-3,-62,25,43,-64,36,103,"); + add("-146,51,42,-111,23,-65,-72,33,67,-134,39,-15,"); + add("-96,44,80,-156,50,-3,-129,54,68,-134,41,-21,"); + add("-134,39,-38,-150,60,54,-117,42,3,-27,36,152,"); + add("-53,11,-44,-6,-26,-159,113,-44,-30,-20,-4,-58,"); + add("-82,9,-121,-125,48,21,-84,50,117,-82,22,-47,"); + add("-147,63,50,-120,52,44,-39,38,132,-100,56,97,"); + add("-23,41,177,-118,61,82,-71,52,123,202,-60,96,"); + add("-114,60,80,93,-7,139,20,19,131,-21,39,142,"); + add("-73,14,-67,-18,-25,-152,-142,44,-57,-88,65,143,"); + add("-97,45,31,-51,46,113,-18,42,157,-42,48,133,"); + add("-38,47,138,18,29,150,86,-9,108,-40,35,75,"); + add("-97,66,102,-47,52,129,-2,40,151,56,18,152,"); + add("-95,59,72,-85,8,-104,-7,-35,-144,-28,-30,-156,"); + add("25,-48,-147,-15,-25,-128,-24,-22,-132,-5,-34,-151,"); + add("73,-59,-120,23,-40,-133,3,-39,-169,21,-33,-111,"); + add("38,-44,-131,-54,-9,-152,126,-67,-76,70,-43,-69,"); + add("53,-45,-120,47,-38,-98,1,-24,-130,48,-43,-128,"); + add("75,-51,-119,85,-50,-97,50,-39,-115,16,-28,-131,"); + add("145,-69,-78,92,-14,130,81,-38,-46,92,-49,-90,"); + add("135,-55,-30,105,-50,-76,120,-56,-82,123,-40,17,"); + add("101,-51,-102,-31,-10,-145,-5,-15,-118,144,-53,-23,"); + add("127,-51,-60,141,-46,15,142,-48,-7,141,-48,-20,"); + add("139,-48,-27,129,-49,-68,142,-47,-20,144,-43,2,"); + add("134,-47,-55,118,-43,-65,95,-41,-118,48,-30,-133,"); + add("40,-27,-148,9,-19,-150,-25,-8,-148,2,-15,-146,"); + add("-5,-12,-156,31,-21,-145,-2,-12,-152,-15,-7,-143,"); + add("9,-13,-157,-86,24,-2,-77,18,-69,16,-15,-167,"); + add("-97,25,-49,-131,35,-68,-99,24,-107,55,-20,-57,"); + add("93,-30,-67,129,-40,-49,84,-29,-95,-35,5,-125,"); + add("-80,19,-128,-38,7,-140,-68,16,-139,-184,54,-42,"); + add("30,-11,-109,-23,5,-131,-40,10,-134,-186,56,-83,"); + add("112,-34,-78,70,-22,-118,55,-16,-134,-40,13,-157,"); + add("4,1,-147,49,-12,-139,-6,5,-150,40,-7,-148,"); + add("4,4,-147,-49,20,-153,-49,20,-120,42,-5,-148,"); + add("39,-4,-144,28,1,-165,-30,17,-116,-70,28,-110,"); + add("110,-29,-54,130,-44,72,26,-16,138,-25,-2,147,"); + add("-13,-5,153,70,-28,142,78,-20,-44,36,-3,-147,"); + add("-24,16,-149,53,-7,-129,110,-37,77,57,-23,124,"); + add("143,-44,74,27,-14,135,126,-36,32,75,-23,68,"); + add("98,-29,76,82,-17,-108,28,0,-145,-68,25,-127,"); + add("24,4,-161,49,-4,-144,86,-13,-128,107,-19,-105,"); + add("27,5,-144,-12,15,-154,84,-6,-166,-127,38,-63,"); + add("-148,36,15,-143,44,-72,-19,20,-144,109,-26,-31,"); + add("136,-40,54,109,-23,-50,-14,17,-123,-89,31,-83,"); + add("-123,39,-67,-87,35,-107,77,-9,-97,155,-46,54,"); + add("104,-16,-88,94,-9,-114,8,18,-157,92,-13,-73,"); + add("110,-17,-77,101,-8,-114,95,-6,-120,67,5,-135,"); + add("95,-5,-114,65,6,-140,81,3,-128,85,1,-126,"); + add("109,-7,-101,130,-14,-76,103,-3,-108,79,6,-131,"); + add("87,5,-123,129,-10,-87,18,26,-156,96,3,-108,"); + add("151,-19,-53,144,-31,23,139,-14,-57,133,-6,-84,"); + add("146,-32,31,140,-18,-24,118,0,-95,127,-12,-39,"); + add("156,-16,-38,134,-22,14,143,-10,-54,81,-45,165,"); + add("104,3,-81,78,19,-143,165,-22,5,-30,-18,107,"); + add("-130,3,66,-57,-19,133,6,-28,137,79,-26,81,"); + add("97,-32,107,88,0,-61,160,-18,-5,141,-19,14,"); + add("98,-1,-51,42,24,-149,104,4,-76,77,5,-66,"); + add("52,22,-135,113,9,-95,125,-16,19,118,4,-70,"); + add("89,-27,97,77,-31,117,41,-30,136,-72,-25,156,"); + add("-144,6,35,-121,-2,69,69,-30,124,161,-14,3,"); + add("37,-21,100,-45,-22,142,-92,-12,117,-82,-13,121,"); + add("-60,-18,139,-79,-13,131,-69,-14,132,-35,-19,147,"); + add("27,-24,148,60,-25,134,135,-21,64,138,-19,55,"); + add("133,-23,87,126,-7,-24,71,13,-132,96,8,-112,"); + add("117,6,-96,151,-12,12,-16,-15,116,-64,-16,145,"); + add("86,-21,123,23,-21,148,-22,-17,154,7,-18,148,"); + add("106,-18,108,92,-18,118,66,-18,136,75,-16,129,"); + add("56,-16,137,9,-14,151,-32,-11,148,-72,-7,133,"); + add("-86,-6,126,-84,-4,126,-14,-8,133,123,-8,18,"); + add("89,4,-130,125,1,-97,157,-11,62,114,1,-81,"); + add("157,-2,-36,120,3,-96,85,8,-121,92,8,-118,"); + add("75,8,-118,108,9,-118,128,6,-80,153,1,-24,"); + add("123,5,-53,115,10,-101,132,8,-74,135,9,-67,"); + add("113,8,-67,85,13,-99,153,6,-28,38,8,-63,"); + add("45,16,-122,89,13,-90,109,16,-106,112,15,-84,"); + add("81,16,-100,104,20,-116,151,21,-102,20,22,-149,"); + add("111,19,-87,53,22,-133,53,22,-123,132,8,1,"); + add("71,16,-73,-64,23,-163,42,23,-122,-1,27,-158,"); + add("66,27,-132,-52,19,-120,-108,12,-98,-88,18,-123,"); + add("-106,12,-92,-181,0,-44,53,12,-52,133,30,-117,"); + add("100,13,-34,82,37,-157,82,20,-73,63,33,-132,"); + add("115,28,-95,35,21,-85,31,32,-130,61,37,-142,"); + add("27,33,-132,16,32,-130,62,36,-128,76,39,-130,"); + add("-76,23,-114,-33,36,-149,-108,11,-73,-26,28,-111,"); + add("74,41,-132,-110,13,-76,9,25,-88,-85,32,-135,"); + add("-90,31,-127,-103,-6,-2,-99,8,-46,-25,40,-142,"); + add("-56,34,-126,-32,47,-159,9,45,-144,40,39,-116,"); + add("-74,30,-107,-14,40,-127,106,39,-102,153,10,-1,"); + add("126,33,-75,143,33,-68,84,42,-106,163,15,-9,"); + add("136,8,12,146,15,-9,154,12,8,123,-13,73,"); + add("140,35,-61,147,12,11,142,13,8,142,26,-26,"); + add("106,40,-77,132,38,-62,143,29,-28,135,34,-44,"); + add("194,36,-27,97,-12,78,124,-4,64,150,16,23,"); + add("159,37,-31,46,48,-115,156,45,-53,-15,-36,94,"); + add("-26,-53,138,147,11,43,118,0,64,138,-8,98,"); + add("120,71,-143,138,11,45,145,21,23,146,6,68,"); + add("113,50,-75,115,32,-22,87,-32,148,71,25,-26,"); + add("148,46,-37,171,21,52,60,55,-120,84,45,-71,"); + add("112,-11,108,134,20,40,147,29,20,107,-15,126,"); + add("147,32,16,131,8,82,130,11,73,131,16,60,"); + add("141,21,56,125,8,85,139,21,58,133,18,65,"); + add("111,2,99,144,26,57,153,29,56,87,53,-79,"); + add("72,62,-121,120,61,-70,123,47,-21,79,-2,88,"); + add("-86,-65,114,-106,-63,88,-125,-59,59,-42,-50,118,"); + add("131,12,99,76,-14,129,81,-11,124,87,-7,121,"); + add("105,3,111,32,-30,145,-31,-50,141,-74,-56,114,"); + add("-40,-47,127,112,11,101,121,18,85,137,36,41,"); + add("131,62,-66,141,35,58,25,-32,158,-43,-49,136,"); + add("95,18,63,95,12,88,17,-29,150,74,7,81,"); + add("119,18,111,27,-25,152,17,-25,144,64,-7,141,"); + add("44,-14,140,73,-1,140,52,-8,136,110,21,107,"); + add("140,49,19,136,45,44,78,7,125,25,-20,159,"); + add("129,47,22,139,49,40,139,48,50,59,4,115,"); + add("7,-23,148,32,-11,148,-6,-27,148,-101,-55,90,"); + add("-76,-48,104,-17,-28,144,16,-18,175,104,29,94,"); + add("124,40,85,58,5,144,73,15,129,78,17,127,"); + add("88,23,124,82,22,122,59,11,135,67,15,133,"); + add("30,-1,147,-6,-17,148,-18,-20,147,-90,-49,114,"); + add("-65,-38,129,-105,-54,130,66,23,86,82,28,102,"); + add("-29,-22,162,43,11,136,-8,-12,155,9,-3,157,"); + add("54,18,141,-20,-14,150,30,9,148,-2,-4,155,"); + add("38,14,144,0,-2,154,-38,-17,145,-30,-13,146,"); + add("-13,-5,165,118,51,49,159,71,70,-58,-25,54,"); + add("-147,-64,16,-117,-49,76,-86,-35,120,-43,-14,142,"); + add("-63,-23,129,-10,1,153,-12,1,149,-21,-2,150,"); + add("-87,-30,128,-7,4,134,-138,-53,64,-79,-30,35,"); + add("-98,-32,115,-59,-15,138,-81,-23,127,-102,-32,104,"); + add("-125,-43,76,-134,-48,36,-137,-54,-19,-115,-37,69,"); + add("-97,-26,116,-95,-26,95,"); + add(""); + //add("/*3*/"); + add("533,1,14413,-10720,-24028,"); + add("106,64,35,41,145,-39,45,121,-25,118,62,45,"); + add("108,59,42,130,65,53,121,63,49,125,156,13,"); + add("105,16,61,116,68,46,134,43,70,123,76,50,"); + add("78,121,2,37,136,-31,102,110,25,28,136,-35,"); + add("3,139,-52,41,137,-25,71,135,-3,71,132,-1,"); + add("106,109,33,94,119,21,23,137,-33,49,144,-17,"); + add("50,142,-13,38,151,-25,25,132,-27,44,100,-1,"); + add("117,83,55,114,84,53,77,128,14,100,11,68,"); + add("77,-59,74,102,-33,85,81,128,19,59,137,0,"); + add("45,141,-9,21,141,-27,40,147,-13,49,131,-2,"); + add("55,141,2,99,120,41,12,152,-33,97,77,53,"); + add("59,144,7,26,145,-17,59,151,8,83,100,39,"); + add("77,-10,61,69,-98,78,-3,-158,37,16,-145,50,"); + add("6,-150,44,28,-68,40,47,-117,69,-62,-183,3,"); + add("25,-97,47,27,-119,56,-34,-144,17,30,-138,66,"); + add("-8,-148,39,-63,-137,-5,-3,-148,45,-37,-145,19,"); + add("-51,-146,9,10,-137,56,16,-141,62,-6,-146,48,"); + add("-18,-141,38,10,-146,62,22,-132,68,43,-119,81,"); + add("8,-136,60,28,-124,73,85,-76,100,103,-39,102,"); + add("114,21,87,118,63,73,114,73,68,103,83,54,"); + add("74,129,12,119,59,79,116,34,89,116,41,87,"); + add("107,90,60,96,110,43,112,66,76,109,71,73,"); + add("114,56,83,102,33,84,106,93,64,98,100,55,"); + add("101,89,63,107,85,72,105,76,74,45,130,-4,"); + add("-39,126,-84,-51,115,-92,-23,126,-65,10,141,-39,"); + add("49,132,2,-28,103,-60,-91,36,-100,-74,6,-72,"); + add("-3,145,-49,-37,155,-83,-53,99,-80,74,82,45,"); + add("87,113,49,72,-11,71,12,-108,44,35,-107,66,"); + add("67,112,31,62,10,57,48,21,40,-31,120,-66,"); + add("19,34,9,75,-92,100,92,-81,115,82,-8,84,"); + add("109,97,80,90,-10,94,116,25,110,106,78,87,"); + add("85,40,76,101,-2,107,98,47,89,108,136,75,"); + add("93,-18,105,101,107,79,72,-5,80,45,4,49,"); + add("66,-13,77,-92,-105,-70,-116,-3,-126,-80,-112,-54,"); + add("-41,-175,10,55,-93,89,75,5,80,98,-28,118,"); + add("99,-9,114,116,57,113,75,-20,92,46,-138,98,"); + add("60,6,68,39,-81,73,60,-72,95,43,-109,90,"); + add("-49,-156,-2,56,-99,103,50,-71,86,-4,-133,46,"); + add("44,-94,90,23,-141,85,-100,-116,-74,-87,-100,-64,"); + add("17,-35,35,10,-127,65,48,36,43,92,-10,115,"); + add("51,51,42,103,56,103,109,16,130,28,-100,78,"); + add("18,-163,94,41,49,31,15,153,-49,18,117,-26,"); + add("99,103,83,78,114,53,90,103,74,89,65,90,"); + add("76,53,79,62,-14,88,19,-118,75,56,19,66,"); + add("49,-39,84,65,59,63,17,-34,39,-23,-173,43,"); + add("60,-55,107,55,99,32,14,-38,36,32,-76,79,"); + add("49,-70,100,-47,-125,-9,-20,-79,9,80,18,105,"); + add("-21,-130,32,56,-2,81,36,-42,73,46,-97,113,"); + add("-68,-135,-32,-26,-92,9,12,-100,68,-109,-64,-125,"); + add("17,-12,31,88,5,126,85,45,101,98,10,141,"); + add("33,-89,96,-10,-72,24,-108,-124,-95,-9,-120,52,"); + add("7,-166,103,59,52,60,73,129,39,75,139,38,"); + add("64,131,26,40,8,56,10,-123,85,35,-95,108,"); + add("38,-102,118,-6,-132,67,-46,-141,11,-57,-137,-9,"); + add("-32,-109,18,35,-92,112,37,-91,117,7,-117,86,"); + add("-8,-141,79,7,-120,92,25,-100,109,43,-74,123,"); + add("53,-57,130,57,-51,132,67,-25,134,61,-36,133,"); + add("69,-2,122,76,10,129,24,-97,116,41,-63,123,"); + add("68,-18,141,49,-44,126,26,-88,117,52,-38,132,"); + add("78,18,135,79,17,141,39,-36,107,37,-65,131,"); + add("30,-62,114,22,-89,124,18,-91,117,14,-95,118,"); + add("40,-60,139,40,-50,134,15,-97,124,-18,-110,68,"); + add("-10,-135,113,59,79,51,69,184,-27,23,-36,85,"); + add("-27,-131,71,-24,-129,79,-54,-125,5,-65,-137,-2,"); + add("-50,-138,32,-25,-122,75,-19,-121,89,-40,-134,59,"); + add("-56,-139,28,-80,-120,-45,-70,-128,-14,-80,-119,-43,"); + add("-82,-123,-40,-83,-118,-49,-75,-119,-27,-53,-167,84,"); + add("100,105,97,60,81,39,98,141,53,-23,-83,47,"); + add("-79,-124,-31,-87,-103,-72,-57,-134,37,63,50,81,"); + add("103,130,75,-27,-77,34,-85,-107,-64,-87,-106,-64,"); + add("-85,-114,-49,-85,-119,-40,-82,-127,-22,-63,-133,29,"); + add("-81,-128,-14,-89,-107,-59,-88,-115,-41,-79,-124,-8,"); + add("-93,-112,-54,-84,-127,-12,-67,-131,32,-71,-133,28,"); + add("-77,-127,10,-81,-128,3,-90,-122,-21,-92,-115,-32,"); + add("-91,-119,-25,-94,-115,-31,-85,-125,-1,-77,-137,40,"); + add("-92,-172,59,-23,-67,51,-85,-127,14,-63,-112,36,"); + add("-33,-122,120,50,-14,128,8,-34,69,-75,-127,40,"); + add("-100,-130,-6,-84,-36,-120,-97,-70,-91,-105,-98,-61,"); + add("-98,-58,-109,-69,-40,-76,-88,-26,-136,-69,0,-135,"); + add("-85,-22,-130,-62,9,-131,-36,52,-145,4,92,-127,"); + add("-10,81,-134,-54,23,-132,-42,37,-127,30,113,-104,"); + add("-19,73,-132,-69,10,-132,-67,12,-130,-64,23,-138,"); + add("-69,12,-130,-82,-5,-128,-97,-18,-133,-83,-38,-84,"); + add("-62,26,-130,-73,16,-134,-92,-30,-104,-67,39,-149,"); + add("-2,101,-125,22,108,-95,31,118,-93,-30,71,-126,"); + add("-69,31,-135,-37,68,-130,-46,59,-131,-44,61,-128,"); + add("-40,68,-130,-79,17,-126,-101,-20,-116,-90,2,-122,"); + add("-82,15,-124,-66,41,-128,-72,36,-130,-66,44,-129,"); + add("-59,54,-129,-54,61,-126,-77,32,-128,-88,16,-122,"); + add("-91,12,-122,-94,8,-120,-101,-6,-112,-94,8,-117,"); + add("-78,34,-120,-119,-51,-88,-117,-66,-71,-117,-80,-56,"); + add("-104,-26,-91,-87,18,-111,-122,-68,-68,-121,-27,-104,"); + add("-86,2,-92,-126,-117,-26,-112,-44,-74,-38,-120,71,"); + add("-98,-130,20,-129,-42,-92,-107,-99,-16,-85,-115,23,"); + add("-124,-98,-31,-87,-113,21,-80,-156,70,-62,-71,9,"); + add("-173,-72,-100,30,103,-70,-25,85,-105,-8,117,-118,"); + add("-31,90,-114,-65,81,-136,-70,41,-102,-11,108,-108,"); + add("11,117,-95,-39,91,-115,36,126,-78,-31,-5,-23,"); + add("-84,-123,30,-33,-105,63,-57,-130,65,4,-102,94,"); + add("11,-104,105,-21,-114,85,-51,-122,66,-60,-146,83,"); + add("84,-30,106,5,-114,113,-106,3,-101,-105,24,-119,"); + add("-2,109,-105,33,121,-83,13,141,-119,-96,-66,-25,"); + add("-122,-121,3,-61,-111,49,-43,-125,79,3,-137,133,"); + add("-119,-18,-87,-85,45,-119,-83,53,-122,-35,-85,51,"); + add("-7,-50,41,-116,-89,-16,-71,-54,-8,227,159,44,"); + add("-34,-26,-6,-122,-85,-24,-113,-99,-1,-100,-112,23,"); + add("-87,-116,39,-22,-117,95,-75,-117,53,-127,-103,-3,"); + add("-114,-89,-7,-114,-97,4,-128,-46,-59,-127,-32,-70,"); + add("-138,-91,-19,-80,19,-83,-136,-18,-88,-123,-15,-80,"); + add("-134,-63,-39,-134,-55,-47,-135,-49,-51,-89,37,-102,"); + add("-50,81,-118,-69,69,-117,-36,76,-99,-50,97,-129,"); + add("-109,-60,-18,27,-110,124,-68,-50,1,-74,71,-120,"); + add("-83,-61,1,-118,-90,6,-118,-72,-10,-166,-79,-35,"); + add("33,81,-56,-45,52,-80,-106,31,-99,-54,89,-120,"); + add("-53,84,-113,-65,76,-112,-91,53,-107,-114,29,-96,"); + add("-127,5,-82,-132,6,-85,-118,12,-81,-75,78,-114,"); + add("-42,85,-100,49,106,-64,45,112,-72,8,121,-99,"); + add("16,118,-92,34,114,-76,-2,118,-100,-22,114,-106,"); + add("-32,107,-105,-28,83,-82,18,123,-89,15,102,-72,"); + add("-23,126,-112,-27,98,-90,16,148,-104,-36,111,-104,"); + add("-29,92,-85,-33,108,-97,-98,84,-113,-57,79,-88,"); + add("-55,94,-96,26,127,-77,-46,113,-103,-21,121,-94,"); + add("3,124,-84,5,131,-85,52,127,-59,3,127,-83,"); + add("-8,125,-85,-2,126,-83,9,129,-78,18,131,-73,"); + add("-17,125,-87,-17,124,-85,46,131,-57,49,127,-52,"); + add("73,127,-39,73,123,-36,98,120,-20,37,121,-51,"); + add("26,144,-69,42,129,-52,37,130,-53,35,153,-67,"); + add("94,112,-12,39,138,-54,130,95,16,83,115,-18,"); + add("94,105,-6,121,87,19,92,135,-20,126,100,16,"); + add("107,31,42,122,95,19,132,110,18,78,104,-8,"); + add("52,139,-39,13,134,-58,91,140,-16,131,17,66,"); + add("131,106,25,24,-114,68,87,14,43,94,98,9,"); + add("73,136,-21,48,153,-43,78,105,-2,70,133,-19,"); + add(""); + //add("/*4*/"); + add("521,1,-7056,27453,9826,"); + add("48,26,-40,102,-3,82,129,39,-21,109,39,-34,"); + add("149,63,-76,128,57,-78,109,51,-74,115,37,-34,"); + add("155,37,-8,74,53,-109,30,53,-140,34,5,8,"); + add("16,-47,150,31,-29,102,147,9,62,99,17,11,"); + add("87,16,4,95,1,51,162,24,19,128,16,22,"); + add("150,20,22,150,21,14,147,40,-44,112,37,-54,"); + add("138,36,-40,141,35,-40,136,40,-59,124,28,-26,"); + add("101,31,-51,-186,8,-106,-101,20,-105,-103,19,-105,"); + add("-143,-14,-27,-148,-10,-40,-143,-34,32,-74,15,-85,"); + add("215,32,9,77,25,-38,-169,-3,-78,-107,8,-83,"); + add("-49,5,-41,160,34,-24,89,49,-114,72,13,-3,"); + add("104,-15,104,144,20,5,117,36,-60,-34,35,-133,"); + add("-138,6,-87,-100,9,-84,-26,2,-22,106,27,-34,"); + add("-46,31,-131,9,15,-50,67,-33,153,51,-38,155,"); + add("115,-8,83,73,-31,138,68,-22,102,-7,-50,156,"); + add("-23,-48,143,63,-35,135,127,12,17,55,24,-51,"); + add("83,-28,119,58,46,-118,28,48,-137,40,54,-155,"); + add("-28,28,-103,19,24,-71,-62,10,-58,48,38,-104,"); + add("-81,31,-138,-60,27,-121,-117,-1,-50,-49,-1,-21,"); + add("156,41,-69,-66,30,-137,-147,-11,-32,-25,17,-76,"); + add("183,8,61,84,29,-64,-116,16,-113,-119,-4,-45,"); + add("77,37,-102,147,-12,121,151,36,-63,12,32,-114,"); + add("100,-13,92,106,9,16,105,-20,118,-3,-3,10,"); + add("-130,-1,-53,79,-42,189,132,10,16,121,14,-3,"); + add("106,20,-32,35,40,-131,-138,11,-95,-50,-21,57,"); + add("10,46,-169,69,37,-110,76,18,-43,138,-12,102,"); + add("87,-21,110,101,33,-87,-53,19,-95,-114,12,-87,"); + add("12,41,-158,-85,7,-59,152,22,-32,-85,29,-153,"); + add("15,11,-41,84,-23,129,122,-16,112,95,37,-117,"); + add("21,34,-136,-87,20,-116,-75,5,-50,179,24,-36,"); + add("-114,10,-86,-64,32,-167,41,27,-107,139,16,-18,"); + add("125,9,5,132,-15,116,94,23,-70,-19,32,-157,"); + add("-106,8,-74,-49,18,-107,81,19,-60,78,3,13,"); + add("-125,21,-150,-109,-17,43,95,44,-183,83,32,-133,"); + add("61,27,-122,133,24,-80,108,28,-115,38,30,-154,"); + add("110,20,-81,127,17,-55,-21,16,-102,-151,-11,11,"); + add("-62,-7,23,131,29,-132,152,-1,58,123,15,-53,"); + add("-21,16,-106,-143,-1,-43,-83,3,-50,228,12,1,"); + add("155,6,10,102,20,-101,124,18,-90,107,21,-118,"); + add("-44,18,-138,-120,9,-92,-151,-8,10,-119,-20,108,"); + add("-142,0,-54,-144,-19,79,-121,-20,92,-119,-20,86,"); + add("-67,-9,34,143,31,-154,100,21,-98,96,22,-124,"); + add("58,22,-139,-64,9,-94,-117,-19,93,-141,-15,49,"); + add("-96,-5,-11,191,29,-131,-90,8,-108,-158,-5,-43,"); + add("-133,-6,-26,-88,-3,-36,207,24,-69,163,2,76,"); + add("131,-2,79,148,8,6,140,11,-31,71,17,-112,"); + add("-85,10,-124,-73,5,-72,0,13,-123,-135,-1,-55,"); + add("-129,-1,-65,-138,-7,-14,-103,-3,-43,161,11,-4,"); + add("140,4,45,135,0,78,110,11,-52,-95,9,-131,"); + add("-94,6,-119,-143,-1,-77,-135,-4,-55,-94,-4,-21,"); + add("-93,-10,28,-41,-13,106,-121,-11,22,-31,17,-204,"); + add("-68,2,-87,-140,-11,-12,-69,-8,23,94,-3,118,"); + add("85,-4,125,-5,-13,134,-42,-6,17,-30,11,-134,"); + add("-79,8,-159,-81,-8,3,-33,-17,156,-47,-12,77,"); + add("-162,-23,72,-64,-5,-20,28,18,-155,0,14,-147,"); + add("4,14,-151,-96,-8,-23,-86,-20,128,-92,-17,74,"); + add("-60,-11,44,-16,16,-196,-135,-16,6,192,35,-159,"); + add("-33,5,-106,-101,-6,-76,-153,-13,-66,-100,-22,129,"); + add("-62,-18,139,-13,-2,1,47,17,-149,52,17,-141,"); + add("-120,-10,-67,-128,-23,88,-156,-23,29,-96,-6,-97,"); + add("-75,-11,9,-161,-17,-91,-135,-17,-46,-158,-24,-9,"); + add("-66,-19,118,82,4,124,20,1,35,-159,-26,8,"); + add("-131,-27,69,-149,-26,5,-115,-15,-68,-79,-5,-112,"); + add("-136,-20,-71,-132,-18,-97,-92,-11,-104,-134,-22,-57,"); + add("-126,-27,35,-85,-27,146,3,-8,117,-31,-12,78,"); + add("-78,-22,78,72,6,114,84,7,125,27,-2,88,"); + add("-125,-28,30,-53,2,-158,-83,-15,-23,37,-8,187,"); + add("-6,-3,18,-45,4,-159,-37,4,-148,-69,-4,-134,"); + add("-122,-27,3,-14,-11,103,23,2,47,-56,-24,133,"); + add("-16,-10,74,-160,-31,-52,-68,-28,146,2,-15,161,"); + add("38,5,36,82,20,-10,39,-2,103,14,-6,92,"); + add("100,14,75,91,6,131,28,-10,139,4,-17,155,"); + add("-15,-22,150,-14,-21,139,-64,-30,120,-86,-26,53,"); + add("-80,-37,132,-46,-34,162,-75,-38,138,-88,-29,54,"); + add("-74,-22,30,-46,-35,152,-96,-36,80,-86,-47,153,"); + add("-106,-40,80,-72,-45,154,-114,-39,58,-87,-20,-17,"); + add("-31,-22,74,-100,-39,73,-184,-50,-1,-85,-46,120,"); + add("47,-12,127,129,32,18,96,30,-20,135,52,-87,"); + add("58,25,-52,-84,-59,192,-29,-33,130,30,-7,72,"); + add("-124,-33,1,72,1,88,-94,-29,17,21,-3,40,"); + add("-42,-19,38,4,-18,88,-59,-44,134,-73,-40,89,"); + add("-68,-28,39,-40,22,-146,2,33,-152,-53,15,-141,"); + add("-78,5,-131,-105,-33,17,-23,-37,147,48,-17,142,"); + add("-9,-35,153,54,-16,137,72,1,89,28,-16,102,"); + add("-118,-44,46,-91,-40,58,-86,-48,95,-70,-32,47,"); + add("-128,-40,7,-97,-41,45,-118,-10,-108,-108,-16,-70,"); + add("-100,-36,16,94,-8,155,118,26,45,30,-3,48,"); + add("-88,-50,90,-5,-29,108,-83,20,-181,-61,13,-130,"); + add("-50,4,-82,-53,-5,-51,-41,-34,87,-148,-38,-42,"); + add("-56,-34,64,161,41,50,129,23,72,36,-12,94,"); + add("100,1,123,7,-9,41,-86,-24,-11,37,-16,107,"); + add("-82,-3,-89,-56,15,-129,-59,16,-141,-96,-15,-64,"); + add("-170,-44,-50,-53,-35,69,117,12,110,106,9,101,"); + add("71,-8,121,15,-30,131,6,-3,21,-63,14,-130,"); + add("-40,21,-135,-110,-11,-99,-118,-16,-95,-78,-29,14,"); + add("-1,-26,101,63,-15,139,-126,-37,-22,-51,-34,62,"); + add("-122,-20,-87,-65,-49,103,145,31,74,142,41,32,"); + add("143,44,17,143,37,37,121,19,78,-6,-8,22,"); + add("-106,-25,-34,-154,-31,-77,-146,-44,-22,-143,-39,-39,"); + add("-139,-40,-33,-62,-35,48,85,-1,116,53,0,68,"); + add("-184,-35,-112,-17,-28,83,-15,-32,96,130,28,64,"); + add("136,29,71,24,-11,68,-165,-25,-119,-135,-42,-24,"); + add("-69,-39,52,-100,-73,125,28,-5,54,51,8,36,"); + add("-181,-67,0,-74,-63,122,195,74,-5,104,26,40,"); + add("119,64,-69,-31,-71,201,-58,-63,136,-23,-15,23,"); + add("1,55,-181,-66,-27,10,-35,-28,52,-152,-42,-51,"); + add("-76,-18,-34,133,15,117,47,-3,66,-180,-32,-116,"); + add("-70,-33,20,3,-16,55,-107,-47,18,47,-7,82,"); + add("12,-6,35,-83,-41,28,22,-12,65,-73,-36,24,"); + add("25,-30,122,-38,-42,84,60,16,22,-98,-49,33,"); + add("-130,-83,94,19,-34,122,-13,-35,90,-21,-28,56,"); + add("54,7,40,-92,-51,43,58,10,37,-98,-67,77,"); + add("57,-17,114,-21,-11,7,-77,-40,22,13,-34,109,"); + add("37,-10,67,-72,-48,51,-35,-37,59,92,13,67,"); + add("126,5,125,142,35,58,116,22,61,41,-17,87,"); + add("-146,-56,-6,60,-3,69,-97,-55,42,59,0,61,"); + add("-3,-18,43,63,-2,65,-120,-76,71,103,34,18,"); + add("-126,-76,63,185,44,72,79,-31,151,88,23,29,"); + add("4,50,-116,-5,45,-116,126,-9,141,57,37,-37,"); + add("21,43,-83,112,43,-3,-39,21,-88,74,12,38,"); + add("12,9,-12,33,17,-10,8,15,-29,95,37,-6,"); + add("19,27,-49,73,31,-12,4,15,-35,104,47,-23,"); + add("84,70,-102,40,56,-109,58,66,-120,125,26,48,"); + add("101,24,26,42,40,-68,85,33,-10,57,40,-58,"); + add("43,2,32,57,10,24,76,29,-11,-12,32,-96,"); + add("127,17,64,44,59,-121,-19,47,-146,170,32,60,"); + add("62,78,-163,57,57,-112,113,7,77,114,33,3,"); + add("98,67,-107,127,23,38,118,1,92,107,28,6,"); + add("82,50,-75,128,61,-78,76,16,15,-11,-28,72,"); + add("-127,-57,64,89,-12,100,147,19,57,106,16,32,"); + add(""); + //add("/*5*/"); + add("321,1,-10216,27876,4312,"); + add("-33,-1,-76,72,20,45,-2,15,-106,-14,19,-164,"); + add("39,12,16,27,27,-123,65,8,111,85,31,-9,"); + add("8,22,-136,71,20,39,8,15,-85,28,3,48,"); + add("4,-19,148,36,-10,148,91,34,-10,5,22,-145,"); + add("-23,12,-142,-74,2,-199,39,5,60,101,19,116,"); + add("97,15,136,111,41,-23,83,46,-134,-80,-19,-64,"); + add("-122,-34,-49,-149,-37,-113,40,14,2,175,50,71,"); + add("-13,9,-102,-138,-39,-64,31,12,-10,122,36,43,"); + add("129,29,115,102,31,16,46,35,-157,-87,-11,-138,"); + add("-56,-6,-113,-222,-73,-11,83,30,-16,-1,8,-72,"); + add("42,15,-13,111,28,86,158,51,1,-51,-7,-85,"); + add("-141,-30,-150,119,40,-9,109,25,97,130,48,-48,"); + add("40,27,-149,-81,-18,-74,-180,-53,-52,108,42,-72,"); + add("-67,-16,-56,21,9,-21,157,48,17,-26,-2,-67,"); + add("-175,-51,-57,83,31,-45,72,26,-34,127,32,93,"); + add("78,33,-99,-164,-42,-116,93,29,7,-46,-7,-95,"); + add("29,9,1,98,22,110,124,39,-10,36,22,-141,"); + add("38,22,-136,-15,5,-146,-116,-29,-96,-131,-52,162,"); + add("-2,9,-138,-168,-59,92,30,17,-111,82,29,-61,"); + add("58,25,-106,-53,-14,-52,-97,-26,-78,108,38,-70,"); + add("84,26,-3,138,41,41,138,44,-54,109,37,-90,"); + add("137,43,-56,61,23,-112,-40,-7,-144,-129,-34,-103,"); + add("-72,-18,-120,-116,-36,59,-11,0,-126,-95,-32,94,"); + add("12,7,-103,-111,-33,-55,-128,-42,81,-118,-41,121,"); + add("9,6,-99,-97,-29,-88,-120,-41,52,-76,-28,121,"); + add("-132,-45,25,-156,-52,-3,31,11,-43,-48,-11,-205,"); + add("55,18,52,82,24,128,114,40,-67,113,40,-102,"); + add("130,44,-64,145,46,-1,132,43,-41,135,42,-15,"); + add("136,40,48,138,41,56,119,33,92,89,26,-38,"); + add("6,5,-152,-47,-11,-143,-92,-26,-117,-137,-39,-88,"); + add("-116,-35,-60,-150,-46,-31,-133,-41,-51,-142,-45,-12,"); + add("-118,-39,-20,-147,-48,5,-147,-49,3,-69,-23,127,"); + add("-17,-7,159,-97,-35,131,-30,-9,-143,16,7,-160,"); + add("-128,-44,2,-123,-44,84,-87,-32,123,5,0,128,"); + add("48,15,108,-26,-10,41,-121,-45,61,-16,-9,122,"); + add("4,-3,150,-18,-12,161,16,-1,147,-33,-20,163,"); + add("142,56,-94,-32,-16,89,-94,-43,172,87,35,-57,"); + add("33,8,63,-16,-15,156,-31,-20,134,77,20,120,"); + add("224,86,-107,-50,-25,106,-45,-24,121,-143,-57,81,"); + add("-4,-6,52,-12,-10,76,-63,-30,87,-88,-41,97,"); + add("-89,-44,123,-97,-26,-101,-126,-48,6,104,26,133,"); + add("61,11,121,-78,-35,67,-48,-33,136,-7,-9,59,"); + add("-98,-47,90,-40,-27,104,-124,-58,86,-110,-55,90,"); + add("-119,-57,82,-121,-47,-10,-139,-52,-35,-26,-26,124,"); + add("28,-11,166,165,60,53,-23,-27,123,-19,-27,133,"); + add("-49,-40,137,-121,-51,7,-58,0,-158,-127,-38,-102,"); + add("72,37,-48,110,57,-83,22,29,-151,-29,8,-149,"); + add("-73,-16,-111,-128,-46,-65,-134,-47,-73,-106,-57,89,"); + add("-119,-68,133,-79,-22,-93,-88,-24,-123,-86,-20,-158,"); + add("-74,-40,60,-104,-51,36,15,11,-34,105,55,-70,"); + add("40,33,-139,8,24,-185,-97,-38,-54,-122,-47,-84,"); + add("-136,-60,-25,-121,-62,56,-57,-38,119,-8,-19,140,"); + add("53,12,112,102,35,117,51,13,85,22,-10,161,"); + add("136,69,-54,9,0,39,-73,-51,134,57,9,131,"); + add("-80,-45,58,-83,-53,109,-76,-54,126,-40,-37,125,"); + add("-10,-27,141,-118,-50,-33,-83,-49,60,-26,-39,160,"); + add("-43,-39,111,5,-29,182,-3,-24,125,-70,-55,117,"); + add("-21,-37,139,21,-21,160,19,-20,146,3,-29,150,"); + add("9,-29,158,108,53,-2,74,56,-98,77,62,-118,"); + add("33,42,-131,48,52,-147,29,36,-118,66,56,-133,"); + add("81,63,-139,58,14,68,-45,-49,153,69,32,-2,"); + add("5,-4,34,-65,-58,148,-52,-49,128,35,12,22,"); + add("6,0,13,-36,-43,131,3,-27,132,-51,-50,126,"); + add("48,17,25,94,46,-11,111,64,-64,148,89,-103,"); + add("-51,-52,135,106,52,-17,93,65,-109,46,40,-98,"); + add("104,66,-102,60,44,-88,59,48,-118,7,33,-157,"); + add("61,47,-111,96,62,-119,45,40,-122,45,33,-83,"); + add("124,73,-132,-1,-12,72,-14,-25,114,85,32,18,"); + add("104,68,-154,13,-7,76,64,28,-15,60,14,63,"); + add("-60,-47,133,21,-19,153,-70,-34,34,1,-17,94,"); + add("169,50,93,-76,-32,11,-140,-45,-62,-77,-48,87,"); + add("-46,-28,50,-52,-44,112,-24,-34,123,-24,-34,117,"); + add("48,9,49,121,63,-59,141,74,-81,41,-4,97,"); + add("74,22,40,108,55,-61,56,6,82,71,52,-120,"); + add("92,12,116,74,35,-30,82,28,15,84,54,-109,"); + add("-55,-3,-90,-92,-25,-50,27,17,-35,-66,-7,-93,"); + add("27,15,-25,168,65,-10,-77,-16,-67,-89,-7,-146,"); + add("62,29,-26,97,33,19,105,56,-96,-22,11,-108,"); + add("61,32,-54,-91,-27,-41,30,18,-40,-51,-10,-57,"); + add("79,38,-48,-64,-18,-37,23,20,-72,30,34,-145,"); + add(""); + //add("/*6*/"); + add("232,1,18592,-4797,-23051,"); + add("-106,15,-88,-120,-24,-91,-119,8,-94,-118,7,-93,"); + add("-120,-52,-82,-108,20,-87,-97,76,-88,-109,63,-95,"); + add("10,142,-19,95,107,50,118,58,78,117,25,84,"); + add("129,55,90,-36,0,-28,-107,-30,-77,-120,-9,-89,"); + add("-118,13,-91,-134,35,-107,36,120,6,-13,12,-11,"); + add("-146,-1,-108,61,204,10,-49,-33,-30,-119,-65,-75,"); + add("-99,38,-78,-75,44,-61,-122,-40,-80,-111,-70,-66,"); + add("-120,-44,-76,-131,-23,-86,-92,-37,-57,-116,-80,-64,"); + add("-78,-127,-30,-86,-126,-34,-63,-120,-20,-133,-100,-68,"); + add("-47,-112,-9,-98,-97,-45,-110,-83,-54,-81,-130,-25,"); + add("-117,-86,-56,-123,-29,-71,-124,-22,-72,-145,-4,-88,"); + add("-117,-41,-63,-131,-11,-75,-123,-34,-66,-185,-57,-96,"); + add("-47,-75,-11,-128,-41,-65,-123,32,-77,40,107,0,"); + add("-100,58,-68,45,25,20,127,31,66,127,50,61,"); + add("118,67,55,-31,116,-41,72,59,30,131,18,74,"); + add("117,87,52,6,176,-30,138,9,81,129,-9,80,"); + add("77,116,25,78,118,27,64,119,19,56,148,9,"); + add("114,75,59,107,85,53,93,102,44,110,89,56,"); + add("63,156,17,62,136,21,-86,71,-66,-129,-7,-82,"); + add("-135,30,-90,-20,131,-30,76,119,32,95,108,47,"); + add("124,25,76,123,42,74,116,64,69,117,74,68,"); + add("122,39,77,132,36,85,29,140,4,8,153,-11,"); + add("81,116,43,89,110,51,116,51,75,100,96,62,"); + add("100,82,63,95,92,60,126,13,89,114,54,78,"); + add("104,83,70,107,77,73,122,28,89,119,30,88,"); + add("117,44,86,115,52,84,111,58,82,111,59,84,"); + add("110,66,82,109,62,83,115,26,92,106,29,84,"); + add("116,62,92,108,32,88,115,2,96,110,49,91,"); + add("106,67,87,105,65,88,107,57,90,101,75,86,"); + add("109,46,94,104,60,91,102,33,91,102,-62,96,"); + add("99,-71,94,20,-114,24,54,-82,54,102,-52,98,"); + add("111,0,105,59,-109,62,65,-115,69,63,-110,69,"); + add("63,-114,69,76,-102,82,93,-48,96,111,34,107,"); + add("62,101,55,41,106,33,51,178,40,49,-74,54,"); + add("47,53,45,60,125,53,28,146,21,13,151,6,"); + add("-26,132,-32,-7,147,-13,49,159,46,26,101,24,"); + add("100,19,104,106,7,112,93,80,97,94,61,99,"); + add("99,46,107,103,0,112,92,-59,102,79,-95,89,"); + add("102,-47,116,95,-44,108,27,-144,35,66,-107,79,"); + add("-26,-80,-28,-89,10,-101,-113,-40,-126,-79,-43,-87,"); + add("-25,-126,-21,-48,-117,-49,-96,-86,-100,-104,-7,-113,"); + add("-103,-7,-111,-104,22,-113,-109,-1,-114,-95,41,-103,"); + add("-39,-73,-36,47,-135,57,106,-18,112,49,35,51,"); + add("92,22,96,70,-108,81,83,-45,93,94,29,101,"); + add("111,-45,126,-51,-80,-51,-99,-57,-104,-78,-112,-76,"); + add("-68,-98,-65,17,-122,30,-25,-150,-12,-85,-55,-86,"); + add("-90,52,-101,-34,127,-48,-36,147,-52,-73,194,-92,"); + add("21,-74,27,-15,-191,2,-79,-92,-74,-104,-65,-102,"); + add("-102,-37,-100,-121,16,-124,34,-53,39,-61,-124,-48,"); + add("-100,-76,-92,-105,-15,-103,-110,-21,-105,-106,-32,-100,"); + add("-102,-61,-90,-104,-53,-94,-108,-63,-94,-102,-25,-93,"); + add("-101,-45,-88,-111,-79,-92,-100,-81,-81,-87,-94,-67,"); + add("-89,-135,-61,-38,-138,-15,-47,-141,-22,-114,-156,-77,"); + add("-40,-83,-22,-121,-73,-93,17,-1,14,130,-9,115,"); + add("-146,-136,-105,90,-8,80,-9,-55,1,-90,-119,-58,"); + add("-3,-143,23,17,-176,48,-104,50,-100,-46,-39,-32,"); + add("-109,-13,-91,-167,68,-154,-25,-111,0,-104,-104,-67,"); + add("-94,-101,-59,-84,-116,-46,-96,-102,-57,"); + add(""); + //add("/*7*/"); + add("154,1,26493,2257,-13893,"); + add("-76,-31,-149,-74,37,-134,-66,79,-108,57,125,126,"); + add("-2,122,18,-70,10,-127,-71,7,-130,-74,49,-125,"); + add("-55,104,-77,43,75,91,54,35,105,57,73,117,"); + add("53,89,117,73,-38,129,-4,82,10,35,49,76,"); + add("65,-40,116,5,32,15,-31,140,-26,-9,133,15,"); + add("53,62,116,26,133,85,38,28,81,59,-90,93,"); + add("25,88,73,47,-149,54,56,-117,82,48,-93,74,"); + add("42,-130,54,50,-135,71,65,-82,116,50,-45,94,"); + add("7,-114,-9,4,-113,-15,66,-64,125,45,19,101,"); + add("66,-38,135,57,-93,104,62,-52,127,54,-50,112,"); + add("33,-153,44,46,-120,83,52,-101,102,42,-120,79,"); + add("45,-118,87,46,-102,92,58,-44,133,58,-36,134,"); + add("57,-37,135,57,-22,139,54,-54,127,26,-133,49,"); + add("25,-75,56,18,-121,35,29,-156,57,6,-124,5,"); + add("-9,-102,-29,81,61,215,46,78,129,40,25,111,"); + add("57,3,156,39,94,117,26,50,77,42,-95,109,"); + add("33,-121,83,9,-151,16,29,-118,75,13,-155,32,"); + add("-4,-158,-18,-19,-112,-56,-28,-126,-82,14,-146,40,"); + add("-12,-145,-30,-32,-83,-88,-10,-97,-26,-50,-35,-138,"); + add("-38,-109,-101,-29,-130,-70,7,-157,32,-8,-110,-14,"); + add("-22,-139,-46,-22,-167,-40,-8,-126,-4,-26,-111,-54,"); + add("-57,-16,-152,-43,-3,-113,-56,-11,-142,-51,28,-136,"); + add("-43,22,-113,-17,22,-44,-20,-161,-27,-26,-159,-42,"); + add("-61,77,-162,-61,-39,-142,-50,59,-128,-32,100,-89,"); + add("-26,34,-66,-52,-93,-110,-56,-29,-123,-35,-99,-66,"); + add("-53,64,-130,-44,15,-99,-56,-73,-114,-34,-133,-54,"); + add("-13,-154,-5,-33,-74,-59,-56,70,-131,-55,59,-128,"); + add("-58,55,-130,-56,67,-126,-38,95,-92,-27,130,-73,"); + add("4,111,-6,-20,68,-47,-22,171,-65,-39,115,-88,"); + add("28,83,49,20,62,35,10,163,7,-47,142,-102,"); + add("-36,123,-79,-12,41,-25,-60,19,-119,-48,126,-100,"); + add("-59,63,-115,-4,145,-12,19,146,35,-8,159,-15,"); + add("-17,144,-31,-32,136,-60,-51,96,-94,-20,76,-35,"); + add("-5,39,-8,-65,-89,-125,-68,-15,-126,-73,10,-133,"); + add("-26,105,-43,53,108,101,61,93,116,55,87,108,"); + add("53,95,104,32,132,70,-50,137,-83,32,133,71,"); + add("38,140,87,23,98,55,49,127,109,6,116,26,"); + add("20,83,51,-86,28,-162,-47,53,-82,38,99,86,"); + add("20,88,52,"); + add(""); + //add("/*8*/"); + add("165,1,-3761,29749,925,"); + add("105,16,-88,20,5,-115,-80,-9,-37,-29,-3,-31,"); + add("-47,-4,-80,-110,-14,-41,-136,-19,81,-100,-17,132,"); + add("1,1,-30,72,13,-169,33,6,-71,95,14,-116,"); + add("-71,-8,-70,-163,-23,48,0,1,-106,9,2,-129,"); + add("-147,-21,-153,-110,-16,31,-7,-1,135,-53,-8,-61,"); + add("-122,-19,-35,-63,-10,95,83,11,213,-84,-12,-44,"); + add("-61,-9,-181,-128,-21,73,71,11,96,120,18,87,"); + add("71,9,180,-31,-5,-34,-70,-9,-133,-142,-22,-76,"); + add("-76,-13,72,82,11,161,14,1,95,-8,-5,121,"); + add("111,15,104,152,24,26,154,20,94,-47,-7,-9,"); + add("-156,-22,-41,-25,-8,124,-41,-6,-17,-91,-11,-125,"); + add("-40,-8,50,-29,-4,-16,-67,-7,-129,-78,-9,-150,"); + add("-110,-19,4,-113,-22,102,-96,-21,116,-46,-7,-35,"); + add("58,13,-93,118,23,-94,104,20,-112,24,7,-151,"); + add("-68,-11,-87,-130,-23,56,-120,-22,56,-114,-23,91,"); + add("-158,-31,75,-82,-16,16,15,-2,197,-113,-21,-44,"); + add("25,8,-118,19,7,-151,-71,-13,-140,-128,-25,-53,"); + add("-165,-34,-4,8,0,136,119,23,111,-68,-14,33,"); + add("-86,-18,2,-119,-25,-28,-119,-27,44,-30,-9,120,"); + add("205,42,85,-71,-15,8,-158,-33,-60,-80,-16,-72,"); + add("15,6,-141,110,26,-69,106,24,-103,-43,-8,-138,"); + add("-141,-31,34,-114,-26,87,-72,-16,-23,-46,-10,-142,"); + add("-126,-28,-99,-150,-36,4,32,7,90,-57,-14,93,"); + add("15,2,148,-64,-18,122,50,10,115,89,18,123,"); + add("30,3,144,-27,-10,120,-120,-32,101,30,2,119,"); + add("126,25,109,91,18,84,144,33,-15,-11,3,-107,"); + add("91,23,-68,12,8,-124,0,6,-162,115,26,-25,"); + add("-3,-2,51,-49,-16,139,46,4,146,133,26,68,"); + add("161,36,-43,69,8,150,100,19,16,75,13,51,"); + add("97,23,-71,60,8,68,132,27,-12,35,13,-141,"); + add("-62,-5,-151,42,10,-41,84,13,67,50,5,82,"); + add("-5,-8,156,61,14,-56,-16,6,-192,78,13,33,"); + add("36,0,138,75,7,128,133,27,-61,21,0,70,"); + add("44,-1,150,152,29,-54,167,24,52,92,10,74,"); + add("145,21,23,139,18,43,150,19,39,151,18,47,"); + add("11,7,-78,-117,-10,-95,-148,-15,-126,48,7,13,"); + add("141,14,96,37,12,-110,20,0,43,101,6,127,"); + add("105,9,88,154,15,60,145,17,13,77,17,-129,"); + add("66,14,-106,21,9,-121,-130,-8,-126,76,8,5,"); + add("41,9,-86,-23,5,-159,-33,-1,-85,-109,-11,-52,"); + add("25,6,-75,8,5,-139,-90,-10,-11,-124,-18,83,"); + add(""); + //add("/*9*/"); + add("141,-1,-21883,20471,1436,"); + add("65,72,-30,87,96,-65,100,105,-11,107,111,-3,"); + add("102,102,54,109,109,17,92,90,60,101,90,127,"); + add("-65,-68,57,36,31,57,109,106,20,79,70,98,"); + add("111,104,51,-8,-21,150,-38,-50,135,-36,-49,136,"); + add("-43,-57,130,-92,-95,31,-111,-115,37,-111,-111,-3,"); + add("-90,-84,-66,-92,-84,-97,-97,-100,-2,16,3,123,"); + add("93,86,76,54,39,143,-62,-78,107,-99,-108,41,"); + add("-99,-110,38,-57,-72,90,77,63,126,93,86,74,"); + add("105,111,-16,107,112,-13,106,102,39,99,89,73,"); + add("106,107,-9,100,116,-107,24,10,84,-82,-96,103,"); + add("-64,-76,75,-8,-30,135,-15,-42,160,116,101,83,"); + add("60,64,-21,94,106,-86,61,78,-109,63,76,-93,"); + add("73,86,-101,3,26,-151,0,22,-151,9,29,-154,"); + add("2,22,-155,-15,3,-139,-8,9,-146,7,24,-151,"); + add("28,40,-138,43,54,-139,91,89,-30,73,74,-77,"); + add("119,111,-7,88,89,-104,118,108,-11,24,31,-124,"); + add("-13,-1,-150,60,61,-116,100,93,-69,110,101,-66,"); + add("28,31,-127,-2,5,-150,26,30,-153,34,34,-165,"); + add("-125,-107,-95,-72,-60,-133,-3,0,-117,-97,-86,-61,"); + add("-81,-72,-89,-64,-57,-131,-43,-39,-140,-43,-40,-140,"); + add("-67,-63,-120,-81,-77,-105,-74,-71,-112,-82,-81,-130,"); + add("-45,-39,74,36,37,155,35,36,139,-75,-70,33,"); + add("-34,-31,69,-4,-3,150,54,51,132,31,29,142,"); + add("51,45,135,68,61,144,-91,-86,86,-2,-5,78,"); + add("4,-1,145,-62,-61,110,-67,-69,114,-13,-20,160,"); + add("38,29,127,56,45,132,16,4,152,38,22,175,"); + add("-80,-81,76,-9,-21,153,-37,-46,111,-91,-95,80,"); + add("-42,-32,-78,-24,-11,-141,0,11,-124,24,35,-148,"); + add("-54,-41,-140,-27,-15,-151,-85,-77,-108,9,12,-37,"); + add("14,18,-89,-17,-13,-76,-97,-91,-71,-97,-92,-70,"); + add("-97,-94,-70,-126,-123,-92,37,32,153,-110,-113,18,"); + add("-105,-107,-20,-102,-103,-53,-103,-107,-10,-100,-104,-41,"); + add("-103,-108,0,-99,-109,34,-103,-112,0,-102,-112,13,"); + add("-90,-102,61,-85,-99,76,-3,-10,140,58,57,128,"); + add("87,91,82,94,99,65,100,107,35,102,110,3,"); + add(""); + //add("/*10*/"); + add("132,1,25827,-2922,-14981,"); + add("-63,23,-112,19,140,5,21,141,11,-16,138,-50,"); + add("13,153,-1,15,150,2,6,149,-11,-3,144,-22,"); + add("16,158,7,42,141,56,-44,112,-86,-60,83,-109,"); + add("-75,-8,-126,-28,-102,-36,-4,-168,10,29,-144,65,"); + add("-51,-124,-70,-63,-96,-91,-77,-86,-116,-10,-125,1,"); + add("4,-160,31,-56,-106,-75,-92,-2,-147,-29,144,-68,"); + add("-75,45,-127,-81,15,-127,-33,114,-68,61,79,85,"); + add("42,105,52,77,107,108,-6,149,-27,-10,119,-28,"); + add("50,128,66,63,116,89,43,135,59,58,105,86,"); + add("82,146,124,-61,9,-101,-61,102,-105,-75,53,-123,"); + add("-69,72,-112,-53,112,-89,-48,117,-79,-64,75,-102,"); + add("-81,-47,-121,-42,124,-68,69,87,103,89,-54,137,"); + add("55,-52,87,80,8,126,72,-53,115,74,-45,120,"); + add("77,43,124,66,-102,111,43,-122,76,61,-53,103,"); + add("75,38,125,38,141,57,63,82,104,52,115,88,"); + add("20,146,31,1,150,0,-27,141,-45,-44,124,-75,"); + add("-68,67,-115,-74,-34,-125,-76,-10,-127,-81,22,-133,"); + add("-73,11,-119,-75,-29,-121,-79,18,-125,-87,6,-138,"); + add("-72,-3,-112,-84,-17,-131,-72,-76,-110,-85,-8,-128,"); + add("-84,18,-126,-83,27,-122,-79,62,-115,-46,119,-65,"); + add("-62,111,-87,-57,114,-77,-48,140,-63,17,126,30,"); + add("71,-46,100,74,-113,101,46,-90,63,68,-92,97,"); + add("80,-71,115,82,-11,122,81,24,124,77,22,118,"); + add("83,-36,125,78,45,123,79,29,125,80,20,129,"); + add("77,10,124,72,58,119,63,41,105,81,33,135,"); + add("38,-108,60,49,-123,78,73,5,124,53,-60,89,"); + add("42,-121,70,42,-135,71,20,-165,34,-5,-129,-7,"); + add("-5,-218,-5,50,-60,89,37,-137,69,31,-131,61,"); + add("-2,-151,4,-6,-157,-1,35,-133,73,10,-147,30,"); + add("52,-105,103,11,-115,32,-4,-145,7,-35,-179,-41,"); + add("-67,-3,-120,-71,-23,-124,-23,-150,-21,-35,-129,-43,"); + add("-10,-165,6,8,-149,38,1,-148,26,17,-139,57,"); + add("-25,-158,-14,-61,-75,-93,-72,30,-132,"); + add(""); + //add("/*11*/"); + add("133,1,29737,2888,-2716,"); + add("9,-113,-12,8,-138,-52,6,-140,-72,-2,-106,-100,"); + add("-2,-111,-113,-5,-99,-114,-5,-101,-110,-4,-106,-109,"); + add("-16,-34,-151,-6,-108,-107,-4,-123,-92,-4,-124,-82,"); + add("-10,-97,-118,1,-147,-41,-1,-134,-54,-18,-43,-138,"); + add("-15,-85,-133,-17,-73,-129,-13,-126,-116,-1,-136,-24,"); + add("-5,-142,-55,-5,-144,-46,-5,-143,-50,-6,-154,-42,"); + add("-20,-65,-126,-23,-73,-133,-11,-130,-64,-16,-117,-89,"); + add("-18,-115,-96,-18,-122,-91,-10,-146,-42,-19,-126,-84,"); + add("-15,-136,-61,-19,-130,-78,-8,-149,-12,-19,-137,-69,"); + add("-25,-105,-103,-24,-111,-94,-22,-131,-73,-26,-107,-100,"); + add("-31,-88,-120,-31,-93,-119,-21,-139,-52,-30,-107,-102,"); + add("-33,-90,-116,-33,-98,-110,-35,-84,-122,-34,-94,-108,"); + add("-38,-70,-134,-36,-100,-107,-31,-118,-80,-38,-108,-108,"); + add("-50,-131,-143,11,129,-8,-21,16,-85,-51,-87,-158,"); + add("-12,85,-78,-28,-11,-98,-44,-106,-121,-14,86,-78,"); + add("11,150,-16,9,150,-19,11,150,-8,11,150,-5,"); + add("19,146,27,-2,156,-48,19,137,34,-6,148,-55,"); + add("-10,124,-58,31,104,87,28,122,77,29,133,80,"); + add("43,39,151,41,13,150,34,-129,151,1,99,-15,"); + add("-14,144,-74,34,85,116,16,106,50,12,151,27,"); + add("9,148,24,24,72,85,40,15,160,31,36,124,"); + add("31,99,122,-1,135,-10,6,103,22,-5,70,-21,"); + add("-27,80,-116,-8,134,-29,24,93,101,33,40,138,"); + add("30,-79,128,48,-65,208,-16,34,-70,-32,86,-138,"); + add("11,125,52,32,29,145,28,59,129,17,117,89,"); + add("8,142,49,21,102,112,25,64,128,25,57,130,"); + add("7,141,61,19,104,114,22,-104,94,17,33,97,"); + add("19,84,121,14,168,114,17,44,107,0,140,42,"); + add("12,110,102,17,81,126,13,95,116,16,79,127,"); + add("17,69,139,9,106,103,17,75,150,-6,95,13,"); + add("3,124,86,0,119,72,3,113,91,7,106,117,"); + add("19,1,150,14,39,141,19,-8,148,18,-11,149,"); + add("13,33,146,5,87,123,5,77,128,14,7,148,"); + add(""); + //add("/*12*/"); + add("129,-1,17606,18970,15171,"); + add("-13,-69,100,24,-118,119,79,-124,60,75,-119,57,"); + add("88,-117,38,105,-103,1,120,-58,-71,115,-15,-117,"); + add("107,-39,-82,114,-100,-19,119,-75,-55,119,-64,-69,"); + add("111,-41,-90,109,-28,-102,103,-17,-111,72,31,-131,"); + add("75,26,-129,69,33,-132,71,28,-131,83,13,-127,"); + add("26,2,-40,-103,181,-91,-89,118,-32,-85,121,-42,"); + add("-65,119,-69,-79,119,-52,-55,115,-80,-90,101,-15,"); + add("-97,78,26,-117,33,112,-71,83,-19,27,21,-65,"); + add("43,18,-83,-112,123,-21,-104,-5,146,-111,83,31,"); + add("-87,114,-44,-49,113,-96,-21,93,-105,128,-44,-107,"); + add("73,-19,-72,88,-33,-72,52,40,-132,35,56,-132,"); + add("-61,93,-54,-129,77,65,-119,82,41,-103,112,-27,"); + add("-111,101,-2,-98,4,127,-60,-33,129,37,-112,118,"); + add("76,-104,52,43,-80,60,-175,159,-1,-94,108,-37,"); + add("-68,104,-66,-36,102,-106,-71,91,-44,-136,52,97,"); + add("-108,31,93,-127,86,30,-99,45,57,-105,116,-45,"); + add("-116,93,3,-111,99,-15,-114,71,31,-118,47,69,"); + add("-37,83,-81,105,-3,-124,117,-34,-92,23,30,-75,"); + add("-173,114,35,-11,82,-119,-5,84,-127,73,16,-120,"); + add("99,0,-126,103,-17,-107,50,18,-95,-136,110,-8,"); + add("-28,92,-120,-61,101,-93,-100,104,-49,-77,98,-69,"); + add("-117,55,57,-84,-14,134,-69,-10,106,-112,43,68,"); + add("-117,32,91,-63,-37,142,-40,-45,124,-33,-54,130,"); + add("-51,-57,155,-69,-21,116,16,-82,112,-33,-62,136,"); + add("6,-73,108,-68,-55,161,-91,-26,142,-28,-31,78,"); + add("65,-125,116,26,-99,118,-5,-63,97,3,-96,136,"); + add("113,-74,-14,126,-73,-31,128,-109,16,69,-71,25,"); + add("101,-143,90,74,-109,72,117,-96,4,112,-93,3,"); + add("122,-91,-11,116,-97,3,118,-79,-27,124,-87,-23,"); + add("119,-92,-12,104,-107,22,117,-94,-11,115,-91,-14,"); + add("122,-32,-100,119,-63,-59,6,-38,42,-102,-1,123,"); + add("-37,-76,143,51,-113,87,48,-116,92,70,-87,27,"); + add(""); + //add("/*13*/"); + add("124,1,19067,-11237,20253,"); + add("-33,-122,-37,-29,-151,-59,-10,-135,-68,31,-113,-96,"); + add("-3,-132,-75,-21,-117,-50,-58,-142,-31,-39,-139,-48,"); + add("-8,-125,-70,25,-112,-96,-3,-132,-82,61,-101,-125,"); + add("57,-50,-88,90,-39,-116,62,-82,-117,98,-12,-107,"); + add("113,52,-80,114,71,-69,115,51,-85,112,14,-108,"); + add("112,48,-86,99,84,-50,84,137,2,78,132,5,"); + add("79,128,-2,81,128,-4,66,137,16,73,133,6,"); + add("68,135,11,59,138,20,67,136,10,71,133,3,"); + add("77,128,-9,71,135,1,69,135,2,65,138,8,"); + add("63,138,7,66,137,4,74,132,-11,62,123,-2,"); + add("67,148,4,69,134,-8,66,137,-2,71,133,-13,"); + add("70,134,-12,64,138,-4,50,138,11,55,142,6,"); + add("15,140,50,55,141,4,81,114,-42,53,86,-22,"); + add("56,154,5,10,135,49,5,138,55,14,146,47,"); + add("79,50,-71,13,-135,-75,51,-82,-97,83,123,-46,"); + add("60,141,-11,13,136,44,-18,131,76,3,142,54,"); + add("22,147,34,18,146,35,14,147,40,-2,145,57,"); + add("-2,136,52,-8,136,58,-47,91,89,-15,145,67,"); + add("-63,151,124,-75,-67,64,-95,-104,75,-2,-149,-48,"); + add("-41,-140,-2,-54,-146,9,-100,-65,91,-94,-118,63,"); + add("-71,56,100,-64,-50,53,-14,-217,-65,-54,-64,35,"); + add("-33,-189,-35,-79,-71,59,-81,-136,36,-8,95,45,"); + add("-59,-48,45,-115,-224,35,-47,52,72,-109,-77,85,"); + add("-93,-85,64,-42,-128,-9,-26,-34,14,-77,54,103,"); + add("-96,-1,98,-95,-83,64,-107,-29,96,-115,-54,94,"); + add("-101,-38,85,-108,-40,91,-38,-156,-28,-71,-134,14,"); + add("-84,-126,28,-80,-121,25,-45,-139,-18,-10,-135,-50,"); + add("-26,-143,-40,-12,-139,-52,16,-129,-77,-24,-134,-40,"); + add("6,-139,-73,2,-130,-66,-41,-141,-31,-45,-126,-20,"); + add("-86,-125,20,-83,-112,23,-94,-127,23,-69,-137,-6,"); + add("-101,-89,49,-79,-92,25,-68,-146,-15,"); + add(""); + //add("/*14*/"); + add("122,1,14146,19873,-17463,"); + add("104,-90,-18,-83,-22,-92,35,-96,-78,124,-19,79,"); + add("34,103,143,90,-59,8,110,-101,-22,114,-79,6,"); + add("38,-117,-98,122,-132,-43,-14,-100,-120,73,-117,-66,"); + add("97,-107,-32,92,-115,-44,111,-100,-11,100,-112,-31,"); + add("95,-109,-32,129,-66,43,117,-85,15,108,-105,-13,"); + add("122,-84,22,126,-56,55,128,-50,65,124,-60,52,"); + add("109,-21,80,-26,124,104,-148,120,-13,56,19,71,"); + add("123,-63,49,59,-112,-61,78,-122,-52,112,-100,3,"); + add("123,-89,27,116,-101,10,61,-129,-71,121,-80,37,"); + add("112,-15,95,39,56,95,115,1,116,111,-11,102,"); + add("120,-40,81,112,-13,103,119,3,127,79,17,103,"); + add("127,-51,83,113,-91,28,118,-84,42,118,-83,43,"); + add("122,-71,62,115,-81,46,105,-30,89,100,-76,36,"); + add("25,-102,-77,-105,-3,-123,-105,13,-106,-64,-64,-135,"); + add("-67,52,-22,-93,123,22,-79,-2,-89,-140,23,-128,"); + add("-81,13,-73,-106,51,-61,-130,25,-112,-119,61,-63,"); + add("-113,41,-75,-90,-25,-115,-91,-16,-107,-52,-37,-88,"); + add("133,-120,16,74,-125,-45,2,-108,-101,-17,-89,-99,"); + add("-88,-30,-115,-106,89,-20,-124,123,-4,-101,92,-11,"); + add("-128,42,-82,-65,56,-8,45,91,128,-73,118,44,"); + add("-75,-7,-77,-47,-80,-121,-48,-27,-69,-113,7,-97,"); + add("-123,-9,-120,-108,79,-23,-159,95,-51,5,-137,-123,"); + add("-122,86,-27,-72,118,46,-148,21,-106,-146,127,-5,"); + add("41,-97,-56,72,-134,-63,-73,11,-52,-131,69,-45,"); + add("-89,124,40,-123,82,-26,-54,64,16,6,109,107,"); + add("-49,118,71,-87,119,44,-104,108,19,-96,105,23,"); + add("-69,120,62,-46,118,80,-34,117,89,-106,120,36,"); + add("-113,25,-66,-58,35,-10,-57,106,63,-108,106,23,"); + add("-116,100,11,-90,116,51,-50,111,78,-30,116,99,"); + add("-18,105,98,26,93,122,-20,107,102,-61,115,79,"); + add("-36,99,82,"); + add(""); + //add("/*15*/"); + add("125,1,-1369,25599,15582,"); + add("-20,-57,92,-68,-54,82,2,-61,99,-37,-16,22,"); + add("-100,-31,38,-10,-85,134,26,-58,95,-46,-77,115,"); + add("-69,-80,116,34,-51,81,137,48,-60,11,-18,29,"); + add("-57,-58,82,-68,-102,148,-8,-72,106,-43,-121,173,"); + add("63,41,-53,40,81,-116,76,85,-120,50,-47,75,"); + add("20,-62,93,45,-78,120,-71,-85,116,-66,-81,111,"); + add("56,-59,90,165,12,-4,137,10,-5,179,39,-45,"); + add("-9,-27,39,-83,-86,117,38,-81,116,105,-49,74,"); + add("34,-64,90,-22,-82,111,-3,-101,137,-99,-17,17,"); + add("-155,-4,-5,-140,-41,46,-127,-85,103,77,-13,24,"); + add("88,-67,94,-29,-83,107,-108,-65,76,-141,-42,42,"); + add("-111,-69,79,75,-53,75,202,7,6,82,-38,55,"); + add("115,-27,42,136,-25,40,204,73,-82,-53,-57,69,"); + add("-93,-72,86,-150,-12,6,-157,0,-10,-113,-56,61,"); + add("-88,-76,87,-105,-74,82,-96,-71,78,-147,-70,71,"); + add("56,-32,44,112,17,-11,108,55,-57,163,21,-12,"); + add("143,-28,44,105,50,-54,71,78,-90,165,19,-14,"); + add("136,-37,50,150,25,-23,162,43,-49,127,8,-6,"); + add("109,-13,17,169,11,-12,154,-12,15,143,34,-43,"); + add("126,40,-51,112,90,-113,-210,52,-62,51,85,-108,"); + add("113,70,-92,97,61,-79,47,88,-116,0,90,-117,"); + add("-95,69,-88,-143,26,-32,-149,-21,30,-109,7,-8,"); + add("53,94,-126,-68,83,-110,-171,63,-86,117,-4,5,"); + add("-23,73,-99,-29,82,-113,-91,80,-113,-134,48,-69,"); + add("-81,47,-67,-50,85,-123,-36,83,-120,-40,84,-123,"); + add("-91,65,-98,-114,49,-77,-131,10,-21,-170,-1,-8,"); + add("40,14,-19,158,50,-66,-58,48,-74,3,15,-24,"); + add("128,39,-52,79,68,-101,63,78,-116,60,76,-117,"); + add("10,69,-108,-137,20,-37,-150,3,-12,-151,2,-11,"); + add("-198,-25,27,48,56,-86,63,67,-102,116,55,-81,"); + add("73,86,-136,-130,13,-29,-172,-18,17,-125,4,-17,"); + add(""); + //add("/*16*/"); + add("107,1,-8155,28629,-3723,"); + add("43,22,74,114,43,87,145,42,14,39,-6,-131,"); + add("-6,-21,-148,-12,-24,-151,-31,-28,-139,-45,-33,-139,"); + add("-123,-45,-76,-72,-40,-127,-132,-55,-107,-93,-12,98,"); + add("-74,-20,6,-81,-15,60,-49,9,155,-49,7,153,"); + add("-17,-12,-53,-6,-18,-105,12,-19,-152,17,-19,-152,"); + add("-76,-38,-93,-155,-41,44,-84,-7,118,-71,-3,126,"); + add("-63,2,143,-30,12,149,-75,-6,125,-103,-19,106,"); + add("-136,-31,101,-16,-15,-73,31,-7,-125,82,8,-136,"); + add("74,5,-129,44,-8,-146,35,-12,-147,24,-16,-149,"); + add("-75,-40,-97,-153,-48,19,-124,-37,26,-124,-25,98,"); + add("-70,-3,130,-87,-6,156,-108,-36,9,-131,-53,-43,"); + add("-145,-48,26,-55,1,138,-46,7,166,-26,8,121,"); + add("-37,7,149,-13,15,152,41,34,148,-9,14,143,"); + add("35,29,142,108,52,114,-85,-25,61,-85,-21,96,"); + add("-99,-27,92,-83,-19,116,-72,-14,140,-20,5,146,"); + add("75,42,168,150,55,-9,-25,-22,-156,57,21,0,"); + add("115,40,-23,5,9,95,60,32,128,-63,-12,140,"); + add("52,26,98,134,46,-35,97,27,-97,155,43,-139,"); + add("47,9,-88,125,37,-72,145,44,-49,139,50,50,"); + add("140,47,24,142,44,-22,144,45,1,147,45,5,"); + add("142,44,11,142,40,-31,131,32,-77,69,7,-136,"); + add("-56,-26,-110,-156,-49,-36,-143,-44,-18,-138,-44,-21,"); + add("-157,-48,5,-91,-36,-72,53,10,-68,141,45,13,"); + add("149,46,9,140,43,3,135,34,-52,119,26,-86,"); + add("-104,-33,-24,-118,-38,-32,3,-15,-141,-15,-17,-108,"); + add("21,4,-18,108,45,108,134,33,-41,111,19,-114,"); + add("-69,-37,-145,-15,-19,-114,"); + add(""); + //add("/*17*/"); + add("87,1,-27734,11163,2489,"); + add("19,13,151,8,-8,114,41,66,143,46,87,101,"); + add("23,15,150,38,58,119,51,92,110,48,75,125,"); + add("23,8,151,18,-5,151,6,-45,174,-52,-82,-123,"); + add("-24,-76,54,7,-30,134,17,-24,175,11,-4,84,"); + add("6,-40,142,33,17,158,-21,-103,125,-4,-70,140,"); + add("15,-33,154,8,-44,138,29,4,148,30,2,146,"); + add("-31,-125,96,-43,-133,48,-13,-95,115,-1,-71,127,"); + add("28,-12,151,33,-11,167,-25,-118,92,-62,-109,-91,"); + add("-74,-129,-116,17,-35,132,34,9,138,41,21,144,"); + add("40,10,150,39,11,143,33,-10,147,25,-31,147,"); + add("56,28,174,28,1,102,54,47,133,73,59,183,"); + add("6,95,-110,5,98,-119,-18,56,-147,-34,13,-147,"); + add("-26,37,-156,35,105,-27,-16,51,-142,-12,48,-123,"); + add("-27,26,-158,-10,45,-116,2,88,-143,-4,36,-84,"); + add("21,121,-126,-13,-44,25,-7,-7,-22,-7,70,-162,"); + add("6,72,-113,2,72,-129,-1,62,-134,-11,32,-121,"); + add("-30,7,-168,-3,53,-136,23,103,-108,13,79,-121,"); + add("-15,27,-150,-4,57,-164,-12,16,-116,-19,16,-168,"); + add("-24,-5,-136,-8,24,-127,-17,10,-152,-24,-7,-150,"); + add("-40,-51,-137,-30,-23,-156,-24,-20,-131,-39,-54,-141,"); + add("-37,-48,-143,-37,-57,-129,-54,-104,-106,-60,-143,-8,"); + add("-25,-50,-49,-33,-45,-160,"); + add(""); + //add("/*18*/"); + add("90,1,-15425,23492,10498,"); + add("-58,1,-87,-121,-46,-78,-123,-67,-36,-115,-76,-3,"); + add("-150,-98,-10,-111,-74,-9,-121,-91,15,-123,-90,8,"); + add("-140,-124,52,-108,-53,-58,-57,-91,109,-74,-19,-79,"); + add("-202,-127,-49,-95,-37,-76,59,-35,174,-100,-68,-17,"); + add("-123,-69,-56,-124,-80,-33,-59,-94,103,93,5,144,"); + add("92,25,97,70,-9,131,68,-15,139,65,-15,129,"); + add("77,6,109,128,39,115,109,47,69,-18,-33,37,"); + add("-91,-67,-3,22,-20,72,98,36,73,82,22,76,"); + add("29,-15,71,-129,-75,-42,-126,-83,-24,-120,-48,-86,"); + add("-25,-57,73,105,25,106,117,75,26,167,94,60,"); + add("55,14,53,138,110,-15,49,4,59,-67,-110,114,"); + add("-92,-81,24,-126,-104,16,10,-33,73,137,84,35,"); + add("2,-23,44,-76,-97,73,64,-24,128,138,100,5,"); + add("95,91,-35,139,135,-62,-112,-42,-70,7,42,-68,"); + add("168,143,-38,-94,-29,-72,-151,-107,-5,9,60,-100,"); + add("90,96,-57,109,58,39,166,93,46,-59,6,-90,"); + add("-109,-28,-94,50,45,-17,31,65,-82,110,82,-11,"); + add("122,87,-4,-28,62,-160,-90,-9,-107,-88,-16,-91,"); + add("-105,-24,-103,-11,43,-103,-60,20,-130,24,49,-67,"); + add("143,89,25,-21,50,-137,-98,-37,-69,-144,-84,-36,"); + add("14,29,-42,109,90,-28,142,98,3,114,74,10,"); + add("124,88,-10,127,75,23,36,67,-95,60,35,11,"); + add("112,50,53,"); + add(""); + //add("/*19*/"); + add("80,1,1236,-19143,-23066,"); + add("4,78,-64,-62,100,-85,-134,51,-49,-152,-25,15,"); + add("-51,9,-9,-6,134,-109,-98,76,-64,-52,106,-86,"); + add("-10,119,-94,-47,131,-104,132,74,-53,141,-39,35,"); + add("96,-86,71,153,-52,48,130,28,-16,140,50,-31,"); + add("184,72,-44,56,78,-56,49,121,-89,49,124,-90,"); + add("106,96,-64,26,-76,59,-28,-145,107,111,52,-31,"); + add("185,68,-34,34,89,-64,6,109,-81,60,113,-78,"); + add("86,128,-85,-13,95,-70,101,119,-75,101,59,-31,"); + add("124,67,-35,156,44,-13,120,51,-21,106,128,-77,"); + add("17,-60,44,-97,-101,58,-37,-121,81,-126,-90,50,"); + add("-22,-105,73,-98,-107,66,-161,-157,98,46,101,-70,"); + add("-19,-20,13,-150,-66,33,-21,-114,83,18,-66,51,"); + add("-79,-123,84,-127,-26,8,17,-62,48,-18,-95,71,"); + add("-63,-151,111,6,-115,90,33,-74,61,33,-132,109,"); + add("18,-117,95,106,-71,68,134,-48,53,68,-90,81,"); + add("-95,-89,64,-140,-46,24,-125,-73,48,-147,-47,27,"); + add("-111,-103,77,4,-80,69,30,-117,102,69,-104,96,"); + add("78,-95,91,-65,-52,40,-140,-75,54,-125,9,-18,"); + add("-117,69,-70,-87,88,-83,-64,99,-91,-71,102,-93,"); + add("-83,99,-89,-74,93,-83,-53,144,-123,"); + add(""); + //add("/*20*/"); + add("78,1,24076,9507,-15164,"); + add("72,-75,68,83,5,136,48,63,117,50,69,127,"); + add("79,-2,131,85,-69,98,67,-149,17,60,-142,10,"); + add("52,-139,2,27,-144,-44,40,-147,-23,64,-144,24,"); + add("35,-135,-20,25,-149,-43,59,-44,76,45,108,140,"); + add("61,-134,28,0,-120,-68,28,-143,-33,12,-137,-55,"); + add("20,-151,-45,-23,-78,-82,-26,-143,-118,-68,139,-44,"); + add("-67,-35,-130,24,-122,-21,90,-111,95,35,-131,-5,"); + add("-23,-58,-67,-46,-79,-116,-75,-39,-142,-69,93,-69,"); + add("-87,51,-117,-59,-72,-129,-41,-96,-108,-47,-146,-139,"); + add("-34,112,-4,-4,168,69,-58,-22,-101,-27,-107,-90,"); + add("-54,-93,-123,-9,-131,-71,-31,-83,-82,-93,-54,-162,"); + add("-1,-132,-55,-55,5,-80,-40,175,12,68,60,126,"); + add("0,101,43,28,143,103,-85,78,-93,13,73,52,"); + add("75,54,137,65,-48,78,35,93,96,45,111,120,"); + add("71,12,116,83,-91,88,54,-93,43,68,62,137,"); + add("8,122,73,-16,158,51,-19,113,25,3,134,74,"); + add("-11,130,50,-77,145,-48,-38,135,11,-128,111,-146,"); + add("-35,5,-54,-60,122,-28,-72,141,-35,-64,134,-25,"); + add("-26,135,36,23,98,92,-11,145,69,-46,146,16,"); + add("-67,132,-25,"); + add(""); + //add("/*21*/"); + add("83,1,2308,-19901,-22330,"); + add("-8,114,-102,37,64,-52,88,-4,12,15,49,-40,"); + add("143,-68,75,129,-20,33,58,130,-108,117,79,-53,"); + add("13,52,-44,159,-88,97,48,-95,90,-6,-118,104,"); + add("58,-104,101,115,-73,82,56,-86,87,28,-109,103,"); + add("-44,-49,39,-48,15,-21,137,-79,94,23,-106,102,"); + add("64,-21,31,128,-64,81,82,-62,72,125,-95,113,"); + add("111,-64,83,114,-43,62,54,-65,75,180,-33,68,"); + add("104,-70,91,75,-72,87,52,-95,106,89,-78,99,"); + add("92,-69,91,5,-84,88,28,-42,50,48,-41,54,"); + add("4,-88,93,43,-78,93,-69,-50,36,-151,-62,32,"); + add("-151,13,-47,-142,-55,28,-128,-40,15,-81,-36,22,"); + add("-166,-20,-10,-139,5,-32,-122,48,-75,-90,81,-102,"); + add("-75,81,-98,-121,75,-99,-19,93,-100,-36,101,-109,"); + add("-26,116,-123,95,51,-36,-142,51,-74,-6,106,-106,"); + add("64,76,-66,-8,10,-11,-117,26,-43,-130,40,-58,"); + add("-86,73,-83,130,90,-69,113,80,-60,71,52,-39,"); + add("-183,-124,91,-130,-69,48,-122,-15,-2,-89,-14,2,"); + add("-131,22,-38,101,77,-61,147,37,-17,75,28,-16,"); + add("-148,29,-47,47,27,-20,-128,29,-44,-120,64,-75,"); + add("-75,86,-89,-59,105,-105,-82,82,-84,-50,84,-81,"); + add("-93,114,-114,49,50,-39,"); + add(""); + //add("/*22*/"); + add("75,1,27917,-4121,-10180,"); + add("-55,-66,-125,-56,-60,-126,-57,-37,-134,-56,-23,-138,"); + add("-57,-18,-139,-57,-16,-138,-52,10,-134,-62,-21,-142,"); + add("-61,-38,-134,-55,13,-137,-48,51,-133,-62,-38,-130,"); + add("-64,-61,-123,-62,-52,-121,-63,-24,-134,-50,5,-112,"); + add("41,208,16,8,151,-34,46,99,69,64,39,130,"); + add("58,-28,139,58,-13,139,55,6,125,62,60,126,"); + add("35,106,46,37,122,49,42,130,59,62,14,144,"); + add("57,36,129,58,46,132,53,31,124,56,17,137,"); + add("49,109,92,42,-55,128,5,-142,61,33,-69,114,"); + add("52,21,133,54,10,146,53,21,139,49,-6,144,"); + add("49,22,134,52,36,139,37,135,61,50,96,115,"); + add("46,11,137,45,32,130,49,64,129,44,70,117,"); + add("32,-31,117,40,-15,136,44,24,140,45,29,144,"); + add("27,-48,110,-1,-141,51,9,-110,80,19,-109,115,"); + add("9,-45,53,-52,-16,-181,-41,3,-146,-48,-63,-137,"); + add("-36,-68,-93,-17,-140,4,-49,-31,-150,-46,-12,-146,"); + add("-49,-24,-145,-48,-52,-130,-49,-60,-128,-51,-35,-140,"); + add("-46,9,-142,-41,48,-142,-48,-18,-133,-52,-9,-148,"); + add("-52,-31,-132,-42,-26,-108,"); + add(""); + //add("/*23*/"); + add("73,1,11139,23963,-14202,"); + add("89,-95,-89,96,-86,-67,88,-87,-74,62,-93,-103,"); + add("27,-75,-102,-2,-91,-146,41,-93,-115,103,-92,-64,"); + add("82,-97,-84,49,-95,-108,72,-97,-91,71,-97,-90,"); + add("86,-97,-78,85,-98,-77,102,-97,-62,46,-94,-100,"); + add("21,-93,-116,65,-102,-94,106,-97,-53,82,-103,-79,"); + add("46,-100,-102,94,-101,-63,99,-102,-60,50,-103,-98,"); + add("-12,-80,-115,-153,136,60,-137,87,12,-101,-27,-114,"); + add("-59,-43,-100,5,-82,-103,-106,161,132,58,36,92,"); + add("-16,109,132,-15,93,115,18,72,113,-37,101,112,"); + add("-80,99,76,-103,98,60,-102,95,58,-98,96,63,"); + add("-108,86,43,-123,40,-33,-120,-28,-129,-46,-66,-128,"); + add("-22,-79,-126,-11,-17,-32,10,103,152,-23,94,117,"); + add("-41,96,110,-32,94,113,-21,90,119,-28,91,115,"); + add("-49,95,107,-44,93,110,-39,90,110,-28,92,123,"); + add("-42,94,116,-47,86,103,-77,88,84,-61,43,25,"); + add("-122,144,145,-50,96,124,-25,80,115,-34,76,105,"); + add("-87,97,101,32,59,126,80,-38,-4,18,-93,-149,"); + add("66,-71,-71,143,-69,-8,122,-18,64,55,-58,-55,"); + add(""); + //add("/*24*/"); + add("68,1,24092,5088,-17137,"); + add("14,-98,-10,-5,-145,-48,33,-140,7,93,-40,121,"); + add("96,-9,134,49,-171,25,57,-37,72,72,-13,102,"); + add("56,-137,47,123,-90,158,-21,70,-12,-5,154,32,"); + add("54,76,103,63,-11,91,88,-70,116,54,-134,47,"); + add("83,-56,112,82,-37,119,74,-87,95,36,-142,21,"); + add("41,-143,30,42,-141,33,-57,-49,-101,-54,145,-53,"); + add("-54,139,-51,-58,116,-63,-56,-80,-107,-75,2,-114,"); + add("-74,-50,-126,-60,146,-55,-78,-17,-121,-65,-72,-115,"); + add("-30,-130,-74,58,-132,56,28,-144,10,-1,-148,-32,"); + add("-21,-132,-58,-60,-86,-105,-70,-71,-115,-78,-52,-121,"); + add("-71,72,-88,-25,-40,-43,3,-135,-19,-55,-11,-80,"); + add("-62,126,-66,-30,143,-15,18,145,53,41,111,80,"); + add("-43,155,-30,-89,144,-92,-48,-107,-90,-25,-135,-62,"); + add("-6,-187,-45,-28,47,-29,-26,172,-2,-61,91,-64,"); + add("-61,132,-55,-17,146,9,25,128,63,-10,163,25,"); + add("4,129,36,30,118,71,-41,143,-19,15,171,66,"); + add("51,99,98,43,85,85,56,91,104,"); + add(""); + //add("/*25*/"); + add("68,1,-3077,27485,11624,"); + add("-135,-30,35,-65,39,-111,-105,10,-54,-99,-64,121,"); + add("-154,-21,2,-120,1,-38,-66,-57,110,-20,0,-4,"); + add("-33,53,-136,-80,19,-73,-139,-60,93,-102,32,-111,"); + add("-81,-55,100,-91,-36,52,-127,-52,72,-35,8,-32,"); + add("-7,58,-140,67,56,-108,-25,45,-117,-63,49,-144,"); + add("-114,16,-88,21,-24,67,-45,-62,133,-100,18,-85,"); + add("-92,-30,34,-25,-40,85,-48,-17,20,-111,-25,13,"); + add("-18,-25,52,131,3,50,151,20,17,116,-18,89,"); + add("-92,-52,85,59,-27,87,-70,-19,17,-141,-8,-40,"); + add("-184,-28,-14,47,-17,60,159,-3,75,33,-37,97,"); + add("90,-9,58,-7,-32,70,-65,-57,100,-173,-51,44,"); + add("79,-27,92,165,9,44,126,-28,110,44,-40,104,"); + add("116,-19,81,130,-23,95,170,15,27,110,36,-41,"); + add("101,29,-31,152,19,8,146,34,-28,138,43,-54,"); + add("144,30,-24,160,37,-36,77,51,-91,115,46,-73,"); + add("38,28,-52,37,37,-73,19,40,-85,-72,46,-121,"); + add("-70,39,-109,-20,60,-144,37,49,-104,"); + add(""); + //add("/*26*/"); + add("58,1,-26874,10130,8671,"); + add("-30,19,-117,-23,66,-151,-42,6,-144,-51,-24,-138,"); + add("-43,-88,-36,31,-48,163,11,-85,140,-45,-130,7,"); + add("-25,-118,58,4,-100,125,-32,-83,-7,-62,-49,-143,"); + add("-43,6,-149,-37,19,-145,-34,20,-136,-35,25,-152,"); + add("-32,27,-147,-55,-103,-67,2,-78,105,18,-88,166,"); + add("54,57,120,44,9,138,34,-28,142,40,-11,145,"); + add("50,23,132,51,8,154,28,-48,138,-3,-114,107,"); + add("-6,-95,79,34,16,85,63,116,69,64,135,53,"); + add("68,67,128,18,-60,109,53,-3,152,69,87,106,"); + add("54,3,144,53,-1,142,48,-14,141,27,-65,128,"); + add("48,29,96,70,121,68,2,113,-98,-17,86,-124,"); + add("-46,19,-139,-52,52,-189,58,60,97,-4,42,-55,"); + add("-57,-7,-146,0,99,-97,-7,69,-95,-41,28,-142,"); + add("-35,39,-140,-28,57,-142,-55,-27,-132,-47,19,-160,"); + add("-67,-83,-107,"); + add(""); + //add("/*27*/"); + add("56,1,12962,21402,-16551,"); + add("83,-38,16,93,-94,-47,24,-103,-113,56,-107,-91,"); + add("92,-105,-58,75,-108,-76,119,-90,-15,74,-104,-67,"); + add("76,-102,-64,114,-19,69,123,34,142,74,-101,-62,"); + add("123,-89,-5,138,-68,34,93,-120,-65,-16,-90,-120,"); + add("45,-102,-82,78,-121,-75,-106,20,-66,-130,85,-8,"); + add("-111,-5,-96,-35,58,38,51,73,126,74,50,120,"); + add("-52,98,73,-114,32,-57,-59,-67,-127,-156,66,-47,"); + add("-124,18,-77,-72,-56,-123,-64,-63,-122,-78,-53,-119,"); + add("-108,-43,-130,-113,119,50,-117,97,24,-127,81,-1,"); + add("-135,60,-29,-130,-6,-100,-136,31,-61,-222,90,-51,"); + add("53,27,67,-12,111,120,-41,101,89,-122,116,52,"); + add("50,-4,30,133,-79,0,125,-16,70,73,54,116,"); + add("107,29,113,63,62,122,53,69,124,39,77,125,"); + add("17,88,122,19,86,122,28,80,125,"); + add(""); + //add("/*28*/"); + add("49,1,-6596,29135,-2761,"); + add("64,5,-105,143,26,-49,-45,-23,-137,-7,-11,-80,"); + add("-52,-24,-120,-117,-14,109,-4,-7,-48,12,-16,-167,"); + add("-112,-12,117,-20,-17,-107,15,-13,-142,-115,-29,-16,"); + add("-102,-10,120,-70,-4,110,64,35,178,-97,-24,-2,"); + add("-46,4,143,-51,3,152,-58,-16,-15,11,-11,-139,"); + add("-6,-17,-145,-41,-26,-149,-146,-33,37,-68,-3,132,"); + add("2,16,151,51,28,150,21,17,128,12,17,157,"); + add("-43,0,130,-45,0,144,64,25,116,130,38,77,"); + add("128,36,64,141,33,-25,-48,-21,-136,56,7,-87,"); + add("145,32,-32,156,37,20,155,37,21,5,-7,-104,"); + add("-96,-31,-111,-131,-29,5,-136,-35,-40,-164,-37,32,"); + add("-15,-13,-109,72,4,-146,157,33,-47,128,29,-12,"); + add(""); + //add("/*29*/"); + add("50,1,-2179,24668,16933,"); + add("-94,-47,56,-114,2,-19,-121,-63,74,-71,-57,72,"); + add("55,-51,81,-74,-79,100,-74,-24,23,-140,1,-23,"); + add("-215,-15,-16,15,-80,115,25,-50,74,-131,-82,90,"); + add("69,-50,81,176,-48,94,-77,-77,92,-116,-97,110,"); + add("78,-13,30,150,24,-7,-7,-19,24,-155,-21,3,"); + add("-117,-60,58,-114,-68,70,-67,-96,113,136,-15,44,"); + add("-56,-41,42,101,-3,22,-24,-38,44,40,-22,35,"); + add("140,9,12,156,30,-14,130,61,-59,134,30,-19,"); + add("124,54,-53,169,33,-22,148,16,-3,87,67,-77,"); + add("60,91,-113,54,87,-110,-12,100,-135,4,79,-107,"); + add("-34,87,-123,50,59,-77,130,54,-61,66,69,-90,"); + add("-38,83,-120,-40,70,-104,-66,70,-108,-232,-9,-14,"); + add("-56,48,-76,"); + add(""); + //add("/*30*/"); + add("50,1,-8496,-28645,2696,"); + add("6,7,97,49,0,144,24,8,146,-32,25,135,"); + add("-71,36,135,-115,45,86,-123,47,78,-138,48,41,"); + add("-135,49,46,-138,49,36,-143,49,26,-145,47,-16,"); + add("-142,48,4,-141,51,18,-144,51,5,-134,43,-34,"); + add("-154,58,22,-65,9,-110,10,-22,-149,67,-40,-132,"); + add("140,-51,-5,133,-47,2,131,-52,-59,147,-52,-17,"); + add("62,-38,-146,114,-35,26,94,-18,115,144,-49,-11,"); + add("-14,-13,-167,-62,6,-134,96,-33,-22,-1,-9,-91,"); + add("43,-21,-74,-3,-8,-95,16,-15,-117,27,-18,-104,"); + add("129,-41,-1,104,-23,110,-59,29,117,5,7,92,"); + add("-49,28,130,53,-10,69,122,-30,76,62,-26,-69,"); + add("82,-16,90,54,-17,-7,-33,-5,-145,-65,6,-150,"); + add("110,-37,-35,"); + add(""); + //add("/*31*/"); + add("48,1,-16082,-24523,6323,"); + add("62,-6,135,71,-10,133,70,-10,134,98,-29,121,"); + add("35,19,149,50,7,135,-18,47,120,-72,37,-32,"); + add("-70,7,-129,-108,41,-100,-120,59,-71,-114,52,-85,"); + add("-119,59,-75,-119,66,-48,-126,76,-37,-158,98,-42,"); + add("-90,76,48,-125,77,-41,-60,16,-96,-79,27,-111,"); + add("6,-32,-100,10,-53,-177,66,-69,-86,106,-91,-66,"); + add("77,-31,92,56,6,173,62,-71,-105,26,-52,-137,"); + add("124,-87,-10,104,-47,95,106,-45,107,63,-54,-47,"); + add("-33,17,-21,-78,27,-102,-70,21,-104,-120,44,-157,"); + add("127,-72,60,-25,-5,-96,-64,3,-173,-15,-21,-138,"); + add("61,-36,23,33,3,116,90,-31,126,78,-22,127,"); + add("38,8,137,98,-37,112,48,5,145,"); + add(""); + //add("/*32*/"); + add("48,-1,-13245,26217,-6103,"); + add("-33,17,145,9,34,134,88,65,92,-23,16,132,"); + add("-12,24,141,56,55,134,71,62,134,67,53,99,"); + add("20,37,146,-27,10,130,31,23,44,30,2,-71,"); + add("45,45,128,43,-2,-129,7,-27,-165,-8,-15,-61,"); + add("47,61,209,-28,10,131,-81,-16,134,-34,-3,80,"); + add("147,46,-148,50,-2,-145,-7,-31,-150,-67,-54,-119,"); + add("-76,-59,-114,-44,-49,-140,20,-21,-151,57,0,-131,"); + add("122,46,-65,113,36,-81,117,32,-108,125,38,-90,"); + add("10,-8,-59,-144,-53,65,-133,-61,10,-154,-69,24,"); + add("-2,-31,-133,-11,-33,-121,-82,-67,-111,-15,-28,-88,"); + add("70,3,-126,39,-12,-127,20,0,-39,-135,-43,95,"); + add("-98,-23,100,-103,-25,110,-57,2,125,"); + add(""); + //add("/*33*/"); + add("47,1,-6930,29187,-252,"); + add("-51,-13,-133,84,20,-8,117,26,-82,65,13,-132,"); + add("-2,-5,-157,-116,-27,-23,-134,-30,78,-112,-25,89,"); + add("-11,1,173,-70,-16,98,-136,-33,52,-146,-37,22,"); + add("-139,-36,-46,-134,-35,28,-161,-44,34,-27,-6,117,"); + add("-79,-21,134,90,24,168,-115,-32,93,2,-2,158,"); + add("22,5,108,34,6,130,-10,-5,92,109,26,166,"); + add("-73,-24,108,-11,-8,138,67,12,154,164,41,55,"); + add("91,26,-33,146,35,46,85,27,-99,66,22,-142,"); + add("32,14,-143,-39,-5,-156,-64,-13,-131,-91,-20,-132,"); + add("-61,-15,-91,53,16,-144,-4,1,-154,36,9,-107,"); + add("132,34,-37,32,8,-118,82,20,-41,55,14,123,"); + add("133,32,-108,101,24,-60,"); + add(""); + //add("/*34*/"); + add("48,1,1042,29488,5419,"); + add("98,-20,87,52,-28,136,48,-30,145,90,-18,74,"); + add("119,-22,80,56,21,-116,10,26,-136,46,1,-20,"); + add("77,-17,65,58,4,-37,18,-24,117,-127,-21,144,"); + add("-84,-16,96,66,-25,107,145,9,-82,87,-4,-10,"); + add("-100,-22,137,57,-12,41,-157,-3,54,75,-34,135,"); + add("146,-18,44,54,-16,58,120,-27,82,3,44,-197,"); + add("-15,34,-151,32,26,-132,-23,34,-158,6,27,-135,"); + add("-22,32,-159,62,22,-133,69,16,-114,-170,29,-92,"); + add("-124,18,-61,-124,26,-103,-78,29,-141,-134,10,-20,"); + add("-23,-23,141,58,-27,135,68,-27,132,-9,-7,38,"); + add("-96,31,-142,-74,27,-129,-76,1,11,-52,-14,94,"); + add("-74,27,-137,-106,-7,63,-63,-14,94,"); + add(""); + //add("/*35*/"); + add("44,-1,14587,-2200,26122,"); + add("18,-53,-14,-39,-136,9,-28,-156,1,7,-151,-19,"); + add("52,-138,-43,34,-136,-35,-65,-137,21,28,-129,-31,"); + add("52,-143,-48,40,-135,-40,75,-119,-60,98,-83,-68,"); + add("86,-101,-64,19,-146,-33,37,-140,-44,83,-113,-67,"); + add("-4,-196,-31,100,-60,-69,118,-90,-87,54,91,-17,"); + add("-44,128,50,-47,126,49,-53,138,54,-57,134,55,"); + add("-15,150,31,-10,135,26,-63,145,57,-85,114,65,"); + add("-118,38,73,-68,131,56,69,122,-25,18,132,6,"); + add("-48,139,43,18,150,5,-67,130,52,3,147,12,"); + add("-9,143,18,-54,138,43,-47,140,37,-31,192,31,"); + add("-63,-85,29,-21,-147,1,-15,-153,-4,"); + add(""); + //add("/*36*/"); + add("44,-1,15944,24781,-5628,"); + add("93,-52,33,124,-87,-25,126,-79,19,127,-81,15,"); + add("127,-78,31,126,-81,22,126,-81,26,115,-62,80,"); + add("121,-74,51,111,-60,83,122,-74,64,118,-78,32,"); + add("107,-60,81,101,-54,99,119,-77,53,109,-66,77,"); + add("84,-39,121,67,-26,127,73,-22,171,52,-52,-63,"); + add("-4,-26,-148,-53,14,-135,-74,29,-129,-81,36,-126,"); + add("-113,69,-72,-121,88,-11,-87,45,-87,-77,36,-94,"); + add("-102,53,-98,-84,33,-122,-109,58,-87,-116,73,-41,"); + add("-107,52,-101,-84,68,40,-92,63,-6,-26,-2,-86,"); + add("-130,82,-29,-117,83,11,-119,89,37,-124,82,-1,"); + add("-123,85,16,-125,86,20,-122,95,65,"); + add(""); + //add("/*37*/"); + add("44,1,6601,28935,4379,"); + add("16,-21,118,74,-36,115,54,-21,53,5,-26,150,"); + add("77,-36,110,77,-8,-64,63,-35,120,137,-8,-153,"); + add("99,-9,-94,-67,34,-105,-78,32,-79,1,17,-112,"); + add("-95,35,-77,-28,26,-131,-93,35,-87,-13,23,-140,"); + add("-53,31,-142,-50,24,-95,-39,28,-148,-21,25,-161,"); + add("-7,20,-157,6,15,-149,-10,18,-150,-12,18,-148,"); + add("-31,21,-151,-53,22,-115,-115,35,-98,-143,30,10,"); + add("-62,2,131,40,-23,150,77,-27,112,14,-20,162,"); + add("-14,-14,160,-51,-2,116,-35,-8,136,20,-18,110,"); + add("-6,-21,176,29,-27,157,59,-32,142,15,-21,127,"); + add("45,-28,124,126,-39,69,80,-10,-54,"); + add(""); + //add("/*38*/"); + add("42,-1,-10564,27211,-6925,"); + add("-102,-15,98,-92,-3,131,66,56,126,44,48,128,"); + add("-57,9,136,-104,-63,-95,-54,-66,-186,-40,2,75,"); + add("9,41,155,35,51,160,133,62,44,-1,29,132,"); + add("-131,-12,184,91,59,109,63,45,100,124,63,73,"); + add("24,-12,-107,-3,-29,-133,85,0,-151,111,20,-101,"); + add("62,43,91,5,40,175,101,33,-17,61,-4,-125,"); + add("29,-22,-150,4,-30,-141,29,-27,-165,44,-16,-138,"); + add("31,-22,-139,26,-52,-249,-70,-3,91,-103,-4,137,"); + add("-17,20,107,-68,9,145,-127,-29,83,-63,-37,-57,"); + add("112,8,-146,-59,-26,-18,-81,-51,-84,-38,-43,-113,"); + add("-39,-46,-124,"); + add(""); + //add("/*39*/"); + add("42,-1,15744,-1075,25514,"); + add("6,-136,-9,63,-186,-49,95,83,-55,94,90,-55,"); + add("119,-70,-79,97,-30,-63,12,-169,-17,55,17,-35,"); + add("-7,158,13,95,44,-59,122,-38,-82,132,139,-81,"); + add("-154,62,105,36,92,-19,83,111,-51,82,122,-51,"); + add("58,107,-36,70,141,-44,14,129,-6,26,143,-16,"); + add("116,32,-79,133,71,-91,-25,92,18,-136,-72,93,"); + add("-92,61,63,-65,100,44,-74,99,49,-106,9,71,"); + add("-92,63,61,-106,-54,69,-100,-66,66,-117,11,75,"); + add("-123,-63,78,-116,-49,73,-53,-98,33,-59,-142,36,"); + add("-45,-145,26,35,-135,-25,-5,-167,0,-37,-133,19,"); + add("-39,-149,18,"); + add(""); + //add("/*40*/"); + add("41,-1,10098,22921,16512,"); + add("73,-48,22,138,-59,-3,139,-57,-9,146,-60,-11,"); + add("142,-45,-30,126,-12,-66,134,-54,-16,141,-51,-25,"); + add("138,-54,-20,147,-37,-50,94,-98,68,58,-99,93,"); + add("28,-94,108,-126,-8,97,-117,-8,91,-8,-77,107,"); + add("-15,-95,133,-18,-79,114,-148,-47,156,50,10,-45,"); + add("121,26,-112,31,60,-98,25,112,-163,21,49,-78,"); + add("108,22,-104,142,-26,-64,12,61,-90,-98,100,-65,"); + add("-59,95,-88,-67,119,-116,-45,3,27,-138,24,63,"); + add("-147,67,8,-111,47,11,-158,44,44,-137,49,23,"); + add("-164,88,-15,-109,6,60,-145,39,38,-141,48,21,"); + add(""); + //add("/*41*/"); + add("41,1,13989,-2192,-26448,"); + add("86,-38,49,159,11,84,-19,-147,3,-25,-168,2,"); + add("103,-47,60,110,-69,67,65,-124,49,84,-90,56,"); + add("118,-11,68,123,-16,72,99,59,50,-6,147,-20,"); + add("43,4,25,33,-150,35,103,-59,67,125,-26,76,"); + add("126,17,72,128,20,76,129,3,77,96,-39,64,"); + add("-67,-118,-28,-129,-48,-73,-115,-87,-58,-94,-19,-54,"); + add("-126,-33,-70,-108,-70,-55,-133,3,-77,-126,3,-73,"); + add("-125,47,-77,-109,65,-69,-126,46,-76,-104,90,-67,"); + add("-74,114,-54,-136,14,-74,-116,80,-71,47,156,9,"); + add("-83,70,-51,-84,109,-55,3,156,-13,72,103,29,"); + add(""); + //add("/*42*/"); + add("42,-1,119,4674,29633,"); + add("-31,-95,15,-26,-156,24,18,-132,19,-62,-159,23,"); + add("-136,104,-15,-64,53,-8,-123,30,-5,-88,126,-20,"); + add("-38,71,-11,-139,147,-25,-6,-84,13,-198,-34,1,"); + add("59,0,1,140,-44,10,126,-68,12,76,-142,22,"); + add("77,-71,11,119,-34,6,90,-119,17,-168,-97,12,"); + add("162,-8,2,59,-58,8,85,-120,15,-8,-136,17,"); + add("-64,-114,14,-133,-14,1,-143,29,-4,5,-38,4,"); + add("141,-66,9,144,-85,10,53,-82,9,12,12,-1,"); + add("65,176,-20,5,123,-15,18,141,-17,-3,172,-22,"); + add("-15,165,-22,-40,106,-15,22,154,-22,-38,130,-19,"); + add("37,142,-22,"); + add(""); + //add("/*43*/"); + add("38,-1,16496,-5129,24527,"); + add("30,-143,-51,63,-127,-70,-14,-142,-22,-2,-152,-34,"); + add("-16,-147,-24,6,-147,-40,-37,-135,-8,-79,-127,21,"); + add("-32,-147,-17,40,-121,-59,23,-149,-56,4,-137,-41,"); + add("-17,-147,-30,65,-116,-79,-4,-132,-36,-3,-139,-41,"); + add("80,-8,-57,66,36,-35,90,-60,-82,-28,223,88,"); + add("-65,92,72,4,149,41,4,148,40,24,146,23,"); + add("-14,143,49,31,146,18,82,121,-26,40,144,9,"); + add("-26,133,51,-64,103,69,-7,139,38,15,147,24,"); + add("-7,146,38,-7,149,37,-52,127,62,-73,108,73,"); + add("-84,19,60,"); + add(""); + //add("/*44*/"); + add("38,-1,18721,21147,10116,"); + add("-41,87,-107,-98,62,52,-143,106,36,-110,75,41,"); + add("-97,105,-49,-39,91,-123,-46,84,-102,-82,96,-61,"); + add("-35,-57,189,-109,39,111,-41,-10,94,-11,-64,155,"); + add("88,-98,52,-75,4,120,98,-117,73,-45,9,59,"); + add("-82,2,132,31,-83,115,63,-100,91,55,-99,103,"); + add("60,-102,97,96,-108,48,92,-108,53,108,-100,10,"); + add("112,-125,47,61,31,-157,50,-8,-69,81,-13,-111,"); + add("107,-67,-56,78,-43,-52,35,42,-143,60,12,-128,"); + add("7,52,-114,-103,91,4,-42,103,-130,-71,104,-81,"); + add("-14,51,-79,"); + add(""); + //add("/*45*/"); + add("36,1,-7108,28862,-4057,"); + add("112,21,-44,141,26,-58,70,-2,-127,59,-8,-140,"); + add("41,-15,-162,-132,-43,-72,-146,-39,-28,-93,-43,-120,"); + add("-79,-41,-127,-101,-41,-90,-99,-46,-118,-72,-42,-130,"); + add("-89,-47,-126,-104,-19,42,-139,-29,46,-140,-32,33,"); + add("-141,-45,-27,-129,-30,33,1,29,162,-10,20,126,"); + add("-22,20,151,107,46,95,125,53,110,13,24,123,"); + add("84,42,122,47,33,137,23,28,147,21,26,147,"); + add("19,25,147,47,31,140,148,38,-8,145,33,-34,"); + add("143,31,-45,90,7,-118,-2,-20,-139,"); + add(""); + //add("/*46*/"); + add("37,1,-12612,27178,1511,"); + add("72,38,-86,51,30,-137,29,20,-140,86,43,-98,"); + add("125,58,-54,2,5,-97,-129,-57,-48,-136,-62,-7,"); + add("-142,-65,0,-127,-59,-16,-136,-65,-10,-141,-68,27,"); + add("-101,-46,-110,-135,-65,-67,-7,-7,122,43,17,161,"); + add("-73,-39,70,-138,-70,15,-30,-19,113,92,41,116,"); + add("125,59,68,102,44,111,135,64,33,21,3,114,"); + add("-78,-46,138,-81,-44,78,-23,-22,149,-10,-16,146,"); + add("117,48,114,81,43,-43,56,36,-114,-34,-6,-149,"); + add("48,26,-31,141,69,-32,100,54,-100,42,28,-134,"); + add(""); + //add("/*47*/"); + add("37,1,29276,3899,5265,"); + add("22,-156,-12,20,-148,-7,25,-149,-40,23,-141,-38,"); + add("27,-130,-71,29,-62,-133,23,8,-143,17,59,-142,"); + add("16,48,-138,12,78,-134,5,102,-112,-8,137,-61,"); + add("-14,147,-29,-24,168,21,-25,121,59,-21,105,46,"); + add("-35,154,89,-29,151,46,-24,87,73,-36,155,77,"); + add("-27,94,71,-31,125,63,-36,109,111,-35,100,108,"); + add("-9,13,37,13,-41,-33,-21,12,111,40,-94,-140,"); + add("-21,-21,139,23,-150,12,9,-135,75,20,-154,24,"); + add("13,-144,45,8,-106,45,28,-187,-8,12,-81,-7,"); + add(""); + //add("/*48*/"); + add("36,1,23365,142,-18817,"); + add("54,94,69,71,84,90,55,106,71,-89,97,-109,"); + add("-51,107,-61,5,156,13,85,6,106,83,-108,102,"); + add("38,-107,44,63,-122,77,59,53,78,-71,119,-88,"); + add("-39,126,-45,12,149,21,2,179,13,60,-35,75,"); + add("58,-128,68,26,-140,27,34,-167,38,-33,-127,-46,"); + add("-5,-131,-9,-18,-143,-27,-26,-127,-33,5,-151,6,"); + add("-42,-120,-55,-55,-125,-68,-98,-123,-122,18,69,21,"); + add("51,128,63,35,139,44,20,146,25,-13,161,-16,"); + add("-91,11,-115,-90,-33,-115,-90,-48,-113,"); + add(""); + //add("/*49*/"); + add("37,1,12054,-19593,-19257,"); + add("58,-35,73,97,-42,105,128,-35,118,76,-28,78,"); + add("119,-11,92,139,38,53,138,60,31,139,47,46,"); + add("150,29,75,20,-63,80,-55,-105,73,-90,-108,53,"); + add("-102,-105,42,-115,-92,20,-144,-146,60,-2,-74,81,"); + add("-90,-96,45,-115,-98,31,-136,-92,12,-107,-61,-2,"); + add("-121,-47,-28,-125,-31,-47,-44,57,-94,2,89,-98,"); + add("-12,104,-125,-58,4,-41,-130,-56,-20,-12,60,-73,"); + add("56,106,-82,24,102,-94,-22,103,-124,4,65,-66,"); + add("55,112,-84,57,124,-94,51,106,-79,89,97,-43,"); + add(""); + //add("/*50*/"); + add("35,-1,19917,21699,5700,"); + add("29,-54,98,74,-89,80,71,-89,81,117,-98,-43,"); + add("149,-117,-89,-65,77,-55,-92,102,-55,-66,74,-48,"); + add("-63,79,-75,-15,46,-128,-73,99,-122,-7,36,-126,"); + add("0,20,-82,55,-15,-153,24,8,-132,59,-21,-154,"); + add("38,-6,-140,57,-21,-152,56,-26,-134,24,4,-131,"); + add("12,19,-164,-98,108,-91,-24,0,117,13,-42,160,"); + add("-47,15,150,-32,3,135,-31,-10,186,-40,10,120,"); + add("-62,32,114,-59,24,133,-18,-19,153,-60,19,148,"); + add("-14,-23,145,51,-77,121,"); + add(""); + //add("/*51*/"); + add("41,1,-4651,29635,-334,"); + add("-52,-9,-74,-147,-23,34,-42,-8,-77,-99,-18,-81,"); + add("-123,-20,85,-33,-7,-116,-111,-20,-20,-90,-14,125,"); + add("-50,-10,-19,-114,-21,-33,-8,1,154,-26,-4,153,"); + add("-56,-10,94,-19,-3,3,-17,-5,-154,-57,-12,-126,"); + add("-136,-26,27,-122,-24,97,-135,-27,24,-69,-14,135,"); + add("99,21,106,-44,-9,81,29,6,59,132,26,32,"); + add("192,38,20,-76,-15,25,68,13,79,90,16,80,"); + add("176,33,59,66,14,-123,115,21,-51,121,22,-35,"); + add("132,23,-23,-34,-5,-74,72,12,-59,92,16,-81,"); + add("130,21,-85,143,23,-50,127,19,-77,-47,-8,-78,"); + add(""); + //add("/*52*/"); + add("36,-1,-17857,23953,-2714,"); + add("-69,-60,-74,-114,-77,71,-109,-75,72,-111,-79,56,"); + add("-48,-29,82,11,18,91,-92,-64,75,-104,-78,30,"); + add("-34,-17,108,-110,-89,-23,-114,-97,-55,-121,-99,-25,"); + add("-87,-64,75,84,79,111,148,122,32,97,77,3,"); + add("108,81,-59,113,84,-44,119,88,-48,109,83,-14,"); + add("127,93,-33,122,88,-40,115,85,-19,118,82,-46,"); + add("120,84,-39,117,82,-19,111,82,21,20,10,-41,"); + add("-121,-93,-68,-89,-63,17,41,6,-221,-119,-96,-77,"); + add("-111,-88,-54,-84,-51,93,-21,-2,111,"); + add(""); + //add("/*53*/"); + add("35,1,18868,16148,-16830,"); + add("-118,111,-25,-43,93,43,11,86,96,13,65,80,"); + add("-48,105,49,114,-9,121,18,89,111,17,51,71,"); + add("110,-37,91,106,-88,33,119,-56,84,104,-67,55,"); + add("59,-94,-25,14,-90,-75,31,-109,-72,-118,47,-94,"); + add("-89,136,32,1,-144,-144,42,-99,-48,106,-129,-3,"); + add("109,-104,29,50,-132,-68,70,-135,-46,-4,-81,-81,"); + add("-71,16,-68,-57,139,63,-46,8,-45,42,-135,-77,"); + add("28,-89,-51,-151,124,-59,-109,73,-57,-77,126,31,"); + add("-77,126,31,-79,109,15,"); + add(""); + //add("/*54*/"); + add("34,-1,-21907,20246,3192,"); + add("-62,-57,-63,-62,-48,-135,-75,-66,-110,-9,14,-170,"); + add("89,99,-5,37,16,170,72,80,-15,8,22,-95,"); + add("-99,-99,-67,-102,-102,-62,-104,-108,-58,-69,-101,179,"); + add("-23,-35,65,4,-14,128,45,28,147,34,15,146,"); + add("79,69,114,66,51,126,59,41,134,78,57,154,"); + add("53,39,99,73,56,121,83,67,108,86,73,96,"); + add("96,95,30,-4,7,-52,-61,-36,-142,-38,-12,-144,"); + add("-92,-70,-152,-38,-33,-48,-3,24,-148,-11,13,-148,"); + add("-54,-35,-133,"); + add(""); + //add("/*55*/"); + add("35,-1,16309,24931,-3533,"); + add("24,-3,89,102,-57,80,68,-50,-39,119,-92,-89,"); + add("3,-15,-89,113,-84,-51,-16,8,-19,-118,83,21,"); + add("-65,59,106,-107,77,39,-82,40,-99,-36,5,-122,"); + add("95,-76,-91,106,-81,-69,108,-83,-62,121,-82,-3,"); + add("117,-79,4,120,-91,-49,114,-76,25,143,-110,-53,"); + add("45,-39,-40,151,-125,-101,-105,68,-46,-62,57,77,"); + add("-92,82,95,-114,79,-6,-96,70,18,-103,81,65,"); + add("-121,83,-3,-122,84,8,-113,84,57,-102,78,64,"); + add("-130,97,79,-13,30,141,"); + add(""); + //add("/*56*/"); + add("34,1,-15019,23246,-11578,"); + add("109,18,-104,-8,-59,-108,-129,-62,43,-61,-2,74,"); + add("-119,-114,-69,-118,-32,90,-114,-45,62,-120,-54,54,"); + add("-76,-47,10,-63,-67,-48,-110,-26,101,-106,-69,10,"); + add("-122,-55,61,-65,16,124,-4,20,46,-69,-112,-125,"); + add("-155,-65,94,-104,-37,77,-117,-37,99,-52,21,122,"); + add("94,83,26,134,97,-1,115,80,-6,112,50,-61,"); + add("129,45,-96,120,79,-9,126,83,-9,123,85,1,"); + add("117,61,-36,110,26,-100,108,20,-106,110,25,-95,"); + add("117,39,-76,"); + add(""); + //add("/*57*/"); + add("31,1,24179,-4896,-17070,"); + add("-65,75,-114,-78,42,-120,-77,49,-120,-76,50,-118,"); + add("-72,60,-113,-75,58,-116,-73,68,-113,-20,115,-55,"); + add("105,9,137,84,-42,122,87,-6,119,85,-18,122,"); + add("87,-9,122,82,-28,122,76,-55,122,38,-121,87,"); + add("63,-80,112,67,-61,115,75,-44,123,64,-73,116,"); + add("48,-105,102,6,-142,53,-20,-122,10,-9,-116,25,"); + add("-88,19,-138,-65,66,-119,-79,37,-127,-50,101,-104,"); + add("-46,108,-98,-25,98,-65,"); + add(""); + //add("/*58*/"); + add("32,-1,13075,24485,11382,"); + add("-40,52,-67,14,58,-144,17,52,-134,58,32,-141,"); + add("64,23,-131,84,3,-110,29,56,-168,-70,28,21,"); + add("28,-54,92,-76,-21,143,-85,-7,120,-75,-15,123,"); + add("-112,2,128,48,-60,76,21,-74,139,51,-82,117,"); + add("6,-62,126,108,-94,76,136,-62,-25,95,-80,56,"); + add("132,-88,31,-6,-35,77,19,-10,-1,87,45,-194,"); + add("-90,24,57,-82,74,-60,-55,107,-160,-47,-20,96,"); + add("-93,19,67,-130,74,-7,6,68,-152,"); + add(""); + //add("/*59*/"); + add("29,1,-3768,-29624,2870,"); + add("45,4,94,51,8,142,59,8,138,57,8,140,"); + add("32,14,147,-48,21,129,-31,19,118,-91,29,135,"); + add("-153,28,63,-79,26,117,-175,25,11,-15,23,147,"); + add("-106,32,113,-149,24,16,-144,16,-43,-99,-1,-109,"); + add("-16,-19,-150,25,-24,-149,63,-27,-134,90,-29,-121,"); + add("104,-29,-106,115,-28,-96,77,-26,-128,55,-24,-143,"); + add("18,-17,-146,25,-18,-143,94,-24,-118,135,-18,2,"); + add(""); + //add("/*60*/"); + add("30,1,-8205,28819,-1455,"); + add("-49,-18,-95,-107,-35,-74,-126,-34,63,-131,-39,-8,"); + add("-112,-37,-59,28,1,-121,135,35,-82,-84,-32,-116,"); + add("-139,-40,39,-129,-35,72,-87,-21,110,-125,-35,71,"); + add("-130,-38,69,-142,-45,39,-90,-25,91,165,60,100,"); + add("-39,-7,122,87,34,140,111,37,34,135,43,22,"); + add("151,48,-12,99,28,-61,93,23,-132,107,34,45,"); + add("114,37,99,118,37,66,92,23,-93,-35,-17,-168,"); + add("71,16,-104,"); + add(""); + //add("/*61*/"); + add("29,1,7341,28492,5857,"); + add("97,-32,32,101,-8,-91,129,-14,-97,162,-48,17,"); + add("98,-50,115,136,-21,-86,121,-12,-115,86,-3,-109,"); + add("72,-2,-102,-8,21,-96,-159,39,35,-146,40,12,"); + add("-144,44,-24,-140,46,-37,-124,42,-50,-140,56,-98,"); + add("-76,35,-88,-83,41,-114,-72,38,-113,-150,34,21,"); + add("-99,7,103,-38,-17,146,65,-39,131,10,-25,118,"); + add("113,-37,53,95,-48,123,24,-30,120,10,-30,139,"); + add(""); + //add("/*62*/"); + add("29,-1,13904,22523,14121,"); + add("-19,93,-130,-23,88,-121,-50,95,-107,-21,87,-123,"); + add("-56,98,-110,21,65,-132,94,11,-117,-1,23,-38,"); + add("-119,33,67,-106,103,-71,-21,80,-120,-112,91,-46,"); + add("-36,86,-118,14,66,-135,29,34,-93,-62,-54,165,"); + add("2,-75,134,67,-88,88,98,-84,48,7,-77,128,"); + add("102,-95,60,3,-81,136,40,-91,114,25,-96,136,"); + add("43,-85,97,37,-90,110,16,-85,122,27,-77,97,"); + add(""); + //add("/*63*/"); + add("28,1,25599,5928,-14475,"); + add("33,-94,20,47,-160,19,25,-90,9,54,-136,45,"); + add("62,-80,82,68,-111,82,64,-115,73,67,-111,84,"); + add("64,-114,80,67,-92,92,70,-85,104,66,-104,89,"); + add("83,-190,98,-58,18,-106,-67,77,-103,-69,92,-101,"); + add("-62,118,-76,-74,76,-112,-63,115,-76,-50,130,-45,"); + add("-49,115,-48,-82,54,-127,-63,120,-70,-85,80,-120,"); + add("-20,137,18,-2,140,50,-28,146,8,"); + add(""); + //add("/*64*/"); + add("32,-1,6784,26265,12812,"); + add("67,-5,-26,37,57,-138,-28,66,-122,80,12,-69,"); + add("61,44,-129,-45,71,-128,-100,88,-136,-27,-50,125,"); + add("-98,-3,60,-133,7,57,-138,81,-102,150,-27,-21,"); + add("-68,39,-49,-93,73,-111,-118,16,28,-118,39,-26,"); + add("-94,67,-101,3,-10,21,80,-70,114,132,-63,72,"); + add("51,-75,137,30,-24,37,111,-40,28,127,-51,42,"); + add("128,-39,13,-13,-32,75,-26,-49,117,-67,10,14,"); + add("-87,2,44,-6,-49,104,157,-56,33,"); + add(""); + //add("/*65*/"); + add("26,1,23238,12726,-14073,"); + add("76,-64,69,88,-121,37,88,-105,55,84,-121,34,"); + add("85,-121,37,85,-123,38,63,-143,-15,66,-149,-15,"); + add("20,-115,-62,24,-144,-78,-22,-86,-109,2,-174,-136,"); + add("-72,113,-31,-71,134,-10,-86,111,-53,-84,118,-43,"); + add("-72,126,-15,-71,138,0,-69,136,2,-69,134,1,"); + add("-84,129,-26,-57,123,16,-79,157,9,20,93,117,"); + add("66,-5,101,"); + add(""); + //add("/*66*/"); + add("30,-1,-15626,24491,7484,"); + add("-83,-67,46,-114,-88,46,-68,-5,-126,97,105,-140,"); + add("-44,-32,12,-109,-104,110,-71,-25,-74,17,58,-157,"); + add("56,86,-168,55,54,-62,99,90,-93,-46,-30,1,"); + add("-111,-81,30,-107,-95,90,51,32,2,18,-7,67,"); + add("-44,-71,143,-29,-57,126,-127,-117,107,61,42,-4,"); + add("84,48,25,129,58,89,23,-29,138,54,-12,150,"); + add("97,37,80,1,22,-66,-33,14,-112,39,65,-125,"); + add("78,80,-95,"); + add(""); + //add("/*67*/"); + add("28,1,5003,28957,-6038,"); + add("-142,13,-55,-88,-5,-93,-122,12,-36,6,39,188,"); + add("-80,41,141,-68,3,-37,111,-44,-128,-14,-26,-135,"); + add("-116,1,-81,-120,35,77,-93,33,90,63,26,174,"); + add("99,6,101,23,27,152,62,-3,38,127,-37,-87,"); + add("58,-6,16,1,28,142,27,27,171,115,-13,30,"); + add("134,-33,-55,109,-32,-70,98,-34,-89,43,-40,-165,"); + add("3,-30,-143,-109,2,-89,-95,20,19,"); + add(""); + //add("/*68*/"); + add("26,1,7323,-10567,-27106,"); + add("121,94,-3,142,73,11,122,50,15,31,-23,18,"); + add("-79,-118,23,-100,-126,21,-116,-102,8,-99,-88,8,"); + add("-118,-114,14,-116,-87,5,-129,-67,-7,-133,-64,-7,"); + add("-148,-82,-3,-104,-89,11,-126,-59,-5,-162,-43,-21,"); + add("-51,84,-47,121,97,-12,115,83,-7,115,86,-8,"); + add("145,83,2,105,59,3,128,90,-4,105,115,-18,"); + add("106,86,-6,"); + add(""); + //add("/*69*/"); + add("26,-1,-20783,20998,5211,"); + add("-67,-40,-109,-67,-36,-125,-76,-30,-203,-20,-37,79,"); + add("-61,-46,-71,-3,31,-149,-35,-6,-136,-49,-20,-142,"); + add("-48,-19,-142,-60,-36,-128,-82,-63,-113,-105,-93,-75,"); + add("-44,-64,90,45,20,138,58,32,135,44,16,144,"); + add("25,-6,149,1,-33,149,37,2,157,44,16,125,"); + add("87,62,112,80,63,76,114,121,-22,74,80,-27,"); + add("100,72,109,"); + add(""); + //add("/*70*/"); + add("27,1,-22450,-137,19899,"); + add("-70,14,-79,-99,23,-113,-98,19,-113,-86,-40,-100,"); + add("-104,11,-123,-96,32,-113,-97,9,-116,-84,-60,-104,"); + add("-22,-179,-28,-32,-108,-41,50,-137,58,-19,-49,-25,"); + add("-30,-140,-42,56,-135,63,66,-76,77,47,77,60,"); + add("23,0,27,79,-32,94,92,11,109,82,77,100,"); + add("97,22,114,89,69,105,33,101,41,70,117,83,"); + add("32,144,39,35,156,42,"); + add(""); + //add("/*71*/"); + add("25,1,23559,-1507,-18512,"); + add("27,-75,40,43,-174,71,-57,80,-80,-63,-34,-78,"); + add("-88,-88,-102,-96,83,-128,-85,-47,-100,-97,-34,-115,"); + add("-66,45,-84,-109,-20,-130,-84,-84,-92,-92,-58,-103,"); + add("-106,-83,-115,-37,97,-53,50,123,46,60,131,59,"); + add("87,78,95,102,9,121,87,54,99,99,35,117,"); + add("97,-53,123,84,32,102,97,-3,120,94,-4,119,"); + add(""); + //add("/*72*/"); + add("25,1,25640,-4315,-14965,"); + add("31,-45,66,54,-65,113,-15,-155,20,-76,-10,-128,"); + add("-74,-2,-127,-82,-20,-132,-78,-42,-117,-79,26,-139,"); + add("-74,13,-124,-72,1,-117,-70,50,-127,-81,13,-132,"); + add("-77,64,-138,-16,182,-75,15,-33,33,65,-78,123,"); + add("50,-80,100,83,61,115,72,4,114,69,-29,120,"); + add("79,35,120,80,57,116,85,40,131,72,15,117,"); + add(""); + //add("/*73*/"); + add("25,1,6329,18585,22684,"); + add("-107,-21,47,-119,-30,56,-133,-23,54,-136,-32,61,"); + add("-142,-5,39,-143,15,24,-151,47,-3,-153,-26,57,"); + add("-110,-33,51,-5,-114,92,127,-70,27,147,-37,-4,"); + add("135,-68,21,136,-61,15,141,-32,-11,132,-59,13,"); + add("114,-83,35,151,-27,-19,56,56,-58,26,118,-100,"); + add("-68,102,-61,-5,117,-92,38,106,-95,58,104,-101,"); + add(""); + //add("/*74*/"); + add("26,-1,7748,26705,11261,"); + add("129,-68,72,75,-7,-35,137,-55,31,-13,-50,125,"); + add("-161,55,-14,49,-48,77,-43,-4,39,-135,66,-60,"); + add("2,-12,25,126,-63,59,99,-70,91,122,-60,54,"); + add("141,-38,-16,147,-75,66,-108,0,77,30,-27,38,"); + add("172,-30,-57,50,41,-128,-18,56,-112,-120,65,-62,"); + add("-126,68,-62,-106,65,-74,-69,75,-127,-124,50,-29,"); + add("-152,41,9,"); + add(""); + //add("/*75*/"); + add("24,1,14610,-1401,-26164,"); + add("-43,-57,-21,-121,-61,-64,-114,-84,-57,-111,-85,-55,"); + add("-108,-95,-52,-127,-52,-64,-100,-97,-45,-86,-118,-37,"); + add("-64,-137,-22,-14,-151,6,-73,-146,-24,-89,52,-51,"); + add("-27,143,-26,41,133,10,95,100,40,117,78,55,"); + add("94,100,41,108,104,50,105,90,50,116,72,58,"); + add("117,80,58,121,59,63,112,86,57,"); + add(""); + //add("/*76*/"); + add("25,1,26396,-4371,-13570,"); + add("27,-28,63,47,-88,120,-11,-160,33,-56,-86,-80,"); + add("-64,15,-130,-65,22,-135,-62,42,-131,-63,33,-130,"); + add("-48,80,-115,-27,-30,-40,-87,-20,-155,-63,65,-133,"); + add("31,142,11,67,-4,122,35,47,51,74,2,136,"); + add("69,92,100,70,-21,139,-48,-125,-52,-73,-63,-118,"); + add("3,-64,27,69,-13,135,70,102,98,63,32,111,"); + add(""); + //add("/*77*/"); + add("23,1,26582,10216,-9436,"); + add("30,-17,65,49,-62,75,75,-102,105,70,-87,108,"); + add("50,-116,22,46,-147,-22,35,-144,-49,-19,-79,-135,"); + add("-30,-43,-131,-46,-32,-162,-77,83,-132,-44,43,-79,"); + add("-77,97,-116,-52,90,-53,-60,147,-15,-92,167,-77,"); + add("-58,74,-78,-40,143,40,36,48,144,48,-10,118,"); + add("63,-23,148,48,1,132,"); + add(""); + //add("/*78*/"); + add("23,1,-8254,28832,-761,"); + add("-97,-27,32,-31,-10,-50,-97,-30,-58,-158,-48,-10,"); + add("-145,-44,-22,-132,-40,25,-139,-43,23,-146,-46,14,"); + add("-16,-2,144,146,49,85,167,51,-32,34,13,112,"); + add("-19,-4,154,118,38,92,128,39,47,135,41,74,"); + add("140,41,77,82,23,-61,17,4,-155,43,11,-104,"); + add("41,10,-148,-16,-8,-141,"); + add(""); + //add("/*79*/"); + add("24,-1,14884,12125,23053,"); + add("-8,-117,67,30,-56,9,26,-101,36,-42,-130,92,"); + add("-29,-120,79,-101,-11,69,-108,-19,77,-76,-80,87,"); + add("-61,-124,97,-48,-109,82,-33,-127,80,-2,-59,28,"); + add("57,166,-112,62,118,-94,74,73,-82,52,104,-83,"); + add("117,0,-73,92,82,-99,54,95,-82,72,29,-62,"); + add("-24,146,-59,-33,131,-46,-56,133,-33,"); + add(""); + //add("/*80*/"); + add("24,1,-6839,29182,-1275,"); + add("-120,-28,3,-163,-38,26,40,6,-75,150,32,-101,"); + add("-80,-22,-42,-160,-38,24,-18,-7,-50,-43,-16,-102,"); + add("-84,-21,-8,-1,8,163,1,10,202,-56,-17,-58,"); + add("-100,-29,-83,-143,-37,2,-35,-4,135,14,11,157,"); + add("134,36,49,74,22,69,135,33,-19,158,41,35,"); + add("152,36,-3,91,18,-110,41,5,-116,"); + add(""); + //add("/*81*/"); + add("22,1,3600,19765,22280,"); + add("-77,-59,64,-106,-70,78,-159,-8,31,-4,-102,89,"); + add("93,-99,72,21,-114,94,35,-110,88,-12,-117,100,"); + add("13,-132,107,38,-71,53,123,-42,16,95,103,-100,"); + add("127,4,-24,82,36,-43,7,116,-98,-1,119,-100,"); + add("-19,110,-91,7,106,-91,-6,104,-89,-74,113,-87,"); + add("-86,90,-65,"); + add(""); + //add("/*82*/"); + add("22,1,17666,16854,-17432,"); + add("58,31,90,67,45,112,127,-40,93,77,-78,4,"); + add("118,-56,71,88,35,127,118,-100,28,110,-93,28,"); + add("132,-78,69,-25,0,-27,-25,-67,-93,41,-117,-70,"); + add("-50,-92,-141,-97,70,-37,-107,106,-14,-97,92,-15,"); + add("-122,47,-83,-86,-65,-151,-117,93,-33,-118,80,-43,"); + add("-51,74,19,"); + add(""); + //add("/*83*/"); + add("23,-1,5861,26752,12246,"); + add("82,-33,32,44,-67,125,76,-64,100,4,-66,137,"); + add("-2,-60,126,26,-61,114,56,-72,119,85,-65,91,"); + add("113,19,-91,-80,25,-13,-77,59,-82,-48,72,-125,"); + add("-16,64,-126,27,80,-182,83,25,-95,1,56,-122,"); + add("-73,49,-71,-16,-45,108,-29,-53,127,-52,-5,37,"); + add("-15,55,-111,-63,57,-93,"); + add(""); + //add("/*84*/"); + add("21,-1,-14603,25601,-5597,"); + add("-10,25,142,72,67,124,9,35,145,-23,16,145,"); + add("-38,6,147,-17,20,157,8,28,124,-63,-10,152,"); + add("-54,-3,159,20,6,-30,59,11,-131,70,16,-134,"); + add("72,16,-137,31,-8,-139,65,22,-75,81,21,-120,"); + add("-49,-52,-125,-49,-56,-141,-43,-51,-128,-51,-59,-142,"); + add(""); + //add("/*85*/"); + add("22,1,-5757,29270,-3178,"); + add("-36,-18,-100,-68,-28,-130,-59,-28,-136,-54,-28,-139,"); + add("-12,-22,-151,-104,-29,-57,-107,-3,153,-77,-12,39,"); + add("-63,-5,65,100,36,117,69,31,137,90,32,119,"); + add("-54,-10,14,-143,-35,-43,22,18,118,56,27,139,"); + add("125,32,58,110,32,92,119,26,24,9,-8,-107,"); + add("35,-5,-114,"); + add(""); + //add("/*86*/"); + add("21,-1,20081,22197,2006,"); + add("-52,51,-44,-84,68,86,-104,80,129,-69,58,28,"); + add("-120,102,37,-73,72,-95,-48,58,-182,-84,68,55,"); + add("-110,87,70,-18,8,85,64,-52,-33,78,-55,-118,"); + add("78,-70,26,34,-43,145,91,-86,70,115,-101,0,"); + add("61,-64,105,67,-57,-30,57,-37,-136,75,-56,-119,"); + add(""); + //add("/*87*/"); + add("20,1,-17819,21913,10114,"); + add("-28,11,-73,-142,-94,-50,-103,-82,-6,-124,-90,-31,"); + add("-113,-92,-6,-78,-105,82,23,-33,112,76,6,124,"); + add("103,33,114,116,67,63,95,87,-16,-56,30,-159,"); + add("-112,-81,-27,-102,-84,-3,-35,13,-90,78,74,-17,"); + add("142,85,72,90,79,-10,109,95,-13,"); + add(""); + //add("/*88*/"); + add("20,-1,7617,6776,28215,"); + add("-100,37,17,-132,61,21,-141,-23,42,-89,78,3,"); + add("-96,12,21,-102,53,13,7,147,-39,-119,93,6,"); + add("-141,-63,49,40,-153,29,77,-127,13,116,-87,-7,"); + add("54,-69,3,16,-124,25,121,-114,-4,95,65,-38,"); + add("115,89,-51,119,41,-40,150,29,-48,"); + add(""); + //add("/*89*/"); + add("19,1,10847,17337,21949,"); + add("-55,-34,54,-136,-1,68,-125,41,27,-145,19,54,"); + add("-134,22,45,-141,-18,79,-130,62,9,-164,26,53,"); + add("-47,-61,68,70,-81,33,147,-15,-54,141,-18,-50,"); + add("144,-61,-18,126,-37,-30,129,17,-74,133,12,-73,"); + add("135,5,-69,64,69,-85,"); + add(""); + //add("/*90*/"); + add("20,1,2092,29573,4591,"); + add("-46,-9,79,-90,13,-48,2,-21,135,-89,7,-11,"); + add("-133,16,-49,-43,-2,32,-29,-14,96,-26,-16,102,"); + add("78,-24,118,217,0,-82,-44,-15,105,58,-18,82,"); + add("160,-5,-33,149,-15,25,91,14,-122,30,20,-136,"); + add("19,23,-151,-57,26,-134,-157,12,-2,"); + add(""); + //add("/*91*/"); + add("20,-1,-20217,21829,-3845,"); + add("-71,-59,41,-110,-106,-18,-100,-95,2,-110,-103,7,"); + add("-95,-95,-14,-36,-35,-3,-92,-87,16,-71,-87,-94,"); + add("0,-28,-153,-18,-16,10,-98,-75,125,44,47,13,"); + add("84,99,88,78,86,54,114,110,-6,97,96,15,"); + add("98,90,-25,111,102,-14,116,111,14,"); + add(""); + //add("/*92*/"); + add("18,1,24559,5678,-16267,"); + add("45,23,76,82,-17,120,53,-117,40,48,-136,28,"); + add("29,-161,-10,79,-73,100,62,-105,63,-13,-129,-61,"); + add("-56,-87,-115,-34,-125,-90,-73,6,-110,-35,134,-13,"); + add("15,127,61,-34,158,-2,-54,138,-37,-51,138,-32,"); + add("-55,139,-37,"); + add(""); + //add("/*93*/"); + add("20,-1,7773,28919,-1814,"); + add("-89,16,-118,-83,13,-134,-41,10,2,-8,13,153,"); + add("162,-37,87,52,-6,135,18,3,148,-94,31,106,"); + add("-54,17,47,200,-56,-53,108,-26,75,31,-8,11,"); + add("11,-11,-150,130,-40,-79,27,-11,-54,-161,49,66,"); + add("-70,20,5,1,-8,-121,-91,22,-50,"); + add(""); + //add("/*94*/"); + add("19,1,28847,-786,-8199,"); + add("14,-81,55,17,10,63,33,-16,120,21,-153,93,"); + add("-27,-81,-85,-41,-5,-147,-26,-117,-78,-18,-132,-42,"); + add("-24,-120,-62,-43,-55,-138,-40,-73,-123,-13,54,-52,"); + add("-1,171,-32,26,67,75,42,57,133,23,143,60,"); + add("13,150,26,24,136,69,"); + add(""); + //add("/*95*/"); + add("19,-1,-13526,25075,-9397,"); + add("-104,-57,0,-169,-104,-31,-81,-44,5,-119,-56,27,"); + add("-136,-62,41,-155,-91,-5,21,21,24,125,71,-5,"); + add("135,72,-11,34,50,83,-79,4,130,-78,13,159,"); + add("39,17,-17,54,-22,-142,66,-7,-119,128,39,-89,"); + add("119,53,-33,130,72,1,"); + add(""); + //add("/*96*/"); + add("20,1,-8960,-28564,-1947,"); + add("-4,-7,116,-2,-8,149,17,-15,170,40,-19,128,"); + add("-19,-1,158,3,-7,144,-60,14,121,-106,34,-11,"); + add("-17,9,-106,-78,25,14,-77,27,-65,101,-30,-68,"); + add("12,1,-102,-83,31,-101,76,-21,-60,44,-10,-76,"); + add("-10,10,-123,16,4,-148,77,-15,-153,"); + add(""); + //add("/*97*/"); + add("17,-1,17593,2406,24180,"); + add("-46,-122,46,-2,-152,15,-14,-147,23,32,-145,-12,"); + add("61,-134,-35,60,-128,-35,91,-110,-59,82,-162,-52,"); + add("51,105,-43,-51,108,31,-94,101,62,-58,133,34,"); + add("-12,155,-3,-12,148,-4,-3,151,-11,-17,154,-2,"); + add(""); + //add("/*98*/"); + add("17,-1,7274,26419,12212,"); + add("-30,-53,132,-26,-63,149,90,-55,61,121,-62,59,"); + add("112,-69,77,111,-66,68,136,-77,76,45,47,-124,"); + add("109,9,-86,69,26,-97,-23,64,-119,-68,73,-111,"); + add("-118,65,-65,-148,50,-12,-139,44,-10,-135,48,-21,"); + add(""); + //add("/*99*/"); + add("18,1,-5378,29484,-1323,"); + add("7,-3,-94,-75,-18,-97,-134,-22,66,-123,-21,55,"); + add("-78,-18,-54,-45,-14,-99,-88,-13,91,-23,2,131,"); + add("-90,-13,129,-141,-28,38,-61,-8,119,130,29,54,"); + add("147,29,-35,140,28,5,121,21,-86,99,14,-122,"); + add("143,25,-49,"); + add(""); + //add("/*100*/"); + add("18,-1,13477,22776,14129,"); + add("109,-76,17,41,-79,87,-6,-77,128,-25,-78,145,"); + add("21,-91,121,32,-82,95,-81,-30,118,-6,-70,111,"); + add("92,-30,-39,85,48,-150,1,51,-78,-51,92,-93,"); + add("-5,96,-142,-21,78,-104,-25,85,-108,-32,83,-102,"); + add("-120,75,-7,"); + add(""); + //add("/*101*/"); + add("17,1,13832,17499,20061,"); + add("-49,-24,54,-87,-54,108,-99,-46,105,-113,-24,96,"); + add("-145,5,90,-63,-73,103,-121,-41,111,20,-94,65,"); + add("118,-79,-9,138,-22,-72,110,42,-106,81,58,-102,"); + add("102,48,-108,-30,92,-58,35,96,-105,73,73,-114,"); + add(""); + //add("/*102*/"); + add("17,1,24192,6529,-16496,"); + add("5,-81,-25,-12,-132,-68,-58,-89,-117,-44,-93,-99,"); + add("9,-107,-24,11,-90,-17,-48,-108,-106,-117,-38,-177,"); + add("-17,120,16,4,156,60,-22,140,20,-18,140,26,"); + add("28,112,82,69,65,123,82,-21,109,87,10,130,"); + add(""); + //add("/*103*/"); + add("16,-1,13005,-9227,25411,"); + add("89,107,-7,117,91,-28,96,129,-5,124,84,-36,"); + add("90,79,-20,135,59,-53,192,71,-80,-94,74,77,"); + add("-136,-44,59,-116,-94,30,-130,-64,47,-93,-97,15,"); + add("-108,-131,10,-73,-112,-2,-93,-119,5,"); + add(""); + //add("/*104*/"); + add("17,-1,12753,25778,8535,"); + add("52,-64,114,99,-58,27,-5,-49,150,9,-5,1,"); + add("88,-14,-90,143,-79,19,196,-98,-11,-76,66,-78,"); + add("-85,33,34,-159,84,-9,-83,82,-118,-127,73,-28,"); + add("-31,59,-134,-108,74,-64,-53,33,-23,131,-100,112,"); + add(""); + //add("/*105*/"); + add("17,-1,-16206,24956,-3814,"); + add("36,36,80,46,51,147,74,60,88,97,75,103,"); + add("123,82,32,170,122,119,112,64,-32,-8,-16,-86,"); + add("-85,-70,-130,-116,-86,-105,-110,-66,20,-171,-113,-32,"); + add("-59,-52,-95,72,44,-17,-35,-27,-34,-79,-59,-52,"); + add(""); + //add("/*106*/"); + add("16,1,-27904,9377,5782,"); + add("14,-34,121,-8,-99,117,14,-47,134,25,-36,169,"); + add("56,65,149,27,-4,118,34,-11,159,32,89,9,"); + add("-6,72,-124,-13,58,-137,-16,45,-140,-25,26,-147,"); + add("-27,16,-146,-35,-14,-143,-43,-42,-136,"); + add(""); + //add("/*107*/"); + add("16,1,24919,6169,-15523,"); + add("-15,-83,-57,15,-144,-32,30,-148,-7,46,-148,19,"); + add("27,-152,-11,-30,-15,-54,-79,68,-101,-85,43,-118,"); + add("-72,102,-77,-78,95,-86,-59,170,-28,55,27,94,"); + add("69,29,118,60,64,119,58,69,119,"); + add(""); + //add("/*108*/"); + add("15,1,25878,-4981,-14336,"); + add("-65,-92,-84,-74,-17,-126,-74,-48,-113,-75,-84,-102,"); + add("-71,-100,-87,-80,-25,-128,-62,61,-127,26,118,4,"); + add("71,113,81,76,61,110,79,105,100,67,7,115,"); + add("75,-1,131,72,-13,133,"); + add(""); + //add("/*109*/"); + add("16,1,5450,29486,-929,"); + add("-154,29,9,-133,25,53,15,0,102,55,-8,59,"); + add("-131,24,83,51,-6,146,117,-19,76,152,-27,86,"); + add("46,-9,-54,171,-34,-108,46,-11,-133,67,-16,-143,"); + add("2,-5,-140,-115,20,-79,-112,23,66,"); + add(""); + //add("/*110*/"); + add("16,-1,17357,24467,-289,"); + add("93,-67,-83,114,-83,-67,118,-86,-7,-13,8,-49,"); + add("-63,46,4,-131,96,35,-99,72,119,-113,81,37,"); + add("-79,53,-96,-30,19,-139,-102,66,-178,18,-10,75,"); + add("61,-39,123,40,-26,142,85,-58,90,"); + add(""); + //add("/*111*/"); + add("16,1,-10217,28170,-1431,"); + add("-65,-26,-59,-121,-47,-38,-112,-47,-83,-64,-32,-142,"); + add("-103,-35,66,-74,-21,123,-113,-36,147,-52,-14,123,"); + add("22,14,136,72,32,111,73,28,-15,127,46,-75,"); + add("129,46,-48,120,40,-116,91,30,-63,"); + add(""); + //add("/*112*/"); + add("15,1,29126,7027,-1524,"); + add("25,-95,61,35,-144,21,37,-153,29,32,-136,22,"); + add("32,-147,-4,36,-156,67,31,-153,-26,-10,34,-50,"); + add("-33,155,-14,-35,150,-55,-27,117,-36,-41,183,10,"); + add("-27,109,-30,-35,145,-19,"); + add(""); + //add("/*113*/"); + add("15,1,6145,29344,-1095,"); + add("-111,18,-111,-53,5,-138,-82,10,-139,-105,16,-86,"); + add("-147,32,55,-78,19,94,-45,14,107,69,-11,60,"); + add("-161,34,74,151,-26,74,141,-26,15,139,-26,36,"); + add("145,-29,16,127,-25,23,"); + add(""); + //add("/*114*/"); + add("15,1,24375,5854,-16479,"); + add("40,-64,35,43,-140,16,59,-133,43,58,-133,43,"); + add("65,-133,54,43,-126,24,37,-157,9,-33,-4,-52,"); + add("-54,137,-39,-51,140,-32,-78,112,-80,-58,111,-51,"); + add("-26,150,12,-23,147,17,"); + add(""); + //add("/*115*/"); + add("15,-1,-17689,24006,-3293,"); + add("3,-14,-112,-73,-60,-41,-34,-11,101,-70,-38,105,"); + add("-89,-57,66,-106,-88,-56,-163,-125,4,-104,-72,56,"); + add("44,39,37,120,91,-4,106,86,36,112,90,43,"); + add("115,84,-14,93,53,-126,"); + add(""); + //add("/*116*/"); + add("14,1,12744,-2905,-27003,"); + add("-5,-145,14,-77,-123,-22,-103,-99,-37,-63,-118,-14,"); + add("-67,-122,-15,-128,-69,-50,-133,51,-66,17,147,-12,"); + add("107,117,35,104,79,37,99,120,32,86,134,25,"); + add("119,58,49,"); + add(""); + //add("/*117*/"); + add("15,1,-12039,24973,-11465,"); + add("-64,-40,-18,-136,-75,-18,-97,-85,-81,-115,-86,-58,"); + add("-106,-47,12,-128,-64,5,-126,-69,-8,-7,38,87,"); + add("99,75,51,156,93,28,61,55,53,130,77,25,"); + add("140,57,-26,124,60,-2,"); + add(""); + //add("/*118*/"); + add("14,1,7404,28675,-4785,"); + add("-29,-17,-146,-17,-21,-148,7,-29,-149,-45,-11,-123,"); + add("-150,53,81,-131,42,51,-114,46,103,-17,24,116,"); + add("7,24,148,56,10,138,125,-25,35,146,-55,-111,"); + add("129,-30,17,"); + add(""); + //add("/*119*/"); + add("15,1,-18411,21935,8938,"); + add("-115,-81,-40,-37,-70,94,-16,-67,130,-6,-58,124,"); + add("71,2,136,-17,-59,103,77,18,109,131,91,45,"); + add("-20,35,-117,-69,-11,-111,-56,16,-148,-52,11,-130,"); + add("18,47,-75,70,90,-75,"); + add(""); + //add("/*120*/"); + add("16,-1,-19925,-10993,19549,"); + add("-85,60,-54,-81,131,-10,-95,132,-25,49,44,74,"); + add("124,-109,68,104,-49,79,-38,35,-20,-106,137,-32,"); + add("-67,38,-48,-111,-16,-125,11,-76,-29,64,-118,1,"); + add("29,-126,-41,51,-24,39,100,-47,78,"); + add(""); + //add("/*121*/"); + add("15,-1,-18321,23571,-2957,"); + add("-21,-25,-65,-55,-44,-12,-127,-88,93,-93,-71,26,"); + add("-105,-81,20,-118,-90,42,-124,-99,20,-24,-4,132,"); + add("89,77,41,107,79,-71,90,60,-111,99,80,11,"); + add("155,117,-44,66,45,-56,"); + add(""); + //add("/*122*/"); + add("13,1,-17336,22935,8569,"); + add("-77,9,-181,-36,-51,65,5,-50,144,-33,-72,123,"); + add("11,-49,149,36,-30,146,45,-23,142,99,30,115,"); + add("31,78,-136,-4,53,-140,-9,49,-144,-26,36,-146,"); + add(""); + //add("/*123*/"); + add("15,1,18292,-22847,6589,"); + add("17,51,129,65,27,-88,38,6,-87,81,84,64,"); + add("-109,-44,152,4,37,115,-16,21,109,75,88,88,"); + add("-100,-69,39,-92,-89,-47,-125,-112,-40,46,6,-100,"); + add("56,0,-148,7,-22,-92,"); + add(""); + //add("/*124*/"); + add("14,1,25183,6987,-14730,"); + add("-19,-68,-66,-34,-107,-106,-1,-140,-65,-8,-124,-68,"); + add("-18,-137,-89,-55,-30,-104,-61,102,-57,-40,142,-5,"); + add("-29,159,24,18,114,80,56,74,126,63,25,117,"); + add("76,10,133,"); + add(""); + //add("/*125*/"); + add("14,1,-8316,28793,1345,"); + add("-112,-33,14,-106,-36,84,-119,-39,70,-83,-31,115,"); + add("70,13,135,41,3,142,12,-7,156,99,28,19,"); + add("108,39,-100,95,35,-109,42,21,-148,-30,0,-150,"); + add("16,13,-150,"); + add(""); + //add("/*126*/"); + add("14,1,-20941,-20602,6087,"); + add("-57,78,65,-69,88,56,-96,95,-13,-76,82,8,"); + add("-54,95,123,-116,124,1,-64,28,-127,47,-74,-79,"); + add("82,-108,-69,97,-111,-29,98,-114,-42,84,-109,-75,"); + add("86,-65,78,"); + add(""); + //add("/*127*/"); + add("13,1,-4213,-29615,2279,"); + add("-54,18,127,-113,24,97,-128,26,79,-138,28,72,"); + add("-56,2,-82,112,-27,-103,78,-21,-118,-45,-5,-145,"); + add("-127,9,-160,135,-23,-23,80,-3,125,149,-19,48,"); + add(""); + //add("/*128*/"); + add("17,1,-7190,25393,-14265,"); + add("78,-15,-66,-8,-71,-121,96,22,-9,103,-22,-88,"); + add("-16,-69,-112,-123,-86,-89,-29,14,39,-51,17,54,"); + add("-61,-48,-53,-53,22,65,-54,65,139,-68,50,122,"); + add("-82,20,78,25,62,96,104,44,25,88,20,-10,"); + add(""); + //add("/*129*/"); + add("14,-1,-19493,22341,-4569,"); + add("21,-10,-138,-18,-17,-9,-18,15,150,-41,-7,140,"); + add("-104,-82,48,-110,-85,68,-76,-41,140,-11,27,201,"); + add("24,10,-64,19,-10,-144,124,90,-106,57,33,-93,"); + add("103,79,-54,"); + add(""); + //add("/*130*/"); + add("14,1,631,-8774,-28681,"); + add("-95,52,-18,-113,74,-25,-126,-17,4,-218,65,-21,"); + add("120,-18,6,3,62,-18,-151,163,-49,118,8,-2,"); + add("126,-59,18,142,-43,15,136,-62,21,142,-64,22,"); + add("-23,-89,26,"); + add(""); + //add("/*131*/"); + add("14,1,19698,-3856,-22297,"); + add("66,-19,63,94,-67,96,59,-115,73,41,-133,62,"); + add("33,-144,58,-56,-44,-42,-112,1,-101,-112,-2,-100,"); + add("-88,89,-95,-79,93,-87,-35,136,-55,18,126,-7,"); + add("109,85,80,"); + add(""); + //add("/*132*/"); + add("13,1,-11506,10377,-25689,"); + add("-24,-106,-32,45,-133,-73,-57,-146,-31,-32,-145,-41,"); + add("-112,-83,18,-96,90,78,-114,58,75,-114,81,84,"); + add("67,117,15,89,117,5,131,76,-30,133,55,-38,"); + add(""); + //add("/*133*/"); + add("13,1,3573,20459,21649,"); + add("-18,-82,80,-121,-55,70,-106,-79,91,11,-107,96,"); + add("42,-113,97,64,-95,76,145,-61,32,58,98,-98,"); + add("18,114,-107,15,110,-103,-40,114,-99,-24,107,-96,"); + add(""); + //add("/*134*/"); + add("14,1,-13127,24311,-11689,"); + add("32,-36,-111,-20,-65,-111,-11,-39,-67,119,108,88,"); + add("119,35,-57,12,-41,-96,-113,-93,-66,-148,-83,-6,"); + add("-78,-59,-31,-99,-15,79,15,71,124,81,88,89,"); + add("49,83,116,"); + add(""); + //add("/*135*/"); + add("14,-1,-27102,-7955,10108,"); + add("-41,40,-76,7,-121,-79,2,-95,-72,50,-76,73,"); + add("60,-59,116,54,-99,63,49,14,140,58,-112,59,"); + add("41,30,130,-56,115,-52,-55,104,-59,-68,105,-94,"); + add("-62,98,-88,"); + add(""); + //add("/*136*/"); + add("13,1,24282,5951,-16583,"); + add("1,-130,-43,-12,-124,-61,-62,-64,-112,21,-145,-17,"); + add("-12,-193,-80,-75,62,-87,-38,114,-17,22,137,75,"); + add("-22,152,20,1,137,49,74,1,106,62,51,109,"); + add(""); + //add("/*137*/"); + add("12,1,-26265,9394,11041,"); + add("-25,-130,52,61,-10,151,61,0,140,56,-11,136,"); + add("72,36,134,82,129,80,-33,84,-143,-47,8,-112,"); + add("-59,12,-145,-60,2,-141,-63,-12,-136,"); + add(""); + //add("/*138*/"); + add("13,1,959,-9398,-28474,"); + add("-96,40,-16,-137,30,-14,-46,96,-32,46,137,-43,"); + add("120,104,-29,106,43,-11,165,-34,17,122,-55,22,"); + add("71,-116,41,34,-132,44,-128,-70,17,-150,-39,7,"); + add(""); + //add("/*139*/"); + add("13,-1,14782,-8096,24818,"); + add("69,-20,-48,119,-33,-82,133,23,-74,129,-1,-79,"); + add("130,19,-76,172,44,-94,-52,24,41,-129,-22,74,"); + add("-124,-10,75,-135,-5,81,-127,-25,69,-127,11,80,"); + add(""); + //add("/*140*/"); + add("13,1,-18588,-22992,5084,"); + add("-30,41,75,-96,84,27,-117,108,51,-121,106,23,"); + add("-116,92,-23,16,-39,-112,126,-112,-27,33,-57,-133,"); + add("146,-119,7,-60,76,116,53,-45,-2,114,-97,-23,"); + add(""); + //add("/*141*/"); + add("13,1,10930,21399,-17962,"); + add("112,-57,2,131,-9,69,89,-43,5,131,-71,-1,"); + add("148,-86,-8,121,-90,-27,-34,-14,-38,-131,74,3,"); + add("-134,81,9,-140,53,-25,-138,61,-13,-155,53,-32,"); + add(""); + //add("/*142*/"); + add("13,-1,2123,5909,29336,"); + add("91,-78,9,130,-73,4,65,-131,20,-85,-112,28,"); + add("-40,-133,28,50,-162,25,34,36,-9,28,139,-28,"); + add("10,135,-25,8,152,-30,-103,116,-14,-132,66,-4,"); + add(""); + //add("/*143*/"); + add("14,-1,-17261,24337,-3127,"); + add("-106,-81,-41,-97,-73,-25,-70,-67,-119,-103,-69,48,"); + add("-89,-51,111,-27,0,147,30,31,74,43,21,-85,"); + add("52,29,-72,125,88,-25,82,75,129,15,1,-77,"); + add("94,67,-2,"); + add(""); + //add("/*144*/"); + add("15,-1,-17925,23424,5478,"); + add("-56,-22,-89,-109,-64,-90,-96,-63,-50,-158,-128,15,"); + add("-122,-105,33,71,48,36,88,74,-14,119,86,31,"); + add("133,87,74,-67,-52,0,43,22,48,109,65,81,"); + add("5,10,-29,16,17,-20,"); + add(""); + //add("/*145*/"); + add("12,1,-11151,25532,-11125,"); + add("-96,-60,-40,-113,-85,-80,-154,-96,-60,-89,-84,-95,"); + add("-39,41,132,43,56,79,187,120,81,-121,-59,-10,"); + add("37,33,37,135,73,29,132,34,-56,"); + add(""); + //add("/*146*/"); + add("13,1,-8245,28241,5871,"); + add("-116,-48,68,-111,-45,51,-55,-33,79,67,-11,142,"); + add("-65,-18,-4,-34,-28,75,111,13,96,134,24,67,"); + add("120,43,-35,8,38,-156,32,40,-143,-27,24,-145,"); + add(""); + //add("/*147*/"); + add("12,-1,-29258,6281,2126,"); + add("-23,-98,-32,-27,-136,29,-23,-141,72,-7,-82,123,"); + add("3,-46,145,8,-25,154,25,105,42,17,119,-83,"); + add("14,113,-102,8,88,-123,9,85,-120,"); + add(""); + //add("/*148*/"); + add("12,-1,15271,556,25816,"); + add("72,107,-45,84,120,-53,109,74,-69,73,123,-48,"); + add("14,199,-17,-60,-36,38,-94,-101,61,-101,-90,64,"); + add("-93,-105,59,-79,-120,50,19,-120,-8,"); + add(""); + //add("/*149*/"); + add("13,1,4573,29647,-405,"); + add("107,-16,122,127,-20,41,164,-26,40,74,-13,16,"); + add("63,-11,-54,48,-10,-152,-74,11,-130,-85,12,-108,"); + add("-165,28,-1,-109,18,26,-117,20,93,-78,13,54,"); + add(""); + //add("/*150*/"); + add("12,-1,9509,25746,12114,"); + add("-81,-25,114,107,-45,12,57,-63,87,-150,26,61,"); + add("42,-29,28,151,-65,19,165,-64,1,86,3,-73,"); + add("-2,67,-137,-128,58,-19,-139,62,-20,"); + add(""); + //add("/*151*/"); + add("12,1,10885,-3987,-27670,"); + add("-99,-113,-22,-113,-91,-30,-130,-74,-39,-127,-67,-37,"); + add("-158,-91,-44,-8,63,-13,108,109,23,122,81,33,"); + add("131,59,41,117,91,32,119,64,37,"); + add(""); + //add("/*152*/"); + add("12,1,-10784,27846,2885,"); + add("31,19,-71,-6,13,-150,-84,-23,-112,-140,-51,-40,"); + add("-139,-55,-1,-127,-56,54,-43,-30,122,55,9,143,"); + add("106,32,100,140,55,3,133,57,-42,"); + add(""); + //add("/*153*/"); + add("12,-1,-20095,-16594,14860,"); + add("-15,59,46,-47,134,85,5,91,106,32,39,83,"); + add("57,25,102,-93,188,76,-37,-61,-113,-25,-95,-134,"); + add("8,-95,-92,-9,-95,-115,80,-131,-38,"); + add(""); + //add("/*154*/"); + add("12,-1,-19229,22976,-1545,"); + add("-67,-58,-11,-88,-82,-108,-97,-85,-32,-80,-76,-92,"); + add("-72,-59,30,-25,-11,149,79,79,162,92,71,-119,"); + add("3,12,140,91,76,-35,97,78,-55,"); + add(""); + //add("/*155*/"); + add("11,1,-1931,-29525,-4956,"); + add("-34,25,-132,27,24,-147,46,23,-144,42,24,-147,"); + add("128,1,-45,118,-27,110,37,-28,139,-44,-23,143,"); + add("-82,-17,128,-119,-8,89,"); + add(""); + //add("/*156*/"); + add("11,1,-7314,-28817,-4011,"); + add("38,10,-135,63,4,-137,36,13,-147,80,3,-145,"); + add("86,-36,93,124,-44,90,31,-23,107,-108,11,103,"); + add("-109,12,101,-119,17,85,"); + add(""); + //add("/*157*/"); + add("14,1,-10998,25512,-11321,"); + add("41,-28,-103,-54,-61,-84,-107,-71,-54,-129,-62,-11,"); + add("25,48,82,-20,9,39,-150,-48,44,17,44,79,"); + add("187,57,-60,-74,-12,49,7,37,75,121,34,-43,"); + add("45,4,-36,"); + add(""); + //add("/*158*/"); + add("11,1,-29990,-14,-784,"); + add("-1,-139,84,-1,-155,84,4,-105,-129,1,-108,22,"); + add("-3,-4,154,-4,87,124,0,134,-44,0,128,-68,"); + add("1,125,-75,2,107,-82,"); + add(""); + //add("/*159*/"); + add("11,1,24220,-1670,-17623,"); + add("-21,-142,-16,-68,-99,-83,-84,-67,-106,-86,-7,-115,"); + add("-81,59,-114,-40,112,-64,55,102,63,79,92,96,"); + add("91,14,122,90,-31,124,"); + add(""); + //add("/*160*/"); + add("11,1,140,28342,-9835,"); + add("-148,16,46,-147,-2,-5,-152,14,45,-96,34,103,"); + add("101,41,118,139,17,48,150,-6,-21,122,-29,-85,"); + add("100,-38,-111,8,-41,-120,"); + add(""); + //add("/*161*/"); + add("11,1,9134,18840,21486,"); + add("134,-66,0,126,-91,25,135,-54,-13,113,-67,8,"); + add("137,-82,8,-43,62,-34,-97,100,-42,-91,95,-42,"); + add("-150,40,31,-124,74,-11,"); + add(""); + //add("/*162*/"); + add("11,1,-21516,19701,6996,"); + add("-54,-7,-149,-52,-18,-114,-56,-12,-145,-50,-13,-130,"); + add("-118,-89,-128,6,-28,106,77,37,149,69,26,145,"); + add("65,33,115,82,47,123,"); + add(""); + //add("/*163*/"); + add("12,1,-2471,26742,-13370,"); + add("-106,37,95,62,32,52,133,23,22,113,42,66,"); + add("158,-1,-29,145,13,5,63,-27,-64,-93,-46,-80,"); + add("-176,5,39,-113,-29,-42,-113,-42,-63,"); + add(""); + //add("/*164*/"); + add("12,1,-10150,-24537,13962,"); + add("-10,36,55,-102,82,68,-147,64,4,-127,49,-11,"); + add("-133,22,-63,-142,13,-86,47,-28,-11,123,-35,34,"); + add("144,-49,22,137,-52,12,136,-74,-31,"); + add(""); + //add("/*165*/"); + add("12,1,-15831,-23712,9333,"); + add("11,39,120,12,45,131,33,43,159,29,38,136,"); + add("-72,62,33,-54,0,-87,-65,29,-36,-103,35,-86,"); + add("60,-92,-122,18,-56,-109,34,-70,-119,"); + add(""); + //add("/*166*/"); + add("11,-1,-26860,12885,-3537,"); + add("-22,-68,-78,-64,-142,-24,-55,-120,-9,-54,-128,-42,"); + add("-98,-217,-5,28,66,16,59,138,29,57,135,39,"); + add("57,134,44,56,133,53,"); + add(""); + //add("/*167*/"); + add("10,-1,21555,20350,4610,"); + add("-13,-13,117,-23,-10,147,-11,-25,149,15,-65,193,"); + add("89,-66,-109,59,-32,-128,32,3,-154,-26,61,-143,"); + add("-71,111,-150,"); + add(""); + //add("/*168*/"); + add("12,1,25080,-2304,-16299,"); + add("36,-91,68,1,-152,24,5,-145,32,28,-138,68,"); + add("-28,-123,-22,-47,63,-85,-54,77,-96,14,96,4,"); + add("34,84,39,-33,137,-73,5,129,-10,"); + add(""); + //add("/*169*/"); + add("11,1,-5147,-29506,1706,"); + add("36,-1,84,-95,24,126,-104,26,108,-85,24,125,"); + add("-103,29,129,-55,5,-80,41,-19,-145,56,-20,-140,"); + add("89,-24,-121,131,-27,-73,"); + add(""); + //add("/*170*/"); + add("11,1,3601,24897,16346,"); + add("-94,-65,119,-106,-2,25,-143,-42,91,31,-83,117,"); + add("72,-63,79,161,-49,38,88,35,-69,12,73,-110,"); + add("37,67,-109,-8,83,-124,"); + add(""); + //add("/*171*/"); + add("12,1,-16031,-24558,6319,"); + add("-29,-8,-108,-28,-23,-166,19,-42,-123,130,-68,69,"); + add("-58,46,37,5,16,79,101,-54,43,132,-49,140,"); + add("-115,70,-13,-118,58,-72,14,12,83,"); + add(""); + //add("/*172*/"); + add("11,1,4179,29039,-6267,"); + add("73,-37,-121,-54,-26,-151,-57,-23,-136,-114,-7,-103,"); + add("-154,15,-24,-87,34,96,96,17,131,92,8,92,"); + add("101,10,108,59,10,82,"); + add(""); + //add("/*173*/"); + add("11,1,7225,28615,-5385,"); + add("-150,30,-40,-139,24,-51,-152,36,-3,-23,32,144,"); + add("-4,26,134,100,-10,76,124,-44,-80,137,-42,-45,"); + add("123,-46,-80,49,-24,-60,"); + add(""); + //add("/*174*/"); + add("10,1,27028,-4267,-12299,"); + add("-47,-101,-69,-68,-50,-128,-76,-143,-112,-39,74,-109,"); + add("-42,100,-123,53,124,69,69,41,132,55,-48,134,"); + add("67,29,136,"); + add(""); + //add("/*175*/"); + add("11,-1,17469,24240,2693,"); + add("-28,25,-38,-83,72,-130,-50,50,-130,-52,49,-133,"); + add("-57,55,-170,-37,23,45,59,-55,143,73,-63,123,"); + add("51,-50,127,70,-63,122,"); + add(""); + //add("/*176*/"); + add("11,1,9832,-4353,-28007,"); + add("-12,-95,11,-32,-144,12,-59,-142,3,-104,-107,-18,"); + add("-134,-122,-24,-2,72,-13,44,125,-7,81,123,7,"); + add("60,126,0,75,131,5,"); + add(""); + //add("/*177*/"); + add("11,-1,3662,25807,14853,"); + add("-135,2,28,-21,-77,138,-117,-27,73,-24,-53,95,"); + add("13,-75,123,53,-20,22,115,39,-92,129,32,-84,"); + add("65,57,-113,-8,65,-110,"); + add(""); + //add("/*178*/"); + add("10,1,-6841,-28848,-4579,"); + add("-89,40,-117,11,19,-132,-44,36,-150,0,26,-145,"); + add("120,-16,-75,82,-38,102,0,-25,145,26,-31,146,"); + add("-18,-20,148,"); + add(""); + //add("/*179*/"); + add("10,1,10303,-4850,-27755,"); + add("-3,-110,18,-87,-118,-10,-139,-39,-44,-145,-16,-49,"); + add("-168,-5,-59,51,128,-5,128,85,30,144,11,50,"); + add("127,49,38,"); + add(""); + //add("/*180*/"); + add("11,1,27435,-3603,-11592,"); + add("23,-70,78,-36,-77,-61,-56,-11,-129,-70,-5,-160,"); + add("-45,48,-118,-47,48,-121,14,73,10,61,-2,139,"); + add("60,0,137,60,1,140,"); + add(""); + //add("/*181*/"); + add("11,-1,-19573,-21914,6055,"); + add("-41,72,126,-22,58,133,28,17,146,73,-23,140,"); + add("-46,47,21,-91,40,-142,13,-52,-136,-19,-29,-159,"); + add("7,-23,-56,76,-90,-80,"); + add(""); + //add("/*182*/"); + add("10,1,-16090,-23678,8971,"); + add("67,-15,80,5,55,152,3,53,138,-68,112,164,"); + add("-100,20,-121,-81,-5,-154,100,-81,-30,55,-62,-63,"); + add("-13,-40,-128,"); + add(""); + //add("/*183*/"); + add("10,1,-7427,29059,-664,"); + add("-79,-23,-102,-94,-27,-62,-135,-36,-21,-102,-25,98,"); + add("-81,-19,122,31,12,139,154,41,18,142,38,-17,"); + add("130,32,-78,"); + add(""); + //add("/*184*/"); + add("10,1,22146,-6178,-19271,"); + add("-60,73,-92,-58,116,-102,55,130,23,75,-34,95,"); + add("107,-20,130,99,39,103,19,-78,46,-68,-127,-39,"); + add("-96,-82,-86,"); + add(""); + //add("/*185*/"); + add("11,-1,13300,25127,9578,"); + add("29,41,-150,-7,56,-141,23,35,-126,-131,89,-57,"); + add("-40,16,13,126,-92,70,-14,-37,123,9,-49,120,"); + add("-29,-40,146,39,-43,58,"); + add(""); + //add("/*186*/"); + add("10,-1,11562,21630,17276,"); + add("116,-40,-28,140,-47,-37,107,-42,-21,214,-140,24,"); + add("-64,64,-33,-121,92,-31,-136,91,-20,-132,38,42,"); + add("-104,7,62,"); + add(""); + //add("/*187*/"); + add("10,1,-25792,5633,14249,"); + add("-43,-12,-74,-78,-55,-120,-19,-181,35,-89,-108,-124,"); + add("22,-32,53,73,1,134,79,31,133,37,137,15,"); + add("34,178,-7,"); + add(""); + //add("/*188*/"); + add("10,1,-11381,25287,-11447,"); + add("56,-2,-59,-84,-68,-68,-114,-80,-60,-126,-71,-28,"); + add("-165,-107,-62,31,58,91,86,77,80,112,81,64,"); + add("118,75,46,"); + add(""); + //add("/*189*/"); + add("11,-1,-17257,23572,6821,"); + add("-79,-32,-89,-16,23,-121,-53,-38,-4,-103,-94,61,"); + add("-62,-78,109,-89,-94,93,16,8,12,124,83,35,"); + add("113,76,31,108,92,-44,"); + add(""); + //add("/*190*/"); + add("9,1,21029,-858,-21378,"); + add("-82,-38,-80,-104,-45,-99,-108,-41,-101,-166,25,-159,"); + add("75,53,68,106,28,100,109,16,104,108,13,105,"); + add(""); + //add("/*191*/"); + add("9,-1,16710,18554,16629,"); + add("40,-81,51,77,-100,31,90,-117,38,114,-123,18,"); + add("63,61,-130,-74,118,-54,-114,76,32,-75,122,-59,"); + add(""); + //add("/*192*/"); + add("10,1,-26154,13570,5641,"); + add("12,-36,142,-22,-92,112,-38,-97,53,-91,-175,-11,"); + add("33,46,40,70,120,43,37,119,-105,21,92,-118,"); + add("-14,33,-142,"); + add(""); + //add("/*193*/"); + add("10,1,-10691,-27735,4062,"); + add("89,-25,58,-53,43,153,-92,50,88,-103,49,54,"); + add("-119,59,77,-44,12,-36,69,-48,-127,98,-54,-100,"); + add("91,-52,-105,"); + add(""); + //add("/*194*/"); + add("9,1,5294,28803,-6509,"); + add("141,-38,-53,58,-14,-13,-125,-7,-132,-82,-14,-124,"); + add("-128,1,-92,-86,43,117,12,33,151,77,15,126,"); + add(""); + //add("/*195*/"); + add("10,1,-13366,24028,-12001,"); + add("65,-24,-120,-58,-49,-32,-118,-69,-5,-122,-71,-3,"); + add("-204,-95,43,57,44,22,133,68,-16,108,81,37,"); + add("61,66,65,"); + add(""); + //add("/*196*/"); + add("9,1,-13524,26719,1794,"); + add("-49,-16,-141,-59,-24,-103,-129,-63,-57,-127,-69,46,"); + add("11,-3,148,97,43,109,110,51,85,128,63,31,"); + add(""); + //add("/*197*/"); + add("10,-1,-19280,22118,-6250,"); + add("3,37,124,-25,20,152,-29,10,132,-36,9,154,"); + add("72,66,13,-1,-41,-155,5,-30,-131,31,-11,-139,"); + add("-4,-39,-126,"); + add(""); + //add("/*198*/"); + add("9,1,-5809,29420,-843,"); + add("-132,-27,-12,-164,-32,56,-135,-28,15,-23,-2,88,"); + add("83,20,143,154,33,14,113,21,-95,112,20,-106,"); + add(""); + //add("/*199*/"); + add("10,-1,-2866,4214,29564,"); + add("-77,-108,8,-26,-121,14,-26,-158,18,141,-133,31,"); + add("54,162,-16,-71,-12,-5,-48,38,-10,28,155,-18,"); + add("20,115,-14,"); + add(""); + //add("/*200*/"); + add("9,1,16380,-17659,-17885,"); + add("-77,86,-154,103,64,31,97,45,45,96,-26,114,"); + add("95,-32,121,-11,-89,78,-111,-41,-64,-107,11,-109,"); + add(""); + //add("/*201*/"); + add("8,1,2405,29362,5664,"); + add("-161,-1,74,55,-28,117,40,-40,180,167,-13,-2,"); + add("108,5,-68,27,32,-171,-115,17,-38,"); + add(""); + //add("/*202*/"); + add("10,-1,15812,18669,17362,"); + add("62,-1,-56,121,-24,-85,101,-18,-76,-52,103,-62,"); + add("26,105,-142,-85,18,62,-29,-52,84,-107,-11,112,"); + add("-38,-69,109,"); + add(""); + //add("/*203*/"); + add("9,-1,-22192,18429,-8241,"); + add("-24,-51,-48,-42,-105,-120,-45,-95,-83,3,-94,-206,"); + add("-31,-5,68,-7,65,158,63,115,82,45,106,111,"); + add(""); + //add("/*204*/"); + add("9,1,11904,-3476,-27317,"); + add("-52,-83,-12,-106,-103,-32,-102,-113,-28,-187,-67,-70,"); + add("48,72,10,85,121,20,114,88,37,122,81,42,"); + add(""); + //add("/*205*/"); + add("9,1,29712,544,-4112,"); + add("13,98,108,12,125,117,18,-20,133,2,-58,5,"); + add("-9,-130,-90,-10,-97,-91,-13,-138,-111,-12,92,-79,"); + add(""); + //add("/*206*/"); + add("9,1,9469,-5342,-27961,"); + add("-76,-64,-13,-89,-111,-8,-123,-76,-26,-193,-36,-55,"); + add("20,109,-15,111,75,21,140,40,38,133,73,30,"); + add(""); + //add("/*207*/"); + add("9,1,-4851,24586,-16492,"); + add("112,-15,-56,112,-35,-83,77,-73,-128,-49,-63,-78,"); + add("-117,34,82,-120,28,75,-155,20,75,46,45,53,"); + add(""); + //add("/*208*/"); + add("9,1,24496,6480,-16061,"); + add("42,-192,-12,-66,29,-89,-56,-72,-113,-60,-98,-126,"); + add("-32,66,-23,30,120,90,46,90,104,59,71,119,"); + add(""); + //add("/*209*/"); + add("9,1,-5809,29356,-2119,"); + add("25,-3,-102,10,-9,-147,-56,-22,-131,-154,-34,-30,"); + add("-109,-15,91,2,14,160,131,31,59,80,23,86,"); + add(""); + //add("/*210*/"); + add("9,-1,28373,6866,-6918,"); + add("16,-102,-31,-1,-97,-101,-9,-80,-107,-21,-107,-180,"); + add("-10,66,19,7,96,117,-9,131,86,7,89,112,"); + add(""); + //add("/*211*/"); + add("9,1,6654,-7693,-28223,"); + add("85,43,9,-37,-186,42,-30,-149,34,-106,-88,0,"); + add("-146,59,-50,24,144,-35,100,82,0,88,19,15,"); + add(""); + //add("/*212*/"); + add("9,1,23496,6501,17484,"); + add("57,-56,-56,91,-46,-107,87,15,-125,87,76,-150,"); + add("-52,72,45,-85,13,113,-84,-4,117,-82,-11,114,"); + add(""); + //add("/*213*/"); + add("9,-1,-6643,25925,-13555,"); + add("69,0,-34,128,-11,-84,105,-27,-99,109,-26,-98,"); + add("-71,-55,-69,-126,21,96,-97,28,97,-76,47,126,"); + add(""); + //add("/*214*/"); + add("9,1,-7497,28006,-7711,"); + add("-100,-11,58,-138,-24,49,27,14,24,77,47,98,"); + add("45,58,175,104,24,-16,36,-35,-168,12,-31,-128,"); + add(""); + //add("/*215*/"); + add("9,-1,-20663,19947,-8671,"); + add("-9,-40,-67,-99,-111,-19,-110,-98,41,-117,-97,63,"); + add("8,54,105,53,64,15,102,73,-80,114,93,-60,"); + add(""); + //add("/*216*/"); + add("9,1,4747,25258,15476,"); + add("-15,-47,81,-25,-76,129,-32,-73,126,23,-91,137,"); + add("39,12,-30,3,79,-126,12,80,-131,10,77,-128,"); + add(""); + //add("/*217*/"); + add("8,1,8037,27999,7173,"); + add("126,-37,4,70,13,-132,-8,42,-161,-67,37,-70,"); + add("-146,35,28,-97,4,97,30,-44,140,"); + add(""); + //add("/*218*/"); + add("8,1,-8206,28777,-2132,"); + add("89,20,-69,43,0,-147,-75,-30,-114,-146,-37,57,"); + add("-176,-46,61,49,22,105,122,42,81,"); + add(""); + //add("/*219*/"); + add("8,1,26623,-4311,-13138,"); + add("27,-94,85,6,-161,68,-36,-68,-50,-84,-1,-169,"); + add("-19,104,-74,-3,147,-55,61,86,94,"); + add(""); + //add("/*220*/"); + add("9,-1,-19193,23050,547,"); + add("-3,0,-116,-126,-104,-79,-91,-76,-9,-51,-45,93,"); + add("-32,-30,123,62,50,72,131,111,3,92,79,-39,"); + add(""); + //add("/*221*/"); + add("9,-1,-21968,17844,-9950,"); + add("-52,-145,-144,-65,-32,87,-53,11,139,-99,-72,94,"); + add("6,11,5,105,80,-92,45,-8,-115,86,123,27,"); + add(""); + //add("/*222*/"); + add("8,1,-9395,-28397,2317,"); + add("-3,14,145,-6,15,151,-50,30,144,-103,31,-45,"); + add("14,-17,-132,18,-21,-163,44,-26,-140,"); + add(""); + //add("/*223*/"); + add("8,1,-23532,-559,18600,"); + add("-51,-140,-71,78,10,100,72,112,94,44,111,58,"); + add("-18,153,-19,-74,-18,-94,-47,-129,-61,"); + add(""); + //add("/*224*/"); + add("8,1,29597,-880,-4821,"); + add("11,119,49,14,132,63,15,122,85,18,-57,120,"); + add("-6,-139,-20,-16,-129,-81,-21,-93,-116,"); + add(""); + //add("/*225*/"); + add("8,1,-4242,28374,8769,"); + add("-111,-19,10,-148,-19,-16,-174,-48,66,87,-11,80,"); + add("150,10,44,156,20,13,59,45,-115,"); + add(""); + //add("/*226*/"); + add("8,-1,23521,18132,-4238,"); + add("22,2,127,85,-98,57,62,-96,-62,2,-37,-146,"); + add("-18,-15,-158,-76,95,-24,-53,98,119,"); + add(""); + //add("/*227*/"); + add("9,-1,-12721,26335,-6680,"); + add("101,34,-59,-12,-37,-121,21,-30,-150,97,11,-132,"); + add("-22,-9,4,-87,-9,120,-32,24,149,-30,19,133,"); + add(""); + //add("/*228*/"); + add("8,1,28556,-1354,-9094,"); + add("4,-123,32,-10,-153,-7,-42,-14,-129,-41,-5,-126,"); + add("-13,145,-64,30,120,73,44,44,129,"); + add(""); + //add("/*229*/"); + add("9,-1,-13304,26737,-2855,"); + add("-76,-34,35,-77,-28,107,23,22,102,145,75,25,"); + add("91,53,92,49,18,-63,-12,-18,-126,-95,-61,-143,"); + add(""); + //add("/*230*/"); + add("9,1,-4166,24261,-17148,"); + add("79,-11,-35,76,-52,-91,33,-64,-96,128,-60,-112,"); + add("-52,-17,-11,-135,41,86,-105,58,105,-31,69,105,"); + add(""); + //add("/*231*/"); + add("10,-1,22208,16310,-11865,"); + add("-45,2,-82,-109,78,-95,-87,149,46,91,-49,101,"); + add("52,-108,-53,29,8,64,39,3,77,28,-4,47,"); + add("-22,-51,-112,"); + add(""); + //add("/*232*/"); + add("8,-1,18389,23461,-3379,"); + add("78,-58,17,126,-102,-8,148,-120,-6,-26,11,-72,"); + add("-120,91,-34,-120,92,-23,-123,105,59,"); + add(""); + //add("/*233*/"); + add("9,-1,-12115,27105,4305,"); + add("73,39,-40,98,61,-114,58,51,-174,-77,-33,0,"); + add("-134,-60,2,-95,-52,66,69,14,109,8,-12,101,"); + add(""); + //add("/*234*/"); + add("9,1,22705,-5,-19608,"); + add("49,-19,57,108,-56,126,-44,-88,-51,-88,25,-103,"); + add("-59,-15,-68,-104,-20,-119,-6,99,-7,89,57,101,"); + add(""); + //add("/*235*/"); + add("9,-1,-21304,20829,-3509,"); + add("-61,-67,-28,-89,-92,7,-93,-82,84,-97,-83,115,"); + add("17,17,-6,85,72,-102,93,83,-81,88,91,-4,"); + add(""); + //add("/*236*/"); + add("8,1,21301,-2864,-20930,"); + add("49,-109,66,-5,-141,14,-17,-126,3,-108,-60,-101,"); + add("-16,142,-38,0,130,-20,43,142,24,"); + add(""); + //add("/*237*/"); + add("8,1,-3541,26084,-14390,"); + add("91,-16,-52,143,-42,-108,-84,-54,-78,-183,-37,-22,"); + add("-110,17,58,-27,44,86,84,68,100,"); + add(""); + //add("/*238*/"); + add("9,1,-17503,-23888,4794,"); + add("98,-63,45,73,-33,99,90,-40,118,83,-41,84,"); + add("-47,33,-2,-82,42,-75,-89,41,-118,-87,42,-97,"); + add(""); + //add("/*239*/"); + add("8,1,-20659,21543,3021,"); + add("-20,-9,-74,-10,14,-179,-30,-5,-194,-34,-42,74,"); + add("-22,-39,146,-6,-28,161,69,56,82,"); + add(""); + //add("/*240*/"); + add("8,1,24748,-885,-16934,"); + add("0,-113,6,-74,-41,-105,-86,34,-125,-97,38,-141,"); + add("31,56,41,88,29,123,87,22,125,"); + add(""); + //add("/*241*/"); + add("8,1,22276,-3747,-19742,"); + add("48,-106,75,49,-132,82,14,-106,39,-61,-71,-56,"); + add("-56,105,-85,-48,125,-80,7,156,-22,"); + add(""); + //add("/*242*/"); + add("10,1,-16881,-24201,5419,"); + add("-73,37,-65,-75,32,-95,-64,29,-74,60,-59,-77,"); + add("117,-85,-15,9,15,101,70,-48,1,35,-8,76,"); + add("-39,49,98,"); + add(""); + //add("/*243*/"); + add("8,1,-26588,12735,5561,"); + add("-52,-110,-1,-64,-123,-29,-32,-112,98,26,1,117,"); + add("60,110,43,41,123,-81,39,119,-83,"); + add(""); + //add("/*244*/"); + add("8,-1,15516,21285,-14359,"); + add("23,35,76,93,9,115,97,-78,-10,65,-106,-84,"); + add("1,-79,-116,-126,63,-47,-117,100,21,"); + add(""); + //add("/*245*/"); + add("8,1,7216,28601,-5469,"); + add("-30,-19,-138,2,-31,-152,-102,13,-61,-63,39,115,"); + add("40,19,146,74,4,118,101,-17,42,"); + add(""); + //add("/*246*/"); + add("8,1,3833,29553,3454,"); + add("2,11,-94,-34,18,-128,11,16,-167,-129,16,5,"); + add("28,-19,150,-9,-15,145,51,-17,88,"); + add(""); + //add("/*247*/"); + add("8,1,8843,28172,5303,"); + add("87,-18,-50,96,-15,-85,-82,41,-80,-143,38,39,"); + add("-156,43,31,-1,-21,116,113,-45,51,"); + add(""); + //add("/*248*/"); + add("7,1,21050,-381,-21372,"); + add("-94,-69,-91,-60,-120,-55,-138,-33,-132,42,113,37,"); + add("87,98,82,100,30,97,"); + add(""); + //add("/*249*/"); + add("7,-1,3999,25672,14999,"); + add("-52,-42,85,-37,-69,127,-3,-123,204,68,48,-97,"); + add("34,74,-133,7,66,-113,"); + add(""); + //add("/*250*/"); + add("8,1,-26361,12892,6235,"); + add("1,-67,145,-25,-108,108,-66,-133,-7,7,-5,35,"); + add("64,140,-9,25,106,-109,6,79,-137,"); + add(""); + //add("/*251*/"); + add("7,1,5148,25410,15094,"); + add("-78,-27,72,-48,-71,134,82,-126,180,79,41,-93,"); + add("22,67,-118,-13,83,-135,"); + add(""); + //add("/*252*/"); + add("7,1,24083,-4111,-17411,"); + add("-86,-14,-114,-93,-6,-126,-79,82,-125,26,70,20,"); + add("82,-15,114,86,-24,122,"); + add(""); + //add("/*253*/"); + add("8,1,12234,-12996,-24113,"); + add("-13,134,-78,-26,127,-81,41,134,-49,38,-2,21,"); + add("7,-140,76,11,-113,66,-8,-133,66,"); + add(""); + //add("/*254*/"); + add("7,1,1263,19267,22961,"); + add("-88,-22,23,-158,-114,102,113,-77,58,145,-30,17,"); + add("99,111,-97,-85,84,-65,"); + add(""); + //add("/*255*/"); + add("7,1,24383,5280,-16661,"); + add("76,-40,99,82,-101,90,0,-112,-34,-83,-22,-130,"); + add("-94,69,-117,-28,126,-2,"); + add(""); + //add("/*256*/"); + add("7,1,-3500,28664,8132,"); + add("-101,3,-56,-87,-33,79,32,-31,122,146,-35,183,"); + add("74,35,-91,-25,38,-140,"); + add(""); + //add("/*257*/"); + add("8,-1,10996,25265,11864,"); + add("114,-70,44,116,-82,64,52,-26,5,-116,97,-94,"); + add("-74,86,-116,-38,46,-62,-72,-30,131,"); + add(""); + //add("/*258*/"); + add("7,1,-8489,-28676,2368,"); + add("-45,2,-135,100,-37,-107,135,-40,-4,125,-27,112,"); + add("-82,28,67,-130,43,60,"); + add(""); + //add("/*259*/"); + add("7,1,-8544,-28708,1696,"); + add("-64,29,149,-100,35,82,-99,28,-39,-66,10,-166,"); + add("105,-33,-17,131,-44,-61,"); + add(""); + //add("/*260*/"); + add("7,1,-13684,26583,2464,"); + add("-102,-45,-76,-137,-72,-1,-98,-61,98,57,23,82,"); + add("129,64,34,127,69,-25,"); + add(""); + //add("/*261*/"); + add("7,1,-26462,13710,-3429,"); + add("-39,-77,-11,-70,-135,9,-110,-205,50,42,81,-8,"); + add("70,130,-33,70,134,-11,"); + add(""); + //add("/*262*/"); + add("8,1,25177,-2424,-16132,"); + add("51,-55,88,15,-120,43,7,-149,35,-50,-56,-68,"); + add("-40,47,-72,-13,136,-42,-1,134,-23,"); + add(""); + //add("/*263*/"); + add("7,1,-3593,28752,7771,"); + add("-130,-26,38,52,-25,114,199,4,74,-100,25,-133,"); + add("94,-2,50,-8,17,-66,"); + add(""); + //add("/*264*/"); + add("7,-1,18992,23204,-949,"); + add("50,-38,79,76,-60,101,116,-98,-56,11,-14,-132,"); + add("-109,85,-121,-102,88,82,"); + add(""); + //add("/*265*/"); + add("8,-1,16204,715,25237,"); + add("81,6,-52,141,-44,-91,9,71,-7,57,116,-41,"); + add("-71,-2,46,-126,-45,84,-122,-29,79,"); + add(""); + //add("/*266*/"); + add("7,1,11947,21012,-17769,"); + add("90,-72,-26,194,-154,-48,-100,47,-12,-129,85,11,"); + add("-141,54,-30,6,35,45,"); + add(""); + //add("/*267*/"); + add("8,1,-16323,24985,3054,"); + add("-64,-37,-40,-137,-88,-25,45,14,127,106,64,47,"); + add("-94,-61,-2,45,28,14,119,78,0,"); + add(""); + //add("/*268*/"); + add("8,-1,7459,26926,10924,"); + add("54,-44,73,122,-54,47,141,-87,112,-11,22,-44,"); + add("-44,63,-124,-40,29,-43,-140,56,-39,"); + add(""); + //add("/*269*/"); + add("7,1,4421,25599,-15005,"); + add("-163,57,51,-149,43,31,21,58,107,177,-45,-28,"); + add("85,-78,-109,70,-35,-40,"); + add(""); + //add("/*270*/"); + add("7,1,-3740,24124,-17437,"); + add("101,-6,-30,60,-71,-110,103,-102,-159,-74,7,24,"); + add("-92,67,110,-103,58,101,"); + add(""); + //add("/*271*/"); + add("7,-1,1630,23899,18060,"); + add("-7,-73,97,26,-79,102,152,4,-20,36,74,-101,"); + add("-85,82,-100,-54,59,-73,"); + add(""); + //add("/*272*/"); + add("8,-1,17320,22752,-9075,"); + add("98,-58,42,126,-77,52,92,-86,-38,-16,-14,-65,"); + add("-118,74,-44,-114,64,-61,-33,40,37,"); + add(""); + //add("/*273*/"); + add("7,1,6068,25608,14403,"); + add("-109,-11,63,-81,-45,113,88,-96,131,38,13,-37,"); + add("76,40,-102,88,57,-137,"); + add(""); + //add("/*274*/"); + add("7,-1,17827,6043,23359,"); + add("31,69,-41,30,130,-58,-71,130,20,-122,-25,100,"); + add("-17,-150,53,104,-86,-57,"); + add(""); + //add("/*275*/"); + add("7,1,1364,-29308,-6258,"); + add("-135,6,-59,24,23,-99,160,6,5,116,9,-12,"); + add("-36,-41,177,-50,-18,77,"); + add(""); + //add("/*276*/"); + add("7,-1,-18191,-23193,5583,"); + add("-74,68,39,-13,62,212,-55,22,-91,-92,34,-161,"); + add("66,-58,-18,115,-88,14,"); + add(""); + //add("/*277*/"); + add("7,1,-5480,29422,-2079,"); + add("-34,-15,-115,-39,-20,-165,-65,-8,54,-52,0,129,"); + add("-26,6,157,144,28,11,"); + add(""); + //add("/*278*/"); + add("7,1,-26312,13467,5132,"); + add("-14,-64,92,38,20,140,63,44,193,-5,18,-68,"); + add("-32,5,-167,-49,-50,-118,"); + add(""); + //add("/*279*/"); + add("7,1,22241,13603,14842,"); + add("-48,6,67,-63,-46,135,-55,-108,176,47,-5,-64,"); + add("67,36,-130,39,71,-123,"); + add(""); + //add("/*280*/"); + add("7,-1,-10783,26096,-10136,"); + add("-73,-35,-11,-140,-53,13,-193,-93,-27,52,35,34,"); + add("133,61,9,143,53,-17,"); + add(""); + //add("/*281*/"); + add("7,1,29783,1256,-3378,"); + add("4,68,62,9,88,122,11,87,149,6,-96,12,"); + add("-11,-65,-136,-11,-87,-135,"); + add(""); + //add("/*282*/"); + add("6,1,-17758,24025,2727,"); + add("-29,-6,-136,-87,-59,-52,-36,-45,161,-5,-25,188,"); + add("115,91,-49,"); + add(""); + //add("/*283*/"); + add("7,-1,-23952,18049,730,"); + add("-55,-75,42,-87,-119,38,-109,-148,28,35,46,27,"); + add("86,118,-37,85,116,-45,"); + add(""); + //add("/*284*/"); + add("7,-1,-1959,8253,28776,"); + add("-85,-33,3,-109,-82,16,-4,-124,34,54,-81,27,"); + add("-38,210,-62,109,71,-12,"); + add(""); + //add("/*285*/"); + add("7,1,24446,-969,-17363,"); + add("-58,-41,-79,-90,6,-125,-105,28,-146,25,31,33,"); + add("90,3,124,90,-3,125,"); + add(""); + //add("/*286*/"); + add("8,1,2887,27868,10725,"); + add("80,24,-85,93,20,-77,7,53,-145,-59,-21,75,"); + add("-54,25,-53,-39,-26,81,-25,-45,125,"); + add(""); + //add("/*287*/"); + add("7,1,21419,-3233,-20756,"); + add("-24,-119,-5,12,-123,32,-51,-112,-33,-75,85,-91,"); + add("2,117,-17,84,108,68,"); + add(""); + //add("/*288*/"); + add("8,1,20078,-7369,-21038,"); + add("-57,-7,-51,-117,-24,-103,-4,61,-24,22,130,-24,"); + add("47,74,19,75,-19,78,19,-139,65,"); + add(""); + //add("/*289*/"); + add("7,1,10608,21446,-18098,"); + add("-155,71,-6,-130,74,14,-41,49,34,179,-75,14,"); + add("129,-71,-9,65,-54,-26,"); + add(""); + //add("/*290*/"); + add("7,1,16151,-1050,-25260,"); + add("73,-1,47,122,24,78,149,-61,101,-61,-44,-39,"); + add("-138,-12,-89,-119,62,-80,"); + add(""); + //add("/*291*/"); + add("7,1,6256,-8530,-28073,"); + add("-89,-10,-17,-70,70,-36,128,113,-6,110,109,-7,"); + add("42,-69,29,-89,-109,12,"); + add(""); + //add("/*292*/"); + add("7,1,21026,13541,-16569,"); + add("85,-69,51,75,-69,41,109,-154,15,-55,43,-35,"); + add("-94,98,-42,-107,95,-60,"); + add(""); + //add("/*293*/"); + add("8,-1,-18859,-22602,5789,"); + add("106,-54,128,-49,49,33,-140,115,-9,47,-48,-33,"); + add("-95,67,-50,48,-51,-39,45,-53,-57,"); + add(""); + //add("/*294*/"); + add("7,-1,13656,23661,12396,"); + add("32,42,-116,-54,77,-89,-37,92,-139,-18,-4,28,"); + add("39,-82,118,30,-82,124,"); + add(""); + //add("/*295*/"); + add("6,1,8006,23007,-17510,"); + add("-151,56,6,-121,86,60,17,53,78,158,-90,-50,"); + add("129,-58,-17,"); + add(""); + //add("/*296*/"); + add("6,1,3087,24735,16693,"); + add("-183,-19,61,72,-85,112,104,-38,36,118,33,-70,"); + add("-33,81,-113,"); + add(""); + //add("/*297*/"); + add("8,1,-12618,24857,-11088,"); + add("2,-45,-102,-53,-74,-102,-86,-31,27,-39,-19,5,"); + add("-60,-22,19,43,77,120,114,79,46,"); + add(""); + //add("/*298*/"); + add("7,1,-11749,25130,-11421,"); + add("-35,-49,-71,-110,-76,-53,-90,-82,-83,-13,29,76,"); + add("66,77,98,79,60,49,"); + add(""); + //add("/*299*/"); + add("6,1,25018,-660,-16543,"); + add("66,-4,101,79,41,119,27,-147,48,-86,-7,-132,"); + add("-78,19,-120,"); + add(""); + //add("/*300*/"); + add("6,1,-15854,-24577,6681,"); + add("-80,25,-102,-66,-1,-162,84,-61,-26,86,-28,105,"); + add("62,-4,134,"); + add(""); + //add("/*301*/"); + add("7,-1,-17115,24557,-2011,"); + add("-4,-10,-84,-33,-36,-146,-32,-36,-148,-29,-18,28,"); + add("31,35,137,43,41,129,"); + add(""); + //add("/*302*/"); + add("6,1,11398,-4172,-27435,"); + add("70,-114,47,-117,-58,-40,-136,-105,-39,19,127,-12,"); + add("86,103,19,"); + add(""); + //add("/*303*/"); + add("6,1,-7436,14318,25292,"); + add("-138,-58,-8,-83,-61,10,93,-96,81,117,106,-25,"); + add("98,110,-33,"); + add(""); + //add("/*304*/"); + add("6,1,23814,-745,-18231,"); + add("5,-93,11,-74,-60,-93,-123,36,-160,55,113,66,"); + add("88,29,112,"); + add(""); + //add("/*305*/"); + add("6,1,-1698,25570,15597,"); + add("-88,-23,28,-115,-50,69,-31,-88,138,120,34,-41,"); + add("93,65,-95,"); + add(""); + //add("/*306*/"); + add("6,1,-11912,25153,-11200,"); + add("122,17,-91,-65,-58,-60,-143,-93,-55,-30,42,124,"); + add("22,55,98,"); + add(""); + //add("/*307*/"); + add("7,-1,-20089,-9689,20064,"); + add("-66,89,-24,-76,153,-4,-18,-81,-56,69,-127,9,"); + add("0,-83,-41,39,-9,36,"); + add(""); + //add("/*308*/"); + add("6,-1,22251,15516,-12811,"); + add("-4,-87,-113,-86,26,-115,-20,54,30,-35,135,102,"); + add("72,-15,105,"); + add(""); + //add("/*309*/"); + add("6,1,-6458,14255,25595,"); + add("-96,-106,34,-5,-26,13,156,64,4,89,105,-36,"); + add("-32,97,-62,"); + add(""); + //add("/*310*/"); + add("6,1,24489,-4261,-16797,"); + add("-10,-92,9,-89,-34,-121,-92,55,-144,55,71,59,"); + add("88,1,127,"); + add(""); + //add("/*311*/"); + add("6,1,-3316,28682,8146,"); + add("-99,13,-88,-180,-9,-46,35,-13,63,114,-17,109,"); + add("104,-4,57,"); + add(""); + //add("/*312*/"); + add("6,1,23528,1053,-18582,"); + add("-67,39,-83,-53,129,-59,31,123,48,82,-81,98,"); + add("24,-132,22,"); + add(""); + //add("/*313*/"); + add("6,1,-6353,29317,-386,"); + add("14,2,-107,-3,-4,-150,-118,-26,-18,-33,-4,162,"); + add("41,10,114,"); + add(""); + //add("/*314*/"); + add("6,1,23124,-10704,15834,"); + add("-88,-20,114,-37,-123,-29,45,-75,-117,87,56,-90,"); + add("11,96,50,"); + add(""); + //add("/*315*/"); + add("6,1,-10965,-27064,6879,"); + add("25,16,101,-67,56,109,-142,44,-53,-20,-23,-122,"); + add("130,-66,-46,"); + add(""); + //add("/*316*/"); + add("6,-1,4917,27988,9617,"); + add("96,-21,12,87,14,-86,-36,72,-196,-54,-7,52,"); + add("-60,-39,146,"); + add(""); + //add("/*317*/"); + add("6,1,-11542,-27125,5570,"); + add("69,-16,65,6,36,182,-109,54,35,-56,5,-86,"); + add("48,-47,-128,"); + add(""); + //add("/*318*/"); + add("6,1,22858,-880,-19409,"); + add("54,-24,64,110,-68,135,-61,-87,-69,-99,7,-118,"); + add("-23,91,-31,"); + add(""); + //add("/*319*/"); + add("6,1,-27648,11150,3354,"); + add("-39,-102,17,-24,-74,43,36,42,159,49,126,-16,"); + add("5,55,-140,"); + add(""); + //add("/*320*/"); + add("6,1,4612,1962,29578,"); + add("-94,-31,17,-91,-132,22,33,-105,1,110,57,-20,"); + add("72,140,-20,"); + add(""); + //add("/*321*/"); + add("6,1,-1839,23767,-18214,"); + add("43,-51,-70,184,-58,-92,-78,-8,-5,-124,19,37,"); + add("-76,60,86,"); + add(""); + //add("/*322*/"); + add("6,1,-26596,11995,6985,"); + add("-39,-139,86,-29,-85,33,2,-50,90,31,136,-108,"); + add("38,127,-73,"); + add(""); + //add("/*323*/"); + add("6,1,23795,-164,-18269,"); + add("46,-55,61,-29,-158,-37,-96,-53,-122,18,74,22,"); + add("25,130,30,"); + add(""); + //add("/*324*/"); + add("6,-1,-22867,-15404,11824,"); + add("41,24,111,-8,76,82,-82,57,-84,-53,-42,-157,"); + add("49,-85,-16,"); + add(""); + //add("/*325*/"); + add("6,1,11693,24510,-12748,"); + add("-64,-20,-97,-125,88,56,42,40,114,136,-64,1,"); + add("67,-45,-25,"); + add(""); + //add("/*326*/"); + add("6,1,-11168,-26833,7435,"); + add("18,20,99,82,1,123,-42,34,56,-107,16,-99,"); + add("-14,-37,-154,"); + add(""); + //add("/*327*/"); + add("6,1,-13936,24051,-11284,"); + add("-74,-76,-70,-60,-62,-58,-96,-32,54,16,53,90,"); + add("118,80,24,"); + add(""); + //add("/*328*/"); + add("6,1,29225,434,-6762,"); + add("18,61,82,30,61,138,16,-62,70,-16,-81,-79,"); + add("-37,-17,-167,"); + add(""); + //add("/*329*/"); + add("5,1,-3608,-29413,4678,"); + add("-92,6,-37,-199,3,-144,96,-6,43,125,-3,78,"); + add(""); + //add("/*330*/"); + add("5,1,27658,11617,-322,"); + add("34,-81,36,84,-207,-52,-36,85,-79,-53,132,33,"); + add(""); + //add("/*331*/"); + add("5,1,-2705,-28959,7352,"); + add("-24,22,78,-115,57,175,-66,-24,-114,139,-38,-97,"); + add(""); + //add("/*332*/"); + add("5,-1,-15874,23873,-8837,"); + add("-68,-40,15,-221,-126,61,94,56,-19,128,75,-31,"); + add(""); + //add("/*333*/"); + add("5,1,-22981,137,19284,"); + add("-96,-29,-116,4,-81,5,107,-35,129,62,114,74,"); + add(""); + //add("/*334*/"); + add("6,1,-7340,25545,-13913,"); + add("87,9,-28,74,-38,-109,-2,-50,-89,-113,4,66,"); + add("-83,37,110,"); + add(""); + //add("/*335*/"); + add("5,1,1932,28169,-10137,"); + add("142,19,82,88,-34,-77,-105,-34,-118,-115,11,8,"); + add(""); + //add("/*336*/"); + add("5,1,-2239,29202,6500,"); + add("-27,-20,78,-46,-58,238,41,25,-94,42,36,-144,"); + add(""); + //add("/*337*/"); + add("5,-1,-24505,2604,17110,"); + add("-50,-99,-58,-20,-122,-12,90,19,128,35,129,31,"); + add(""); + //add("/*338*/"); + add("6,1,-20336,-21189,6121,"); + add("-11,37,90,-61,85,91,-79,63,-47,19,-48,-101,"); + add("71,-85,-53,"); + add(""); + //add("/*339*/"); + add("4,1,4254,3683,-29468,"); + add("320,25,52,-163,-16,-27,-105,-40,-21,"); + add(""); + //add("/*340*/"); + add("5,1,4284,29586,2515,"); + add("59,0,-105,-86,24,-147,-98,6,99,20,-12,112,"); + add(""); + //add("/*341*/"); + add("5,1,-26886,10733,7871,"); + add("29,-12,114,85,100,149,-24,16,-99,-51,-28,-135,"); + add(""); + //add("/*342*/"); + add("5,1,-13498,24234,-11425,"); + add("-105,-65,-12,-169,-85,22,68,62,51,135,68,-19,"); + add(""); + //add("/*343*/"); + add("6,-1,22043,16210,-12301,"); + add("-56,32,-58,-70,134,52,64,2,117,-33,-4,-66,"); + add("48,-85,-26,"); + add(""); + //add("/*344*/"); + add("5,1,22450,-6144,-18928,"); + add("-111,30,-140,55,152,16,59,16,65,15,-137,61,"); + add(""); + //add("/*345*/"); + add("5,1,20013,16577,-14989,"); + add("52,-6,63,140,-83,97,-48,-44,-114,-124,73,-85,"); + add(""); + //add("/*346*/"); + add("5,1,8227,28696,2972,"); + add("-15,23,-188,-99,29,-5,-66,8,107,111,-40,86,"); + add(""); + //add("/*347*/"); + add("5,1,-6380,29120,-3367,"); + add("-28,-18,-102,-113,-43,-141,-18,11,124,101,37,117,"); + add(""); + //add("/*348*/"); + add("5,1,23793,-10289,15101,"); + add("-94,-116,68,-13,-97,-48,94,56,-108,39,97,6,"); + add(""); + //add("/*349*/"); + add("5,1,18853,-3180,23118,"); + add("48,-117,-55,67,16,-53,-36,157,51,-37,80,41,"); + add(""); + //add("/*350*/"); + add("5,1,-2898,29718,2905,"); + add("106,19,-87,-6,15,-174,-95,-14,55,-20,-16,149,"); + add(""); + //add("/*351*/"); + add("5,1,4133,24673,-16558,"); + add("22,-39,-52,-49,-76,-124,-81,-28,-61,43,111,173,"); + add(""); + //add("/*352*/"); + add("5,1,-17359,23518,6748,"); + add("-106,-60,-61,-67,-75,87,88,36,99,82,64,-9,"); + add(""); + //add("/*353*/"); + add("5,1,24745,-5658,-15990,"); + add("-70,25,-116,-48,118,-113,42,17,57,54,-81,111,"); + add(""); + //add("/*354*/"); + add("5,1,-6134,29314,-1752,"); + add("-118,-26,-10,-166,-33,39,76,20,58,144,29,-27,"); + add(""); + //add("/*355*/"); + add("5,-1,-18455,-22892,5946,"); + add("-81,50,-58,-89,38,-136,53,-53,-39,76,-27,138,"); + add(""); + //add("/*356*/"); + add("5,1,7506,28869,-3200,"); + add("-114,35,46,63,-2,141,110,-29,-5,21,-19,-124,"); + add(""); + //add("/*357*/"); + add("5,1,-19149,-22531,5067,"); + add("-69,67,39,-156,123,-52,66,-66,-41,108,-86,30,"); + add(""); + //add("/*358*/"); + add("4,1,-11154,10714,-25706,"); + add("-86,-136,-19,-138,16,67,39,94,22,"); + add(""); + //add("/*359*/"); + add("5,1,-11977,-26541,7220,"); + add("35,14,107,21,37,167,-80,16,-72,-11,-35,-141,"); + add(""); + //add("/*360*/"); + add("5,-1,12975,18669,19573,"); + add("11,61,-65,-125,125,-37,-62,-53,91,109,-97,21,"); + add(""); + //add("/*361*/"); + add("5,1,-10778,27815,3183,"); + add("3,14,-112,-37,-4,-95,-103,-47,69,52,2,161,"); + add(""); + //add("/*362*/"); + add("5,1,5802,24352,16532,"); + add("54,21,-49,116,84,-168,-73,-13,47,-91,-61,122,"); + add(""); + //add("/*363*/"); + add("5,1,10271,19027,20796,"); + add("-105,-43,91,86,-57,9,138,-37,-34,-25,72,-53,"); + add(""); + //add("/*364*/"); + add("5,1,-3812,-7158,-28883,"); + add("-111,23,9,13,124,-32,177,-2,-23,-12,-93,24,"); + add(""); + //add("/*365*/"); + add("5,-1,-26344,13706,4261,"); + add("-48,-69,-76,-47,-96,15,4,-31,122,74,139,13,"); + add(""); + //add("/*366*/"); + add("4,1,4332,-21849,-20096,"); + add("26,-143,162,-151,20,-55,29,71,-71,"); + add(""); + //add("/*367*/"); + add("5,1,11385,17811,21287,"); + add("-72,-41,73,-16,-121,108,94,11,-58,28,107,-104,"); + add(""); + //add("/*368*/"); + add("5,1,-25127,12810,-10224,"); + add("-25,-70,-26,-55,-132,-27,-31,-66,-6,84,203,43,"); + add(""); + //add("/*369*/"); + add("5,1,12061,-19379,-19468,"); + add("5,59,-55,129,111,-29,57,-24,58,-99,-108,46,"); + add(""); + //add("/*370*/"); + add("5,1,14601,-4888,-25747,"); + add("-33,-105,1,-141,-47,-70,-24,67,-26,108,73,46,"); + add(""); + //add("/*371*/"); + add("5,1,3182,28027,10215,"); + add("85,25,-94,-63,50,-119,-84,-20,80,0,-45,125,"); + add(""); + //add("/*372*/"); + add("5,1,24760,-13205,-10611,"); + add("48,83,9,95,156,31,-11,-49,34,-80,-123,-34,"); + add(""); + //add("/*373*/"); + add("5,1,22676,-468,-19636,"); + add("56,-46,66,-18,-132,-18,-76,-21,-86,-5,159,-11,"); + add(""); + //add("/*374*/"); + add("5,1,-8077,26065,-12464,"); + add("24,-25,-69,23,-83,-185,-55,7,48,-13,63,140,"); + add(""); + //add("/*375*/"); + add("5,1,-16783,-24152,5918,"); + add("73,-71,-85,118,-89,-31,-30,39,75,-98,81,53,"); + add(""); + //add("/*376*/"); + add("5,1,3471,29597,3461,"); + add("97,-6,-45,40,14,-168,-80,10,-3,-41,-11,138,"); + add(""); + //add("/*377*/"); + add("5,1,-23913,14805,-10440,"); + add("-45,-76,-3,-118,-129,90,31,66,22,92,106,-63,"); + add(""); + //add("/*378*/"); + add("5,1,-13537,24149,-11558,"); + add("-78,-47,-6,-155,-73,31,19,38,57,133,62,-27,"); + add(""); + //add("/*379*/"); + add("5,1,25723,-3019,-15140,"); + add("2,-81,20,-24,-199,1,-13,55,-33,15,150,-7,"); + add(""); + //add("/*380*/"); + add("5,1,18791,-8648,-21728,"); + add("-47,28,-51,-101,94,-124,74,33,50,73,-79,94,"); + add(""); + //add("/*381*/"); + add("5,1,-8993,-28620,-183,"); + add("89,-27,-50,148,-46,22,-1,0,52,-139,43,28,"); + add(""); + //add("/*382*/"); + add("5,1,-8768,-28641,-1673,"); + add("23,-13,95,-32,2,151,-70,24,-46,16,3,-153,"); + add(""); + //add("/*383*/"); + add("5,-1,16062,838,25324,"); + add("49,20,-32,167,83,-110,-83,-10,54,-116,-55,76,"); + add(""); + //add("/*384*/"); + add("5,1,-26157,14015,4405,"); + add("-30,-67,29,-77,-171,83,22,47,-18,57,127,-58,"); + add(""); + //add("/*385*/"); + add("5,1,21813,15801,-13211,"); + add("-2,-58,-71,-52,-66,-164,-11,47,39,26,72,126,"); + add(""); + //add("/*386*/"); + add("5,-1,-19641,22184,4702,"); + add("-76,-56,-55,-110,-117,85,52,40,29,78,83,-59,"); + add(""); + //add("/*387*/"); + add("5,1,15005,-1299,-25945,"); + add("-59,-53,-32,-124,-41,-69,-8,102,-9,133,23,75,"); + add(""); + //add("/*388*/"); + add("5,1,-10453,11094,-25839,"); + add("67,-43,-46,-1,-102,-42,-151,-27,49,32,108,33,"); + add(""); + //add("/*389*/"); + add("5,1,-26735,12315,5795,"); + add("-46,-82,-39,-37,-127,97,35,47,62,40,120,-67,"); + add(""); + //add("/*390*/"); + add("5,-1,-16802,23231,-8833,"); + add("-19,-44,-78,-139,-124,-58,33,33,22,101,96,58,"); + add(""); + //add("/*391*/"); + add("5,1,14422,-5109,-25805,"); + add("-79,-114,-21,-125,-36,-62,57,63,19,112,85,45,"); + add(""); + //add("/*392*/"); + add("5,1,10064,-5982,-27621,"); + add("-68,-60,-12,-159,-76,-40,16,47,-5,131,70,32,"); + add(""); + //add("/*393*/"); + add("5,1,24783,-4317,-16345,"); + add("6,-74,28,-42,-75,-43,-68,125,-136,56,14,81,"); + add(""); + //add("/*394*/"); + add("5,1,-13180,26791,2922,"); + add("52,32,-58,2,16,-147,-90,-46,20,-26,-27,133,"); + add(""); + //add("/*395*/"); + add("4,1,-1749,25344,15957,"); + add("-94,-46,62,119,-78,137,-3,58,-93,"); + add(""); + //add("/*396*/"); + add("5,1,-26328,14008,-3259,"); + add("-27,-66,-62,-66,-147,-86,14,34,27,52,118,77,"); + add(""); + //add("/*397*/"); + add("4,1,24089,7261,-16340,"); + add("48,-182,-10,-71,8,-101,-20,136,32,"); + add(""); + //add("/*398*/"); + add("4,1,-7194,13999,25540,"); + add("129,4,33,19,128,-65,-131,-13,-29,"); + add(""); + //add("/*399*/"); + add("5,-1,-24613,17122,1025,"); + add("-3,-11,108,-31,-55,138,11,15,3,31,54,-135,"); + add(""); + //add("/*400*/"); + add("5,1,20152,-5943,21414,"); + add("-22,-105,-8,22,-119,-55,45,37,-32,-6,160,52,"); + add(""); + //add("/*401*/"); + add("5,1,-1915,23677,-18322,"); + add("-91,-20,-17,-173,3,23,42,15,15,142,5,-9,"); + add(""); + //add("/*402*/"); + add("5,1,-23760,17289,6048,"); + add("47,40,67,89,121,3,20,27,-4,-112,-147,-13,"); + add(""); + //add("/*403*/"); + add("5,1,-14558,23775,-11081,"); + add("15,-31,-86,-12,-74,-142,-40,-5,41,4,69,142,"); + add(""); + //add("/*404*/"); + add("5,1,-12479,24643,-11704,"); + add("-55,-50,-48,-152,-89,-22,17,26,36,120,74,27,"); + add(""); + //add("/*405*/"); + add("4,1,5264,29534,-120,"); + add("82,-15,-121,-123,21,-60,-42,9,160,"); + add(""); + //add("/*406*/"); + add("5,1,13262,-5908,-26253,"); + add("-65,-72,-16,-137,-56,-56,7,54,-9,131,60,52,"); + add(""); + //add("/*407*/"); + add("4,1,-20288,22087,756,"); + add("19,19,-81,-118,-104,-125,29,23,110,"); + add(""); + //add("/*408*/"); + add("5,1,19086,-2847,22970,"); + add("38,55,-25,26,149,-4,-46,33,42,-22,-149,1,"); + add(""); + //add("/*409*/"); + add("4,1,-2873,28899,7523,"); + add("-133,-13,0,14,-30,117,144,12,10,"); + add(""); + //add("/*410*/"); + add("5,1,15596,18597,-17633,"); + add("67,-43,14,89,-115,-41,-45,-18,-58,-66,96,41,"); + add(""); + //add("/*411*/"); + add("5,-1,-28925,7951,348,"); + add("9,27,78,35,121,116,-1,-1,-35,-24,-79,-152,"); + add(""); + //add("/*412*/"); + add("5,-1,9541,23385,16190,"); + add("-2,-50,73,79,-109,108,19,19,-38,-53,97,-107,"); + add(""); + //add("/*413*/"); + add("5,1,29210,473,-6823,"); + add("15,77,72,31,35,138,-2,-56,-13,-30,-68,-138,"); + add(""); + //add("/*414*/"); + add("5,1,-25829,15180,1561,"); + add("-4,2,-86,-23,-24,-175,1,0,31,20,19,148,"); + add(""); + //add("/*415*/"); + add("5,1,-20000,22355,530,"); + add("-25,-22,-75,-69,-59,-143,-15,-14,47,64,55,123,"); + add(""); + //add("/*416*/"); + add("4,1,-444,-28368,9750,"); + add("52,35,103,-161,22,54,22,-47,-132,"); + add(""); + //add("/*417*/"); + add("4,1,2286,29384,5600,"); + add("-108,22,-73,-64,-19,124,98,-19,59,"); + add(""); + //add("/*418*/"); + add("4,1,-9750,11346,-26004,"); + add("114,-63,-70,-93,-91,-4,-88,65,60,"); + add(""); + //add("/*419*/"); + add("4,1,29357,1075,-6086,"); + add("26,-12,125,3,-133,-7,-25,20,-118,"); + add(""); + //add("/*420*/"); + add("5,1,-4180,-7285,-28800,"); + add("-96,6,12,12,67,-18,173,35,-34,-21,-79,23,"); + add(""); + //add("/*421*/"); + add("4,1,21812,-2819,-20403,"); + add("43,-216,77,-30,61,-41,-39,132,-60,"); + add(""); + //add("/*422*/"); + add("4,1,-6475,29293,-129,"); + add("-137,-31,54,34,8,102,130,29,-57,"); + add(""); + //add("/*423*/"); + add("4,1,-9851,-28219,2574,"); + add("-20,18,125,-123,38,-61,54,-29,-113,"); + add(""); + //add("/*424*/"); + add("4,1,6163,-10670,-27353,"); + add("84,30,8,-8,-122,46,-130,-35,-16,"); + add(""); + //add("/*425*/"); + add("5,1,24033,10600,14493,"); + add("-1,-61,47,-4,-116,90,29,-16,-37,-1,119,-84,"); + add(""); + //add("/*426*/"); + add("4,1,-10404,28061,2080,"); + add("-168,-58,-65,15,0,83,149,52,44,"); + add(""); + //add("/*427*/"); + add("4,-1,-6287,25435,-14613,"); + add("-175,-65,-37,-33,20,50,109,54,46,"); + add(""); + //add("/*428*/"); + add("4,1,3313,24533,16946,"); + add("72,-54,64,137,8,-41,-83,49,-52,"); + add(""); + //add("/*429*/"); + add("5,1,-17749,22168,9672,"); + add("-55,-22,-51,-134,-84,-55,35,14,33,110,69,45,"); + add(""); + //add("/*430*/"); + add("4,1,-24211,14614,-10014,"); + add("-45,-101,-37,-61,-44,84,77,151,33,"); + add(""); + //add("/*431*/"); + add("5,1,6168,20534,20984,"); + add("78,-19,-5,155,-9,-37,-14,11,-7,-148,19,25,"); + add(""); + //add("/*432*/"); + add("4,1,25249,3517,-15816,"); + add("54,-55,75,-32,-104,-73,-61,98,-77,"); + add(""); + //add("/*433*/"); + add("5,1,24510,6812,-15901,"); + add("-3,-70,-35,-47,-99,-113,-7,16,-4,32,110,94,"); + add(""); + //add("/*434*/"); + add("4,1,8900,28579,2013,"); + add("-28,18,-145,-98,29,17,48,-23,129,"); + add(""); + //add("/*435*/"); + add("4,1,-19110,-22514,5287,"); + add("-134,112,-16,34,-47,-73,77,-68,-7,"); + add(""); + //add("/*436*/"); + add("4,1,-26431,12476,6763,"); + add("-53,-173,112,21,25,32,28,120,-106,"); + add(""); + //add("/*437*/"); + add("4,1,-6923,29146,-1603,"); + add("-11,-10,-135,-86,-21,-1,12,12,153,"); + add(""); + //add("/*438*/"); + add("4,1,-7322,29032,-1885,"); + add("-93,-29,-71,-84,-16,84,116,34,54,"); + add(""); + //add("/*439*/"); + add("4,1,3874,29626,2697,"); + add("158,-14,-71,-62,11,-39,-140,12,75,"); + add(""); + //add("/*440*/"); + add("5,-1,-20399,-10562,19296,"); + add("-47,54,-21,-103,82,-64,4,-32,-13,72,-61,43,"); + add(""); + //add("/*441*/"); + add("4,1,-12040,-26645,6714,"); + add("91,-7,132,-57,34,35,-79,-3,-151,"); + add(""); + //add("/*442*/"); + add("4,1,-8141,28851,-1154,"); + add("-44,-19,-149,-67,-18,19,46,19,149,"); + add(""); + //add("/*443*/"); + add("4,1,-26611,11542,7659,"); + add("-88,-157,-73,26,23,58,70,125,54,"); + add(""); + //add("/*444*/"); + add("4,1,-25420,7629,13987,"); + add("24,-119,108,39,84,24,-21,80,-81,"); + add(""); + //add("/*445*/"); + add("4,1,-361,26098,14791,"); + add("-10,-64,111,54,-28,50,26,82,-142,"); + add(""); + //add("/*446*/"); + add("4,1,-10298,18382,21356,"); + add("130,-27,85,49,46,-16,-147,13,-81,"); + add(""); + //add("/*447*/"); + add("4,1,-6714,29188,-1727,"); + add("-94,-24,-29,-73,-10,108,114,26,-7,"); + add(""); + //add("/*448*/"); + add("4,1,-14486,-9145,-24628,"); + add("-107,-23,72,0,72,-27,104,40,-76,"); + add(""); + //add("/*449*/"); + add("3,1,-12116,27417,1220,"); + add("-145,-70,134,73,33,-17,"); + add(""); + //add("/*450*/"); + add("4,1,12149,-27337,-2254,"); + add("-8,3,-82,91,46,-59,-14,-19,153,"); + add(""); + //add("/*451*/"); + add("3,1,4304,29609,2188,"); + add("-48,20,-185,-38,-3,124,"); + add(""); + //add("/*452*/"); + add("4,1,-12276,24972,-11211,"); + add("-4,-43,-90,-130,-57,15,74,60,50,"); + add(""); + //add("/*453*/"); + add("4,1,3993,24360,17048,"); + add("106,2,-27,-55,80,-102,-56,-28,53,"); + add(""); + //add("/*454*/"); + add("4,1,4361,29555,2736,"); + add("-38,14,-91,-116,16,2,75,-20,101,"); + add(""); + //add("/*455*/"); + add("4,1,-18479,-23127,4866,"); + add("-52,67,118,-61,35,-66,59,-62,-71,"); + add(""); + //add("/*456*/"); + add("4,-1,2259,21690,20602,"); + add("163,40,-61,-51,30,-26,-119,-48,64,"); + add(""); + //add("/*457*/"); + add("4,1,20331,14288,-16807,"); + add("113,-62,84,2,-51,-41,-116,87,-67,"); + add(""); + //add("/*458*/"); + add("4,1,-16786,-24244,5517,"); + add("-13,-14,-98,115,-77,10,-36,41,70,"); + add(""); + //add("/*459*/"); + add("4,1,-1657,25010,16486,"); + add("-107,31,-59,-27,-59,86,106,-9,25,"); + add(""); + //add("/*460*/"); + add("4,1,-1331,-20857,-21523,"); + add("-32,87,-81,12,31,-31,94,-42,35,"); + add(""); + //add("/*461*/"); + add("3,1,-26552,5728,12735,"); + add("86,-10,182,-41,30,-98,"); + add(""); + //add("/*462*/"); + add("3,1,-11118,27856,637,"); + add("-170,-68,5,82,32,63,"); + add(""); + //add("/*463*/"); + add("4,1,2831,-28218,9783,"); + add("42,27,67,-99,15,70,-19,-40,-108,"); + add(""); + //add("/*464*/"); + add("3,1,23950,2362,-17911,"); + add("20,-179,4,-44,82,-49,"); + add(""); + //add("/*465*/"); + add("3,1,29304,688,-6390,"); + add("3,-151,3,-18,18,-82,"); + add(""); + //add("/*466*/"); + add("3,1,-9197,-28136,4878,"); + add("-159,68,85,75,-37,-64,"); + add(""); + //add("/*467*/"); + add("4,1,-10259,28140,1705,"); + add("-56,-25,63,62,17,101,34,17,-76,"); + add(""); + //add("/*468*/"); + add("3,1,29280,766,-6487,"); + add("34,42,158,-23,-96,-116,"); + add(""); + //add("/*469*/"); + add("4,1,6865,26520,12229,"); + add("-38,-15,54,43,-56,96,50,31,-93,"); + add(""); + //add("/*470*/"); + add("3,1,13499,-19327,-18554,"); + add("45,135,-107,13,-80,93,"); + add(""); + //add("/*471*/"); + add("3,-1,16732,5918,24187,"); + add("-123,131,53,50,-84,-14,"); + add(""); + //add("/*472*/"); + add("3,1,13670,-4696,-26288,"); + add("-146,-71,-63,60,85,15,"); + add(""); + //add("/*473*/"); + add("3,1,2313,23926,-17950,"); + add("-161,-16,-41,80,47,72,"); + add(""); + //add("/*474*/"); + add("3,1,3781,28274,9290,"); + add("93,34,-146,-91,-6,58,"); + add(""); + //add("/*475*/"); + add("3,1,25584,3122,-15352,"); + add("-85,-26,-147,17,59,39,"); + add(""); + //add("/*476*/"); + add("3,1,29702,3744,-1936,"); + add("17,-153,-35,-15,89,-55,"); + add(""); + //add("/*477*/"); + add("3,1,24789,6574,-15566,"); + add("65,-169,34,-52,102,-40,"); + add(""); + //add("/*478*/"); + add("3,-1,-29247,6430,1802,"); + add("-11,-85,122,17,72,23,"); + add(""); + //add("/*479*/"); + add("3,1,-6095,14636,25468,"); + add("-135,-95,22,97,7,20,"); + add(""); + //add("/*480*/"); + add("3,1,-10821,10826,-25801,"); + add("-167,-23,61,65,41,-11,"); + add(""); + //add("/*481*/"); + add("3,1,29023,590,-7570,"); + add("34,-5,129,-19,-95,-79,"); + add(""); + //add("/*482*/"); + add("3,1,23976,5439,-17192,"); + add("39,-177,-1,-33,87,-18,"); + add(""); + //add("/*483*/"); + add("4,1,5247,29038,-5412,"); + add("-99,36,100,26,0,28,97,-32,-81,"); + add(""); + //add("/*484*/"); + add("4,1,-18202,-23335,4919,"); + add("15,5,73,-62,62,68,2,-22,-100,"); + add(""); + //add("/*485*/"); + add("3,1,5756,-9056,-28015,"); + add("57,-84,39,-130,-10,-23,"); + add(""); + //add("/*486*/"); + add("3,1,-11472,-27071,5962,"); + add("-89,67,132,14,-25,-86,"); + add(""); + //add("/*487*/"); + add("3,1,-12893,26395,6088,"); + add("-47,3,-113,-50,-50,112,"); + add(""); + //add("/*488*/"); + add("3,1,5886,-8242,-28239,"); + add("26,166,-42,24,-67,24,"); + add(""); + //add("/*489*/"); + add("4,1,8245,18657,21999,"); + add("-25,-59,59,73,-66,28,2,70,-60,"); + add(""); + //add("/*490*/"); + add("3,1,5232,21275,20494,"); + add("58,-123,112,-13,69,-68,"); + add(""); + //add("/*491*/"); + add("4,1,-16253,-24546,5776,"); + add("-9,-21,-120,76,-43,33,-12,23,62,"); + add(""); + //add("/*492*/"); + add("3,-1,9502,25942,11694,"); + add("165,-65,8,-75,35,-15,"); + add(""); + //add("/*493*/"); + add("3,1,-12159,27406,1045,"); + add("-141,-66,59,88,39,12,"); + add(""); + //add("/*494*/"); + add("3,1,5425,21100,20624,"); + add("135,-94,60,-70,58,-40,"); + add(""); + //add("/*495*/"); + add("3,-1,3389,22127,19973,"); + add("-144,69,-53,28,-42,42,"); + add(""); + //add("/*496*/"); + add("3,1,-29998,-271,-211,"); + add("1,-103,-27,-1,44,124,"); + add(""); + //add("/*497*/"); + add("3,1,-6646,3953,28986,"); + add("154,-35,40,-66,64,-23,"); + add(""); + //add("/*498*/"); + add("3,1,17776,-4397,-23763,"); + add("-125,-94,-76,59,61,33,"); + add(""); + //add("/*499*/"); + add("3,1,15919,-2901,-25262,"); + add("-86,-113,-41,2,103,-10,"); + add(""); + //add("/*500*/"); + add("3,1,10276,18702,21087,"); + add("34,-115,84,49,48,-65,"); + add(""); + //add("/*501*/"); + add("3,1,-27182,9729,8156,"); + add("24,-63,152,0,71,-83,"); + add(""); + //add("/*502*/"); + add("3,1,-5062,29557,-877,"); + add("-151,-26,15,102,19,47,"); + add(""); + //add("/*503*/"); + add("3,1,5323,-9639,-27906,"); + add("94,-7,20,-115,-91,10,"); + add(""); + //add("/*504*/"); + add("3,1,9566,21962,-18060,"); + add("80,-60,-30,-146,87,28,"); + add(""); + //add("/*505*/"); + add("3,1,7782,19198,21700,"); + add("98,-114,65,-23,74,-57,"); + add(""); + //add("/*506*/"); + add("3,1,-25374,8277,13699,"); + add("37,132,-12,-48,-43,-63,"); + add(""); + //add("/*507*/"); + add("3,1,-21077,21320,1096,"); + add("-106,-101,-82,53,50,70,"); + add(""); + //add("/*508*/"); + add("3,1,24281,-1036,-17589,"); + add("-21,-166,-18,-1,96,-8,"); + add(""); + //add("/*509*/"); + add("3,1,-22788,37,19512,"); + add("-85,-52,-100,83,-20,97,"); + add(""); + //add("/*510*/"); + add("3,1,5240,28832,-6422,"); + add("-69,36,103,119,-31,-39,"); + add(""); + //add("/*511*/"); + add("3,1,-7468,-28825,-3652,"); + add("127,-23,-73,-26,-5,83,"); + add(""); + //add("/*512*/"); + add("3,1,24788,6981,-15389,"); + add("-28,-91,-85,-27,111,6,"); + add(""); + //add("/*513*/"); + add("3,1,-23208,-6,19010,"); + add("-80,-82,-98,74,14,91,"); + add(""); + //add("/*514*/"); + add("3,1,-2403,29024,7200,"); + add("6,-38,153,37,26,-90,"); + add(""); + //add("/*515*/"); + add("3,1,-8354,27070,9869,"); + add("31,63,-147,-39,-31,53,"); + add(""); + //add("/*516*/"); + add("3,1,25819,2792,-15019,"); + add("68,-90,100,-56,16,-93,"); + add(""); + //add("/*517*/"); + add("3,1,-13037,26839,3117,"); + add("36,33,-139,-71,-42,72,"); + add(""); + //add("/*518*/"); + add("3,1,19424,15377,-16920,"); + add("93,-132,-12,-64,64,-15,"); + add(""); + //add("/*519*/"); + add("3,1,25368,-2667,-15790,"); + add("-16,-138,-3,-25,82,-54,"); + add(""); + //add("/*520*/"); + add("3,1,-27385,6432,10424,"); + add("17,-117,116,-6,67,-55,"); + add(""); + //add("/*521*/"); + add("3,1,-16689,-24298,5573,"); + add("100,-55,59,-44,42,51,"); + add(""); + //add("/*522*/"); + add("3,1,7818,28361,5876,"); + add("-144,51,-56,68,-29,50,"); + add(""); + //add("/*523*/"); + add("3,1,-1083,23630,-18452,"); + add("50,-78,-102,-92,30,44,"); + add(""); + //add("/*524*/"); + add("3,1,25414,6393,-14604,"); + add("-41,-106,-116,11,70,48,"); + add(""); + //add("/*525*/"); + add("3,1,-11631,906,-27639,"); + add("120,91,-47,-49,-80,18,"); + add(""); + //add("/*526*/"); + add("3,1,3474,212,29797,"); + add("-59,-123,8,98,50,-12,"); + add(""); + //add("/*527*/"); + add("3,1,2829,27930,10580,"); + add("17,48,-134,-69,-20,73,"); + add(""); + //add("/*528*/"); + add("3,1,-18229,-23261,5161,"); + add("-120,85,-43,79,-65,-12,"); + add(""); + //add("/*529*/"); + add("3,1,1852,23822,18140,"); + add("-125,-44,70,101,2,-12,"); + add(""); + //add("/*530*/"); + add("3,1,17469,17022,-17466,"); + add("116,-106,12,-62,33,-30,"); + add(""); + //add("/*531*/"); + add("3,1,-13668,26130,5512,"); + add("-117,-58,-16,61,16,79,"); + add(""); + //add("/*532*/"); + add("3,1,-16825,22385,-10761,"); + add("-69,-60,-18,116,107,41,"); + add(""); + //add("/*533*/"); + add("3,1,-17801,-23670,4779,"); + add("-107,95,71,39,-40,-52,"); + add(""); + //add("/*534*/"); + add("3,-1,-16972,24643,-2166,"); + add("-50,-47,-138,-6,3,78,"); + add(""); + //add("/*535*/"); + add("3,1,-29510,-1408,5213,"); + add("-15,-102,-117,12,23,79,"); + add(""); + //add("/*536*/"); + add("3,1,-8023,14394,25068,"); + add("-68,34,-40,15,-116,71,"); + add(""); + //add("/*537*/"); + add("3,1,18663,8080,22054,"); + add("-75,93,30,-31,-36,39,"); + add(""); + //add("/*538*/"); + add("3,1,20234,-5953,-21335,"); + add("-49,130,-81,31,-57,45,"); + add(""); + //add("/*539*/"); + add("3,1,9465,-4873,-28048,"); + add("-62,-145,5,10,86,-12,"); + add(""); + //add("/*540*/"); + add("3,1,11849,-3988,-27271,"); + add("-79,-106,-18,-3,100,-16,"); + add(""); + //add("/*541*/"); + add("3,1,19173,8661,21387,"); + add("61,-39,-39,-116,87,69,"); + add(""); + //add("/*542*/"); + add("3,1,-25383,8079,13799,"); + add("-8,-129,61,32,94,5,"); + add(""); + //add("/*543*/"); + add("3,1,-947,23612,-18482,"); + add("119,-50,-69,-79,-3,0,"); + add(""); + //add("/*544*/"); + add("3,1,-20303,-21276,5923,"); + add("-76,41,-110,64,-56,18,"); + add(""); + //add("/*545*/"); + add("3,1,-3266,29707,2611,"); + add("37,16,-138,-65,-11,47,"); + add(""); + //add("/*546*/"); + add("3,1,29437,5643,-1268,"); + add("24,-114,44,-6,9,-82,"); + add(""); + //add("/*547*/"); + add("3,1,5941,-8348,-28196,"); + add("33,-77,30,-118,6,-27,"); + add(""); + //add("/*548*/"); + add("3,1,8674,28665,1747,"); + add("63,-15,-64,-102,33,-41,"); + add(""); + //add("/*549*/"); + add("3,1,12119,-27290,-2892,"); + add("132,54,46,-68,-33,16,"); + add(""); + //add("/*550*/"); + add("3,1,16774,7079,-23844,"); + add("82,-124,22,-73,54,-36,"); + add(""); + //add("/*551*/"); + add("3,1,20757,13260,17126,"); + add("63,-128,22,-13,88,-51,"); + add(""); + //add("/*552*/"); + add("3,1,-23106,319,19132,"); + add("-14,-153,-16,23,75,27,"); + add(""); + //add("/*553*/"); + add("3,1,28708,8390,-2334,"); + add("41,-117,87,-18,41,-74,"); + add(""); + //add("/*554*/"); + add("3,-1,-17143,22854,-9157,"); + add("-56,-49,-15,111,102,47,"); + add(""); + //add("/*555*/"); + add("3,1,24593,-4420,-16602,"); + add("-58,81,-108,42,-1,63,"); + add(""); + //add("/*556*/"); + add("3,1,-5670,29343,-2618,"); + add("-124,-24,0,70,19,69,"); + add(""); + //add("/*557*/"); + add("3,1,29384,4265,-4286,"); + add("19,-142,-11,-16,73,-41,"); + add(""); + //add("/*558*/"); + add("3,-1,-26493,13413,-4266,"); + add("73,129,-48,-41,-79,9,"); + add(""); + //add("/*559*/"); + add("3,1,-12215,8751,25965,"); + add("50,90,-6,-110,-43,-38,"); + add(""); + //add("/*560*/"); + add("3,1,942,-9821,-28331,"); + add("-127,40,-18,18,36,-12,"); + add(""); + //add("/*561*/"); + add("3,1,5791,-10962,-27318,"); + add("72,-41,31,-101,-56,1,"); + add(""); + //add("/*562*/"); + add("3,1,-16110,-24557,6118,"); + add("-55,1,-140,52,-15,77,"); + add(""); + //add("/*563*/"); + add("3,1,24603,7780,-15303,"); + add("19,-130,-35,-41,81,-25,"); + add(""); + //add("/*564*/"); + add("3,1,-11587,7787,26554,"); + add("-77,78,-57,3,-100,31,"); + add(""); + //add("/*565*/"); + add("3,-1,-16566,24953,-1701,"); + add("-34,-32,-139,-15,-5,72,"); + add(""); + //add("/*566*/"); + add("3,1,-10538,27951,2769,"); + add("-113,-50,71,82,32,-2,"); + add(""); + //add("/*567*/"); + add("3,1,-26227,14265,-2946,"); + add("-29,-81,-126,8,32,76,"); + add(""); + //add("/*568*/"); + add("3,1,-29996,-410,275,"); + add("1,-64,-4,0,96,102,"); + add(""); + //add("/*569*/"); + add("3,1,-1328,24397,17407,"); + add("-88,-68,88,79,22,-24,"); + add(""); + //add("/*570*/"); + add("3,1,28640,5411,-7103,"); + add("16,-124,-30,-25,81,-41,"); + add(""); + //add("/*571*/"); + add("3,1,2879,27986,10415,"); + add("44,45,-133,-48,-14,52,"); + add(""); + //add("/*572*/"); + add("3,1,-10402,-26170,10341,"); + add("-140,40,-40,64,-24,4,"); + add(""); + //add("/*573*/"); + add("3,1,-10281,28087,2329,"); + add("-106,-42,34,78,24,50,"); + add(""); + //add("/*574*/"); + add("3,1,2742,27846,10820,"); + add("85,35,-111,-70,-7,34,"); + add(""); + //add("/*575*/"); + add("3,1,-3438,-29243,-5748,"); + add("43,20,-125,29,-18,76,"); + add(""); + //add("/*576*/"); + add("3,1,-26723,12841,4584,"); + add("-66,-110,-80,29,43,47,"); + add(""); + //add("/*577*/"); + add("3,1,-1401,24087,17828,"); + add("-1,-60,81,89,26,-28,"); + add(""); + //add("/*578*/"); + add("3,1,5935,-7944,-28314,"); + add("15,145,-37,11,-47,15,"); + add(""); + //add("/*579*/"); + add("3,1,22691,-404,-19620,"); + add("90,-40,105,-74,0,-86,"); + add(""); + //add("/*580*/"); + add("3,1,-615,23609,-18500,"); + add("-27,-62,-78,-73,25,34,"); + add(""); + //add("/*581*/"); + add("3,1,-7610,27327,9765,"); + add("86,9,39,11,34,-85,"); + add(""); + //add("/*582*/"); + add("3,1,3275,28106,9967,"); + add("66,34,-120,-66,-8,46,"); + add(""); + //add("/*583*/"); + add("3,1,-1798,26125,-14637,"); + add("-125,-47,-69,60,25,37,"); + add(""); + //add("/*584*/"); + add("3,1,3404,28154,9786,"); + add("16,34,-104,-83,-3,38,"); + add(""); + //add("/*585*/"); + add("3,1,-19236,-22431,5182,"); + add("-95,81,-4,41,-48,-59,"); + add(""); + //add("/*586*/"); + add("3,1,16386,-1104,25106,"); + add("-73,82,50,-24,-52,14,"); + add(""); + //add("/*587*/"); + add("3,1,19553,-4260,-22350,"); + add("63,-51,65,-69,-44,-52,"); + add(""); + //add("/*588*/"); + add("3,1,-22905,18425,5990,"); + add("96,104,47,-33,-35,-18,"); + add(""); + //add("/*589*/"); + add("3,1,-12241,25010,-11164,"); + add("-117,-70,-28,42,42,46,"); + add(""); + //add("/*590*/"); + add("3,1,-6089,-28902,-5253,"); + add("34,14,-117,43,-22,71,"); + add(""); + //add("/*591*/"); + add("3,1,14736,-4824,-25682,"); + add("-43,-106,-5,-40,63,-34,"); + add(""); + //add("/*592*/"); + add("3,1,19044,17073,-15679,"); + add("94,-108,-3,-64,54,-19,"); + add(""); + //add("/*593*/"); + add("3,1,-16277,25021,3001,"); + add("-102,-58,-78,32,15,59,"); + add(""); + //add("/*594*/"); + add("3,1,3248,24619,16833,"); + add("-38,-76,118,31,32,-52,"); + add(""); + //add("/*595*/"); + add("3,1,-19337,-22287,5420,"); + add("18,15,122,-54,25,-89,"); + add(""); + //add("/*596*/"); + add("3,1,3510,24558,16869,"); + add("47,-68,89,36,36,-59,"); + add(""); + //add("/*597*/"); + add("3,1,-6842,29209,-35,"); + add("-123,-29,15,65,16,45,"); + add(""); + //add("/*598*/"); + add("3,1,-15937,22907,-11013,"); + add("-119,-62,44,55,39,1,"); + add(""); + //add("/*599*/"); + add("3,1,27779,11315,-526,"); + add("-49,121,-23,9,-22,44,"); + add(""); + //add("/*600*/"); + add("3,1,-12034,25103,-11183,"); + add("-63,-58,-60,-41,5,55,"); + add(""); + //add("/*601*/"); + add("3,1,11603,-4113,-27358,"); + add("-14,-103,10,-64,53,-35,"); + add(""); + //add("/*602*/"); + add("3,1,12813,-2626,-26999,"); + add("-4,-132,12,-36,71,-25,"); + add(""); + //add("/*603*/"); + add("3,1,-25308,8431,13728,"); + add("38,-43,95,1,89,-52,"); + add(""); + //add("/*604*/"); + add("3,1,-25475,7114,14157,"); + add("31,120,-5,-42,-62,-45,"); + add(""); + //add("/*605*/"); + add("3,1,13199,-12085,-24077,"); + add("70,108,-16,5,-60,32,"); + add(""); + //add("/*606*/"); + add("3,1,-14219,23894,-11265,"); + add("-85,-85,-73,26,40,52,"); + add(""); + //add("/*607*/"); + add("3,1,4551,-23163,-18514,"); + add("29,-77,104,-49,25,-44,"); + add(""); + //add("/*608*/"); + add("3,1,5199,-9999,-27803,"); + add("75,10,11,-79,-92,18,"); + add(""); + //add("/*609*/"); + add("3,1,-3465,-29255,-5667,"); + add("-50,-13,95,-26,22,-95,"); + add(""); + //add("/*610*/"); + add("3,1,20448,-6320,21022,"); + add("74,-52,-87,-11,63,29,"); + add(""); + //add("/*611*/"); + add("3,1,-11210,-27380,4968,"); + add("-67,47,106,7,-15,-70,"); + add(""); + //add("/*612*/"); + add("3,1,-7114,29104,-1523,"); + add("-31,-14,-125,-26,-3,61,"); + add(""); + //add("/*613*/"); + add("3,1,11126,17559,21631,"); + add("8,-111,86,4,44,-38,"); + add(""); + //add("/*614*/"); + add("3,-1,-17516,22482,-9368,"); + add("-37,-44,-36,77,91,75,"); + add(""); + //add("/*615*/"); + add("3,1,23571,-1939,-18457,"); + add("-68,34,-90,37,41,43,"); + add(""); + //add("/*616*/"); + add("3,1,-6394,-28910,-4832,"); + add("-27,25,-112,68,-24,51,"); + add(""); + //add("/*617*/"); + add("3,1,5794,26057,13692,"); + add("-56,-45,108,58,8,-38,"); + add(""); + //add("/*618*/"); + add("3,1,-23934,17129,5813,"); + add("-32,-36,-30,79,85,78,"); + add(""); + //add("/*619*/"); + add("3,1,-23357,-76,18827,"); + add("-56,-97,-71,41,25,52,"); + add(""); + //add("/*620*/"); + add("3,1,7231,-5628,-28566,"); + add("-117,22,-34,64,34,9,"); + add(""); + //add("/*621*/"); + add("3,-1,8011,-2165,28829,"); + add("-86,-20,23,42,-72,-17,"); + add(""); + //add("/*622*/"); + add("3,1,-17637,-23714,5158,"); + add("-108,70,-51,50,-34,13,"); + add(""); + //add("/*623*/"); + add("3,1,21913,-8820,18494,"); + add("66,118,-23,-34,-46,20,"); + add(""); + //add("/*624*/"); + add("3,1,9869,19293,20746,"); + add("-85,-38,75,55,-24,-4,"); + add(""); + //add("/*625*/"); + add("3,1,22899,-4077,-18947,"); + add("-26,-86,-13,-37,52,-57,"); + add(""); + //add("/*626*/"); + add("3,1,-14038,23901,-11476,"); + add("-107,-72,-17,35,39,38,"); + add(""); + //add("/*627*/"); + add("3,1,4353,24653,16531,"); + add("69,-61,72,12,41,-63,"); + add(""); + //add("/*628*/"); + add("3,1,-18051,-23470,4832,"); + add("-30,48,118,-10,-6,-67,"); + add(""); + //add("/*629*/"); + add("3,1,28220,10019,-1806,"); + add("23,-82,-83,-25,72,3,"); + add(""); + //add("/*630*/"); + add("3,1,-20490,-21140,5764,"); + add("-5,32,100,-44,19,-85,"); + add(""); + //add("/*631*/"); + add("3,1,3983,28240,9309,"); + add("12,35,-113,-52,-6,40,"); + add(""); + //add("/*632*/"); + add("3,1,-18699,-22936,4930,"); + add("-91,67,-33,37,-37,-36,"); + add(""); + //add("/*633*/"); + add("3,1,627,18932,23264,"); + add("-84,-62,52,85,7,-8,"); + add(""); + //add("/*634*/"); + add("3,1,19354,14991,17340,"); + add("50,-98,28,14,46,-55,"); + add(""); + //add("/*635*/"); + add("3,1,-28747,8411,1693,"); + add("22,50,121,-5,-4,-59,"); + add(""); + //add("/*636*/"); + add("3,1,-8901,26791,10151,"); + add("-2,39,-105,-41,-14,0,"); + add(""); + //add("/*637*/"); + add("3,1,-1847,24835,16728,"); + add("-27,-53,75,84,19,-19,"); + add(""); + //add("/*638*/"); + add("3,1,-10396,25971,10836,"); + add("84,12,51,-45,21,-93,"); + add(""); + //add("/*639*/"); + add("3,1,-1746,26561,13836,"); + add("46,-54,110,4,27,-50,"); + add(""); + //add("/*640*/"); + add("3,-1,-16548,24985,-1391,"); + add("30,12,-123,-40,-23,44,"); + add(""); + //add("/*641*/"); + add("3,1,-23092,1143,19117,"); + add("-29,-97,-30,49,20,58,"); + add(""); + //add("/*642*/"); + add("3,-1,-9616,27575,-6867,"); + add("-86,-18,48,81,35,28,"); + add(""); + //add("/*643*/"); + add("3,1,37,-8773,-28689,"); + add("-83,89,-27,70,-24,8,"); + add(""); + //add("/*644*/"); + add("3,1,-5877,24660,-16042,"); + add("29,-63,-107,-41,19,43,"); + add(""); + //add("/*645*/"); + add("3,1,-7063,29124,1383,"); + add("-106,-24,-46,12,1,50,"); + add(""); + //add("/*646*/"); + add("3,1,9491,-28294,3062,"); + add("88,35,49,-28,-5,40,"); + add(""); + //add("/*647*/"); + add("3,1,-10563,28011,-1955,"); + add("-92,-37,-31,2,5,62,"); + add(""); + //add("/*648*/"); + add("3,1,-23006,339,19251,"); + add("-51,-80,-59,52,6,61,"); + add(""); + //add("/*649*/"); + add("3,-1,24368,17193,-3258,"); + add("40,-67,-52,-54,71,-25,"); + add(""); + //add("/*650*/"); + add("3,1,-8017,28176,6466,"); + add("-87,-36,52,72,15,24,"); + add(""); + //add("/*651*/"); + add("3,1,-26550,11424,8038,"); + add("29,-20,121,-1,36,-53,"); + add(""); + //add("/*652*/"); + add("3,1,28996,6412,-4254,"); + add("-29,112,-31,13,-29,48,"); + add(""); + //add("/*653*/"); + add("3,1,-11839,8554,26204,"); + add("61,27,19,-107,18,-54,"); + add(""); + //add("/*654*/"); + add("3,1,-20098,-21617,5362,"); + add("-31,53,101,-18,2,-58,"); + add(""); + //add("/*655*/"); + add("3,1,21155,4033,-20886,"); + add("40,-117,19,-35,34,-29,"); + add(""); + //add("/*656*/"); + add("3,1,5515,20897,20806,"); + add("103,-68,41,-37,35,-25,"); + add(""); + //add("/*657*/"); + add("3,1,-29988,-222,-832,"); + add("-2,50,61,3,22,-100,"); + add(""); + //add("/*658*/"); + add("3,1,5034,26084,13938,"); + add("21,-49,84,54,10,-38,"); + add(""); + //add("/*659*/"); + add("3,1,1691,19298,22907,"); + add("-89,3,4,81,-54,40,"); + add(""); + //add("/*660*/"); + add("3,1,2119,26865,13182,"); + add("-116,-3,25,58,-16,24,"); + add(""); + //add("/*661*/"); + add("3,1,10789,18377,21116,"); + add("-103,-6,58,62,-29,-7,"); + add(""); + //add("/*662*/"); + add("3,1,-11870,-26301,8207,"); + add("27,19,101,-65,14,-51,"); + add(""); + //add("/*663*/"); + add("3,1,-18344,-23246,4807,"); + add("-84,74,38,27,-34,-58,"); + add(""); + //add("/*664*/"); + add("3,1,-11295,25251,-11610,"); + add("-65,-58,-63,-15,21,60,"); + add(""); + //add("/*665*/"); + add("3,1,6300,20443,21033,"); + add("123,-14,-23,-36,19,-8,"); + add(""); + //add("/*666*/"); + add("3,1,29102,725,-7249,"); + add("27,3,111,-11,-45,-52,"); + add(""); + //add("/*667*/"); + add("3,1,-29997,-152,-412,"); + add("-1,22,82,1,52,-85,"); + add(""); + //add("/*668*/"); + add("3,1,-28040,10545,1595,"); + add("-32,-71,-94,4,4,55,"); + add(""); + //add("/*669*/"); + add("3,1,11026,18001,21316,"); + add("-97,-31,76,47,1,-24,"); + add(""); + //add("/*670*/"); + add("3,1,24332,1794,-17457,"); + add("32,101,56,1,-69,-6,"); + add(""); + //add("/*671*/"); + add("3,1,4781,16690,24466,"); + add("-96,20,5,32,-59,34,"); + add(""); + //add("/*672*/"); + add("3,1,21656,-5891,-19908,"); + add("21,116,-11,16,-38,28,"); + add(""); + //add("/*673*/"); + add("3,1,-19012,-22658,5013,"); + add("-83,57,-54,41,-38,-15,"); + add(""); + //add("/*674*/"); + add("3,-1,-25345,15903,2173,"); + add("-67,-106,-3,15,21,14,"); + add(""); + //add("/*675*/"); + add("3,1,22404,-4219,-19500,"); + add("44,-78,68,-52,23,-66,"); + add(""); + //add("/*676*/"); + add("3,1,-10163,28146,2130,"); + add("-89,-29,-52,21,3,69,"); + add(""); + //add("/*677*/"); + add("3,1,-725,25703,15454,"); + add("-107,19,-37,23,-25,44,"); + add(""); + //add("/*678*/"); + add("3,1,25446,6214,-14625,"); + add("2,-95,-36,-28,38,-33,"); + add(""); + //add("/*679*/"); + add("3,1,-18014,-23519,4728,"); + add("-68,67,75,12,-18,-46,"); + add(""); + //add("/*680*/"); + add("3,1,8350,18419,22159,"); + add("86,-67,23,-8,45,-34,"); + add(""); + //add("/*681*/"); + add("3,1,-16265,24998,3250,"); + add("-89,-55,-27,11,2,45,"); + add(""); + //add("/*682*/"); + add("3,1,-29435,3954,4235,"); + add("-7,-102,43,10,58,20,"); + add(""); + //add("/*683*/"); + add("3,1,14345,-4396,-25979,"); + add("-2,-120,20,-17,45,-17,"); + add(""); + //add("/*684*/"); + add("3,1,-20159,-21497,5615,"); + add("-47,63,68,-11,-7,-64,"); + add(""); + //add("/*685*/"); + add("3,1,17291,-23956,5209,"); + add("-23,-40,-109,33,32,41,"); + add(""); + //add("/*686*/"); + add("3,1,6171,20591,20926,"); + add("108,-24,-8,-25,33,-25,"); + add(""); + //add("/*687*/"); + add("3,1,-8736,-28700,-52,"); + add("-34,11,92,-38,11,-52,"); + add(""); + //add("/*688*/"); + add("3,1,-5134,25663,-14664,"); + add("63,-34,-82,-50,-7,5,"); + add(""); + //add("/*689*/"); + add("3,1,23474,-4238,-18194,"); + add("-71,-46,-80,21,43,16,"); + add(""); + //add("/*690*/"); + add("3,1,-12945,26676,4562,"); + add("4,17,-91,-51,-38,80,"); + add(""); + //add("/*691*/"); + add("3,1,11880,-13958,-23749,"); + add("-2,99,-60,27,-28,31,"); + add(""); + //add("/*692*/"); + add("3,1,9893,18457,21482,"); + add("67,-72,30,17,31,-34,"); + add(""); + //add("/*693*/"); + add("3,1,-14530,23658,-11366,"); + add("-35,-60,-80,-23,11,53,"); + add(""); + //add("/*694*/"); + add("3,1,-17616,-23753,5046,"); + add("-93,61,-37,33,-27,-10,"); + add(""); + //add("/*695*/"); + add("3,1,25086,-5507,-15503,"); + add("-51,11,-86,23,44,21,"); + add(""); + //add("/*696*/"); + add("3,1,-15610,-24492,7515,"); + add("-12,-16,-78,52,-2,101,"); + add(""); + //add("/*697*/"); + add("3,1,-15472,22928,-11615,"); + add("-58,-51,-24,-15,24,68,"); + add(""); + //add("/*698*/"); + add("3,1,-12165,24913,-11461,"); + add("34,-28,-96,-48,-12,24,"); + add(""); + //add("/*699*/"); + add("3,1,5310,21296,20452,"); + add("21,-66,64,46,12,-25,"); + add(""); + //add("/*700*/"); + add("3,-1,17800,23716,-4555,"); + add("58,-61,-85,-31,27,21,"); + add(""); + //add("/*701*/"); + add("3,1,18987,-4163,22851,"); + add("56,89,-31,-54,-31,40,"); + add(""); + //add("/*702*/"); + add("3,1,-13833,24181,-11133,"); + add("4,-47,-107,-21,7,43,"); + add(""); + //add("/*703*/"); + add("3,1,6651,29245,-700,"); + add("50,-11,4,-96,20,-60,"); + add(""); + //add("/*704*/"); + add("3,1,-25607,5901,14473,"); + add("-58,-52,-82,27,-3,49,"); + add(""); + //add("/*705*/"); + add("3,1,-19397,-22308,5108,"); + add("1,25,114,-14,3,-42,"); + add(""); + //add("/*706*/"); + add("3,1,-23259,-297,18946,"); + add("-53,-60,-67,39,-10,48,"); + add(""); + //add("/*707*/"); + add("3,1,-13405,24297,-11400,"); + add("11,-34,-86,-50,-16,26,"); + add(""); + //add("/*708*/"); + add("3,1,25842,-4398,-14590,"); + add("-3,-99,25,-21,27,-45,"); + add(""); + //add("/*709*/"); + add("3,1,-25303,12454,-10231,"); + add("-57,-52,78,24,41,-8,"); + add(""); + //add("/*710*/"); + add("3,1,-8255,26088,-12300,"); + add("82,-6,-67,-56,-15,5,"); + add(""); + //add("/*711*/"); + add("3,1,6152,-8008,-28249,"); + add("-89,40,-31,63,17,9,"); + add(""); + //add("/*712*/"); + add("3,1,-25934,14888,2405,"); + add("-36,-47,-101,8,8,37,"); + add(""); + //add("/*713*/"); + add("3,1,-6774,29199,-1229,"); + add("-15,-8,-109,-22,-3,41,"); + add(""); + //add("/*714*/"); + add("3,1,-1560,24786,16830,"); + add("-10,-53,77,53,17,-21,"); + add(""); + //add("/*715*/"); + add("3,-1,-21338,21065,-960,"); + add("-45,-41,97,19,19,-19,"); + add(""); + //add("/*716*/"); + add("3,1,-5625,24695,-16078,"); + add("11,-41,-67,-64,-5,15,"); + add(""); + //add("/*717*/"); + add("3,1,-26663,12045,6635,"); + add("-9,-70,90,11,38,-27,"); + add(""); + //add("/*718*/"); + add("3,1,-27183,11286,5804,"); + add("-3,-54,92,15,44,-17,"); + add(""); + //add("/*719*/"); + add("3,1,-20085,-21491,5891,"); + add("-63,66,28,2,-16,-51,"); + add(""); + //add("/*720*/"); + add("3,1,11920,-13784,-23831,"); + add("22,98,-45,15,-28,23,"); + add(""); + //add("/*721*/"); + add("3,1,-19179,-22536,4928,"); + add("-34,47,83,-13,-1,-57,"); + add(""); + //add("/*722*/"); + add("3,1,-355,23212,19002,"); + add("-92,11,-15,20,-33,40,"); + add(""); + //add("/*723*/"); + add("3,1,10541,18339,21273,"); + add("-78,-33,68,42,-8,-15,"); + add(""); + //add("/*724*/"); + add("3,1,-14382,25139,7820,"); + add("-90,-56,16,38,15,21,"); + add(""); + //add("/*725*/"); + add("3,1,-17775,-23685,4805,"); + add("-61,60,70,10,-16,-41,"); + add(""); + //add("/*726*/"); + add("3,1,15192,-711,-25859,"); + add("-36,-88,-18,-22,47,-15,"); + add(""); + //add("/*727*/"); + add("3,1,-25173,6788,14841,"); + add("3,81,-33,-30,-45,-31,"); + add(""); + //add("/*728*/"); + add("3,1,23886,-136,-18151,"); + add("33,-60,45,-38,-20,-50,"); + add(""); + //add("/*729*/"); + add("3,1,-17001,21978,11312,"); + add("-63,-71,42,24,10,16,"); + add(""); + //add("/*730*/"); + add("3,1,11428,-4389,-27389,"); + add("22,-99,25,-34,23,-17,"); + add(""); + //add("/*731*/"); + add("3,1,-14644,23549,-11447,"); + add("-47,-58,-57,-17,11,44,"); + add(""); + //add("/*732*/"); + add("3,1,20716,-6655,20653,"); + add("26,-20,-32,-11,92,40,"); + add(""); + //add("/*733*/"); + add("3,1,-27252,6392,10793,"); + add("0,-79,45,16,25,26,"); + add(""); + //add("/*734*/"); + add("3,1,8257,18817,21858,"); + add("-26,-56,57,41,-17,-1,"); + add(""); + //add("/*735*/"); + add("3,1,17728,-4370,-23804,"); + add("-69,-43,-43,-2,40,-9,"); + add(""); + //add("/*736*/"); + add("3,1,7081,29143,-744,"); + add("46,-10,33,-16,1,-93,"); + add(""); + //add("/*737*/"); + add("3,1,20340,-6075,-21198,"); + add("-58,54,-71,24,-5,24,"); + add(""); + //add("/*738*/"); + add("3,1,-10500,-27772,4297,"); + add("13,7,78,-57,18,-24,"); + add(""); + //add("/*739*/"); + add("3,1,-21551,16797,-12387,"); + add("-61,-25,74,20,27,1,"); + add(""); + //add("/*740*/"); + add("3,1,-23937,14156,-11253,"); + add("40,42,-32,-29,-72,-28,"); + add(""); + //add("/*741*/"); + add("3,1,2497,24497,17137,"); + add("31,52,-79,-35,-7,14,"); + add(""); + //add("/*742*/"); + add("3,1,21770,-2150,-20529,"); + add("-61,-66,-57,14,28,12,"); + add(""); + //add("/*743*/"); + add("3,1,-10876,-27085,6937,"); + add("24,15,94,-38,8,-29,"); + add(""); + //add("/*744*/"); + add("3,1,-26625,11639,7461,"); + add("-2,-58,82,13,34,-9,"); + add(""); + //add("/*745*/"); + add("3,-1,-25621,14760,-5070,"); + add("-8,16,87,27,22,-74,"); + add(""); + //add("/*746*/"); + add("3,1,-16344,22674,-10897,"); + add("-89,-53,23,21,14,-3,"); + add(""); + //add("/*747*/"); + add("3,1,-15599,23126,-11040,"); + add("-60,-53,-25,-14,9,38,"); + add(""); + //add("/*748*/"); + add("3,1,2618,27824,10908,"); + add("49,19,-60,-43,11,-19,"); + add(""); + //add("/*749*/"); + add("3,-1,13838,15180,21865,"); + add("70,-66,2,3,22,-18,"); + add(""); + //add("/*750*/"); + add("3,1,29104,5954,-4186,"); + add("-25,89,-43,9,-21,32,"); + add(""); + //add("/*751*/"); + add("3,-1,-17298,24161,-4125,"); + add("-9,-22,-94,-19,-8,36,"); + add(""); + //add("/*752*/"); + add("3,1,7494,29029,1081,"); + add("29,-6,-36,-80,21,-19,"); + add(""); + //add("/*753*/"); + add("3,-1,-19537,-11007,19928,"); + add("-32,64,4,-30,8,-25,"); + add(""); + //add("/*754*/"); + add("3,1,-18953,-22734,4895,"); + add("-43,49,59,-8,-4,-50,"); + add(""); + //add("/*755*/"); + add("3,1,13593,-5535,-26165,"); + add("-86,-27,-39,14,23,3,"); + add(""); + //add("/*756*/"); + add("3,-1,-19136,21815,-7612,"); + add("-73,-60,14,6,12,19,"); + add(""); + //add("/*757*/"); + add("3,1,-24002,17079,5677,"); + add("-28,-7,-99,6,1,24,"); + add(""); + //add("/*758*/"); + add("3,1,-26057,14705,-2194,"); + add("-28,-61,-74,6,16,44,"); + add(""); + //add("/*759*/"); + add("3,1,-25874,9131,12130,"); + add("37,-3,82,4,26,-11,"); + add(""); + //add("/*760*/"); + add("3,-1,-22516,16997,-10205,"); + add("-66,-59,49,14,16,-6,"); + add(""); + //add("/*761*/"); + add("3,1,15992,-257,25381,"); + add("-2,95,2,-18,-43,11,"); + add(""); + //add("/*762*/"); + add("3,1,-8284,26137,-12175,"); + add("54,-16,-71,-23,-10,-5,"); + add(""); + //add("/*763*/"); + add("3,1,-20414,-21222,5734,"); + add("10,12,81,-31,24,-22,"); + add(""); + //add("/*764*/"); + add("3,1,-15647,23076,-11075,"); + add("-62,-58,-33,0,15,30,"); + add(""); + //add("/*765*/"); + add("3,1,-28391,9662,-763,"); + add("-10,-37,-88,-2,-1,37,"); + add(""); + //add("/*766*/"); + add("3,1,23132,6353,18016,"); + add("60,-29,-68,-13,23,9,"); + add(""); + //add("/*767*/"); + add("3,-1,-24613,16950,2623,"); + add("-44,-58,-39,16,15,55,"); + add(""); + //add("/*768*/"); + add("3,-1,10870,-14991,23603,"); + add("35,-65,-58,7,21,11,"); + add(""); + //add("/*769*/"); + add("3,1,-27204,11625,4977,"); + add("-5,-47,82,5,20,-16,"); + add(""); + //add("/*770*/"); + add("3,1,-26269,14142,-3158,"); + add("-28,-66,-58,-1,3,22,"); + add(""); + //add("/*771*/"); + add("3,1,2537,27833,10903,"); + add("-20,-29,79,23,2,-9,"); + add(""); + //add("/*772*/"); + add("3,1,-27160,11434,5619,"); + add("0,-35,71,12,28,5,"); + add(""); + //add("/*773*/"); + add("3,1,29168,5584,-4248,"); + add("-10,72,27,7,-18,25,"); + add(""); + //add("/*774*/"); + add("3,1,29735,1076,-3832,"); + add("3,68,47,2,-31,8,"); + add(""); + //add("/*775*/"); + add("3,-1,-1224,25269,16124,"); + add("-57,-36,52,10,1,0,"); + add(""); + //add("/*776*/"); + add("3,1,-28530,9221,1000,"); + add("22,64,44,0,1,-17,"); + add(""); + add("0,"); + } + + private void add(String s) { + d.add(s); + } + + public List getLines() { + return d; + } + + +} \ No newline at end of file diff --git a/src/com/ctreber/acearth/MapDataReader.java b/src/com/ctreber/acearth/MapDataReader.java new file mode 100644 index 000000000..472975189 --- /dev/null +++ b/src/com/ctreber/acearth/MapDataReader.java @@ -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. + * + *

+ * © 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; + + /** + *

+ * 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); + } + + /** + *

+ * 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(); + } + +} diff --git a/src/com/ctreber/acearth/gui/CanvasACearth.java b/src/com/ctreber/acearth/gui/CanvasACearth.java new file mode 100644 index 000000000..cd251cc0d --- /dev/null +++ b/src/com/ctreber/acearth/gui/CanvasACearth.java @@ -0,0 +1,21 @@ +package com.ctreber.acearth.gui; + +import com.ctreber.acearth.ACearth; + +/** + *

+ * Adds some mouse magic to the normal PixelCanvas. + *

+ * + *

+ * © 2002 Christian Treber, ct@ctreber.com (Nov 8, 2002) + *

+ * + * @author Christian Treber, ct@ctreber.com + * + */ +public class CanvasACearth extends PixelCanvas { + public CanvasACearth(ACearth pParent, int pWidth, int pHeight) { + super(pWidth, pHeight); + } +} diff --git a/src/com/ctreber/acearth/gui/PixelCanvas.java b/src/com/ctreber/acearth/gui/PixelCanvas.java new file mode 100644 index 000000000..79da3f73c --- /dev/null +++ b/src/com/ctreber/acearth/gui/PixelCanvas.java @@ -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; + +/** + *

+ * Swing compatible drawing surface for images and graphics. + * + *

+ * © 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; + + /** + *

+ * 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); + } + +} diff --git a/src/com/ctreber/acearth/plugins/Plugin.java b/src/com/ctreber/acearth/plugins/Plugin.java new file mode 100644 index 000000000..ddf3ec46d --- /dev/null +++ b/src/com/ctreber/acearth/plugins/Plugin.java @@ -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; + +/** + *

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 6, 2002)

+ * @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; + } +} diff --git a/src/com/ctreber/acearth/plugins/markers/Marker.java b/src/com/ctreber/acearth/plugins/markers/Marker.java new file mode 100644 index 000000000..d059db43b --- /dev/null +++ b/src/com/ctreber/acearth/plugins/markers/Marker.java @@ -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; + +/** + *

+ * Marks a location on the globe. + * + *

+ * © 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); + } +} diff --git a/src/com/ctreber/acearth/plugins/markers/PluginMarkers.java b/src/com/ctreber/acearth/plugins/markers/PluginMarkers.java new file mode 100644 index 000000000..b3b7f5f1b --- /dev/null +++ b/src/com/ctreber/acearth/plugins/markers/PluginMarkers.java @@ -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; + +/** + *

+ * Renders markers to the render target. a + *

+ * © 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 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"; + } +} diff --git a/src/com/ctreber/acearth/projection/Projection.java b/src/com/ctreber/acearth/projection/Projection.java new file mode 100644 index 000000000..bae3534f5 --- /dev/null +++ b/src/com/ctreber/acearth/projection/Projection.java @@ -0,0 +1,271 @@ +package com.ctreber.acearth.projection; + +import com.ctreber.acearth.util.*; + +/** + *

A projection for a globe on a flat surface (must be subclassed). + * + *

© 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; + /**

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; + + /** + *

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(); + + /** + *

Project 3D point on y axis. + */ + abstract public double projectY(double pY); + + abstract public double inverseProjectY(double pY); + + /** + *

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); + } + + /** + *

Translate screen point into coordinate on Earth. + * + * @param pX + * @param pY + * @return + */ + abstract public Coordinate getLocation(int pX, int pY); + + /** + *

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. + * + *

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. + * + *

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())); + } + + /** + *

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; + } + + /** + *

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; + } + + /** + *

Transform screen to image coordinates. + */ + public double inverseFinalizeX(double x) + { + return (x - fXOffset) / fScale; + } + + /** + *

Transform screen to image coordinates. + */ + public double inverseFinalizeY(double y) + { + return (fYOffset - y) / fScale; + } + + /** + *

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; + } +} diff --git a/src/com/ctreber/acearth/projection/ProjectionCyl.java b/src/com/ctreber/acearth/projection/ProjectionCyl.java new file mode 100644 index 000000000..d30d6644d --- /dev/null +++ b/src/com/ctreber/acearth/projection/ProjectionCyl.java @@ -0,0 +1,72 @@ +package com.ctreber.acearth.projection; + +import com.ctreber.acearth.util.Coordinate; +import com.ctreber.acearth.util.Point3D; + +/** + *

Cylindrical projection. Show Earth flatly spread out on rectangle. + * + *

© 2002 Christian Treber, ct@ctreber.com + * @author Christian Treber, ct@ctreber.com + * + */ +public class ProjectionCyl extends Projection +{ + /** + *

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(); + } + + /** + *

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)); + } +} diff --git a/src/com/ctreber/acearth/projection/ProjectionMerc.java b/src/com/ctreber/acearth/projection/ProjectionMerc.java new file mode 100644 index 000000000..e27d0b92d --- /dev/null +++ b/src/com/ctreber/acearth/projection/ProjectionMerc.java @@ -0,0 +1,75 @@ +package com.ctreber.acearth.projection; + +import com.ctreber.acearth.util.Coordinate; +import com.ctreber.acearth.util.Point3D; + + +/** + *

Mercator projection. Show Earth flatly spread out on rectangle. + * + *

© 2002 Christian Treber, ct@ctreber.com + * @author Christian Treber, ct@ctreber.com + * + */ +public class ProjectionMerc extends Projection +{ + /** + *

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(); + } + + /** + *

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)); + } +} diff --git a/src/com/ctreber/acearth/projection/ProjectionOrtho.java b/src/com/ctreber/acearth/projection/ProjectionOrtho.java new file mode 100644 index 000000000..e227277a1 --- /dev/null +++ b/src/com/ctreber/acearth/projection/ProjectionOrtho.java @@ -0,0 +1,71 @@ +package com.ctreber.acearth.projection; + +import com.ctreber.acearth.util.Coordinate; +import com.ctreber.acearth.util.Point3D; + + +/** + *

Orthographic projection (show Earth as a ball). + * + *

© 2002 Christian Treber, ct@ctreber.com + * @author Christian Treber, ct@ctreber.com + * + */ +public class ProjectionOrtho extends Projection +{ + /** + *

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; + } + + /** + *

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; + } +} diff --git a/src/com/ctreber/acearth/renderer/RenderTarget.java b/src/com/ctreber/acearth/renderer/RenderTarget.java new file mode 100644 index 000000000..84ebfc7f7 --- /dev/null +++ b/src/com/ctreber/acearth/renderer/RenderTarget.java @@ -0,0 +1,24 @@ +package com.ctreber.acearth.renderer; + +import java.awt.Color; + +/** + *

. + * + *

+ * © 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(); + +} diff --git a/src/com/ctreber/acearth/renderer/Renderer.java b/src/com/ctreber/acearth/renderer/Renderer.java new file mode 100644 index 000000000..eca8905ba --- /dev/null +++ b/src/com/ctreber/acearth/renderer/Renderer.java @@ -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; + +/** + *

+ * Uses defined RowTypeRenderers and Shader to render to render target. + * + *

+ * © 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); + } + } + + /** + *

+ * 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; + } + + /** + *

+ * 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); + } +} diff --git a/src/com/ctreber/acearth/renderer/RowTypeRenderer.java b/src/com/ctreber/acearth/renderer/RowTypeRenderer.java new file mode 100644 index 000000000..5287a2789 --- /dev/null +++ b/src/com/ctreber/acearth/renderer/RowTypeRenderer.java @@ -0,0 +1,26 @@ +package com.ctreber.acearth.renderer; + +/** + *

Renders a row of pixel types.

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)

+ * @author Christian Treber, ct@ctreber.com + * + */ +public interface RowTypeRenderer +{ + /** + *

Each time when rendering an image, call startNewRun() first. + */ + public void startNewRun(); + + /** + *

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); +} diff --git a/src/com/ctreber/acearth/renderer/RowTypeRendererScanBit.java b/src/com/ctreber/acearth/renderer/RowTypeRendererScanBit.java new file mode 100644 index 000000000..8ae020f6f --- /dev/null +++ b/src/com/ctreber/acearth/renderer/RowTypeRendererScanBit.java @@ -0,0 +1,82 @@ +package com.ctreber.acearth.renderer; + +import com.ctreber.acearth.scanbit.ScanBit; +import com.ctreber.acearth.scanbit.BitGeneratorMap; + +/** + *

Renders a row of ScanBits to pixel types.

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)

+ * @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; + } +} diff --git a/src/com/ctreber/acearth/renderer/RowTypeRendererScanDot.java b/src/com/ctreber/acearth/renderer/RowTypeRendererScanDot.java new file mode 100644 index 000000000..11191abab --- /dev/null +++ b/src/com/ctreber/acearth/renderer/RowTypeRendererScanDot.java @@ -0,0 +1,60 @@ +package com.ctreber.acearth.renderer; + +import com.ctreber.acearth.scanbit.BitGeneratorMap; +import com.ctreber.acearth.scandot.ScanDot; + +/** + *

Renders a row of ScanDots to pixel types.

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)

+ * @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; + } +} diff --git a/src/com/ctreber/acearth/scanbit/BitGeneratorMap.java b/src/com/ctreber/acearth/scanbit/BitGeneratorMap.java new file mode 100644 index 000000000..be84ee7e8 --- /dev/null +++ b/src/com/ctreber/acearth/scanbit/BitGeneratorMap.java @@ -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; + +/** + *

+ * A BitGeneratorMap scans a map into ScanBits. + * + *

+ * © 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; + } + + /** + *

+ * 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); + } +} diff --git a/src/com/ctreber/acearth/scanbit/BitGeneratorMapDefault.java b/src/com/ctreber/acearth/scanbit/BitGeneratorMapDefault.java new file mode 100644 index 000000000..2defe754f --- /dev/null +++ b/src/com/ctreber/acearth/scanbit/BitGeneratorMapDefault.java @@ -0,0 +1,263 @@ +package com.ctreber.acearth.scanbit; + +import java.util.Comparator; + +import com.ctreber.acearth.projection.Projection; +import com.ctreber.acearth.util.*; + +/** + *

Map scanner for mercator and cylindrical projections. + * + *

© 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; + } + + /** + *

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)); + } + + /** + *

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); + } + + /** + *

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); + } + } + + /** + *

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"); + } + } +} diff --git a/src/com/ctreber/acearth/scanbit/BitGeneratorMapOrtho.java b/src/com/ctreber/acearth/scanbit/BitGeneratorMapOrtho.java new file mode 100644 index 000000000..7a069746a --- /dev/null +++ b/src/com/ctreber/acearth/scanbit/BitGeneratorMapOrtho.java @@ -0,0 +1,168 @@ +package com.ctreber.acearth.scanbit; + +import java.util.Comparator; + +import com.ctreber.acearth.projection.Projection; +import com.ctreber.acearth.util.*; + +/** + *

Map scanner for orthographic projection. + * + *

© 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; + } + } +} diff --git a/src/com/ctreber/acearth/scanbit/ScanBit.java b/src/com/ctreber/acearth/scanbit/ScanBit.java new file mode 100644 index 000000000..89f522f9f --- /dev/null +++ b/src/com/ctreber/acearth/scanbit/ScanBit.java @@ -0,0 +1,62 @@ +package com.ctreber.acearth.scanbit; + +/** + *

Instruction to paint points xFrom to xTo on line y. + * + *

What I don't understand: why do values get summed to determine the + * pixel type? + * + *

© 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; + } + + /** + *

See values for + * @see com.ctreber.acearth.util.Polygon + */ + public int getType() + { + return fType; + } +} diff --git a/src/com/ctreber/acearth/scanbit/ScanBitGenerator.java b/src/com/ctreber/acearth/scanbit/ScanBitGenerator.java new file mode 100644 index 000000000..ec6f4a108 --- /dev/null +++ b/src/com/ctreber/acearth/scanbit/ScanBitGenerator.java @@ -0,0 +1,32 @@ +package com.ctreber.acearth.scanbit; + +/** + *

A ScanBitGenerator produces ScanBits.

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)

+ * @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; + } +} diff --git a/src/com/ctreber/acearth/scanbit/ScanBuf.java b/src/com/ctreber/acearth/scanbit/ScanBuf.java new file mode 100644 index 000000000..9e3d07061 --- /dev/null +++ b/src/com/ctreber/acearth/scanbit/ScanBuf.java @@ -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; + +/** + *

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. + * + *

© 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; + + /** + *

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(); + } + } + + /** + *

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; + } + + /** + *

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; + } +} diff --git a/src/com/ctreber/acearth/scandot/DotGeneratorLines.java b/src/com/ctreber/acearth/scandot/DotGeneratorLines.java new file mode 100644 index 000000000..f544a8f8c --- /dev/null +++ b/src/com/ctreber/acearth/scandot/DotGeneratorLines.java @@ -0,0 +1,70 @@ +package com.ctreber.acearth.scandot; + +import com.ctreber.acearth.projection.Projection; +import com.ctreber.acearth.util.*; + +/** + *

Generate latitude and longitude grid as dots. + * + *

Refactored 08.11.2002 + * + *

© 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; + } + + /** + *

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)); + } + } + } +} diff --git a/src/com/ctreber/acearth/scandot/DotGeneratorStars.java b/src/com/ctreber/acearth/scandot/DotGeneratorStars.java new file mode 100644 index 000000000..09cf49aa9 --- /dev/null +++ b/src/com/ctreber/acearth/scandot/DotGeneratorStars.java @@ -0,0 +1,51 @@ +package com.ctreber.acearth.scandot; + +import java.util.Random; + +/** + *

Generate random stars as dots. + * + *

© 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)); + } + } + } +} diff --git a/src/com/ctreber/acearth/scandot/ScanDot.java b/src/com/ctreber/acearth/scandot/ScanDot.java new file mode 100644 index 000000000..3b25bceed --- /dev/null +++ b/src/com/ctreber/acearth/scandot/ScanDot.java @@ -0,0 +1,67 @@ +package com.ctreber.acearth.scandot; + +import com.ctreber.acearth.util.Point2D; + +/** + *

A single scandot (opposed to a Polygon). + * + *

© 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; + } +} diff --git a/src/com/ctreber/acearth/scandot/ScanDotGenerator.java b/src/com/ctreber/acearth/scandot/ScanDotGenerator.java new file mode 100644 index 000000000..c52d87472 --- /dev/null +++ b/src/com/ctreber/acearth/scandot/ScanDotGenerator.java @@ -0,0 +1,27 @@ +package com.ctreber.acearth.scandot; + +import java.util.ArrayList; +import java.util.List; + + +/** + *

A ScanDotGenerator produces ScanDots. + * + *

© 2002 Christian Treber, ct@ctreber.com + * @author Christian Treber, ct@ctreber.com + * + */ +abstract public class ScanDotGenerator +{ + List fDots = new ArrayList(); + + /** + *

Generate whatever dots are generated. + */ + abstract public void generateScanDots(); + + public List getScanDots() + { + return fDots; + } +} diff --git a/src/com/ctreber/acearth/shader/Shader.java b/src/com/ctreber/acearth/shader/Shader.java new file mode 100644 index 000000000..3be67ed4a --- /dev/null +++ b/src/com/ctreber/acearth/shader/Shader.java @@ -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; + +/** + *

A shader computes Colors for a row of pixel types, depending + * on lighting parameters.

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)

+ * @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); + + /**

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; + } +} diff --git a/src/com/ctreber/acearth/shader/ShaderDefault.java b/src/com/ctreber/acearth/shader/ShaderDefault.java new file mode 100644 index 000000000..1aa561352 --- /dev/null +++ b/src/com/ctreber/acearth/shader/ShaderDefault.java @@ -0,0 +1,59 @@ +package com.ctreber.acearth.shader; + +import java.awt.*; + +/** + *

Shader for projections which display the whole surface.

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)

+ * @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; + } +} diff --git a/src/com/ctreber/acearth/shader/ShaderFlat.java b/src/com/ctreber/acearth/shader/ShaderFlat.java new file mode 100644 index 000000000..18fab74af --- /dev/null +++ b/src/com/ctreber/acearth/shader/ShaderFlat.java @@ -0,0 +1,24 @@ +package com.ctreber.acearth.shader; + +import java.awt.*; + +/** + *

Flat shader (does not care for Projection).

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)

+ * @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; + } +} diff --git a/src/com/ctreber/acearth/shader/ShaderOrtho.java b/src/com/ctreber/acearth/shader/ShaderOrtho.java new file mode 100644 index 000000000..227523fb5 --- /dev/null +++ b/src/com/ctreber/acearth/shader/ShaderOrtho.java @@ -0,0 +1,55 @@ +package com.ctreber.acearth.shader; + +import java.awt.*; + +/** + *

Shader for the orthographic projection.

+ * + *

© 2002 Christian Treber, ct@ctreber.com (Nov 11, 2002)

+ * @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; + } +} diff --git a/src/com/ctreber/acearth/util/Coordinate.java b/src/com/ctreber/acearth/util/Coordinate.java new file mode 100644 index 000000000..4c12bf2ed --- /dev/null +++ b/src/com/ctreber/acearth/util/Coordinate.java @@ -0,0 +1,153 @@ +package com.ctreber.acearth.util; + +import java.io.IOException; +import java.io.Writer; + +/** + *

+ * Latitude and longitude coordinate. Can be used as declination and right + * ascension as well. + * + *

+ * © 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() { + } + + /** + *

+ * 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("\n"); + writer.write(" " + fLat + "\n"); + writer.write(" " + fLong + "\n"); + writer.write("\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); + } + + /** + *

+ * 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); + } + + /** + *

+ * 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); + } + + /** + *

+ * Add position to this position, make sure coordinates are valid. + */ + public void add(Coordinate lOther) { + fLat += lOther.fLat; + fLong += lOther.fLong; + wrap(); + } + + /** + *

+ * 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; + } +} diff --git a/src/com/ctreber/acearth/util/EdgeCrossing.java b/src/com/ctreber/acearth/util/EdgeCrossing.java new file mode 100644 index 000000000..e565bd9d4 --- /dev/null +++ b/src/com/ctreber/acearth/util/EdgeCrossing.java @@ -0,0 +1,59 @@ +package com.ctreber.acearth.util; + +/** + *

Holds information about a line crossing "the edge of Earth". + * + *

© 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; + } +} diff --git a/src/com/ctreber/acearth/util/Point2D.java b/src/com/ctreber/acearth/util/Point2D.java new file mode 100644 index 000000000..fde40d0e3 --- /dev/null +++ b/src/com/ctreber/acearth/util/Point2D.java @@ -0,0 +1,35 @@ +package com.ctreber.acearth.util; + +/** + *

A point in a 2 axis space. + * + *

© 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; + } +} diff --git a/src/com/ctreber/acearth/util/Point3D.java b/src/com/ctreber/acearth/util/Point3D.java new file mode 100644 index 000000000..5c689e234 --- /dev/null +++ b/src/com/ctreber/acearth/util/Point3D.java @@ -0,0 +1,48 @@ +package com.ctreber.acearth.util; + +/** + *

A point in a 2 axis space. + * + *

© 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))); + } +} diff --git a/src/com/ctreber/acearth/util/Polygon.java b/src/com/ctreber/acearth/util/Polygon.java new file mode 100644 index 000000000..afc4faff4 --- /dev/null +++ b/src/com/ctreber/acearth/util/Polygon.java @@ -0,0 +1,49 @@ +package com.ctreber.acearth.util; + + +/** + *

A polygon in a 3 axis space. + * + *

© 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"; + } +} diff --git a/src/com/ctreber/acearth/util/StringParser.java b/src/com/ctreber/acearth/util/StringParser.java new file mode 100644 index 000000000..e3f00502d --- /dev/null +++ b/src/com/ctreber/acearth/util/StringParser.java @@ -0,0 +1,99 @@ +package com.ctreber.acearth.util; + +import java.util.ArrayList; +import java.util.List; + +/** + *

Cuts a string in words separated by white space. Quotes and square + * brackets are recognized (that is, white space within is ignored). + * + *

© 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; + } +} diff --git a/src/com/ctreber/acearth/util/SunPositionCalculator.java b/src/com/ctreber/acearth/util/SunPositionCalculator.java new file mode 100644 index 000000000..9054a30a4 --- /dev/null +++ b/src/com/ctreber/acearth/util/SunPositionCalculator.java @@ -0,0 +1,258 @@ +package com.ctreber.acearth.util; + +import java.util.*; + +/** + *

Calculates the position of the point on Earth which is directly + * below the sun or the moon. + * + *

© 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; + + /** + *

Calculate the position of the mean sun: where the sun would + * be if the earth's orbit were circular instead of ellipictal. + * + *

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; + } + + /** + *

Compute ecliptic longitude of sun (in radians) + * (after duffett-smith, section 47) + * + *

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) + * + *

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; + } + + + /** + *

computing julian dates (assuming gregorian calendar, thus this is + * only valid for dates of 1582 oct 15 or later) + * (after duffett-smith, section 4) + * + *

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; + } + + + /** + *

compute greenwich mean sidereal time (getGST) corresponding to a given + * number of milliseconds since the unix epoch + * (after duffett-smith, section 12) + * + *

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; + } + + /** + *

Given a particular time (expressed in milliseconds since the unix + * epoch), compute position on the earth (lat, lon) such that sun is + * directly overhead. + * + *

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)); + } + + /** + *

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. + * + *

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)); + } +} diff --git a/src/com/ctreber/acearth/util/Toolkit.java b/src/com/ctreber/acearth/util/Toolkit.java new file mode 100644 index 000000000..453f83b5a --- /dev/null +++ b/src/com/ctreber/acearth/util/Toolkit.java @@ -0,0 +1,135 @@ +package com.ctreber.acearth.util; + +import java.util.HashSet; +import java.util.StringTokenizer; + +/** + *

Some tools. + * + *

© 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); + } + + /** + *

Verified. + */ + public static double fmod(double pValue, double pMod) + { + while(pValue < 0) + { + pValue += pMod; + } + while(pValue > pMod) + { + pValue -= pMod; + } + + return pValue; + } + + /** + *

Examples: min -2, max 2: range 4 + * + *

+ */ + 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; + } + + /** + *

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(); + } +} diff --git a/src/com/ctreber/aclib/gui/MOBoolean.java b/src/com/ctreber/aclib/gui/MOBoolean.java new file mode 100644 index 000000000..a7a0207b0 --- /dev/null +++ b/src/com/ctreber/aclib/gui/MOBoolean.java @@ -0,0 +1,38 @@ +package com.ctreber.aclib.gui; + +/** + *

+ * + *

© 2002 Christian Treber, ct@ctreber.com

+ * @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; + } +} diff --git a/src/com/ctreber/aclib/gui/MOChangeListener.java b/src/com/ctreber/aclib/gui/MOChangeListener.java new file mode 100644 index 000000000..d11fee1f4 --- /dev/null +++ b/src/com/ctreber/aclib/gui/MOChangeListener.java @@ -0,0 +1,13 @@ +package com.ctreber.aclib.gui; + +/** + *

Implemented by classes interetested in MonitoredObject values changes.

+ * + *

© 2002 Christian Treber, ct@ctreber.com

+ * @author Christian Treber, ct@ctreber.com + * + */ +public interface MOChangeListener +{ + public void valueChanged(MonitoredObject pObject); +} diff --git a/src/com/ctreber/aclib/gui/MODouble.java b/src/com/ctreber/aclib/gui/MODouble.java new file mode 100644 index 000000000..01ea06b1e --- /dev/null +++ b/src/com/ctreber/aclib/gui/MODouble.java @@ -0,0 +1,74 @@ +package com.ctreber.aclib.gui; + +/** + *

+ * + *

© 2002 Christian Treber, ct@ctreber.com

+ * @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); + } +} diff --git a/src/com/ctreber/aclib/gui/MOEnum.java b/src/com/ctreber/aclib/gui/MOEnum.java new file mode 100644 index 000000000..08f42b36a --- /dev/null +++ b/src/com/ctreber/aclib/gui/MOEnum.java @@ -0,0 +1,86 @@ +package com.ctreber.aclib.gui; + +import java.util.HashSet; + +/** + *

+ * Monitored enumeration value. + *

+ * + *

+ * © 2002 Christian Treber, ct@ctreber.com + *

+ * + * @author Christian Treber, ct@ctreber.com + * + */ +public class MOEnum extends MonitoredObject { + private HashSet fValidValues = new HashSet(); + /** + *

+ * 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; + } +} diff --git a/src/com/ctreber/aclib/gui/MOInteger.java b/src/com/ctreber/aclib/gui/MOInteger.java new file mode 100644 index 000000000..8a3f004fc --- /dev/null +++ b/src/com/ctreber/aclib/gui/MOInteger.java @@ -0,0 +1,74 @@ +package com.ctreber.aclib.gui; + +/** + *

+ * + *

© 2002 Christian Treber, ct@ctreber.com

+ * @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); + } +} diff --git a/src/com/ctreber/aclib/gui/MOString.java b/src/com/ctreber/aclib/gui/MOString.java new file mode 100644 index 000000000..e26ca40f8 --- /dev/null +++ b/src/com/ctreber/aclib/gui/MOString.java @@ -0,0 +1,36 @@ +package com.ctreber.aclib.gui; + + + +/** + *

+ * + *

© 2002 Christian Treber, ct@ctreber.com

+ * @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; + } +} diff --git a/src/com/ctreber/aclib/gui/MonitoredObject.java b/src/com/ctreber/aclib/gui/MonitoredObject.java new file mode 100644 index 000000000..c2df8bfe0 --- /dev/null +++ b/src/com/ctreber/aclib/gui/MonitoredObject.java @@ -0,0 +1,44 @@ +package com.ctreber.aclib.gui; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + *

+ *

+ * + *

+ * © 2002 Christian Treber, ct@ctreber.com + *

+ * + * @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); + } + } + + /** + *

+ * Check value agains (possibly defined) constraints. + * + * @return True if value is within range or range is not checked. + */ + abstract public boolean checkRange(); +} diff --git a/src/com/ctreber/aclib/sort/CTSort.java b/src/com/ctreber/aclib/sort/CTSort.java new file mode 100644 index 000000000..5075c5e7b --- /dev/null +++ b/src/com/ctreber/aclib/sort/CTSort.java @@ -0,0 +1,20 @@ +package com.ctreber.aclib.sort; + +import java.util.Comparator; + +/** + *

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); +} diff --git a/src/com/ctreber/aclib/sort/DefaultComparator.java b/src/com/ctreber/aclib/sort/DefaultComparator.java new file mode 100644 index 000000000..10aa0abc6 --- /dev/null +++ b/src/com/ctreber/aclib/sort/DefaultComparator.java @@ -0,0 +1,19 @@ +package com.ctreber.aclib.sort; + +import java.util.Comparator; + +/** + *

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); + } +} diff --git a/src/com/ctreber/aclib/sort/QuickSort.java b/src/com/ctreber/aclib/sort/QuickSort.java new file mode 100644 index 000000000..588bc6dfb --- /dev/null +++ b/src/com/ctreber/aclib/sort/QuickSort.java @@ -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; + } + } +} diff --git a/src/jcckit/GraphicsPlotCanvas.java b/src/jcckit/GraphicsPlotCanvas.java new file mode 100644 index 000000000..5d2b41b4a --- /dev/null +++ b/src/jcckit/GraphicsPlotCanvas.java @@ -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 Graphics context based on the + * {@link jcckit.renderer.GraphicsRenderer}. This class is not a subclass of + * java.awt.Component. The actual AWT component presenting the plot + * is an innerclass. Its instance wrapped by GraphicsPlotCanvas can + * be obtained with {@link #getGraphicsCanvas}. + *

+ * 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 Component 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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
background = default background color of the wrapped + * AWT componentColornoBackground color of the wrapped AWT component.
foreground = default foreground color of the wrapped + * AWT componentColornoForeground color of the wrapped AWT component.
doubleBuffering = truebooleannoIf true the plot will be painted by using + * double-buffering and pre-rendered view of the coordinate system. + *
+ * In addition the configuration parameters of the + * + * constructor 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 + * Graphics 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 null. + * + * @param marker + * Marker element. Can be null. + */ + public void setMarker(GraphicalElement marker) { + _marker = marker; + } + +} diff --git a/src/jcckit/data/DataContainer.java b/src/jcckit/data/DataContainer.java new file mode 100644 index 000000000..444cf7299 --- /dev/null +++ b/src/jcckit/data/DataContainer.java @@ -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. + *

+ * 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 + * DataContainer. 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 DataListener must only be registered at the + * {@link DataPlot} instance and it will automatically also received events + * caused by manipulating one of its DataCurves. + *

+ * Concrete subclasses have to implement {@link #isValid} which + * checks whether the added or inserted DataElement 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 element 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 element will be inserted. + * All elements with an index >= index will be shifted. + * @param element DataElement to be added. + * @throws IllegalArgumentException if element 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 > index 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 + * element. + * @param element The new DataElement. + * @throws IllegalArgumentException if element 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 true if the specified {@link DataElement} has the + * correct type. Concrete subclasses have to implement this method. + * @param element DataElement to be checked. + */ + protected abstract boolean isValid(DataElement element); +} diff --git a/src/jcckit/data/DataCurve.java b/src/jcckit/data/DataCurve.java new file mode 100644 index 000000000..caf94f3fc --- /dev/null +++ b/src/jcckit/data/DataCurve.java @@ -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. + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
title = empty stringStringnoCurve title.
xdouble[]yesx-coordinates of the curve points.
ydouble[]yesy-coordinates of the curve points.
+ */ + 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 true if element is an instance of + * {@link DataPoint}. + */ + protected boolean isValid(DataElement element) { + return element instanceof DataPoint; + } +} diff --git a/src/jcckit/data/DataElement.java b/src/jcckit/data/DataElement.java new file mode 100644 index 000000000..a66ce4993 --- /dev/null +++ b/src/jcckit/data/DataElement.java @@ -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 null if this element is not an element of a container. + */ + public DataContainer getContainer(); + + /** + * Sets the container which should contain this element. + * This method should not used outside {@link DataContainer}.. + * @param container Container which should contains this element. Cann be + * null if this element does not belong to a container. + */ + public void setContainer(DataContainer container); +} diff --git a/src/jcckit/data/DataEvent.java b/src/jcckit/data/DataEvent.java new file mode 100644 index 000000000..8839f1350 --- /dev/null +++ b/src/jcckit/data/DataEvent.java @@ -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 ELEMENT_ADDED 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 ELEMENT_INSERTED 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 index. + * @return ELEMENT_REPLACED 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 index. + * @return ELEMENT_REMOVED 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 null if either an element has been added or inserted. + */ + public DataElement getDeletedElement() { + return _deletedElement; + } +} diff --git a/src/jcckit/data/DataEventType.java b/src/jcckit/data/DataEventType.java new file mode 100644 index 000000000..116139b33 --- /dev/null +++ b/src/jcckit/data/DataEventType.java @@ -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(); + +} diff --git a/src/jcckit/data/DataListener.java b/src/jcckit/data/DataListener.java new file mode 100644 index 000000000..cd2c70841 --- /dev/null +++ b/src/jcckit/data/DataListener.java @@ -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); +} diff --git a/src/jcckit/data/DataPlot.java b/src/jcckit/data/DataPlot.java new file mode 100644 index 000000000..43511d52e --- /dev/null +++ b/src/jcckit/data/DataPlot.java @@ -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. + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
curvesString[]yesList of keys denoting data curves. Each key refers to + * config parameters used in the + * + * constructor of {@link DataCurve}.
+ */ + 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 DataPlot based on the specified + * config parameters. It is a short-cut of + * new DataPlot(config.getNode("data")). + */ + public static DataPlot create(ConfigParameters config) { + return new DataPlot(config.getNode(DATA_KEY)); + } + + /** + * Returns true if element is an instance of + * {@link DataCurve}. + */ + protected boolean isValid(DataElement element) { + return element instanceof DataCurve; + } +} + diff --git a/src/jcckit/data/DataPoint.java b/src/jcckit/data/DataPoint.java new file mode 100644 index 000000000..38810ebf3 --- /dev/null +++ b/src/jcckit/data/DataPoint.java @@ -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 null. */ + public DataContainer getContainer() { + return null; + } + + /** Does nothing. */ + public void setContainer(DataContainer container) {} +} diff --git a/src/jcckit/graphic/Anchor.java b/src/jcckit/graphic/Anchor.java new file mode 100644 index 000000000..71ad63638 --- /dev/null +++ b/src/jcckit/graphic/Anchor.java @@ -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}. + *

+ * The anchor factor can be used in a position formular. Its value + * for the three instances reads: + *

+ *

+ * + * + * + * + * + *
InstanceFactor
LEFT_BOTTOM0
CENTER1
RIGHT_TOP2
+ *
+ * + * @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. null is not allowed. + * @param defaultValue The default value. + * @return one of the three instances of Anchor. + * @throws FactoryException if the value of key is + * neither left, center, + * nor right. + * 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. null is not allowed. + * @param defaultValue The default value. + * @return one of the three instances of Anchor. + * @throws FactoryException if the value of key is + * neither top, center, + * nor bottom. + * 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; + } +} + diff --git a/src/jcckit/graphic/BasicGraphicAttributes.java b/src/jcckit/graphic/BasicGraphicAttributes.java new file mode 100644 index 000000000..251dc7946 --- /dev/null +++ b/src/jcckit/graphic/BasicGraphicAttributes.java @@ -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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
textColor = default foreground color of the + * rendererColornoThe text color.
fontName = default font name of the + * rendererStringnoThe 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}. + *
fontStyle = normalString + * noThe font style. Possible values are: + *
  • normal
  • bold
  • italic + *
  • bold italic
+ *
fontSize = default font size of the + * rendererdoublenoThe font size in units of the device-independent + * coordinates.
orientationAngle = 0doublenoThe orientation angle of the text (in degree). + * Zero means normal orientation whereas a positive value means + * a rotation in counter-clockweise direction.
horizontalAnchor = leftString + * noAnchor for horizontal text position. Possible values are + * left, center, and right.
verticalAnchor = centerString + * noAnchor for vertical text position. Possible values are + * top, center, and bottom.
+ * 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 null. + * @param lineColor The line color. May be null. + * @param lineThickness Thickness of the line. + * Negative numbers will be trimmed to zero. + * @param linePattern Line pattern. May be null. + * @param textColor The text color. May be null. + * @param fontName The font name. May be null. + * @param fontStyle The font style. May be null. + * @param fontSize The font size in units of the device-independent + * coordinates. May be null. + * @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 null means default color of the renderer. + */ + public Color getTextColor() { + return _textColor; + } + + /** + * Returns the font name. + * @return null means default font name of the renderer. + */ + public String getFontName() { + return _fontName; + } + + /** + * Returns the font style. + * @return null 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 before + * it is rotated by the orientation angle. + * @return one of the three instances of Anchor. + */ + public Anchor getHorizontalAnchor() { + return _horizontalAnchor; + } + + /** + * Returns the anchor for vertical position of the text. + * Note, that the anchor is related to the text before + * it is rotated by the orientation angle. + * @return one of the three instances of Anchor. + */ + public Anchor getVerticalAnchor() { + return _verticalAnchor; + } +} + diff --git a/src/jcckit/graphic/BasicGraphicalElement.java b/src/jcckit/graphic/BasicGraphicalElement.java new file mode 100644 index 000000000..37ed247ff --- /dev/null +++ b/src/jcckit/graphic/BasicGraphicalElement.java @@ -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 null if undefined. + */ + public BasicGraphicalElement(GraphicAttributes attributes) { + _attributes = attributes; + } + + /** + * Returns the drawing attributes. + * @return null if undefined. + */ + public GraphicAttributes getGraphicAttributes() { + return _attributes; + } + + /** + * Returns whether this basic graphical element has a closed shape + * or not. By default always true. Subclasses may override + * this behaviour. + * @return true if the shape is closed. + */ + public boolean isClosed() { + return true; + } +} diff --git a/src/jcckit/graphic/ClippingRectangle.java b/src/jcckit/graphic/ClippingRectangle.java new file mode 100644 index 000000000..3c56241c2 --- /dev/null +++ b/src/jcckit/graphic/ClippingRectangle.java @@ -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 true 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); + } +} diff --git a/src/jcckit/graphic/ClippingShape.java b/src/jcckit/graphic/ClippingShape.java new file mode 100644 index 000000000..8559a9e8b --- /dev/null +++ b/src/jcckit/graphic/ClippingShape.java @@ -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 true 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(); +} diff --git a/src/jcckit/graphic/FillAttributes.java b/src/jcckit/graphic/FillAttributes.java new file mode 100644 index 000000000..7af1b56f2 --- /dev/null +++ b/src/jcckit/graphic/FillAttributes.java @@ -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 null means no filling. + */ + public Color getFillColor(); +} + diff --git a/src/jcckit/graphic/FontStyle.java b/src/jcckit/graphic/FontStyle.java new file mode 100644 index 000000000..fb3d5d90e --- /dev/null +++ b/src/jcckit/graphic/FontStyle.java @@ -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 FontStyle. + * @throws FactoryException if the value of the key-value pair denoted + * by key is neither normal, bold, + * italic, nor bold italic, + * 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; + } +} diff --git a/src/jcckit/graphic/GraphPoint.java b/src/jcckit/graphic/GraphPoint.java new file mode 100644 index 000000000..a85de78a3 --- /dev/null +++ b/src/jcckit/graphic/GraphPoint.java @@ -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 vector is null 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); + } +} diff --git a/src/jcckit/graphic/GraphicAttributes.java b/src/jcckit/graphic/GraphicAttributes.java new file mode 100644 index 000000000..a418c1cd1 --- /dev/null +++ b/src/jcckit/graphic/GraphicAttributes.java @@ -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 + * BasicGraphicalElement. Whether they are used and how + * they are interpreted depends on the concrete Renderer. + *

+ * 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 { +} + diff --git a/src/jcckit/graphic/GraphicalComposite.java b/src/jcckit/graphic/GraphicalComposite.java new file mode 100644 index 000000000..b981343d7 --- /dev/null +++ b/src/jcckit/graphic/GraphicalComposite.java @@ -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 null if no clipping. + */ + public GraphicalComposite(ClippingShape clippingShape) { + _clippingShape = clippingShape; + } + + /** + * Returns the clipping shape. + * @return null 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. null is not allowed. + * @throws NullPointerException if element == null + */ + 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. null is not allowed. + * @throws NullPointerException if element == null + */ + 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 renderer is not + * an instance of GraphicalCompositeRenderer. + */ + 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."); + } + } +} diff --git a/src/jcckit/graphic/GraphicalCompositeRenderer.java b/src/jcckit/graphic/GraphicalCompositeRenderer.java new file mode 100644 index 000000000..f3c7ba402 --- /dev/null +++ b/src/jcckit/graphic/GraphicalCompositeRenderer.java @@ -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 + * GraphicalCompositeRenderer does not + * render the element of a GraphicalComposite + * + * @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 + * composite. + */ + public void startRendering(GraphicalComposite composite); + + /** Finishes rendering of the specified composite. */ + public void finishRendering(GraphicalComposite composite); +} diff --git a/src/jcckit/graphic/GraphicalElement.java b/src/jcckit/graphic/GraphicalElement.java new file mode 100644 index 000000000..2b28fa40a --- /dev/null +++ b/src/jcckit/graphic/GraphicalElement.java @@ -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 GraphicalElements + * without touching existing code. + * + * @author Franz-Josef Elmer + */ +public interface GraphicalElement { + /** + * Renders this element according to the type of renderer. + * Concrete GraphicalElements who are not instances of + * {@link GraphicalComposite} dynamically cast renderer. + * If it does not implement the type of renderer specific for + * the concrete GraphicalElement it should throw an + * IllegalArgumentException. + */ + public abstract void renderWith(Renderer renderer); +} diff --git a/src/jcckit/graphic/LineAttributes.java b/src/jcckit/graphic/LineAttributes.java new file mode 100644 index 000000000..2d8f7a178 --- /dev/null +++ b/src/jcckit/graphic/LineAttributes.java @@ -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 null 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 null means solid line. + */ + public double[] getLinePattern(); +} + diff --git a/src/jcckit/graphic/Oval.java b/src/jcckit/graphic/Oval.java new file mode 100644 index 000000000..9d49621a6 --- /dev/null +++ b/src/jcckit/graphic/Oval.java @@ -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 null. + */ + 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 renderer is not + * an instance of OvalRenderer. + */ + public void renderWith(Renderer renderer) { + if (renderer instanceof OvalRenderer) { + ((OvalRenderer) renderer).render(this); + } else { + throw new IllegalArgumentException(renderer + + " does not implements OvalRenderer."); + } + } +} + diff --git a/src/jcckit/graphic/OvalRenderer.java b/src/jcckit/graphic/OvalRenderer.java new file mode 100644 index 000000000..97108eb2e --- /dev/null +++ b/src/jcckit/graphic/OvalRenderer.java @@ -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); +} diff --git a/src/jcckit/graphic/Polygon.java b/src/jcckit/graphic/Polygon.java new file mode 100644 index 000000000..45245b4d8 --- /dev/null +++ b/src/jcckit/graphic/Polygon.java @@ -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 true if this polygon is closed. + */ + public Polygon(GraphicAttributes attributes, boolean closed) { + super(attributes); + _closed = closed; + } + + /** Returns true 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 renderer is not + * an instance of PolygonRenderer. + */ + public void renderWith(Renderer renderer) { + if (renderer instanceof PolygonRenderer) { + ((PolygonRenderer) renderer).render(this); + } else { + throw new IllegalArgumentException(renderer + + " does not implements PolygonRenderer."); + } + } +} diff --git a/src/jcckit/graphic/PolygonRenderer.java b/src/jcckit/graphic/PolygonRenderer.java new file mode 100644 index 000000000..0c07f905d --- /dev/null +++ b/src/jcckit/graphic/PolygonRenderer.java @@ -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 Polygon instance. */ + public void render(Polygon polygon); +} diff --git a/src/jcckit/graphic/Rectangle.java b/src/jcckit/graphic/Rectangle.java new file mode 100644 index 000000000..f66a3c5f1 --- /dev/null +++ b/src/jcckit/graphic/Rectangle.java @@ -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 null. + */ + 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 renderer is not + * an instance of RectangleRenderer. + */ + public void renderWith(Renderer renderer) { + if (renderer instanceof RectangleRenderer) { + ((RectangleRenderer) renderer).render(this); + } else { + throw new IllegalArgumentException(renderer + + " does not implements RectangleRenderer."); + } + } +} + diff --git a/src/jcckit/graphic/RectangleRenderer.java b/src/jcckit/graphic/RectangleRenderer.java new file mode 100644 index 000000000..6a1d01c66 --- /dev/null +++ b/src/jcckit/graphic/RectangleRenderer.java @@ -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); +} diff --git a/src/jcckit/graphic/Renderer.java b/src/jcckit/graphic/Renderer.java new file mode 100644 index 000000000..b3d722645 --- /dev/null +++ b/src/jcckit/graphic/Renderer.java @@ -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 {} diff --git a/src/jcckit/graphic/ShapeAttributes.java b/src/jcckit/graphic/ShapeAttributes.java new file mode 100644 index 000000000..23e14d13f --- /dev/null +++ b/src/jcckit/graphic/ShapeAttributes.java @@ -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. + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
fillColor = no fillingColornoThe fill color of the shape.
lineColor = no lineColornoThe color of a line, a polygon, or the border of a shape.
lineThickness = 0doublenoThe thickness of a line. A thickness of zero means that + * the renderer will draw the thinest line possible.
linePattern = solid linedouble[]noA sequence of lengths where the pen is alternatively + * down or up. For example, 0.1 0.1 will lead to a dashed + * line whereas 0.02 0.02 is the pattern of a dotted + * line and 0.02 0.02 0.1 0.02 of a dashed-dotted + * line.
+ */ + 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 null. + * @param lineColor The line color. May be null. + * @param lineThickness Thickness of the line. + * Negative numbers will be trimmed to zero. + * @param linePattern Line pattern. May be null. + */ + 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; + } +} + diff --git a/src/jcckit/graphic/Text.java b/src/jcckit/graphic/Text.java new file mode 100644 index 000000000..23133c260 --- /dev/null +++ b/src/jcckit/graphic/Text.java @@ -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 null. + */ + 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 renderer is not + * an instance of TextRenderer. + */ + public void renderWith(Renderer renderer) { + if (renderer instanceof TextRenderer) { + ((TextRenderer) renderer).render(this); + } else { + throw new IllegalArgumentException(renderer + + " does not implements TextRenderer."); + } + } +} diff --git a/src/jcckit/graphic/TextAttributes.java b/src/jcckit/graphic/TextAttributes.java new file mode 100644 index 000000000..3e6080d85 --- /dev/null +++ b/src/jcckit/graphic/TextAttributes.java @@ -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 null means default color of the renderer. + */ + public Color getTextColor(); + + /** + * Returns the font name. + * @return null means default font name of the renderer. + */ + public String getFontName(); + + /** + * Returns the font style. + * @return null 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 before + * it is rotated by the orientation angle. + * @return one of the three instances of Anchor. + */ + public Anchor getHorizontalAnchor(); + + /** + * Returns the anchor for vertical position of the text. + * Note, that the anchor is related to the text before + * it is rotated by the orientation angle. + * @return one of the three instances of Anchor. + */ + public Anchor getVerticalAnchor(); +} + diff --git a/src/jcckit/graphic/TextRenderer.java b/src/jcckit/graphic/TextRenderer.java new file mode 100644 index 000000000..98f2124ee --- /dev/null +++ b/src/jcckit/graphic/TextRenderer.java @@ -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 Text instance. */ + public void render(Text text); +} diff --git a/src/jcckit/plot/AbstractSymbolFactory.java b/src/jcckit/plot/AbstractSymbolFactory.java new file mode 100644 index 000000000..f88f18abd --- /dev/null +++ b/src/jcckit/plot/AbstractSymbolFactory.java @@ -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. + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
size = 0.01doublenoSize of the symbol in device-independent units.
attributesConfigParametersnoConfiguration parameters for the attributes of the symbol. + * className has to be a class which is an instance of + * {@link GraphicAttributes}.
+ */ + public AbstractSymbolFactory(ConfigParameters config) { + _size = config.getDouble(SIZE_KEY, DEFAULT_SIZE); + _attributes = (GraphicAttributes) Factory.createOrGet( + config.getNode(ATTRIBUTES_KEY), null); + } + + /** + * Creates a symbol. + * Evaluate hintFromPreviousPoint 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 Symbol object. + * @param hintFromPreviousCurve Hint from the previous curve. + * Will be delivered unchanged in the return Symbol 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); +} diff --git a/src/jcckit/plot/AttributesHint.java b/src/jcckit/plot/AttributesHint.java new file mode 100644 index 000000000..0ab44166f --- /dev/null +++ b/src/jcckit/plot/AttributesHint.java @@ -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(); +} diff --git a/src/jcckit/plot/AxisParameters.java b/src/jcckit/plot/AxisParameters.java new file mode 100644 index 000000000..3fd2aa089 --- /dev/null +++ b/src/jcckit/plot/AxisParameters.java @@ -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. + *

+ * 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. + *

+ * Note, that there is a direct access of these parameters without getters + * and setters but only for classes in the package jcckit.plot. + * + * @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 true 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 null 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 null 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 true grid lines are drawn. */ + boolean grid; + /** + * Attributes of the grid lines. + * Can be null 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 minimumTic, maximumTic, + * and numberOfTics. If automaticTicCalculation == true + * 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 adjustingValue if value is very close + * to adjustingValue. Otherwise value is returned. + */ + private static double adjust(double adjustingValue, double value) { + return value != 0 && Math.abs(adjustingValue / value - 1) < 1e-11 + ? adjustingValue : value; + } + + /** + * Returns a Properties 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 Properties 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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
automaticTicCalculation = truebooleannoHas to be true if the tics should be calculated + * automatically.
axisAttributes = default values of + * {@link ShapeAttributes}ConfigParametersnoAttributes of the axis box.
axisLabel = xStringnoAxis label.
axisLabelAttributes = default values of + * {@link BasicGraphicAttributes} with a text anchor CENTER + * TOP.ConfigParametersnoText attributes of axis label.
axisLabelPosition = 0 -0.05double[]noPosition of the anchor of the axis + * label relative to the center of the x-axis line.
axisLength = 0.8doublenoLength of the x-axis.
grid = falsebooleannoIf true grid lines will be drawn through the axis + * tics.
gridAttributes = default values of + * {@link ShapeAttributes}ConfigParametersnoAttributes of the grid lines.
logScale = falsebooleannoIf true the axis will be logarithmic. Otherwise + * the axis is linear.
maximum = 1doublenoThe corresponding data value of one end of the axis.
maximumTic = result from automatic calculationdoublenoThe corresponding data value of the tic nearest the maximum end + * of the axis.
minimum = 0doublenoThe corresponding data value of one end of the axis.
minimumTic = result from automatic calculationdoublenoThe corresponding data value of the tic nearest the minimum end + * of the axis.
numberOfTics = result from automatic calculationintnoNumber of tics. The tics between the minimum and maximum tic + * are spaced equidistantly.
ticAttributes = default values of + * {@link ShapeAttributes}ConfigParametersnoAttributes of the tics.
ticLabelAttributes = default values of + * {@link BasicGraphicAttributes} with a text anchor CENTER + * TOP.ConfigParametersnoText attributes of tic labels.
ticLabelFormat = %1.1fString or ConfigParametersnoDefines rendering of the tic label. By default a + * printf-like format string is given (see {@link Format}). + * Note, that an empty string means that tic labels are dropped. + *

+ * 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 className key-value pair overwrites any string + * definition.

ticLabelPosition = 0 -0.01double[]noPosition of the anchor of the tic label relative to the + * tic position on the axis.
ticLength = 0.01doublenoLength of the tics. Negative/positive values mean tics + * inside/outside the box.
+ */ + public static AxisParameters createXAxis(ConfigParameters config) { + return createAxis(config, createDefaultXAxisProperties()); + } + + /** + * Returns a Properties 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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
automaticTicCalculation = truebooleannoHas to be true if the tics should be calculated + * automatically.
axisAttributes = default values of + * {@link ShapeAttributes}ConfigParametersnoAttributes of the axis box.
axisLabel = yStringnoAxis label.
axisLabelAttributes = default values of + * {@link BasicGraphicAttributes} with a text anchor CENTER + * BOTTOM and the text rotated by 90 degree.ConfigParametersnoText attributes of axis label.
axisLabelPosition = -0.1 0double[]noPosition of the anchor of the axis + * label relative to the center of the y-axis line.
axisLength = 0.45doublenoLength of the y-axis.
grid = falsebooleannoIf true grid lines will be drawn through the axis + * tics.
gridAttributes = default values of + * {@link ShapeAttributes}ConfigParametersnoAttributes of the grid lines.
logScale = falsebooleannoIf true the axis will be logarithmic. Otherwise + * the axis is linear.
maximum = 1doublenoThe corresponding data value of one end of the axis.
maximumTic = result from automatic calculationdoublenoThe corresponding data value of the tic nearest the maximum end + * of the axis.
minimum = 0doublenoThe corresponding data value of one end of the axis.
minimumTic = result from automatic calculationdoublenoThe corresponding data value of the tic nearest the minimum end + * of the axis.
numberOfTics = result from automatic calculationintnoNumber of tics. The tics between the minimum and maximum tic + * are spaced equidistantly.
ticAttributes = default values of + * {@link ShapeAttributes}ConfigParametersnoAttributes of the tics.
ticLabelAttributes = default values of + * {@link BasicGraphicAttributes} with a text anchor RIGHT CENTER. + * ConfigParametersnoText attributes of tic labels.
ticLabelFormat = %1.1fStringnoDefines rendering of the tic label. By default a + * printf-like format string is given (see {@link Format}). + * Note, that an empty string means that tic labels are dropped. + *

+ * 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 className key-value pair overwrites any string + * definition.

ticLabelPosition = -0.01 0double[]noPosition of the anchor of the tic label relative to the + * tic position on the axis.
ticLength = 0.01doublenoLength of the tics. Negative/positive values mean tics + * inside/outside the box.
+ */ + 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; + } +} diff --git a/src/jcckit/plot/BarFactory.java b/src/jcckit/plot/BarFactory.java new file mode 100644 index 000000000..4f8e4c98b --- /dev/null +++ b/src/jcckit/plot/BarFactory.java @@ -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. + *

+ * 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. + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
horizontalBars = falsebooleannoIf true horizontal bars will be drawn. Otherwise + * vertical bars are drawn.
stacked = falsebooleannoIf true the bars of several curves will be + * stacked.
+ * In addition the configuration parameters of the + * + * constructor 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 hintFromPreviousCurve + * 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 null because this method isn't needed but has to be + * implemented. + */ + protected GraphicalElement createPlainSymbol( + GraphPoint centerPosition, double size, GraphicAttributes attributes) { + return null; + } +} diff --git a/src/jcckit/plot/CartesianCoordinateSystem.java b/src/jcckit/plot/CartesianCoordinateSystem.java new file mode 100644 index 000000000..36fd2c73f --- /dev/null +++ b/src/jcckit/plot/CartesianCoordinateSystem.java @@ -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. + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
origin = 0.15, 0.1double[]noPosition (in device-independent coordinates) of the lower-left + * corner of the axis box.
xAxisConfigParametersnoParameters defining the x-axis. For definitions and default + * values see {@link AxisParameters#createXAxis + * AxisParameters.createXAxis()}.
yAxisConfigParametersnoParameters defining the y-axis. For definitions and default + * values see {@link AxisParameters#createYAxis + * AxisParameters.createYAxis()}.
+ */ + 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; + } +} diff --git a/src/jcckit/plot/CircleSymbolFactory.java b/src/jcckit/plot/CircleSymbolFactory.java new file mode 100644 index 000000000..6b3f4246d --- /dev/null +++ b/src/jcckit/plot/CircleSymbolFactory.java @@ -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 + * + * constructor 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); + } +} diff --git a/src/jcckit/plot/CoordinateSystem.java b/src/jcckit/plot/CoordinateSystem.java new file mode 100644 index 000000000..62aeb7e35 --- /dev/null +++ b/src/jcckit/plot/CoordinateSystem.java @@ -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 + * CoordinateSystem 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(); +} diff --git a/src/jcckit/plot/Curve.java b/src/jcckit/plot/Curve.java new file mode 100644 index 000000000..47b1bb866 --- /dev/null +++ b/src/jcckit/plot/Curve.java @@ -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. + *

+ * 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(); +} diff --git a/src/jcckit/plot/CurveFactory.java b/src/jcckit/plot/CurveFactory.java new file mode 100644 index 000000000..0e6ee53fa --- /dev/null +++ b/src/jcckit/plot/CurveFactory.java @@ -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); +} diff --git a/src/jcckit/plot/ErrorBarFactory.java b/src/jcckit/plot/ErrorBarFactory.java new file mode 100644 index 000000000..2c55462d3 --- /dev/null +++ b/src/jcckit/plot/ErrorBarFactory.java @@ -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}. + *

+ * Curves with error bars are based on two + * {@link jcckit.data.DataCurve DataCurves}: + *

  1. The plain curve. + *
  2. An instance which stores the errors in x and y. + * It is assumed that the errors are positive values defining + * the error symmetrically around the curve points. + *
+ *

+ * The ErrorBarFactory 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 PositionHint 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. + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
symbolFactory = nullConfigParametersnoDefinition of the wrapped {@link SymbolFactory} which generates + * the curve symbol without bars. By default an empty + * {@link GraphicalComposite} will be created.
size = 0doublenoWidth of the error bars.
attributes = nullConfigParametersnoDefinition of the {@link GraphicAttributes} of the error + * bars.
+ */ + 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 hintFromPreviousCurve is an instance of + * {@link PositionHint} and its position attribute is not null. + * 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 PositionHint. The hint for + * the next curve wrapped by the returned Symbol is always + * a PositionHint. + */ + 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)); + } + } +} diff --git a/src/jcckit/plot/Hint.java b/src/jcckit/plot/Hint.java new file mode 100644 index 000000000..ff565b8f4 --- /dev/null +++ b/src/jcckit/plot/Hint.java @@ -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 {} diff --git a/src/jcckit/plot/Legend.java b/src/jcckit/plot/Legend.java new file mode 100644 index 000000000..aa5f93418 --- /dev/null +++ b/src/jcckit/plot/Legend.java @@ -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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
bottomDistance = 0.02doublenoDistance between the last row and the bottom of the legend box. + *
boxAttributes = default values of + * {@link ShapeAttributes} with a white fill color.ConfigParametersnoAttributes of the legend box.
boxHeight = 0.1doublenoHeight of the legend box.
boxWidth = 0.2doublenoWidth of the legend box.
curveTitleAttributes = default values of + * {@link BasicGraphicAttributes}ConfigParametersnoText attributes of curve titles printed in the legend.
curveTitleDistance = 0.005doublenoHorizontal distance between the line part of the legend symbol + * and the curve title.
leftDistance = 0.01doublenoHorizontal distance between the line part of the legend symbol + * and the left border of the legend box.
lineLength = 0.035doublenoLength of the line part of the legend symbol.
symbolSize = 0.01doublenoSize of the symbol part of the legend symbol. Will be the + * size argument of {@link SymbolFactory#createLegendSymbol + * createLegendSymbol} in a {@link SymbolFactory}.
titleAttributes = default values of + * {@link BasicGraphicAttributes} with a text anchor CENTER + * TOP.ConfigParametersnoText attributes of the title of the legend box.
title = LegendStringnoTitle of the legend box.
titleDistance = 0.005doublenoDistance between the center of the upper line of the legend box + * and the anchor of the legend title.
topDistance = 0.04doublenoDistance between the first row and the top of the legend box. + *
upperRightCorner = 0.94, 0.54double[]noPosition of the upper-right corner of the legend box.
+ */ + 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 null. + * @param withLine true 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); + } +} diff --git a/src/jcckit/plot/Plot.java b/src/jcckit/plot/Plot.java new file mode 100644 index 000000000..0a2c7d274 --- /dev/null +++ b/src/jcckit/plot/Plot.java @@ -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. + *

+ * Registrated {@link PlotListener PlotListeners} will be informed + * when the plot changes. + *

+ * A {@link DataPlot} can be connected with a Plot instance. + * This is done with the method {@link #connect connect()} which registrates + * this Plot instance as + * a {@link DataListener} at the connected DataPlot. + * After an received {@link DataEvent DataEvents} has been handled + * the registrated PlotListeners 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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
coordinateSystem = {@link CartesianCoordinateSystem}ConfigParametersnoDefinition of the {@link CoordinateSystem}.
curveFactory = {@link SimpleCurveFactory}ConfigParametersnoDefinition of the {@link CurveFactory}.
initialHintForNextCurve = nullConfigParametersnoDefinition of the initial {@link Hint} which is needed by some + * {@link SymbolFactory SymbolFactories} like {@link BarFactory}. + *
legend = default values of {@link Legend}ConfigParametersnoConfiguration parameters of a {@link Legend}.
legendVisible = truebooleannoIf true the {@link Legend} will be created.
+ */ + 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. + *

+ * If this Plot instance is already connected with a + * DataPlot 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}. + *

+ * It registers itself at dataPlot and + * all its {@link DataCurve DataCurves}. + *

+ * Finally all curves will be generated and a PlotEvent + * of the type {@link PlotEventType#DATA_PLOT_CONNECTED} will be transmitted. + * @param dataPlot Data to be connected with this plot instance. + * Can be null in order to disconnect this instance from + * any DataPlot. + */ + 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 point. + */ + public DataPoint transform(GraphPoint point) { + return _transformation.transformToData(point); + } + + /** + * Creates a graphical representation of the complete plot. + * @return GraphicalComposite 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 null 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 null. + */ + public void setAnnotation(GraphicalElement annotation) + { + _annotation = annotation; + } + + /** Returns true 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: + * + * + * + * + * + * + * + *
Source of eventAll hints for the next curve are null?ActionType of sent {@link PlotEvent}
{@link DataCurve}YesRecreate changed curve. + * DATA_CURVE_CHANGED
{@link DataCurve}NoRecreate changed curve + * and all curves with large curve index. + * DATA_PLOT_CHANGED
{@link DataPlot}-Recreate all curves + * and {@link Legend} view. + * DATA_PLOT_CHANGED
+ */ + 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); + } +} diff --git a/src/jcckit/plot/PlotCanvas.java b/src/jcckit/plot/PlotCanvas.java new file mode 100644 index 000000000..9c5480d5b --- /dev/null +++ b/src/jcckit/plot/PlotCanvas.java @@ -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 paper. 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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
horizontalAnchor = centerStringnoHorizontal position of the paper relative to the device border. + * Possible values are left, center, and + * right.
paper = 0, 0, 1, 0.6double[]noRectangle 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.
plot = default values of {@link Plot}ConfigParametersnoDefinition of the {@link Plot}.
verticalAnchor = centerStringnoVertical position of the paper relative to the device border. + * Possible values are top, center, and + * bottom.
+ *

+ * 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 + * null in order to disconnect this instance from a + * DataPlot. + */ + 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) { + } +} diff --git a/src/jcckit/plot/PlotEvent.java b/src/jcckit/plot/PlotEvent.java new file mode 100644 index 000000000..b1fecc382 --- /dev/null +++ b/src/jcckit/plot/PlotEvent.java @@ -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: + *

+ * + * + * @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 null + */ + 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; + } +} diff --git a/src/jcckit/plot/PlotEventType.java b/src/jcckit/plot/PlotEventType.java new file mode 100644 index 000000000..24a2a3cfc --- /dev/null +++ b/src/jcckit/plot/PlotEventType.java @@ -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() {} +} diff --git a/src/jcckit/plot/PlotListener.java b/src/jcckit/plot/PlotListener.java new file mode 100644 index 000000000..ed37113f8 --- /dev/null +++ b/src/jcckit/plot/PlotListener.java @@ -0,0 +1,29 @@ +/* + * 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; + +/** + * Listener for changes of plots, diagrams, and charts. + * + * @author Franz-Josef Elmer + */ +public interface PlotListener { + /** Receives the specified plot event.*/ + public void plotChanged(PlotEvent event); +} diff --git a/src/jcckit/plot/PositionHint.java b/src/jcckit/plot/PositionHint.java new file mode 100644 index 000000000..d068e2970 --- /dev/null +++ b/src/jcckit/plot/PositionHint.java @@ -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.plot; + +import jcckit.graphic.GraphPoint; +import jcckit.util.ConfigParameters; + +/** + * An immutable {@link Hint} capsulating two {@link GraphPoint GraphPoints}. + * + * @author Franz-Josef Elmer + */ +public class PositionHint implements Hint { + /** Configuration parameter key. */ + public static final String POSITION_KEY = "position", + ORIGIN_KEY = "origin"; + private final GraphPoint _position; + private final GraphPoint _origin; + + /** + * Creates an instance from the specified configuration parameters. + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
position = nulldouble[]noDefinition of position.
origin = position or (0,0) if position + * undefineddouble[]noDefinition of origin.
+ */ + public PositionHint(ConfigParameters config) { + double[] point = config.getDoubleArray(POSITION_KEY, null); + _position = point == null ? null : new GraphPoint(point); + _origin = new GraphPoint(config.getDoubleArray(ORIGIN_KEY, point)); + } + + /** + * Creates an instance based on two points. + * @param origin The origin. + * @param position The position. + */ + public PositionHint(GraphPoint origin, GraphPoint position) { + _origin = origin; + _position = position; + } + + /** Returns the position. */ + public GraphPoint getPosition() { + return _position; + } + + /** Returns the origin. */ + public GraphPoint getOrigin() { + return _origin; + } +} diff --git a/src/jcckit/plot/ShapeAttributesHint.java b/src/jcckit/plot/ShapeAttributesHint.java new file mode 100644 index 000000000..4c71835af --- /dev/null +++ b/src/jcckit/plot/ShapeAttributesHint.java @@ -0,0 +1,140 @@ +/* + * 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.awt.Color; + +import jcckit.graphic.GraphicAttributes; +import jcckit.graphic.ShapeAttributes; +import jcckit.util.ConfigParameters; + +/** + * An {@link AttributesHint} which wraps {@link ShapeAttributes}. + * Each call of {@link #getNextHint()} returns a new instance of + * ShapeAttributes where fill color, line color and/or + * line thickness has been increased by a constant amount. + * + * @author Franz-Josef Elmer + */ +public class ShapeAttributesHint implements AttributesHint, Cloneable { + /** Configuration parameter key. */ + public static final String INITIAL_ATTRIBUTES_KEY = "initialAttributes", + FILL_COLOR_HSB_INCREMENT_KEY + = "fillColorHSBIncrement", + LINE_COLOR_HSB_INCREMENT_KEY + = "lineColorHSBIncrement", + LINE_THICKNESS_INCREMENT_KEY + = "lineThicknessIncrement"; + private static float[] extractHSB(Color color) { + return color == null ? null + : Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), + null); + } + + private static Color createColor(float[] colorHSB) { + return colorHSB == null ? null + : Color.getHSBColor(colorHSB[0], colorHSB[1], colorHSB[2]); + } + + private static float[] incrementColor(float[] colorHSB, + double[] increments) { + float[] result = null; + if (colorHSB != null) { + result = (float[]) colorHSB.clone(); + for (int i = 0; i < 3; i++) { + result[i] += increments[i]; + } + } + return result; + } + + private float[] _fillColorHSB; + private float[] _lineColorHSB; + private double _lineThickness; + private double[] _linePattern; + private double[] _fillColorHSBIncrement; + private double[] _lineColorHSBIncrement; + private double _lineThicknessIncrement; + + /** + * Creates an instance from the specified configuration parameters. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
initialAttributes = default values of + * {@link ShapeAttributes}ConfigParametersnoInitial values of shape attributes. Note, that default + * fill and line colors are undefined (they depend on the + * Renderer). In this case color increments have no effects. + *
fillColorHSBIncrement = 0 0 0double[]noHue, saturation, and brightness increments of the fill color. + *
lineColorHSBIncrement = 0 0 0double[]noHue, saturation, and brightness increments of the line color. + *
lineThicknessIncrement = 0doublenoLine thickness increment.
+ */ + public ShapeAttributesHint(ConfigParameters config) { + ShapeAttributes attributes + = new ShapeAttributes(config.getNode(INITIAL_ATTRIBUTES_KEY)); + _fillColorHSB = extractHSB(attributes.getFillColor()); + _lineColorHSB = extractHSB(attributes.getLineColor()); + _lineThickness = attributes.getLineThickness(); + _linePattern = attributes.getLinePattern(); + + _fillColorHSBIncrement + = config.getDoubleArray(FILL_COLOR_HSB_INCREMENT_KEY, new double[3]); + _lineColorHSBIncrement + = config.getDoubleArray(LINE_COLOR_HSB_INCREMENT_KEY, new double[3]); + _lineThicknessIncrement + = config.getDouble(LINE_THICKNESS_INCREMENT_KEY, 0); + } + + /** + * Creates a new ShapeAttributesHint where all attributes has been + * incremented. + */ + public AttributesHint getNextHint() { + ShapeAttributesHint nextHint = null; + try { + nextHint = (ShapeAttributesHint) clone(); + } catch (CloneNotSupportedException e) {} + nextHint._fillColorHSB + = incrementColor(_fillColorHSB, _fillColorHSBIncrement); + nextHint._lineColorHSB + = incrementColor(_lineColorHSB, _lineColorHSBIncrement); + nextHint._lineThickness + = Math.max(0, _lineThickness + _lineThicknessIncrement); + return nextHint; + } + + /** Returns the wrapped {@link ShapeAttributes} instance. */ + public GraphicAttributes getAttributes() { + return new ShapeAttributes(createColor(_fillColorHSB), + createColor(_lineColorHSB), + _lineThickness, _linePattern); + } +} diff --git a/src/jcckit/plot/SimpleCurve.java b/src/jcckit/plot/SimpleCurve.java new file mode 100644 index 000000000..7477d2c24 --- /dev/null +++ b/src/jcckit/plot/SimpleCurve.java @@ -0,0 +1,185 @@ +/* + * 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.awt.Color; + +import jcckit.graphic.ClippingShape; +import jcckit.graphic.GraphPoint; +import jcckit.graphic.GraphicalComposite; +import jcckit.graphic.GraphicalElement; +import jcckit.graphic.LineAttributes; +import jcckit.graphic.Polygon; +import jcckit.graphic.ShapeAttributes; +import jcckit.util.ConfigParameters; +import jcckit.util.Factory; + +/** + * A simple curve is the basic implementation of the {@link Curve} interface. + * + * @author Franz-Josef Elmer + */ +public class SimpleCurve implements Curve { + /** Configuration parameter key. */ + public static final String SYMBOL_FACTORY_KEY = "symbolFactory", + WITH_LINE_KEY = "withLine", + SOFT_CLIPPING_KEY = "softClipping", + LINE_ATTRIBUTES_KEY = "lineAttributes", + INITIAL_HINT_FOR_NEXT_POINT_KEY + = "initialHintForNextPoint"; + private final ClippingShape _clippingShape; + private final SymbolFactory _symbolFactory; + private final GraphicalComposite _symbols; + private final GraphicalComposite _completeCurve; + private final GraphicalElement _legendSymbol; + private final Hint _initialHintForNextPoint; + private final Polygon _curve; + private final boolean _softClipping; + private Hint _hintForNextPoint; + + /** + * Creates a new curve. The parameter config contains: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
initialHintForNextPoint = nullConfigParametersnoDefinition of an initial {@link Hint} for the first curve point. + *
lineAttributes = a {@link ShapeAttributes} + * instances with default values and line colors based on + * the formula Color.getHSBColor(curveIndex/6,1,0.8)ConfigParametersnoConfiguration parameters of an instances of + * {@link jcckit.graphic.GraphicAttributes} for the + * {@link Polygon Polygons} connecting curve points.
symbolFactory = nullConfigParametersnoConfiguration parameters defining an instances of + * {@link SymbolFactory} for the {@link Symbol Symbols} + * decorating curve points.
softClipping = truebooleannoIf true no explicit clipping takes + * place but the symbol is not drawn if the corresponding curve + * point is outside the axis box.
+ * If false the symbol is + * drawn in any case but it may be clipped by the axis box. + * Soft-clipping should be set to false if the + * symbols are not located around the curve point (like for bars). + *
withLine = truebooleannoIf true curve points are connected by a + * {@link jcckit.graphic.Polygon}.
+ * @param config Configuration parameters described above. + * @param curveIndex Index of this curve in the collection of curves + * defining a {@link Plot}. + * @param numberOfCurves Number of curves in this collection. + * @param clippingShape Clipping shape. Can be null. + * @param legend Legend. Will be used to calculate the legend symbol. + * @throws IllegalArgumentException if symbolFactory == null and + * withLine == false. + * + */ + public SimpleCurve(ConfigParameters config, int curveIndex, + int numberOfCurves, ClippingShape clippingShape, + Legend legend) { + _symbolFactory = (SymbolFactory) Factory.createOrGet( + config.getNode(SYMBOL_FACTORY_KEY), null); + boolean withLine = config.getBoolean(WITH_LINE_KEY, true); + LineAttributes lineAttributes = (LineAttributes) Factory.createOrGet( + config.getNode(LINE_ATTRIBUTES_KEY), + new ShapeAttributes(null, Color.getHSBColor((curveIndex % 6) / 6f, + 1f, 0.8f), + 0, null)); + if (_symbolFactory != null || withLine) { + _clippingShape = clippingShape; + _completeCurve = new GraphicalComposite(null); + if (withLine) { + GraphicalComposite container = new GraphicalComposite(clippingShape); + _curve = new Polygon(lineAttributes, false); + container.addElement(_curve); + _completeCurve.addElement(container); + } else { + _curve = null; + } + _softClipping = config.getBoolean(SOFT_CLIPPING_KEY, true); + if (_symbolFactory != null) { + _symbols = new GraphicalComposite(_softClipping ? null + : clippingShape); + _completeCurve.addElement(_symbols); + } else { + _symbols = null; + } + } else { + throw new IllegalArgumentException( + "Either a SymbolFactory must exist or withLines == true."); + } + _hintForNextPoint = _initialHintForNextPoint + = (Hint) Factory.createOrGet( + config.getNode(INITIAL_HINT_FOR_NEXT_POINT_KEY), null); + _legendSymbol = legend.createSymbol(curveIndex, numberOfCurves, + _symbolFactory, withLine, + lineAttributes); + } + + /** + * Returns the graphical representation of a curve. + * @return always the same instance. + */ + public GraphicalElement getView() { + return _completeCurve; + } + + /** Returns the legend symbol. */ + public GraphicalElement getLegendSymbol() { + return _legendSymbol; + } + + /** Appends a new point to the curve if inside the clipping shape. */ + public Hint addPoint(GraphPoint point, Hint hintFromPreviousCurve) { + if (_curve != null) { + _curve.addPoint(point); + } + Hint hintForNextCurve = hintFromPreviousCurve; + if (_symbolFactory != null) { + Symbol symbol = _symbolFactory.createSymbol(point, _hintForNextPoint, + hintFromPreviousCurve); + if (_clippingShape == null || !_softClipping + || _clippingShape.isInside(point)) { + _symbols.addElement(symbol.getSymbol()); + } + _hintForNextPoint = symbol.getHintForNextPoint(); + hintForNextCurve = symbol.getHintForNextCurve(); + } + return hintForNextCurve; + } + + public void removeAllPoints() { + if (_curve != null) { + _curve.removeAllPoints(); + } + if (_symbols != null) { + _symbols.removeAllElements(); + } + _hintForNextPoint = _initialHintForNextPoint; + } +} diff --git a/src/jcckit/plot/SimpleCurveFactory.java b/src/jcckit/plot/SimpleCurveFactory.java new file mode 100644 index 000000000..4d7b2bc02 --- /dev/null +++ b/src/jcckit/plot/SimpleCurveFactory.java @@ -0,0 +1,80 @@ +/* + * 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 java.util.StringTokenizer; + +import jcckit.graphic.ClippingShape; +import jcckit.util.ConfigParameters; +import jcckit.util.PropertiesBasedConfigData; + +/** + * Factory for {@link SimpleCurve SimpleCurves}. + * + * @author Franz-Josef Elmer + */ +public class SimpleCurveFactory implements CurveFactory { + /** Configuration parameter key. */ + public static final String DEFINITIONS_KEY = "definitions"; + + private ConfigParameters[] _configs = new ConfigParameters[] + {new ConfigParameters(new PropertiesBasedConfigData(new Properties()))}; + + /** + * Creates an instance from the specified configuration parameter. + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
definitions = one empty ConfigParameters + * instanceString[]noKeys of subtrees defining {@link ConfigParameters} + * used by the {@link SimpleCurve#SimpleCurve constructor} of + * {@link SimpleCurve}.
+ */ + public SimpleCurveFactory(ConfigParameters config) { + String value = config.get(DEFINITIONS_KEY, null); + if (value != null) { + StringTokenizer tokenizer = new StringTokenizer(value); + _configs = new ConfigParameters[tokenizer.countTokens()]; + for (int i = 0; i < _configs.length; i++) { + _configs[i] = config.getNode(tokenizer.nextToken()); + } + } + } + + /** + * Creates an instance of {@link SimpleCurve}. + * @param curveIndex Index of the curve. Will be used to select the + * {@link ConfigParameters} object and the line attributes. + * In addition it will be used to calculate the y-coordinate + * of the legend symbol. + * @param numberOfCurves Number of curves. Will be needed to calculate + * the y-coordinate of the legend symbol. + * @param clippingShape The clipping shape. + * @param legend The legend. Will be needed to create the legend symbol. + */ + public Curve create(int curveIndex, int numberOfCurves, + ClippingShape clippingShape, Legend legend) { + return new SimpleCurve(_configs[curveIndex % _configs.length], curveIndex, + numberOfCurves, clippingShape, legend); + } +} diff --git a/src/jcckit/plot/SquareSymbolFactory.java b/src/jcckit/plot/SquareSymbolFactory.java new file mode 100644 index 000000000..10eecb751 --- /dev/null +++ b/src/jcckit/plot/SquareSymbolFactory.java @@ -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.Rectangle; +import jcckit.util.ConfigParameters; + +/** + * A factory of square symbols. + * + * @author Franz-Josef Elmer + */ +public class SquareSymbolFactory extends AbstractSymbolFactory { + /** + * Creates an instance from the specified configuration parameters. + * For the configuration parameters see the + * + * constructor of the superclass {@link AbstractSymbolFactory}. + */ + public SquareSymbolFactory(ConfigParameters config) { + super(config); + } + + /** + * Creates a {@link Rectangle}. + * @param centerPosition Position of the center of the rectangle. + * @param size Diameter of the rectangle. + * @param attributes Rectangle attributes. + */ + protected GraphicalElement createPlainSymbol(GraphPoint centerPosition, + double size, + GraphicAttributes attributes) { + return new Rectangle(centerPosition, size, size, attributes); + } +} diff --git a/src/jcckit/plot/Symbol.java b/src/jcckit/plot/Symbol.java new file mode 100644 index 000000000..69a2aa5db --- /dev/null +++ b/src/jcckit/plot/Symbol.java @@ -0,0 +1,56 @@ +/* + * 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; + +/** + * Immutable class holding the graphical represention of the symbol and + * two {@link Hint Hints}. + * + * @author Franz-Josef Elmer + */ +public class Symbol { + private final GraphicalElement _symbol; + private final Hint _hintForNextPoint; + private final Hint _hintForNextCurve; + + /** Creates an instance for the specified symbol and hints. */ + public Symbol(GraphicalElement symbol, Hint hintForNextPoint, + Hint hintForNextCurve) { + _symbol = symbol; + _hintForNextPoint = hintForNextPoint; + _hintForNextCurve = hintForNextCurve; + } + + /** Returns the graphical symbol. */ + public GraphicalElement getSymbol() { + return _symbol; + } + + /** Returns the hint for the next point. */ + public Hint getHintForNextPoint() { + return _hintForNextPoint; + } + + /** Returns the hint for the next curve. */ + public Hint getHintForNextCurve() { + return _hintForNextCurve; + } +} diff --git a/src/jcckit/plot/SymbolFactory.java b/src/jcckit/plot/SymbolFactory.java new file mode 100644 index 000000000..605275e13 --- /dev/null +++ b/src/jcckit/plot/SymbolFactory.java @@ -0,0 +1,65 @@ +/* + * 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; + +/** + * Interface of a symbol factory. A symbol is a {@link GraphicalElement} + * or {@link jcckit.graphic.GraphicalComposite}. A symbol factory creates + * the same type of symbols. In general, they have all the same size. + * But they are distinguished from each other by their positions. + * In addition they may also differ in other properties which will + * be determined by {@link Hint Hints}. + * + * @author Franz-Josef Elmer + */ +public interface SymbolFactory { + /** Common configuration parameter key need by implementing classes. */ + public static final String SIZE_KEY = "size", + ATTRIBUTES_KEY = "attributes"; + + /** Default size of a symbol = 0.01. */ + public static final double DEFAULT_SIZE = 0.01; + + /** + * Creates a symbol for the specified point taking into account + * the specified hints. + * @param point The position of the symbol. In general it is a transformation + * of a corresponding {@link jcckit.data.DataPoint} into a + * {@link GraphPoint}. + * @param hintFromPreviousPoint Hint from the previous point of the same + * {@link Curve} or null. + * @param hintFromPreviousCurve Hint from the previous + * {@link Curve} or null. + */ + public Symbol createSymbol(GraphPoint point, Hint hintFromPreviousPoint, + Hint hintFromPreviousCurve); + + /** + * Creates a symbol for the legend at the specified position. + * @param centerPosition Center position of the symbol. + * @param size The size of the symbol. Will not be used if the symbol + * of the curve points have all the same size. In this case + * the symbol for the legend has the size of the curve symbols. + */ + public GraphicalElement createLegendSymbol(GraphPoint centerPosition, + double size); +} diff --git a/src/jcckit/plot/TicLabelMap.java b/src/jcckit/plot/TicLabelMap.java new file mode 100644 index 000000000..d2989e481 --- /dev/null +++ b/src/jcckit/plot/TicLabelMap.java @@ -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 java.util.StringTokenizer; + +import jcckit.util.ConfigParameters; +import jcckit.util.TicLabelFormat; + +/** + * Map of number intervals onto a text label. The map is defined by a + * map description string provided by configuration data. + *

+ * The map description is a list + * of conditions separated by ';'. The conditions are tested from left to + * right until a condition is fulfilled for the tic value. If no condition + * is fullfilled a '?' will be returned. + *

+ * A condition description has one of the following forms: + *

<label>
+ *
<number>=<label>
+ *
<number1>:<number2>=<label>
+ *

+ * The first type of condition is always fulfilled. It will return + * <label>. This is a kind of else condtion + * which is put at the end of the condition list. + *

+ * The second form maps a particular number onto a label. In order to be + * equal with the sepcified number the tic value should not deviate more + * than 1 ppm (part per millions) from <number>. + *

+ * The third form maps an interval onto a label. The condition reads + *

+ * <number1> <= tic label < <number2> + *

+ * Examples: + *


+ * 1=monday;2=tuesday;3=wednesday;4=thursday;5=friday;6=saturday;7=sunday 
+ * 0.5:1.5=I; 1.5:2.5 = II; 2.5:3.5 = III; the rest 
+ * 
+ * + * @author Franz-Josef Elmer + */ +public class TicLabelMap implements TicLabelFormat { + public static final String MAP_KEY = "map"; + + private static class MapItem { + private double _min = Double.MIN_VALUE; + private double _max = Double.MAX_VALUE; + private final String label; + public MapItem(String item) { + int index = item.indexOf('='); + if (index < 0) { + label = item; + } else { + label = item.substring(index + 1).trim(); + item = item.substring(0, index).trim(); + index = item.indexOf(':'); + if (index < 0) { + _min = new Double(item).doubleValue(); + _max = _min == 0 ? Double.MIN_VALUE : _min * 1.000001d; + _min = _min * 0.999999d; + if (_min > _max) { + double z = _min; + _min = _max; + _max = z; + } + } else { + _min = new Double(item.substring(0, index)).doubleValue(); + _max = new Double(item.substring(index + 1)).doubleValue(); + } + } + } + public boolean isInside(double value) { + return value >= _min && value < _max; + } + } + + private final MapItem[] _map; + + /** + * Creates an instance from the specified configuration parameters. + * + * + * + * + * + * + *
Key & Default ValueTypeMandatoryDescription
mapStringyesMap description as explained above.
+ */ + public TicLabelMap(ConfigParameters config) { + StringTokenizer tokenizer = new StringTokenizer(config.get(MAP_KEY), ";"); + _map = new MapItem[tokenizer.countTokens()]; + for (int i = 0; i < _map.length; i++) + { + String item = tokenizer.nextToken(); + try { + _map[i] = new MapItem(item.trim()); + } catch (NumberFormatException e) { + throw new NumberFormatException("Item '" + item + "' of " + + config.getFullKey(MAP_KEY) + " has an invalid number."); + } + } + } + + /** + * Maps the specified tic value onto a text label in accordance + * with the map description. + */ + public String form(double ticValue) { + String result = "?"; + for (int i = 0; i < _map.length; i++) { + if (_map[i].isInside(ticValue)) { + result = _map[i].label; + break; + } + } + return result; + } +} diff --git a/src/jcckit/renderer/Graphics2DRenderer.java b/src/jcckit/renderer/Graphics2DRenderer.java new file mode 100644 index 000000000..9b229ebf9 --- /dev/null +++ b/src/jcckit/renderer/Graphics2DRenderer.java @@ -0,0 +1,313 @@ +/* + * 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.renderer; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import jcckit.graphic.BasicGraphicalElement; +import jcckit.graphic.ClippingRectangle; +import jcckit.graphic.ClippingShape; +import jcckit.graphic.FillAttributes; +import jcckit.graphic.FontStyle; +import jcckit.graphic.GraphPoint; +import jcckit.graphic.GraphicAttributes; +import jcckit.graphic.GraphicalComposite; +import jcckit.graphic.GraphicalCompositeRenderer; +import jcckit.graphic.LineAttributes; +import jcckit.graphic.Oval; +import jcckit.graphic.OvalRenderer; +import jcckit.graphic.Polygon; +import jcckit.graphic.PolygonRenderer; +import jcckit.graphic.Rectangle; +import jcckit.graphic.RectangleRenderer; +import jcckit.graphic.Text; +import jcckit.graphic.TextAttributes; +import jcckit.graphic.TextRenderer; + +/** + * Renderer who draws the {@link jcckit.graphic.GraphicalElement + * GraphicalElements} into a java.awt.Graphics2D context. + *

+ * The default color for lines and texts is determined by the current color of + * the Graphics2D context when a new instance of + * Graphics2DRenderer is created. + *

+ * The default font is SansSerif-12. + * + * @author Franz-Josef Elmer + */ +public class Graphics2DRenderer implements GraphicalCompositeRenderer, PolygonRenderer, OvalRenderer, TextRenderer, + RectangleRenderer { + private static final int FS = 1; + private static final String DEFAULT_FONT_NAME = "SansSerif"; + private static final FontStyle DEFAULT_FONT_STYLE = FontStyle.NORMAL; + private static final int DEFAULT_FONT_SIZE = 12; + + private Color _defaultColor; + private Graphics2D _graphics; + + /** + * Initializes this instance. During renderering the current transformation + * will be leaved unchanged. But the current Clip may be cleared. + * + * @param graphics + * Graphics2D context into which the + * {@link BasicGraphicalElement BaiscGraphicalElements} are + * painted. + * @return this instance. + */ + public Graphics2DRenderer init(Graphics2D graphics) { + _graphics = graphics; + _defaultColor = graphics.getColor(); // the foreground color + return this; + } + + /** + * Starts rendering of the specified composite. Does nothing except if + * composite has a {@link ClippingShape}. In this case the Clip + * of the Graphics2D context becomes the clipping rectangle + * determined by the bounding box of the ClippingShape. + */ + public void startRendering(GraphicalComposite composite) { + ClippingShape shape = composite.getClippingShape(); + if (shape != null) { + ClippingRectangle rect = shape.getBoundingBox(); + _graphics.clip(new Rectangle2D.Double(rect.getMinX(), rect.getMinY(), rect.getMaxX() - rect.getMinX(), rect + .getMaxY() + - rect.getMinY())); + } + } + + /** + * Finishes rendering of the specified composite. Does nothing except if + * composite has a {@link ClippingShape}. In this case the Clip + * of the Graphics2D context will be cleared. + */ + public void finishRendering(GraphicalComposite composite) { + _graphics.setClip(null); + } + + /** Paints the specified polygon into the Graphics2D context. */ + public void render(Polygon polygon) { + int numberOfPoints = polygon.getNumberOfPoints(); + if (numberOfPoints > 0) { + Color currentColor = _graphics.getColor(); + GeneralPath p = new GeneralPath(GeneralPath.WIND_EVEN_ODD, numberOfPoints); + p.moveTo((float) polygon.getPoint(0).getX(), (float) polygon.getPoint(0).getY()); + for (int i = 1; i < numberOfPoints; i++) { + p.lineTo((float) polygon.getPoint(i).getX(), (float) polygon.getPoint(i).getY()); + } + if (polygon.isClosed()) { + p.closePath(); + } + drawShape(p, polygon, currentColor); + } + } + + /** + * Paints the specified rectangle into the current Graphics + * context. + */ + public void render(Rectangle rectangle) { + Color currentColor = _graphics.getColor(); + GraphPoint center = rectangle.getCenter(); + double width = rectangle.getWidth(); + double height = rectangle.getHeight(); + Rectangle2D rect = new Rectangle2D.Double(center.getX() - 0.5 * width, center.getY() - 0.5 * height, width, + height); + drawShape(rect, rectangle, currentColor); + } + + /** + * Paints the specified oval into the current Graphics context. + */ + public void render(Oval oval) { + Color currentColor = _graphics.getColor(); + GraphPoint center = oval.getCenter(); + double width = oval.getWidth(); + double height = oval.getHeight(); + Ellipse2D ellipse = new Ellipse2D.Double(center.getX() - 0.5 * width, center.getY() - 0.5 * height, width, + height); + drawShape(ellipse, oval, currentColor); + } + + private void drawShape(Shape shape, BasicGraphicalElement element, Color backupColor) { + GraphicAttributes attributes = element.getGraphicAttributes(); + Color fillColor = null; + if (element.isClosed() && attributes instanceof FillAttributes) { + fillColor = ((FillAttributes) attributes).getFillColor(); + } + if (fillColor != null) { + _graphics.setColor(fillColor); + _graphics.fill(shape); + } + Color lineColor = _defaultColor; + if (attributes instanceof LineAttributes) { + LineAttributes la = (LineAttributes) attributes; + BasicStroke stroke = new BasicStroke((float) la.getLineThickness()); + double[] linePattern = la.getLinePattern(); + if (linePattern != null) { + float[] dash = new float[linePattern.length]; + for (int i = 0; i < dash.length; i++) { + dash[i] = (float) la.getLinePattern()[i]; + } + stroke = new BasicStroke(stroke.getLineWidth(), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, + dash, 0f); + } + _graphics.setStroke(stroke); + if (la.getLineColor() != null || fillColor != null) { + lineColor = la.getLineColor(); + } + } + if (lineColor != null) { + _graphics.setColor(lineColor); + _graphics.draw(shape); + } + _graphics.setColor(backupColor); + } + + /** + * Paints the specified text into the current Graphics context. + *

+ * If the font size is zero the default font size will be used. + *

+ * If the orientation angle is unequal zero the text will first be painted + * into an off-screen image and rotated. Finally, it will be drawn into the + * current Graphics context. Note, that only integer multiples of + * 90 degree rotation are performed. Other orientation angles will be + * adjusted to the nearest integer multiple of 90 degree. + */ + public void render(Text text) { + final GraphicAttributes ga = text.getGraphicAttributes(); + if (ga instanceof TextAttributes) { + final TextAttributes ta = (TextAttributes) ga; + final Color currentColor = _graphics.getColor(); + Color fontColor = ta.getTextColor(); + if (fontColor == null) { + fontColor = _defaultColor; + } + _graphics.setColor(fontColor); + + final double scale = _graphics.getTransform().getScaleX(); + final String str = text.getText(); + + AffineTransform before = _graphics.getTransform(); + _graphics.setTransform(new AffineTransform()); + + double fs = ta.getFontSize(); + fs = fs == 0 ? 1 : fs * scale / DEFAULT_FONT_SIZE; + + Font font = createFont(ta, 0); + + AffineTransform fontTransform = new AffineTransform(); + fontTransform.scale(fs, fs); + fontTransform.rotate(-ta.getOrientationAngle() * Math.PI / 180); + font = font.deriveFont(fontTransform); + _graphics.setFont(font); + Rectangle2D bounds = _graphics.getFontMetrics().getStringBounds(str, _graphics); + + fontTransform.rotate(-ta.getOrientationAngle() * Math.PI / 180); + + final double yy = bounds.getHeight() + bounds.getY(); + + Point2D.Double pos = new Point2D.Double(text.getPosition().getX(), text.getPosition().getY()); + before.transform(pos, pos); + + double x = 0; + double y = 0; + if (ta.getOrientationAngle() == 0) { + x = -0.5 * ta.getHorizontalAnchor().getFactor() * bounds.getWidth(); + y = 0.5 * ta.getVerticalAnchor().getFactor() * bounds.getHeight() - yy; + x = pos.x + x; + y = pos.y + y; + } else { + x = 0.5 * ta.getVerticalAnchor().getFactor() * bounds.getHeight(); + y = 0.5 * ta.getHorizontalAnchor().getFactor() * bounds.getWidth(); + // System.err.println("yy="+y+" dx="+x+" dy="+y); + // x = 0; + // y = 0; + x = pos.x + x; + y = pos.y + y; + } + +// if (ta.getOrientationAngle() == 0) { +//// System.err.println("x0=" + x); +//// System.err.println("y0=" + y); +// } else { +// System.err.println("bounds=" + bounds + " y=" + bounds.getY() + " h=" + bounds.getHeight() + " vert=" +// + ta.getVerticalAnchor().getFactor()+" horz="+ta.getHorizontalAnchor().getFactor()); +// System.err.println("x1=" + x); +// System.err.println("y1=" + y); +// } + + + _graphics.drawString(str, (float) x, (float) y); + // _graphics.fillRect((int)x, (int)y, 5, 5); + _graphics.setTransform(before); + _graphics.setColor(currentColor); + } + } + + /** + * Creates a font instance based on the specified text attributes and font + * size. + * + * @param attributes + * Text attributes (font name and style). + * @param size + * Font size in pixel. If 0 {@link #DEFAULT_FONT_SIZE} will be + * used. + * @return new font instance. + */ + static Font createFont(TextAttributes attributes, int size) { + String fontName = attributes.getFontName(); + if (fontName == null) { + fontName = DEFAULT_FONT_NAME; + } + + FontStyle fontStyle = attributes.getFontStyle(); + if (fontStyle == null) { + fontStyle = DEFAULT_FONT_STYLE; + } + int style = Font.PLAIN; + if (fontStyle == FontStyle.BOLD) { + style = Font.BOLD; + } else if (fontStyle == FontStyle.ITALIC) { + style = Font.ITALIC; + } else if (fontStyle == FontStyle.BOLD_ITALIC) { + style = Font.BOLD + Font.ITALIC; + } + + if (size == 0) { + size = DEFAULT_FONT_SIZE; + } + + return new Font(fontName, style, size); + } + +} diff --git a/src/jcckit/renderer/Transformation.java b/src/jcckit/renderer/Transformation.java new file mode 100644 index 000000000..beea06ad2 --- /dev/null +++ b/src/jcckit/renderer/Transformation.java @@ -0,0 +1,107 @@ +/* + * 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.renderer; + +import java.awt.Graphics2D; + +import jcckit.graphic.Anchor; +import jcckit.graphic.GraphPoint; +import jcckit.graphic.ClippingRectangle; + +/** + * Transformation between device-independent coordinates + * and standard Java coordinates. The aspect-ratio will + * be the same. The position in the canvas is determined by a + * {@link jcckit.graphic.Rectangle Rectangle} defining a (virtual) + * paper which is placed in the canvas according to an anchor point. + * Depending on the aspect ratio of the canvas the paper width or + * height occupies the canvas width or height. + * + * @author Franz-Josef Elmer + */ +public class Transformation { + private final double _scale, _x0, _y0; + + public String toString() { + return "_scale=" + _scale + " _x0=" + _x0 + " _y0=" + _y0; + } + + /** + * Creates an instance for the specified canvas size, paper size, + * and anchor points of the paper. + * @param width Width of the canvas. + * @param height Height of the canvas. + * @param paper Rectangle defining the paper in device-independent + * coordinates. + * @param horizontalAnchor Horizontal anchor of the paper in the canvas. + * @param verticalAnchor Vertical anchor of the paper in the canvas. + */ + public Transformation(int width, int height, ClippingRectangle paper, + Anchor horizontalAnchor, Anchor verticalAnchor) { + double pWidth = paper.getMaxX() - paper.getMinX(); + double pHeight = paper.getMaxY() - paper.getMinY(); + _scale = Math.min(width / pWidth, height / pHeight); + _x0 = 0.5 * horizontalAnchor.getFactor() * (width - _scale * pWidth) + - _scale * paper.getMinX(); + _y0 = 0.5 * verticalAnchor.getFactor() * (_scale * pHeight - height) + + height + _scale * + paper.getMinY(); + } + + /** Transforms the device-independent x coordinate into Java coordinates. */ + public int transformX(double x) { + return trim(_scale * x + _x0); + } + + /** Transforms the device-independent y coordinate into Java coordinates. */ + public int transformY(double y) { + return trim(_y0 - _scale * y); + } + + /** Transforms the device-independent width into Java width. */ + public int transformWidth(double width) { + return trim(_scale * width + 0.5); + } + + /** Transforms the device-independent height into Java height. */ + public int transformHeight(double height) { + return trim(_scale * height + 0.5); + } + + private static int trim(double number) + { + return number > Short.MAX_VALUE + ? Short.MAX_VALUE + : (number < Short.MIN_VALUE ? Short.MIN_VALUE : (int) number); + } + + /** + * Transforms a point in Java coordinates back into device-independent + * coordinates. + */ + public GraphPoint transformBack(int x, int y) { + return new GraphPoint((x - _x0) / _scale, (_y0 - y) / _scale); + } + +public void apply(Graphics2D g) { + g.translate(_x0, _y0); + g.scale(_scale, -_scale); + +} +} + diff --git a/src/jcckit/transformation/CartesianTransformation.java b/src/jcckit/transformation/CartesianTransformation.java new file mode 100644 index 000000000..d2c30da49 --- /dev/null +++ b/src/jcckit/transformation/CartesianTransformation.java @@ -0,0 +1,96 @@ +/* + * 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.transformation; + +import jcckit.data.DataPoint; +import jcckit.graphic.GraphPoint; +import jcckit.util.Util; + +/** + * Two-dimensional Cartesian transformation. The two independent + * transformations for the x-axis and the y-axis can be logarithmic + * from data coordinates to device-independent coordinates in order to + * realize diagrams with logarithmic scales. + * + * @author Franz-Josef Elmer + */ +public class CartesianTransformation implements Transformation { + private final boolean _xLogScale; + private final double _xOffset; + private final double _xScale; + private final boolean _yLogScale; + private final double _yOffset; + private final double _yScale; + + /** + * Creates an instance from the specified reference points. + * Note, that the reference points must differ in x and y coordinates + * otherwise a transformation would not be possible. + * @param xLogScale true if logarithmic x axis. + * @param yLogScale true if logarithmic y axis. + * @param dataPoint1 First reference point in data coordinates. + * @param graphPoint1 First reference point in device-independent + * coordinates. + * @param dataPoint2 Second reference point in data coordinates. + * @param graphPoint2 Second reference point in device-independent + * coordinates. + * @throws IllegalArgumentException if transformation in at least + * one of both directions is not possible. + */ + public CartesianTransformation(boolean xLogScale, boolean yLogScale, + DataPoint dataPoint1, GraphPoint graphPoint1, + DataPoint dataPoint2, GraphPoint graphPoint2) { + _xLogScale = xLogScale; + double d1 = Util.log(dataPoint1.getX(), xLogScale); + double dd = Util.log(dataPoint2.getX(), xLogScale) - d1; + check(dd, "data", "x", d1); + _xScale = (graphPoint2.getX() - graphPoint1.getX()) / dd; + check(_xScale, "graphical", "x", graphPoint1.getX()); + _xOffset = graphPoint1.getX() - d1 * _xScale; + + _yLogScale = yLogScale; + d1 = Util.log(dataPoint1.getY(), yLogScale); + dd = Util.log(dataPoint2.getY(), yLogScale) - d1; + check(dd, "data", "y", d1); + _yScale = (graphPoint2.getY() - graphPoint1.getY()) / dd; + check(_yScale, "graphical", "y", graphPoint1.getY()); + _yOffset = graphPoint1.getY() - d1 * _yScale; + } + + private void check(double valueToCheck, String type, String axis, + double value) { + if (valueToCheck == 0) { + throw new IllegalArgumentException("The " + type + + " reference points in " + axis + " must be different; both are " + + value); + } + } + + public GraphPoint transformToGraph(DataPoint point) { + return new GraphPoint( + _xOffset + Util.log(point.getX(), _xLogScale) * _xScale, + _yOffset + Util.log(point.getY(), _yLogScale) * _yScale); + } + + public DataPoint transformToData(GraphPoint point) { + return new DataPoint( + Util.exp((point.getX() - _xOffset) / _xScale, _xLogScale), + Util.exp((point.getY() - _yOffset) / _yScale, _yLogScale)); + } +} diff --git a/src/jcckit/transformation/Transformation.java b/src/jcckit/transformation/Transformation.java new file mode 100644 index 000000000..46b3d16a9 --- /dev/null +++ b/src/jcckit/transformation/Transformation.java @@ -0,0 +1,44 @@ +/* + * 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.transformation; + +import jcckit.data.DataPoint; +import jcckit.graphic.GraphPoint; + +/** + * Interface for transformations between data coordinates + * and device-independent coordinates. + * + * @author Franz-Josef Elmer + */ +public interface Transformation { + /** + * Transforms a {@link DataPoint} into a {@link GraphPoint}. + * @param point A point in data coordinates. + * @return point tranformed into device-independent coordinates.. + */ + public GraphPoint transformToGraph(DataPoint point); + + /** + * Transforms a {@link GraphPoint} into a {@link DataPoint}. + * @param point A point in device-independent coordinates.. + * @return point tranformed into data coordinates. + */ + public DataPoint transformToData(GraphPoint point); +} diff --git a/src/jcckit/util/AppletBasedConfigData.java b/src/jcckit/util/AppletBasedConfigData.java new file mode 100644 index 000000000..e46b7208d --- /dev/null +++ b/src/jcckit/util/AppletBasedConfigData.java @@ -0,0 +1,53 @@ +/* + * 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.util; + +import java.applet.Applet; + +/** + * Implementation of {@link FlatConfigData} based on + * java.applet.Applet. + * + * @author Franz-Josef Elmer + */ +public class AppletBasedConfigData extends FlatConfigData { + private final Applet _applet; + + /** + * Creates an instance based on the specified applet. + * The path is undefined. + */ + public AppletBasedConfigData(Applet applet) { + this(applet, null); + } + + /** Creates an instance based on the specified properties and path. */ + private AppletBasedConfigData(Applet applet, String path) { + super(path); + _applet = applet; + } + + protected String getValue(String fullKey) { + return _applet.getParameter(fullKey); + } + + protected ConfigData createConfigData(String path) { + return new AppletBasedConfigData(_applet, path); + } +} diff --git a/src/jcckit/util/ConfigData.java b/src/jcckit/util/ConfigData.java new file mode 100644 index 000000000..7a48bb395 --- /dev/null +++ b/src/jcckit/util/ConfigData.java @@ -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.util; + +/** + * Interface for hierarchically managed key-value pairs. The key is + * always a string which contains any kind of printable character except + * '/', '=', ':', and whitespace characters like ' ' and '\t'. + * The value is either a string or a ConfigData object. + *

+ * This interface will be used by {@link ConfigParameters} in accordance + * with the Strategy design pattern. + * + * @author Franz-Josef Elmer + */ +public interface ConfigData { + /** + * Returns the full key. + * @param key A (relative) key. null is not allowed. + * @return the full key including path. + */ + public String getFullKey(String key); + + /** + * Returns the value associated with this key. + * @param key The relative key. null is not allowed. + * @return the associated value. Will be null if no value exists + * for key. + */ + public String get(String key); + + /** + * Returns the ConfigData object associated with this key. + * @param key The relative key. null is not allowed. + * @return the associated value. Will never return null. + * Instead an empty ConfigData is returned. + */ + public ConfigData getNode(String key); +} diff --git a/src/jcckit/util/ConfigParameters.java b/src/jcckit/util/ConfigParameters.java new file mode 100644 index 000000000..6936be490 --- /dev/null +++ b/src/jcckit/util/ConfigParameters.java @@ -0,0 +1,318 @@ +/* + * 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.util; + +import java.awt.Color; +import java.util.StringTokenizer; + +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; + +/** + * Read-only class for hierarchically organized key-value pairs. + * The key is always a string. The following value types are + * supported: + *

+ *

+ * In accordance with the Strategy design pattern the retrieval of + * a key-value pair is delegated to an instance of + * {@link ConfigData}. + * + * @author Franz-Josef Elmer + */ +public class ConfigParameters { + private final ConfigData _configData; + + /** Creates an instance from the specified ConfigData object. */ + public ConfigParameters(ConfigData configData) { + _configData = configData; + } + + /** + * Returns the full key. + * @return the path concatenated with key. + * @see ConfigData#getFullKey + */ + public String getFullKey(String key) { + return _configData.getFullKey(key); + } + + /** + * Returns the string value associated with the specified key. + * @param key The (relative) key. null is not allowed. + * @return the corresponding value. Will always be not null. + * @throws IllegalArgumentException if no value exists for key. + * The exception message is the full key. + */ + public String get(String key) { + String result = _configData.get(key); + if (result == null) { + throw new IllegalArgumentException(getFullKey(key)); + } + return result; + } + + /** + * Returns the string value associated with the specified key or + * defaultValue if undefined. + * @param key The (relative) key. null is not allowed. + * @param defaultValue The default value. Can be null. + * @return the corresponding value or defaultValue. + */ + public String get(String key, String defaultValue) { + String result = _configData.get(key); + if (result == null) { + result = defaultValue; + } + return result; + } + + /** + * Returns the boolean associated with the specified key. + * @param key The (relative) key. null is not allowed. + * @return true if the value is "true" otherwise false. + * @throws IllegalArgumentException if no value exists for key. + * The exception message is the full key. + * @throws NumberFormatException if the value is neither "true" nor "false". + */ + public boolean getBoolean(String key) { + return parseBoolean(get(key), key); + } + + /** + * Returns the boolean associated with the specified key. + * @param key The (relative) key. null is not allowed. + * @param defaultValue The default value. Can be null. + * @return true if the value is "true" otherwise false. + * @throws NumberFormatException if the value is neither "true" nor "false". + */ + public boolean getBoolean(String key, boolean defaultValue) { + String value = _configData.get(key); + return value == null ? defaultValue : parseBoolean(value, key); + } + + private boolean parseBoolean(String value, String key) { + if (value.equals("true")) { + return true; + } else if (value.equals("false")) { + return false; + } else { + throw createNumberFormatException("boolean", value, key); + } + } + + private NumberFormatException createNumberFormatException(String text, + String value, + String key) { + return new NumberFormatException("Not a " + text + ": " + getFullKey(key) + + " = " + value); + } + + /** + * Returns the integer associated with the specified key. + * The value can be either + *

+ * @param key The (relative) key. null is not allowed. + * @return the integer value. + * @throws IllegalArgumentException if no value exists for key. + * The exception message is the full key. + * @throws NumberFormatException if the value is not a number. + * The exception message contains the full key and the invalid value. + */ + public int getInt(String key) { + return parseInt(get(key), key); + } + + /** + * Returns the integer associated with the specified key or + * defaultValue if no key-value pair exists for the specified key. + * The value can be either + * + * @param key The (relative) key. null is not allowed. + * @param defaultValue The default value. Can be null. + * @return the integer value. + * @throws NumberFormatException if the value exists but is not a number. + * The exception message contains the full key and the invalid value. + */ + public int getInt(String key, int defaultValue) { + String value = _configData.get(key); + return value == null ? defaultValue : parseInt(value, key); + } + + private int parseInt(String value, String key) { + try { + return Integer.decode(value).intValue(); + } catch (NumberFormatException e) { + throw createNumberFormatException("number", value, key); + } + } + + /** + * Returns the double associated with the specified key. + * @param key The (relative) key. null is not allowed. + * @return the double value. + * @throws IllegalArgumentException if no value exists for key. + * The exception message is the full key. + * @throws NumberFormatException if the value is not a valid number. + * The exception message contains the full key and the invalid value. + */ + public double getDouble(String key) { + return parseDouble(get(key), key); + } + + /** + * Returns the double associated with the specified key or + * defaultValue if no key-value pair exists for the specified key. + * @param key The (relative) key. null is not allowed. + * @param defaultValue The default value. Can be null. + * @return the double value. + * @throws NumberFormatException if the value exists but is not a valid + * number. + * The exception message contains the full key and the invalid value. + */ + public double getDouble(String key, double defaultValue) { + String value = _configData.get(key); + return value == null ? defaultValue : parseDouble(value, key); + } + + private double parseDouble(String value, String key) { + try { + return new Double(value).doubleValue(); + } catch (NumberFormatException e) { + throw createNumberFormatException("number", value, key); + } + } + + /** + * Returns the array of doubles associated with the specified key. + * The numbers are separated by whitespaces. + * @param key The (relative) key. null is not allowed. + * @return the array of double values. + * @throws IllegalArgumentException if no value exists for key. + * The exception message is the full key. + * @throws NumberFormatException if the value exists but is not a + * sequence of number. The exception message contains + * the full key and the invalid value. + */ + public double[] getDoubleArray(String key) { + return parseDoubleArray(get(key), key); + } + + /** + * Returns the array of doubles associated with the specified key + * or defaultValue if no key-value pair exists for + * the specified key. The numbers are separated by whitespaces. + * @param key The (relative) key. null is not allowed. + * @param defaultValue The default value. Can be null. + * @return the array of double values. + * @throws NumberFormatException if the value exists but is not a + * sequence of number. The exception message contains + * the full key and the invalid value. + */ + public double[] getDoubleArray(String key, double[] defaultValue) { + String value = _configData.get(key); + return value == null ? defaultValue : parseDoubleArray(value, key); + } + + private double[] parseDoubleArray(String value, String key) { + try { + StringTokenizer tokenizer = new StringTokenizer(value); + double[] result = new double[tokenizer.countTokens()]; + for (int i = 0; i < result.length; i++) { + result[i] = new Double(tokenizer.nextToken()).doubleValue(); + } + return result; + } catch (NumberFormatException e) { + throw createNumberFormatException("sequence of numbers", value, key); + } + } + + /** + * Returns the color associated with the specified key. + * The color is coded as + * + * @param key The (relative) key. null is not allowed. + * @return the color. + * @throws NumberFormatException if the value exists but is not a number. + * The exception message contains the full key and the invalid value. + */ + public Color getColor(String key) { + return parseColor(get(key), key); + } + + /** + * Returns the color associated with the specified key or the specified + * default value if no key-value pair exists for the specified key. + * The color is coded as + * + * @param key The (relative) key. null is not allowed. + * @param defaultValue The default value. Can be null. + * @return the color or null if the value is an empty string. + * @throws NumberFormatException if the value exists but is not a number. + * The exception message contains the full key and the invalid value. + */ + public Color getColor(String key, Color defaultValue) { + String value = _configData.get(key); + return value == null ? defaultValue : parseColor(value, key); + } + + private Color parseColor(String value, String key) { + try { + return value.length() == 0 ? null : decodeInternal(value); + } catch (NumberFormatException e) { + throw createNumberFormatException("number", value, key); + } + } + +private Color decodeInternal(String value) { + if (HtmlColor.isValid(value)) { + return new ColorMapperIdentity().getMappedColor(HtmlColor.getColorIfValid(value)); + } + return Color.decode(value); +} + + /** + * Returns the child node associated with the specified key. + * This method returns in any case a non-null result. + * @param key The (relative) key. null is not allowed. + * @return the corresponding child node which may be empty. + */ + public ConfigParameters getNode(String key) { + return new ConfigParameters(_configData.getNode(key)); + } +} diff --git a/src/jcckit/util/ConfigParametersBasedConfigData.java b/src/jcckit/util/ConfigParametersBasedConfigData.java new file mode 100644 index 000000000..77138a7ea --- /dev/null +++ b/src/jcckit/util/ConfigParametersBasedConfigData.java @@ -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.util; + +/** + * An implementation of {@link ConfigData} based on two instances of + * {@link ConfigParameters}. The second one serves as a set of + * default parameters. It will be used if the first one has not the requested + * key-value pair. + * + * @author Franz-Josef Elmer + */ +public class ConfigParametersBasedConfigData implements ConfigData { + private ConfigParameters _config; + private ConfigParameters _defaultConfig; + + /** + * Creates an instance. + * @param config A set of key-value pairs. + * @param defaultConfig The default set of key-value pairs. + */ + public ConfigParametersBasedConfigData(ConfigParameters config, + ConfigParameters defaultConfig) { + _config = config; + _defaultConfig = defaultConfig; + } + + /** + * Returns the full key. + * @param key A (relative) key. null is not allowed. + * @return the full key including path. + */ + public String getFullKey(String key) { + return _config.getFullKey(key); + } + + /** + * Returns the value associated with this key. + * @param key The relative key. null is not allowed. + * @return the associated value. Will be null if no value exists + * for key. + */ + public String get(String key) { + String value = _config.get(key, null); + return value == null ? _defaultConfig.get(key, null) : value; + } + + /** + * Returns the ConfigData object associated with this key. + * @param key The relative key. null is not allowed. + * @return the associated value. Will never return null. + * Instead an empty ConfigData is returned. + */ + public ConfigData getNode(String key) { + return new ConfigParametersBasedConfigData(_config.getNode(key), + _defaultConfig.getNode(key)); + } +} diff --git a/src/jcckit/util/Factory.java b/src/jcckit/util/Factory.java new file mode 100644 index 000000000..d3b82562d --- /dev/null +++ b/src/jcckit/util/Factory.java @@ -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.util; + +import java.lang.reflect.*; + +/** + * General purpose factory method based on {@link ConfigParameters} + * and Java's Reflection API. + * + * @author Franz-Josef Elmer + */ +public class Factory { + /** The constant defining the key className. */ + public static final String CLASS_NAME_KEY = "className"; + + /** No public constructor necessary. */ + private Factory() {} + + /** + * Creates an instance of the specified class. + * @param className Fully-qualified name of a class with a default + * constructor. + * @return a new instance. + * @throws IllegalArgumentException if the instance could be created. + */ + public static Object create(String className) { + try { + return Class.forName(className).newInstance(); + } catch (Throwable t) { + throw new IllegalArgumentException("Could not create an instance of " + + className + " because of " + t); + } + } + + /** + * Creates an object based on the specified configuration + * parameters. The class of the object is determined by the + * parameter with the key {@link #CLASS_NAME_KEY}. + * The constructor with a single argument of the type + * ConfigParameter is invoked with the argument + * configParameters. If such a constructor + * does not exists the default constructor is invoked. If + * neither of these constructors exist a {@link FactoryException} + * is thrown. + * @param configParameters Configuration parameters. + * @return the newly created object. + * @throws IllegalArgumentException if key className is missing. + * @throws FactoryException wrapping any kind of exception or error occured. + */ + public static Object create(ConfigParameters configParameters) { + String className = configParameters.get(CLASS_NAME_KEY); + return createObject(configParameters, className); + } + + /** + * Creates an object based on the specified configuration + * parameters and default class name. If the + * parameter with the key {@link #CLASS_NAME_KEY} is missed in + * configParameters defaultClassName is used. + * Otherwise it works as {@link #create(jcckit.util.ConfigParameters)}. + * @param configParameters Configuration parameters. + * @param defaultClassName Default class name. + * @return the newly created object. + * @throws FactoryException wrapping any kind of exception or error occured. + */ + public static Object create(ConfigParameters configParameters, + String defaultClassName) { + String className = configParameters.get(CLASS_NAME_KEY, defaultClassName); + return createObject(configParameters, className); + } + + /** + * Creates an object based on the specified configuration + * parameters or returns the default object. This method behaves + * as {@link #create(jcckit.util.ConfigParameters)}, except that is does + * not throw an IllegalArgumentException if key className + * is missing. Instead defaultObject is returned. + */ + public static Object createOrGet(ConfigParameters configParameters, + Object defaultObject) { + String className = configParameters.get(CLASS_NAME_KEY, null); + return className == null ? defaultObject + : createObject(configParameters, className); + } + + private static Object createObject(ConfigParameters configParameters, + String className) { + try { + Class c = Class.forName(className); + Object result = null; + Constructor constructor = null; + try { + constructor = c.getConstructor(new Class[] {ConfigParameters.class}); + result = constructor.newInstance(new Object[] {configParameters}); + } catch (NoSuchMethodException e) { + result = c.newInstance(); + } + return result; + } catch (Throwable t) { + throw new FactoryException(configParameters, CLASS_NAME_KEY, t); + } + } +} diff --git a/src/jcckit/util/FactoryException.java b/src/jcckit/util/FactoryException.java new file mode 100644 index 000000000..e33f325b9 --- /dev/null +++ b/src/jcckit/util/FactoryException.java @@ -0,0 +1,79 @@ +/* + * 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.util; + +import java.lang.reflect.*; + +/** + * Exception thrown in the case of an error during creation of a new + * object by {@link Factory#create}. + * + * @author Franz-Josef Elmer + */ +public class FactoryException extends RuntimeException { + private final String _fullKey; + private final String _className; + private final Object _reason; + + /** + * Creates a new instance based on the specified configuration parameters + * and reason object. + *

+ * If reason is an instance of InvocationTargetException + * it will be replaced by the wrapped Throwable. + * @param configParameters Configuration parameters from which the + * className will be extracted (if it exists, otherwise + * null will be taken). + * @param reason The reason causing this exception. Most often an + * an exception. + */ + public FactoryException(ConfigParameters configParameters, String key, + Object reason) { + _fullKey = configParameters.getFullKey(key); + _className = configParameters.get(key, null); + if (reason instanceof InvocationTargetException) { + reason = ((InvocationTargetException) reason).getTargetException(); + } + _reason = reason; + } + + /** Returns the full class name key. */ + public String getFullKey() { + return _fullKey; + } + + /** Returns the fully qualified class name. */ + public String getClassName() { + return _className; + } + + /** Returns the reason object causing this exception. */ + public Object getReason() { + return _reason; + } + + /** + * Renders this instance as follows: jcckit.util.FactoryException: + * full key = class name: reason. + */ + public String toString() { + return getClass().getName() + ": " + _fullKey + " = " + _className + + ": " + _reason; + } +} diff --git a/src/jcckit/util/FlatConfigData.java b/src/jcckit/util/FlatConfigData.java new file mode 100644 index 000000000..1384e5ca1 --- /dev/null +++ b/src/jcckit/util/FlatConfigData.java @@ -0,0 +1,187 @@ +/* + * 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.util; + +/** + * An implementation of ConfigData based on a flat + * representation of the hierachically organized key-value pairs. + * Concrete subclasses must implement the methods + * {@link #getValue} and {@link #createConfigData} in accordance + * with the Template Method pattern and Factory Method pattern, + * respectively. + *

+ * In a flat representation of hierachically organized key-value + * pairs all key-value pairs are stored in a single Hashtable. + * Its key is the full key of the configuration data (i.e. the key + * including its path). + *

+ * Example (using the notation for a .properties file): + *

+ *  title = example
+ *  symbolAttributes/className = jcckit.graphic.BasicDrawingAttributes
+ *  symbolAttributes/fillColor = 0xcaffee
+ *  symbolAttributes/lineColor = 0xff0000
+ *  
+ * The following table shows the result of some method calls at a + * FlatConfigData instance prepared with + * this example: + *

+ *

+ * + * + * + * + *
Method callResult
get("title")example
getNode("symbolAttributes").get("fillColor") + * 0xcaffee
+ *
+ *

+ * In addition FlatConfigData implements inheritance + * of key-value pairs. + * Basically a node in the tree of key-value pairs + * may extend another node in the tree. + * The extended node inherit all key-value pairs from the extending + * one including the key-value pairs of all descendants. + * The value of a inherited key-value pair may be overridden. + * Also new key-value pairs may be placed in the inherited node or + * anywhere in the subtree. + * Note, that the extending node has to be a node which is not a + * descendant of the extended node (otherwise a circulary chain + * of references occurs). As a consequence not more than 20 inheritance + * levels are allowed. + *

+ * The implementation of this kind of inheritance in a flat hashtable + * is done by an additional key-value pair of the form + *

+ *    extending-node/ = extended-node/
+ *  
+ * Example: + *
+ *  A/a/priority = high
+ *  A/a/alpha/hello = universe
+ *  A/a/alpha/answer = 42
+ *  A/b/1/ = A/a/
+ *  A/b/1/alpha/hello = world
+ *  A/b/1/alpha/question = 6 * 7
+ *  
+ * The following table shows the result of various method calls + * applied at the node A/b/1/ of a FlatConfigData + * instance prepared with this example: + *

+ *

+ * + * + * + * + * + * + *
Method callResultComment
get("priority")highinherited
getNode("alpha").get("hello") + * worldoverridden
getNode("alpha").get("question") + * 6 * 7added
getNode("alpha").get("answer") + * 42inherited
+ *
+ * + * @author Franz-Josef Elmer + */ +public abstract class FlatConfigData implements ConfigData { + private final String _path; + + /** Creates a new instance for the specified path. */ + public FlatConfigData(String path) { + _path = path; + } + + /** + * Returns the full key. + * @param key A (relative) key. null is not allowed. + * @return the path concatenated with key or key + * if the path is undefined. + */ + public String getFullKey(String key) { + return _path == null ? key : _path + key; + } + + /** + * Returns the value associated with this key. + * @param key The relative key. null is not allowed. + * @return the associated value. Will be null if no value exists + * for key. + */ + public String get(String key) { + return get(_path, key, 0); + } + + /** + * Obtains a value in accordance with hierarchy (path) and + * inheritance (recursive calls of this routine). + */ + private String get(String path, String key, int numberOfLevels) { + String result = null; + if (numberOfLevels < 20) { + String fullKey = path == null ? key : path + key; + result = getValue(fullKey); + if (result == null) { + // posAfterDelim is the index in path just after '/' + int posAfterDelim = path == null ? -1 : path.length(); + String replacement; + while (posAfterDelim > 0) { + // look for a sub-tree + replacement = getValue(path.substring(0, posAfterDelim)); + if (replacement != null) { + // sub-tree found, add last part of the original path + result = get(replacement + path.substring(posAfterDelim), key, + numberOfLevels + 1); + // break whether result is null or not. + break; + } + // remove last element from the path + posAfterDelim = path.lastIndexOf('/', posAfterDelim - 2) + 1; + } + } + } + return result; + } + + /** + * Returns the ConfigData object associated with this key. + * @param key The relative key. + * @return the associated value. Will never return null. + * Instead an empty ConfigData is returned. + */ + public ConfigData getNode(String key) { + String path = (_path == null ? key : _path + key) + '/'; + return createConfigData(path); + } + + /** + * Returns the value for the specified full key from the flat + * representation of the hierarchically organized key-value pairs. + * @param fullKey The full key including path. null is not allowed. + * @return the value or null if not found. + */ + protected abstract String getValue(String fullKey); + + /** + * Returns the FlatConfigData object for the specified full path. + * In general path will be used in the constructor with + * path argument. + * @param path The full path. + * @return a new instance in any case. + */ + protected abstract ConfigData createConfigData(String path); +} diff --git a/src/jcckit/util/Format.java b/src/jcckit/util/Format.java new file mode 100644 index 000000000..c4e04e2b4 --- /dev/null +++ b/src/jcckit/util/Format.java @@ -0,0 +1,208 @@ +/* + * 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.util; + +import java.util.Vector; + +/** + * A helper class for formatting numbers according to + * a printf-like format string. Each instance of + * this class is initialized by a format string for a + * single number. + * + * @author Franz-Josef Elmer + */ +public class Format implements TicLabelFormat { + /** + * Creates a new instance based of specified key-value pair of the + * specified configuration parameters. + * @param config Config parameters. + * @param key The key of the key-value pair in config containing + * the format string. + * @return null if undefined key-value pair or format string + * is an empty string. + * @throws FactoryException if the format string is invalid. + */ + public static Format create(ConfigParameters config, String key) { + Format result = null; + String format = config.get(key, null); + if (format != null && format.length() > 0) { + try { + result = new Format(format); + } catch (Exception e) { + throw new FactoryException(config, key, e); + } + } + return result; + } + + private final FormatElement[] _formatElements; + private final Vector _staticParts; + + /** + * Creates an instance for the specified format string. + * The format string is an alternation of some static texts and + * format elements. + * A format element has to start with '%' and it must end with + * one of the following format descriptors: + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ddecimal integer
ooctal integer
xhex integer
ffloating point number with a fixed decimal point
e, Efloating point number in logarithmic format
g, Gfloating point number rendered either in fixed-decimal + * format of logarithmic format depending on the size of + * the mantissa.
+ * The characters between '%' and the decriptor are optional. + * They can be grouped into + * + * A plain '%' is coded as '%%'. + * @param formatString The format string. + * @exception IllegalArgumentException if invalid format string. + */ + public Format(String formatString) { + _staticParts = new Vector(); + Vector formatElements = new Vector(); + StringBuffer part = new StringBuffer(); + boolean insideFormatElement = false; + boolean atPercentSymbol = false; + for (int i = 0, n = formatString.length(); i < n; i++) { + char c = formatString.charAt(i); + if (insideFormatElement) { + part.append(c); + if (FormatElement.DESCRIPTORS.indexOf(c) >= 0) { + formatElements.addElement(new String(part)); + part.setLength(0); + insideFormatElement = false; + } + } else if (atPercentSymbol) { + atPercentSymbol = false; + if (c != '%') { + _staticParts.addElement(new String(part)); + part.setLength(0); + insideFormatElement = true; + } + part.append(c); + if (FormatElement.DESCRIPTORS.indexOf(c) >= 0) { + formatElements.addElement(new String(part)); + part.setLength(0); + insideFormatElement = false; + } + } else { + if (c == '%') { + atPercentSymbol = true; + } else { + part.append(c); + } + } + } + if (insideFormatElement) { + formatElements.addElement(new String(part)); + } else { + _staticParts.addElement(new String(part)); + } + + _formatElements = new FormatElement[formatElements.size()]; + for (int i = 0; i < _formatElements.length; i++) { + _formatElements[i] + = new FormatElement((String) formatElements.elementAt(i)); + } + } + + /** + * Format a number. + * If there are no format elements the numbers will be ignored. + * If there are more than one format elements the + * additional format elements will be ignored and only the static parts + * are taken. + * @param number Number to be formated. + * @return Formated number. + */ + public String form(long number) { + StringBuffer result = new StringBuffer(); + result.append(_staticParts.elementAt(0)); + if (_formatElements.length > 0) { + _formatElements[0].form(result, number); + } + return appendRest(result); + } + + /** + * Format a number. + * If there are no format elements the numbers will be ignored. + * If there are more than one format elements the + * additional format elements will be ignored and only the static parts + * are taken. + * @param number Number to be formated. + * @return Formated number. + */ + public String form(double number) { + StringBuffer result = new StringBuffer(); + result.append(_staticParts.elementAt(0)); + if (_formatElements.length > 0) { + _formatElements[0].form(result, number); + } + return appendRest(result); + } + + private String appendRest(StringBuffer buffer) { + for (int i = 1, n = _staticParts.size(); i < n; i++) { + buffer.append(_staticParts.elementAt(i)); + } + return new String(buffer); + } + + /** + * Format an array of double numbers. + * If there are less format elements than numbers the additional numbers + * will be ignored. If there are less numbers than format elements the + * additional format elements will be ignored and only the static parts + * are taken. + * @param numbers Numbers to be formated. + * @return Formated numbers. + */ + public String form(double[] numbers) { + StringBuffer result = new StringBuffer(); + for (int i = 0, n = _staticParts.size(); i < n; i++) { + result.append(_staticParts.elementAt(i)); + if (i < _formatElements.length && i < numbers.length) { + _formatElements[i].form(result, numbers[i]); + } + } + return new String(result); + } +} diff --git a/src/jcckit/util/FormatElement.java b/src/jcckit/util/FormatElement.java new file mode 100644 index 000000000..84f629a99 --- /dev/null +++ b/src/jcckit/util/FormatElement.java @@ -0,0 +1,242 @@ +/* + * 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.util; + +/** + * + * + * @author Franz-Josef Elmer + */ +class FormatElement { + /** All descriptor characters. */ + static final String DESCRIPTORS = "doxfeEgG"; + private static final String INT_DESCRIPTORS = "dox"; + private static final int INT_DESCRIPTOR = 0; + private static final int FLOAT_DESCRIPTOR = 1; + /** + * Calculate the integer power of a floating point number. + * @param n Exponent. + * @param x Number. + * @return x^n. + */ + private static final double power(double x, int n) { + return n < 0 ? 1.0 / power2(x, -n) : power2(x, n); + } + + /** Calculate x^n recursively assuming n > 0. */ + private static final double power2(double x, int n) { + switch (n) { + case 0: return 1; + case 1: return x; + default: + double p = power2(x, n / 2); + return p * p * power2(x, n % 2); + } + } + + private final char _descriptor; + private final int _descriptorType; + private final double _tenToPrecision; + private boolean _decimalPoint; + private boolean _flushLeft; + private boolean _leadingZeros; + private boolean _alwaysSign; + private int _width; + private int _precision; + + /** Creates an instance for the specified format string. */ + FormatElement(String formatString) { + int len = formatString.length() - 1; + _descriptor = formatString.charAt(len); + if (DESCRIPTORS.indexOf(_descriptor) < 0) { + throw new IllegalArgumentException("Format element '" + formatString + + "' does not ends with one of the following characters: " + + DESCRIPTORS); + } + _descriptorType = INT_DESCRIPTORS.indexOf(_descriptor) >= 0 + ? INT_DESCRIPTOR : FLOAT_DESCRIPTOR; + if (formatString.length() > 1) { + switch (formatString.charAt(0)) { + case '-': + _flushLeft = true; + formatString = formatString.substring(1); + break; + case '0': + _leadingZeros = true; + formatString = formatString.substring(1); + break; + case '+': + _alwaysSign = true; + formatString = formatString.substring(1); + break; + } + len = formatString.length() - 1; + int index = formatString.indexOf('.'); + _decimalPoint = index >= 0; + int last = _decimalPoint ? index : len; + if (last > 0) { + _width = Integer.parseInt(formatString.substring(0, last)); + } + if (_decimalPoint) { + index++; + if (index < len) { + _precision = Integer.parseInt(formatString.substring(index, len)); + } + } + } + _tenToPrecision = power(10, _precision); + } + + /** + * Format a number in accordance of the format string + * given at the initialisation of this instance. + * @param buffer Buffer to which the formated output will be appended. + * @param number Number to be formated. + */ + public void form(StringBuffer buffer, long number) { + if (_descriptorType == FLOAT_DESCRIPTOR) { + form(buffer, (double) number); + } else { + // Format absolut value in the right base + buffer.append(form(number < 0, + Long.toString(Math.abs(number), + _descriptor == 'o' ? 8 + : (_descriptor == 'x' ? 16 : 10)), + "")); + } + } + + /** + * Format a number in accordance of the format string + * given at the initialisation of this instance. + * @param buffer Buffer to which the formated output will be appended. + * @param number Number to be formated. + */ + public void form(StringBuffer buffer, double number) { + if (_descriptorType == INT_DESCRIPTOR) { + form(buffer, (long) Math.floor(number + 0.5)); + } else if (_descriptor == 'f') { + buffer.append(formF(number)); + } else if (_descriptor == 'e' || _descriptor == 'E') { + buffer.append(formE(number)); + } else if (_descriptor == 'g' || _descriptor == 'G') { + String formF = formF(number); + String formE = formE(number); + buffer.append(formF.length() > formE.length() ? formE : formF); + } + } + + private String form(boolean negativeValue, String intPart, String fracPart) { + int len = intPart.length() + fracPart.length(); + + // Buffer holding the result + StringBuffer result = new StringBuffer(); + int count = 0; + + // add sign if necessary + if (_alwaysSign || negativeValue) { + result.append(negativeValue ? '-' : '+'); + count++; + } + + // add zeros if necessary + if (_leadingZeros) { + for (int i = count + len; i < _width; i++) { + result.append('0'); + count++; + } + } + + // add number + result.append(intPart).append(fracPart); + count += len; + + // add spaces if necessary + if (_flushLeft) { + for (; count < _width; count++) { + result.append(' '); + } + } else { + for (; count < _width; count++) { + result.insert(0, ' '); + } + } + + return new String(result); + } + + /** Format floating point number with exponent. */ + private String formE(double number) { + // format absolute mantisse + int exponent = 0; + String zeros = "00000000000000000000000".substring(0, _precision + 1); + if (number != 0) { + exponent = (int) Math.floor(Math.log(Math.abs(number)) / Math.log(10)); + double mantisse = Math.floor(Math.abs(number * power(10.0, + _precision - exponent)) + 0.5); + if (mantisse >= 10 * _tenToPrecision) { + exponent++; + mantisse = Math.floor(Math.abs(number * power(10.0, + _precision - exponent)) + 0.5); + } + zeros = Long.toString((long) mantisse); + } + + // make fractional part + StringBuffer fracPart = new StringBuffer(); + if (_decimalPoint) { + fracPart.append('.').append(zeros.substring(1)); + } + + // make exponent + fracPart.append(Character.isLowerCase(_descriptor) ? 'e': 'E') + .append(exponent < 0 ? '-' : '+'); + exponent = Math.abs(exponent); + for (int i = 0, n = fracPart.length(); i < 3; i++) { + fracPart.insert(n, Character.forDigit(exponent % 10, 10)); + exponent /= 10; + } + + return form(number < 0, zeros.substring(0, 1), new String(fracPart)); + } + + /** Format floating point number. */ + private String formF(double number) { + // Format absolut value + double multiplier = number < 0 ? - _tenToPrecision : _tenToPrecision; + String digits + = Long.toString((long) Math.floor(number * multiplier + 0.5)); + String intPart = digits; + StringBuffer fracPart = new StringBuffer(); + if (_decimalPoint) { + int len = digits.length() - _precision; + fracPart.append('.').append(digits.substring(Math.max(0, len))); + if (len > 0) { + intPart = digits.substring(0, len); + } else { + intPart = "0"; + for (; len < 0; len++) { + fracPart.insert(1, '0'); + } + } + } + + return form(number < 0, intPart, new String(fracPart)); + } +} diff --git a/src/jcckit/util/Point.java b/src/jcckit/util/Point.java new file mode 100644 index 000000000..623c78fc1 --- /dev/null +++ b/src/jcckit/util/Point.java @@ -0,0 +1,65 @@ +/* + * 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.util; + +/** + * Immutable class of a two-dimensional point with floating point + * coordinates. + * + * @author Franz-Josef Elmer + */ +public class Point { + private final double _x; + private final double _y; + + /** + * Creates an instance for the specified vector. The value of the + * first/second element of vector denotes the x/y value. + * If vector is null or not long enough 0 will be used + * as default values. + */ + public Point(double[] vector) { + double x = 0; + double y = 0; + if (vector != null && vector.length > 0) { + x = vector[0]; + if (vector.length > 1) { + y = vector[1]; + } + } + _x = x; + _y = y; + } + + /** Creates an instance for the specified coordinates. */ + public Point(double x, double y) { + _x = x; + _y = y; + } + + /** Returns the x-coordinate of the point. */ + public double getX() { + return _x; + } + + /** Returns the y-coordinate of the point. */ + public double getY() { + return _y; + } +} diff --git a/src/jcckit/util/PropertiesBasedConfigData.java b/src/jcckit/util/PropertiesBasedConfigData.java new file mode 100644 index 000000000..6ecdd1f11 --- /dev/null +++ b/src/jcckit/util/PropertiesBasedConfigData.java @@ -0,0 +1,80 @@ +/* + * 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.util; + +import java.io.*; +import java.util.Properties; + +/** + * Implementation of {@link FlatConfigData} based on + * java.util.Properties. + * + * @author Franz-Josef Elmer + */ +public class PropertiesBasedConfigData extends FlatConfigData { + private final Properties _properties; + + /** + * Creates an instance from the specified .properties file. + * @param fileName File name of the .properties file relative + * to the working directory or absolute. + * @throws IOException if the .properties does not exist or could + * not be read. + */ + public PropertiesBasedConfigData(String fileName) throws IOException { + super(null); + _properties = new Properties(); + _properties.load(new FileInputStream(fileName)); + } + + /** + * Creates an instance based on the specified properties. + * The path is undefined. + */ + public PropertiesBasedConfigData(Properties properties) { + this(properties, null); + } + + /** Creates an instance based on the specified properties and path. */ + private PropertiesBasedConfigData(Properties properties, String path) { + super(path); + _properties = properties; + } + + /** + * Returns the value for the specified full key. The call will be delegated + * to the wrapped java.util.properties object. + * @param fullKey The full key including path. null is not allowed. + * @return the value or null if not found. + */ + protected String getValue(String fullKey) { + return _properties.getProperty(fullKey); + } + + /** + * Returns a new instance of PropertiesBasedConfigData + * for the specified full path. The wrapped java.util.Properties + * will be the same as of this instance. + * @param path The full path. + * @return a new instance. + */ + protected ConfigData createConfigData(String path) { + return new PropertiesBasedConfigData(_properties, path); + } +} diff --git a/src/jcckit/util/TicLabelFormat.java b/src/jcckit/util/TicLabelFormat.java new file mode 100644 index 000000000..61d924c58 --- /dev/null +++ b/src/jcckit/util/TicLabelFormat.java @@ -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.util; + +/** + * Format interface for tic labels. Maps a numerical tic value onto a string. + * + * @author Franz-Josef Elmer + */ +public interface TicLabelFormat +{ + /** + * Forms the specified tic value to a string. Note, the numerical + * ticValue may be mapped onto a non-numerical one. + */ + public String form(double ticValue); +} diff --git a/src/jcckit/util/Util.java b/src/jcckit/util/Util.java new file mode 100644 index 000000000..5715d5a46 --- /dev/null +++ b/src/jcckit/util/Util.java @@ -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.util; + +/** + * Collection of static utility methods. + * + * @author Franz-Josef Elmer + */ +public class Util { + /** Private constructor to prevent instanciation of this class. */ + private Util() {} + + /** + * Returns the natural logarithm of the specified number if + * logScale is true. + * @return x if logScale == false. + */ + public static double log(double x, boolean logScale) { + return logScale ? Math.log(x) : x; + } + + /** + * Returns the exponential function of the specified number if + * logScale is true. + * @return x if logScale == false. + */ + public static double exp(double x, boolean logScale) { + return logScale ? Math.exp(x) : x; + } +} diff --git a/src/net/sourceforge/plantuml/BlockUml.java b/src/net/sourceforge/plantuml/BlockUml.java index 981d64e9d..c4fdd7bc7 100644 --- a/src/net/sourceforge/plantuml/BlockUml.java +++ b/src/net/sourceforge/plantuml/BlockUml.java @@ -45,7 +45,7 @@ public class BlockUml { private final List data; private PSystem system; - private static final Pattern patternFilename = Pattern.compile("^@start[-\\w.]+\\s+\"?(.*?)\"?$"); + private static final Pattern patternFilename = Pattern.compile("^@start\\S+\\s+\"?(.*?)\"?$"); BlockUml(String... strings) { this(Arrays.asList(strings)); diff --git a/src/net/sourceforge/plantuml/DiagramType.java b/src/net/sourceforge/plantuml/DiagramType.java index eb393baf8..08d60beb7 100644 --- a/src/net/sourceforge/plantuml/DiagramType.java +++ b/src/net/sourceforge/plantuml/DiagramType.java @@ -34,7 +34,7 @@ package net.sourceforge.plantuml; public enum DiagramType { - UML, DITAA, DOT, PROJECT, UNKNOWN; + UML, DITAA, DOT, PROJECT, JCCKIT, SALT, UNKNOWN; static DiagramType getTypeFromArobaseStart(String s) { if (s.startsWith("@startuml")) { @@ -43,12 +43,18 @@ public enum DiagramType { if (s.startsWith("@startdot")) { return DOT; } + if (s.startsWith("@startjcckit")) { + return JCCKIT; + } if (s.startsWith("@startditaa")) { return DITAA; } if (s.startsWith("@startproject")) { return PROJECT; } + if (s.startsWith("@startsalt")) { + return SALT; + } return UNKNOWN; } } diff --git a/src/net/sourceforge/plantuml/Dimension2DDouble.java b/src/net/sourceforge/plantuml/Dimension2DDouble.java index 0e81d6d06..0a8949708 100644 --- a/src/net/sourceforge/plantuml/Dimension2DDouble.java +++ b/src/net/sourceforge/plantuml/Dimension2DDouble.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6843 $ + * Revision $Revision: 7157 $ * */ package net.sourceforge.plantuml; @@ -79,6 +79,12 @@ public class Dimension2DDouble extends Dimension2D { return new Dimension2DDouble(width, height); } + public static Dimension2D mergeLR(Dimension2D left, Dimension2D right) { + final double height = Math.max(left.getHeight(), right.getHeight()); + final double width = left.getWidth() + right.getWidth(); + return new Dimension2DDouble(width, height); + } + public static Dimension2D mergeTB(Dimension2D top1, Dimension2D top2, Dimension2D bottom) { final double width = MathUtils.max(top1.getWidth(), top2.getWidth(), bottom.getWidth()); final double height = top1.getHeight() + top2.getHeight() + bottom.getHeight(); diff --git a/src/net/sourceforge/plantuml/FontParam.java b/src/net/sourceforge/plantuml/FontParam.java index 89e24b2fb..b75cf3b59 100644 --- a/src/net/sourceforge/plantuml/FontParam.java +++ b/src/net/sourceforge/plantuml/FontParam.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6866 $ + * Revision $Revision: 7130 $ * */ package net.sourceforge.plantuml; @@ -88,14 +88,14 @@ public enum FontParam { } public final int getDefaultSize(ISkinParam skinParam) { - if (OptionFlags.SVEK && this==CLASS_ATTRIBUTE) { + if (skinParam.isSvek() && this==CLASS_ATTRIBUTE) { return 11; } return defaultSize; } public final int getDefaultFontStyle(ISkinParam skinParam) { - if (OptionFlags.SVEK && this==PACKAGE) { + if (skinParam.isSvek() && this==PACKAGE) { return Font.BOLD; } return fontStyle; diff --git a/src/net/sourceforge/plantuml/ISkinParam.java b/src/net/sourceforge/plantuml/ISkinParam.java index 39b0b4d17..b0e4b6f36 100644 --- a/src/net/sourceforge/plantuml/ISkinParam.java +++ b/src/net/sourceforge/plantuml/ISkinParam.java @@ -69,5 +69,7 @@ public interface ISkinParam { public DotSplines getDotSplines(); public GraphvizLayoutStrategy getStrategy(); + + public boolean isSvek(); } \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/OptionFlags.java b/src/net/sourceforge/plantuml/OptionFlags.java index 9c2f8890f..739db4470 100644 --- a/src/net/sourceforge/plantuml/OptionFlags.java +++ b/src/net/sourceforge/plantuml/OptionFlags.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6922 $ + * Revision $Revision: 7135 $ * */ package net.sourceforge.plantuml; diff --git a/src/net/sourceforge/plantuml/PSystemBuilder.java b/src/net/sourceforge/plantuml/PSystemBuilder.java index 96804d942..ce556d1dc 100644 --- a/src/net/sourceforge/plantuml/PSystemBuilder.java +++ b/src/net/sourceforge/plantuml/PSystemBuilder.java @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import net.sourceforge.plantuml.acearth.PSystemXearthFactory; import net.sourceforge.plantuml.activitydiagram.ActivityDiagramFactory; import net.sourceforge.plantuml.activitydiagram2.ActivityDiagramFactory2; import net.sourceforge.plantuml.classdiagram.ClassDiagramFactory; @@ -49,11 +50,13 @@ import net.sourceforge.plantuml.eggs.PSystemEggFactory; import net.sourceforge.plantuml.eggs.PSystemLostFactory; import net.sourceforge.plantuml.eggs.PSystemPathFactory; import net.sourceforge.plantuml.eggs.PSystemRIPFactory; +import net.sourceforge.plantuml.jcckit.PSystemJcckitFactory; import net.sourceforge.plantuml.objectdiagram.ObjectDiagramFactory; import net.sourceforge.plantuml.oregon.PSystemOregonFactory; import net.sourceforge.plantuml.postit.PostIdDiagramFactory; import net.sourceforge.plantuml.printskin.PrintSkinFactory; import net.sourceforge.plantuml.project.PSystemProjectFactory; +import net.sourceforge.plantuml.salt.PSystemSaltFactory; import net.sourceforge.plantuml.sequencediagram.SequenceDiagramFactory; import net.sourceforge.plantuml.statediagram.StateDiagramFactory; import net.sourceforge.plantuml.sudoku.PSystemSudokuFactory; @@ -103,16 +106,21 @@ public class PSystemBuilder { factories.add(new PostIdDiagramFactory()); factories.add(new PrintSkinFactory()); factories.add(new PSystemVersionFactory()); + factories.add(new PSystemSaltFactory(DiagramType.SALT)); + factories.add(new PSystemSaltFactory(DiagramType.UML)); factories.add(new PSystemDotFactory(DiagramType.DOT)); factories.add(new PSystemDotFactory(DiagramType.UML)); factories.add(new PSystemDitaaFactory(DiagramType.DITAA)); factories.add(new PSystemDitaaFactory(DiagramType.UML)); + factories.add(new PSystemJcckitFactory(DiagramType.JCCKIT)); + factories.add(new PSystemJcckitFactory(DiagramType.UML)); factories.add(new PSystemSudokuFactory()); factories.add(new PSystemEggFactory()); factories.add(new PSystemRIPFactory()); factories.add(new PSystemLostFactory()); factories.add(new PSystemPathFactory()); factories.add(new PSystemOregonFactory()); + factories.add(new PSystemXearthFactory()); factories.add(new PSystemProjectFactory()); return factories; } diff --git a/src/net/sourceforge/plantuml/SkinParam.java b/src/net/sourceforge/plantuml/SkinParam.java index f0f64fe3f..804b3edb5 100644 --- a/src/net/sourceforge/plantuml/SkinParam.java +++ b/src/net/sourceforge/plantuml/SkinParam.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6866 $ + * Revision $Revision: 7180 $ * */ package net.sourceforge.plantuml; @@ -64,6 +64,12 @@ public class SkinParam implements ISkinParam { private static final String stereoPatternString = "\\<\\<(.*?)\\>\\>"; private static final Pattern stereoPattern = Pattern.compile(stereoPatternString); + private final UmlDiagramType type; + + public SkinParam(UmlDiagramType type) { + this.type = type; + } + static String cleanForKey(String key) { key = key.toLowerCase().trim(); key = key.replaceAll("_|\\.|\\s", ""); @@ -211,8 +217,8 @@ public class SkinParam implements ISkinParam { if (stereotype != null) { checkStereotype(stereotype); } - return new UFont(getFontFamily(fontParam, stereotype), getFontStyle(fontParam, stereotype), - getFontSize(fontParam, stereotype)); + return new UFont(getFontFamily(fontParam, stereotype), getFontStyle(fontParam, stereotype), getFontSize( + fontParam, stereotype)); } public int getCircledCharacterRadius() { @@ -333,4 +339,16 @@ public class SkinParam implements ISkinParam { return new ColorMapperIdentity(); } + public boolean isSvek() { + boolean defaultValue = false; + if (OptionFlags.SVEK && type == UmlDiagramType.CLASS) { + defaultValue = true; + } + final String value = getValue("svek"); + if (value == null) { + return defaultValue; + } + return "true".equalsIgnoreCase(value); + } + } diff --git a/src/net/sourceforge/plantuml/SkinParamBackcolored.java b/src/net/sourceforge/plantuml/SkinParamBackcolored.java index 4e21590c5..41b0aba9c 100644 --- a/src/net/sourceforge/plantuml/SkinParamBackcolored.java +++ b/src/net/sourceforge/plantuml/SkinParamBackcolored.java @@ -119,4 +119,8 @@ public class SkinParamBackcolored implements ISkinParam { return skinParam.getColorMapper(); } + public boolean isSvek() { + return skinParam.isSvek(); + } + } diff --git a/src/net/sourceforge/plantuml/SkinParamBackcoloredReference.java b/src/net/sourceforge/plantuml/SkinParamBackcoloredReference.java index b47af959a..6830e6d0d 100644 --- a/src/net/sourceforge/plantuml/SkinParamBackcoloredReference.java +++ b/src/net/sourceforge/plantuml/SkinParamBackcoloredReference.java @@ -106,13 +106,17 @@ public class SkinParamBackcoloredReference implements ISkinParam { public GraphvizLayoutStrategy getStrategy() { return skinParam.getStrategy(); } - + public HorizontalAlignement getHorizontalAlignement(AlignParam param) { return skinParam.getHorizontalAlignement(param); } - + public ColorMapper getColorMapper() { return skinParam.getColorMapper(); } - + + public boolean isSvek() { + return skinParam.isSvek(); + } + } diff --git a/src/net/sourceforge/plantuml/StringUtils.java b/src/net/sourceforge/plantuml/StringUtils.java index f58a8fa9a..a305643f6 100644 --- a/src/net/sourceforge/plantuml/StringUtils.java +++ b/src/net/sourceforge/plantuml/StringUtils.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6923 $ + * Revision $Revision: 7064 $ * */ package net.sourceforge.plantuml; @@ -230,7 +230,7 @@ public class StringUtils { public static char hiddenBiggerThan() { return '\u0006'; } - + public static String hideComparatorCharacters(String s) { s = s.replace('<', hiddenLesserThan()); s = s.replace('>', hiddenBiggerThan()); diff --git a/src/net/sourceforge/plantuml/UmlDiagram.java b/src/net/sourceforge/plantuml/UmlDiagram.java index b961eaed1..7fcff94a1 100644 --- a/src/net/sourceforge/plantuml/UmlDiagram.java +++ b/src/net/sourceforge/plantuml/UmlDiagram.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6922 $ + * Revision $Revision: 7173 $ * */ package net.sourceforge.plantuml; @@ -75,7 +75,7 @@ public abstract class UmlDiagram extends AbstractPSystem implements PSystem { private final Pragma pragma = new Pragma(); private Scale scale; - private final SkinParam skinParam = new SkinParam(); + private final SkinParam skinParam = new SkinParam(getUmlDiagramType()); final public void setTitle(List strings) { this.title = strings; diff --git a/src/net/sourceforge/plantuml/acearth/PSystemXearth.java b/src/net/sourceforge/plantuml/acearth/PSystemXearth.java new file mode 100644 index 000000000..8f9f2dd54 --- /dev/null +++ b/src/net/sourceforge/plantuml/acearth/PSystemXearth.java @@ -0,0 +1,125 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 4041 $ + * + */ +package net.sourceforge.plantuml.acearth; + +import java.io.IOException; +import java.io.OutputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +import net.sourceforge.plantuml.AbstractPSystem; +import net.sourceforge.plantuml.FileFormatOption; + +import com.ctreber.acearth.ACearth; +import com.ctreber.acearth.ConfigurationACearth; +import com.ctreber.acearth.plugins.markers.Marker; + +public class PSystemXearth extends AbstractPSystem { + + final private int width; + final private int height; + final private Map config; + final private List markers; + + final private Collection enums = Arrays.asList("viewPositionType"); + final private Collection doubles = Arrays.asList("sunPosRelLat", "sunPosRelLong", "orbitPeriod", + "orbitInclination", "viewPosLat", "viewPosLong", "starFrequency", "viewMagnification"); + final private Collection integers = Arrays.asList("daySideBrightness", "nightSideBrightness", + "terminatorDiscontinuity", "gridDivision", "gridPixelDivision", "bigStars"); + final private Collection booleans = Arrays.asList("shadeP", "gridP", "starsP"); + + public PSystemXearth(int width, int height, Map config, List markers) { + this.width = width; + this.height = height; + this.config = config; + this.markers = markers; + } + + public void exportDiagram(OutputStream os, StringBuilder cmap, int index, FileFormatOption fileFormat) + throws IOException { + final ACearth earth = new ACearth(markers); + final ConfigurationACearth conf = earth.getConf(); + conf.setInt("imageWidth", width); + conf.setInt("imageHeight", height); + + for (Map.Entry ent : config.entrySet()) { + final String key = ent.getKey(); + final String value = ent.getValue(); + if (key.equalsIgnoreCase("GMT")) { + final Date date = extractGmt(value); + conf.setInt("fixedTime", (int) (date.getTime() / 1000L)); + } else if (enums.contains(key)) { + conf.getMOEnum(key).set(value); + } else if (doubles.contains(key)) { + conf.setDouble(key, Double.parseDouble(value)); + } else if (integers.contains(key)) { + conf.setInt(key, Integer.parseInt(value)); + } else if (booleans.contains(key)) { + conf.setBoolean(key, value.equalsIgnoreCase("true")); + } else { + throw new UnsupportedOperationException(key); + } + } + earth.exportPng(os); + } + + private Date extractGmt(String s) { + final SimpleDateFormat timeFormat; + if (s.matches("\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}")) { + timeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + } else if (s.matches("\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}")) { + timeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm"); + } else { + throw new UnsupportedOperationException(s); + } + timeFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + try { + return timeFormat.parse(s); + } catch (ParseException e) { + throw new UnsupportedOperationException(s); + } + + } + + public String getDescription() { + return "(XEarth)"; + } + +} diff --git a/src/net/sourceforge/plantuml/acearth/PSystemXearthFactory.java b/src/net/sourceforge/plantuml/acearth/PSystemXearthFactory.java new file mode 100644 index 000000000..ac8ac0db3 --- /dev/null +++ b/src/net/sourceforge/plantuml/acearth/PSystemXearthFactory.java @@ -0,0 +1,111 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3837 $ + * + */ +package net.sourceforge.plantuml.acearth; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.ctreber.acearth.plugins.markers.Marker; + +import net.sourceforge.plantuml.DiagramType; +import net.sourceforge.plantuml.PSystemBasicFactory; + +public class PSystemXearthFactory implements PSystemBasicFactory { + + private PSystemXearth system; + private final Map config = new LinkedHashMap(); + private final List markers = new ArrayList(); + private int width; + private int height; + + public void init(String startLine) { + this.width = 512; + this.height = 512; + this.config.clear(); + } + + private void extractDimension(String startLine) { + final Pattern p = Pattern.compile("\\((\\d+),(\\d+)\\)"); + final Matcher m = p.matcher(startLine); + final boolean ok = m.find(); + if (ok) { + width = Integer.parseInt(m.group(1)); + height = Integer.parseInt(m.group(2)); + } + } + + public PSystemXearth getSystem() { + return system; + } + + public boolean executeLine(String line) { + if (line.startsWith("xearth")) { + extractDimension(line); + system = new PSystemXearth(width, height, config, markers); + return true; + } + if (system == null) { + return false; + } + if (line.startsWith("#") || line.startsWith("'")) { + return true; + } + final Pattern p = Pattern.compile("(\\w+)\\s*=\\s*(.*)"); + final Matcher m = p.matcher(line); + if (m.find()) { + config.put(m.group(1), m.group(2)); + return true; + } + try { + final Marker marker = Marker.loadMarkerFile(line); + if (marker != null) { + markers.add(marker); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return false; + } + + public DiagramType getDiagramType() { + return DiagramType.UML; + } + +} diff --git a/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java b/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java index 1a7900a5f..36ffbd9f0 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java +++ b/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6892 $ + * Revision $Revision: 7135 $ * */ package net.sourceforge.plantuml.cucadiagram; @@ -57,7 +57,6 @@ import java.util.TreeMap; import net.sourceforge.plantuml.FileFormat; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.Log; -import net.sourceforge.plantuml.OptionFlags; import net.sourceforge.plantuml.UmlDiagram; import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.cucadiagram.dot.CucaDiagramFileMaker; @@ -232,7 +231,7 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, } final public Map entities() { - if (OptionFlags.SVEK) { + if (getSkinParam().isSvek()) { return Collections.unmodifiableMap(entities); } return Collections.unmodifiableMap(new TreeMap(entities)); @@ -413,7 +412,7 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return; } final ICucaDiagramFileMaker maker; - if (OptionFlags.SVEK) { + if (getSkinParam().isSvek()) { maker = new CucaDiagramFileMakerSvek(this, flashcodes); } else { maker = new CucaDiagramFileMaker(this, flashcodes); diff --git a/src/net/sourceforge/plantuml/cucadiagram/LinkDecor.java b/src/net/sourceforge/plantuml/cucadiagram/LinkDecor.java index e2ad08d4c..f311ec9eb 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/LinkDecor.java +++ b/src/net/sourceforge/plantuml/cucadiagram/LinkDecor.java @@ -63,6 +63,24 @@ public enum LinkDecor { } } + public String getArrowDotSvek() { + if (this == LinkDecor.NONE) { + return "none"; + } else if (this == LinkDecor.EXTENDS) { + return "empty"; + } else if (this == LinkDecor.COMPOSITION) { + return "diamond"; + } else if (this == LinkDecor.AGREGATION) { + return "ediamond"; + } else if (this == LinkDecor.ARROW) { + return "open"; + } else if (this == LinkDecor.PLUS) { + return "empty"; + } else { + throw new UnsupportedOperationException(); + } + } + public int getSize() { return size; } diff --git a/src/net/sourceforge/plantuml/cucadiagram/LinkType.java b/src/net/sourceforge/plantuml/cucadiagram/LinkType.java index 3bb8508f8..93a58d33b 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/LinkType.java +++ b/src/net/sourceforge/plantuml/cucadiagram/LinkType.java @@ -142,6 +142,41 @@ public class LinkType { return sb.toString(); } + public String getSpecificDecorationSvek() { + final StringBuilder sb = new StringBuilder(); + + if (decor1 == LinkDecor.NONE && decor2 != LinkDecor.NONE) { + sb.append("dir=back,"); + } + if (decor1 != LinkDecor.NONE && decor2 != LinkDecor.NONE) { + sb.append("dir=both,"); + } + + sb.append("arrowtail="); + sb.append(decor2.getArrowDotSvek()); + sb.append(",arrowhead="); + sb.append(decor1.getArrowDotSvek()); + + if (decor1 == LinkDecor.EXTENDS || decor2 == LinkDecor.EXTENDS) { + sb.append(",arrowsize=2"); + } + if (decor1 == LinkDecor.PLUS || decor2 == LinkDecor.PLUS) { + sb.append(",arrowsize=1.5"); + } + + if (style == LinkStyle.DASHED) { + sb.append(",style=dashed"); + } + if (style == LinkStyle.DOTTED) { + sb.append(",style=dotted,"); + } + if (style == LinkStyle.BOLD) { + sb.append(",style=bold,"); + } + + return sb.toString(); + } + public final LinkDecor getDecor1() { return decor1; } diff --git a/src/net/sourceforge/plantuml/graph/MethodsOrFieldsArea2.java b/src/net/sourceforge/plantuml/graph/MethodsOrFieldsArea2.java index 1e14f3013..1a4c901c4 100644 --- a/src/net/sourceforge/plantuml/graph/MethodsOrFieldsArea2.java +++ b/src/net/sourceforge/plantuml/graph/MethodsOrFieldsArea2.java @@ -58,7 +58,7 @@ import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGroup; -public class MethodsOrFieldsArea2 { +public class MethodsOrFieldsArea2 implements TextBlock { private final UFont font; private final List members = new ArrayList(); @@ -94,7 +94,7 @@ public class MethodsOrFieldsArea2 { x = Math.max(dim.getWidth(), x); } if (hasSmallIcon()) { - x += skinParam.getCircledCharacterRadius(); + x += skinParam.getCircledCharacterRadius() + 3; } return new Dimension2DDouble(x, y); } @@ -103,16 +103,16 @@ public class MethodsOrFieldsArea2 { return TextBlockUtils.create(Arrays.asList(s), new FontConfiguration(font, color), HorizontalAlignement.LEFT); } - public void drawTOBEREMOVED(Graphics2D g2d, double x, double y) { + public void drawTOBEREMOVED(ColorMapper colorMapper, Graphics2D g2d, double x, double y) { throw new UnsupportedOperationException(); } - public void draw(UGraphic ug, double x, double y) { + public void drawU(UGraphic ug, double x, double y) { final Dimension2D dim = calculateDimension(ug.getStringBounder()); final UGroup group; if (hasSmallIcon()) { - group = new UGroup(new PlacementStrategyVisibility(ug.getStringBounder(), - skinParam.getCircledCharacterRadius())); + group = new UGroup(new PlacementStrategyVisibility(ug.getStringBounder(), skinParam + .getCircledCharacterRadius() + 3)); for (Member att : members) { final String s = att.getDisplayWithoutVisibilityChar(); final TextBlock bloc = createTextBlock(s); @@ -148,8 +148,8 @@ public class MethodsOrFieldsArea2 { } }; } - final HtmlColor back = modifier.getBackground() == null ? null : rose.getHtmlColor(skinParam, - modifier.getBackground()); + final HtmlColor back = modifier.getBackground() == null ? null : rose.getHtmlColor(skinParam, modifier + .getBackground()); final HtmlColor fore = rose.getHtmlColor(skinParam, modifier.getForeground()); final TextBlock uBlock = modifier.getUBlock(skinParam.getCircledCharacterRadius(), fore, back); diff --git a/src/net/sourceforge/plantuml/graphic/GraphicStrings.java b/src/net/sourceforge/plantuml/graphic/GraphicStrings.java index c6b983607..65c8400dc 100644 --- a/src/net/sourceforge/plantuml/graphic/GraphicStrings.java +++ b/src/net/sourceforge/plantuml/graphic/GraphicStrings.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6937 $ + * Revision $Revision: 7144 $ * */ package net.sourceforge.plantuml.graphic; @@ -193,4 +193,8 @@ public class GraphicStrings implements IEntityImage { return background; } + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/graphic/HtmlColor.java b/src/net/sourceforge/plantuml/graphic/HtmlColor.java index 2d01f97bf..09ed9e091 100644 --- a/src/net/sourceforge/plantuml/graphic/HtmlColor.java +++ b/src/net/sourceforge/plantuml/graphic/HtmlColor.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6577 $ + * Revision $Revision: 6983 $ * */ package net.sourceforge.plantuml.graphic; @@ -41,7 +41,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; -import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.ugraphic.ColorChangerMonochrome; public class HtmlColor { diff --git a/src/net/sourceforge/plantuml/graphic/StringBounderUtils.java b/src/net/sourceforge/plantuml/graphic/StringBounderUtils.java index 126e86e03..ea407dc80 100644 --- a/src/net/sourceforge/plantuml/graphic/StringBounderUtils.java +++ b/src/net/sourceforge/plantuml/graphic/StringBounderUtils.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7060 $ * */ package net.sourceforge.plantuml.graphic; @@ -51,21 +51,6 @@ public class StringBounderUtils { final Rectangle2D rect = fm.getStringBounds(text, g2d); return new Dimension2DDouble(rect.getWidth(), rect.getHeight()); } - -// public double getFontDescent(Font font) { -// final FontMetrics fm = g2d.getFontMetrics(font); -// return fm.getDescent(); -// } -// -// public double getFontAscent(Font font) { -// final FontMetrics fm = g2d.getFontMetrics(font); -// return fm.getAscent(); -// } - -// public UnusedSpace getUnusedSpace(Font font, char c) { -// //return new UnusedSpace(7, 6, 0, 2); -// return new UnusedSpace(font, c); -// } }; } } diff --git a/src/net/sourceforge/plantuml/graphic/TextBlock.java b/src/net/sourceforge/plantuml/graphic/TextBlock.java index e0032860a..aa74e8dd6 100644 --- a/src/net/sourceforge/plantuml/graphic/TextBlock.java +++ b/src/net/sourceforge/plantuml/graphic/TextBlock.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6577 $ + * Revision $Revision: 7163 $ * */ package net.sourceforge.plantuml.graphic; @@ -37,14 +37,10 @@ import java.awt.Graphics2D; import java.awt.geom.Dimension2D; import net.sourceforge.plantuml.ugraphic.ColorMapper; -import net.sourceforge.plantuml.ugraphic.UGraphic; -public interface TextBlock { +public interface TextBlock extends UDrawable3 { Dimension2D calculateDimension(StringBounder stringBounder); void drawTOBEREMOVED(ColorMapper colorMapper, Graphics2D g2d, double x, double y); - - void drawU(UGraphic ug, double x, double y); - } \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockHorizontal.java b/src/net/sourceforge/plantuml/graphic/TextBlockHorizontal.java new file mode 100644 index 000000000..227fd7442 --- /dev/null +++ b/src/net/sourceforge/plantuml/graphic/TextBlockHorizontal.java @@ -0,0 +1,69 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6577 $ + * + */ +package net.sourceforge.plantuml.graphic; + +import java.awt.Graphics2D; +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.ugraphic.ColorMapper; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class TextBlockHorizontal implements TextBlock { + + private final TextBlock b1; + private final TextBlock b2; + + public TextBlockHorizontal(TextBlock b1, TextBlock b2) { + this.b1 = b1; + this.b2 = b2; + } + + public Dimension2D calculateDimension(StringBounder stringBounder) { + final Dimension2D dim1 = b1.calculateDimension(stringBounder); + final Dimension2D dim2 = b2.calculateDimension(stringBounder); + return Dimension2DDouble.mergeLR(dim1, dim2); + } + + public void drawTOBEREMOVED(ColorMapper colorMapper, Graphics2D g2d, double x, double y) { + throw new UnsupportedOperationException(); + } + + public void drawU(UGraphic ug, double x, double y) { + b1.drawU(ug, x, y); + final Dimension2D dim1 = b1.calculateDimension(ug.getStringBounder()); + b2.drawU(ug, x + dim1.getWidth(), y); + } + +} \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockMarged.java b/src/net/sourceforge/plantuml/graphic/TextBlockMarged.java new file mode 100644 index 000000000..3e0ba2d2b --- /dev/null +++ b/src/net/sourceforge/plantuml/graphic/TextBlockMarged.java @@ -0,0 +1,72 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6577 $ + * + */ +package net.sourceforge.plantuml.graphic; + +import java.awt.Graphics2D; +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.ugraphic.ColorMapper; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class TextBlockMarged implements TextBlock { + + private final TextBlock textBlock; + private final double x1; + private final double x2; + private final double y1; + private final double y2; + + public TextBlockMarged(TextBlock textBlock, double x1, double x2, double y1, double y2) { + this.textBlock = textBlock; + this.x1 = x1; + this.x2 = x2; + this.y1 = y1; + this.y2 = y2; + } + + public Dimension2D calculateDimension(StringBounder stringBounder) { + final Dimension2D dim = textBlock.calculateDimension(stringBounder); + return Dimension2DDouble.delta(dim, x1 + x2, y1 + y2); + } + + public void drawTOBEREMOVED(ColorMapper colorMapper, Graphics2D g2d, double x, double y) { + throw new UnsupportedOperationException(); + } + + public void drawU(UGraphic ug, double x, double y) { + textBlock.drawU(ug, x + x1, y + y1); + } + +} \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java b/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java index 4656ada92..ecbf794a4 100644 --- a/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java +++ b/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java @@ -28,15 +28,23 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6570 $ + * Revision $Revision: 7157 $ * */ package net.sourceforge.plantuml.graphic; +import java.awt.Graphics2D; +import java.awt.geom.Dimension2D; +import java.awt.geom.Point2D; import java.util.List; import net.sourceforge.plantuml.cucadiagram.Stereotype; +import net.sourceforge.plantuml.posimo.Positionable; +import net.sourceforge.plantuml.posimo.PositionableImpl; import net.sourceforge.plantuml.sequencediagram.MessageNumber; +import net.sourceforge.plantuml.svek.IEntityImage; +import net.sourceforge.plantuml.ugraphic.ColorMapper; +import net.sourceforge.plantuml.ugraphic.UGraphic; public class TextBlockUtils { @@ -63,9 +71,9 @@ public class TextBlockUtils { HorizontalAlignement horizontalAlignement) { final Stereotype stereotype = (Stereotype) texts.get(0); if (stereotype.isSpotted()) { - final CircledCharacter circledCharacter = new CircledCharacter(stereotype.getCharacter(), - stereotype.getRadius(), stereotype.getCircledFont(), stereotype.getHtmlColor(), null, - fontConfiguration.getColor()); + final CircledCharacter circledCharacter = new CircledCharacter(stereotype.getCharacter(), stereotype + .getRadius(), stereotype.getCircledFont(), stereotype.getHtmlColor(), null, fontConfiguration + .getColor()); if (stereotype.getLabel() == null) { return new TextBlockSpotted(circledCharacter, texts.subList(1, texts.size()), fontConfiguration, horizontalAlignement); @@ -75,9 +83,41 @@ public class TextBlockUtils { return new TextBlockSimple(texts, fontConfiguration, horizontalAlignement); } + public static TextBlock withMargin(TextBlock textBlock, double marginX, double marginY) { + return new TextBlockMarged(textBlock, marginX, marginX, marginY, marginY); + } + // static private Font deriveForCircleCharacter(Font font) { // final float size = font.getSize2D(); // return font.deriveFont(size - 1).deriveFont(Font.BOLD); // } + public static Positionable asPositionable(TextBlock textBlock, StringBounder stringBounder, Point2D pt) { + return new PositionableImpl(pt, textBlock.calculateDimension(stringBounder)); + } + + public static TextBlock fromIEntityImage(final IEntityImage image) { + return new TextBlock() { + public Dimension2D calculateDimension(StringBounder stringBounder) { + return image.getDimension(stringBounder); + } + + public void drawTOBEREMOVED(ColorMapper colorMapper, Graphics2D g2d, double x, double y) { + throw new UnsupportedOperationException(); + } + + public void drawU(UGraphic ug, double x, double y) { + image.drawU(ug, x, y); + } + }; + } + + public static TextBlock mergeLR(TextBlock b1, TextBlock b2) { + return new TextBlockHorizontal(b1, b2); + } + + public static TextBlock mergeTB(TextBlock b1, TextBlock b2) { + return new TextBlockVertical(b1, b2); + } + } diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockVertical.java b/src/net/sourceforge/plantuml/graphic/TextBlockVertical.java new file mode 100644 index 000000000..803a3750c --- /dev/null +++ b/src/net/sourceforge/plantuml/graphic/TextBlockVertical.java @@ -0,0 +1,69 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6577 $ + * + */ +package net.sourceforge.plantuml.graphic; + +import java.awt.Graphics2D; +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.ugraphic.ColorMapper; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class TextBlockVertical implements TextBlock { + + private final TextBlock b1; + private final TextBlock b2; + + public TextBlockVertical(TextBlock b1, TextBlock b2) { + this.b1 = b1; + this.b2 = b2; + } + + public Dimension2D calculateDimension(StringBounder stringBounder) { + final Dimension2D dim1 = b1.calculateDimension(stringBounder); + final Dimension2D dim2 = b2.calculateDimension(stringBounder); + return Dimension2DDouble.mergeTB(dim1, dim2); + } + + public void drawTOBEREMOVED(ColorMapper colorMapper, Graphics2D g2d, double x, double y) { + throw new UnsupportedOperationException(); + } + + public void drawU(UGraphic ug, double x, double y) { + b1.drawU(ug, x, y); + final Dimension2D dim1 = b1.calculateDimension(ug.getStringBounder()); + b2.drawU(ug, x, y + dim1.getHeight()); + } + +} \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/graphic/UDrawable3.java b/src/net/sourceforge/plantuml/graphic/UDrawable3.java new file mode 100644 index 000000000..489604d3f --- /dev/null +++ b/src/net/sourceforge/plantuml/graphic/UDrawable3.java @@ -0,0 +1,42 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6577 $ + * + */ +package net.sourceforge.plantuml.graphic; + +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public interface UDrawable3 { + + void drawU(UGraphic ug, double x, double y); + +} \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/jcckit/PSystemJcckit.java b/src/net/sourceforge/plantuml/jcckit/PSystemJcckit.java new file mode 100644 index 000000000..35c67c93b --- /dev/null +++ b/src/net/sourceforge/plantuml/jcckit/PSystemJcckit.java @@ -0,0 +1,82 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 4041 $ + * + */ +package net.sourceforge.plantuml.jcckit; + +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Properties; + +import javax.imageio.ImageIO; + +import jcckit.GraphicsPlotCanvas; +import jcckit.data.DataPlot; +import jcckit.util.ConfigParameters; +import jcckit.util.PropertiesBasedConfigData; +import net.sourceforge.plantuml.AbstractPSystem; +import net.sourceforge.plantuml.FileFormatOption; + +public class PSystemJcckit extends AbstractPSystem { + + private final PropertiesBasedConfigData prop; + private final int width; + private final int height; + + public PSystemJcckit(Properties p, int width, int height) { + this.width = width; + this.height = height; + prop = new PropertiesBasedConfigData(p); + } + + public void exportDiagram(OutputStream os, StringBuilder cmap, int index, FileFormatOption fileFormat) + throws IOException { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + + // Sets up a Graphics2DPlotCanvas + ConfigParameters config = new ConfigParameters(prop); + GraphicsPlotCanvas plotCanvas = new GraphicsPlotCanvas(config, image); + plotCanvas.connect(DataPlot.create(config)); + plotCanvas.paint(); + + // Writes the off-screen image into a PNG file + ImageIO.write(image, "png", os); + } + + public String getDescription() { + return "(JCCKit)"; + } + +} diff --git a/src/net/sourceforge/plantuml/jcckit/PSystemJcckitFactory.java b/src/net/sourceforge/plantuml/jcckit/PSystemJcckitFactory.java new file mode 100644 index 000000000..54904503b --- /dev/null +++ b/src/net/sourceforge/plantuml/jcckit/PSystemJcckitFactory.java @@ -0,0 +1,122 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3837 $ + * + */ +package net.sourceforge.plantuml.jcckit; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import net.sourceforge.plantuml.DiagramType; +import net.sourceforge.plantuml.Log; +import net.sourceforge.plantuml.PSystemBasicFactory; + +public class PSystemJcckitFactory implements PSystemBasicFactory { + + private StringBuilder data; + private boolean first; + private int width; + private int height; + + private final DiagramType diagramType; + + public PSystemJcckitFactory(DiagramType diagramType) { + this.diagramType = diagramType; + } + + + public void init(String startLine) { + this.data = null; + this.width = 640; + this.height = 400; + if (diagramType == DiagramType.UML) { + first = true; + } else if (diagramType == DiagramType.JCCKIT) { + first = false; + extractDimension(startLine); + data = new StringBuilder(); + } else { + throw new IllegalStateException(diagramType.name()); + } + + } + + private void extractDimension(String startLine) { + final Pattern p = Pattern.compile("\\((\\d+),(\\d+)\\)"); + final Matcher m = p.matcher(startLine); + final boolean ok = m.find(); + if (ok) { + width = Integer.parseInt(m.group(1)); + height = Integer.parseInt(m.group(2)); + } + } + + String getDimension() { + return ""+width+"-"+height; + } + + + public PSystemJcckit getSystem() { + final Properties p = new Properties(); + try { + p.load(new StringReader(data.toString())); + } catch (IOException e) { + Log.error("Error " + e); + e.printStackTrace(); + return null; + } + return new PSystemJcckit(p, width, height); + } + + public boolean executeLine(String line) { + if (first && line.startsWith("jcckit")) { + data = new StringBuilder(); + extractDimension(line); + return true; + } + first = false; + if (data == null) { + return false; + } + data.append(line.trim()); + data.append("\n"); + return true; + } + + public DiagramType getDiagramType() { + return diagramType; + } + +} diff --git a/src/net/sourceforge/plantuml/oregon/OregonBasicGame.java b/src/net/sourceforge/plantuml/oregon/OregonBasicGame.java index 4c09e9349..999b2edac 100644 --- a/src/net/sourceforge/plantuml/oregon/OregonBasicGame.java +++ b/src/net/sourceforge/plantuml/oregon/OregonBasicGame.java @@ -33,6 +33,7 @@ */ package net.sourceforge.plantuml.oregon; +import java.util.Date; import java.util.Random; public class OregonBasicGame implements BasicGame { @@ -50,11 +51,10 @@ public class OregonBasicGame implements BasicGame { private double ma; - private final String da[] = new String[] { "March 29", "April 12", "April 26", "May 10", "May 24", "June 7", "June 21", "July 5", "July 19", "August 2", "August 16", "August 31", "September 13", "September 27", "October 11", "October 25", "November 8", "November 22", "December 6", "December 20" }; - + private final int ep[] = new int[] { 6, 11, 13, 15, 17, 22, 32, 35, 37, 42, 44, 54, 64, 69, 95 }; public Screen getScreen() { @@ -439,31 +439,37 @@ public class OregonBasicGame implements BasicGame { } private void southPass2750(int j) throws NoInputException { - if (kp == 1) { - - } - kp = 1; - if (rnd() < .8) { - - } - print("You made it safely through the South Pass....no snow!"); - km = 1; - if (rnd()<.7) { - print("Blizzard in the mountain pass. Going is slow; supplies are lost."); - kb = 1; - m = m - 30 - 40 * rnd(); - f = f - 12; - b = b - 200; - r = r - 5; - if (c>=18+2*rnd()) { + if (kp == 0) { + kp = 1; + if (rnd() < .8) { + blizzard2840(j); return; } - dealWithIllness2880(j); + print("You made it safely through the South Pass....no snow!"); + } + if (m < 1700) { + return; + } + if (km == 0) { + km = 1; + if (rnd() < .7) { + blizzard2840(j); + } } } - + private void blizzard2840(int j) throws NoInputException { + print("Blizzard in the mountain pass. Going is slow; supplies are lost."); + kb = 1; + m = m - 30 - 40 * rnd(); + f = f - 12; + b = b - 200; + r = r - 5; + if (c < 18 + 2 * rnd()) { + dealWithIllness2880(j); + } + } private void dealWithIllness2880(int j) throws NoInputException { if (100 * rnd() < 10 + 35 * (e - 1)) { @@ -656,6 +662,9 @@ public class OregonBasicGame implements BasicGame { print(); print("| Cash | Food | Ammo | Clothes | Medicine/parts/... |"); print("+------+------+------+---------+--------------------+"); + if (t < 0) { + t = 0; + } if (f < 0) { f = 0; } @@ -855,62 +864,74 @@ public class OregonBasicGame implements BasicGame { private int dr; private double m; - private int getTime() { - return (int) ((System.currentTimeMillis() / 1000L) % 83); + enum ShootingWord { + POW, BANG, BLAM, WHOP, WHAM, ZING, ZACK, ZANG, WOOSH, BAM, ZAP, BOOM, WOW, CLANG, BOING, ZOW, PANG, ZOSH, KAZ, KOOG, ZOOP, PONG, PING, BAZ, ZONG, PAM, POOM, DOING; + + public static ShootingWord safeValueOf(String s) { + try { + return valueOf(s.toUpperCase()); + } catch (IllegalArgumentException e) { + return null; + } + } + + public int decode(ShootingWord key) { + return (ordinal() + key.ordinal()) % NB_WORDS; + } + + public ShootingWord encode(int v) { + v = v - this.ordinal(); + if (v < 0) { + v += NB_WORDS; + } + return ShootingWord.values()[v]; + } } - private String getRandomShootingWord() { - int rn = (int) (rnd() * 4); - switch (rn) { - case 0: - return "pow"; - case 1: - return "bang"; - case 2: - return "blam"; - } - return "whop"; + private static int NB_WORDS = ShootingWord.values().length; + + private int getTime() { + return (int) ((System.currentTimeMillis() / 1000L) % NB_WORDS); } private int shoot3870() throws NoInputException { - final String word1 = getRandomShootingWord() + getTime(); - print("Type: " + word1); + final int time1 = getTime(); + final ShootingWord word1Printed = ShootingWord.values()[time1]; + if (skb.hasMore() == false) { + print("Type: " + word1Printed); + } final String typed1 = skb.input(screen); - final int time = getDeltaTime(typed1); - final String word2 = getRandomShootingWord() + time; - print("Type: " + word2); + ShootingWord wordType1 = ShootingWord.safeValueOf(typed1); + final int delta; + if (wordType1 == null) { + delta = NB_WORDS - 1; + wordType1 = ShootingWord.values()[NB_WORDS - 1]; + } else { + delta = protect(getTime() - wordType1.ordinal()); + } + // print("delta="+delta); + final ShootingWord word2 = wordType1.encode(delta); + if (skb.hasMore() == false) { + print("Type: " + word2); + } final String typed2 = skb.input(screen); - int duration = extractInt(typed2) - dr - 1; - // 3870 'Subroutine to shoot gun - // 3880 RN = 1 + INT(4 * RND(1)) : 'Pick a random shooting word - // 3890 S1 = 60 * VAL(MID$(TIME$, 4, 2)) + VAL(RIGHT$(TIME$, 2)) : - // 'Start timer - // 3900 PRINT "Type " S$(RN); : INPUT X$ - // 3910 IF S$(RN)< >X$ AND S$(RN + 4)< >X$ THEN PRINT "Nope. Try again. - // "; : GOTO 3900 - // 3920 S2 = 60 * VAL(MID$(TIME$, 4, 2)) + VAL(RIGHT$(TIME$, 2)) : 'End - // timer - // 3930 BR = S2 - S1 - DR - 1 : RETURN + final ShootingWord wordType2 = ShootingWord.safeValueOf(typed2); + final int duration = wordType2 == null ? NB_WORDS : wordType1.decode(wordType2) - dr; + // print("duration=" + duration); if (duration < 0) { return 0; } return duration; } - private int extractInt(String typed) { - final String s = typed.replaceAll("\\D", ""); - if (s.length() == 0) { - return 0; + private int protect(int v) { + while (v >= NB_WORDS) { + v -= NB_WORDS; } - return Integer.parseInt(s); + while (v < 0) { + v += NB_WORDS; + } + return v; } - private int getDeltaTime(String typed) { - final int was = extractInt(typed); - int diff = getTime() - was; - if (diff < 0) { - diff += 83; - } - return diff; - } } diff --git a/src/net/sourceforge/plantuml/oregon/PSystemOregonFactory.java b/src/net/sourceforge/plantuml/oregon/PSystemOregonFactory.java index 0233b90f1..ef129842b 100644 --- a/src/net/sourceforge/plantuml/oregon/PSystemOregonFactory.java +++ b/src/net/sourceforge/plantuml/oregon/PSystemOregonFactory.java @@ -38,6 +38,7 @@ import java.util.List; import net.sourceforge.plantuml.DiagramType; import net.sourceforge.plantuml.PSystemBasicFactory; +import net.sourceforge.plantuml.StringUtils; public class PSystemOregonFactory implements PSystemBasicFactory { @@ -67,7 +68,9 @@ public class PSystemOregonFactory implements PSystemBasicFactory { if (inputs == null) { return false; } - inputs.add(line); + if (StringUtils.isNotEmpty(line)) { + inputs.add(line); + } return true; } diff --git a/src/net/sourceforge/plantuml/posimo/EntityImageClass2.java b/src/net/sourceforge/plantuml/posimo/EntityImageClass2.java index 17e813805..351ba0f24 100644 --- a/src/net/sourceforge/plantuml/posimo/EntityImageClass2.java +++ b/src/net/sourceforge/plantuml/posimo/EntityImageClass2.java @@ -206,12 +206,12 @@ public class EntityImageClass2 extends AbstractEntityImage2 { x = xTheoricalPosition; ug.getParam().setColor(getColor(ColorParam.classBorder)); ug.draw(x, y, new ULine(widthTotal, 0)); - fields.draw(ug, x + xMarginFieldsOrMethod, y); + fields.drawU(ug, x + xMarginFieldsOrMethod, y); y += getMethodOrFieldHeight(fields.calculateDimension(stringBounder)); ug.getParam().setColor(getColor(ColorParam.classBorder)); ug.draw(x, y, new ULine(widthTotal, 0)); - methods.draw(ug, x + xMarginFieldsOrMethod, y); + methods.drawU(ug, x + xMarginFieldsOrMethod, y); } } diff --git a/src/net/sourceforge/plantuml/posimo/PositionableImpl.java b/src/net/sourceforge/plantuml/posimo/PositionableImpl.java new file mode 100644 index 000000000..0a5d290e4 --- /dev/null +++ b/src/net/sourceforge/plantuml/posimo/PositionableImpl.java @@ -0,0 +1,62 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 4236 $ + * + */ +package net.sourceforge.plantuml.posimo; + +import java.awt.geom.Dimension2D; +import java.awt.geom.Point2D; + +public class PositionableImpl implements Positionable { + + private final Point2D pos; + + private final Dimension2D dim; + + public PositionableImpl(double x, double y, Dimension2D dim) { + this.pos = new Point2D.Double(x, y); + this.dim = dim; + } + + public PositionableImpl(Point2D pt, Dimension2D dim) { + this(pt.getX(), pt.getY(), dim); + } + + public Point2D getPosition() { + return pos; + } + + public Dimension2D getSize() { + return dim; + } + +} diff --git a/src/net/sourceforge/plantuml/posimo/PositionableUtils.java b/src/net/sourceforge/plantuml/posimo/PositionableUtils.java index ee8919b78..be9bf5a33 100644 --- a/src/net/sourceforge/plantuml/posimo/PositionableUtils.java +++ b/src/net/sourceforge/plantuml/posimo/PositionableUtils.java @@ -68,6 +68,36 @@ public class PositionableUtils { return true; } + static public boolean intersect(Positionable big, Positionable small) { + final Rectangle2D bigR = convert(big); + final Rectangle2D smallR = convert(small); + return bigR.intersects(smallR); + // final Point2D pt = small.getPosition(); + // final Dimension2D dim = small.getSize(); + // + // if (contains(big, pt)) { + // return true; + // } + // if (contains(big, new Point2D.Double(pt.getX() + dim.getWidth(), + // pt.getY()))) { + // return true; + // } + // if (contains(big, new Point2D.Double(pt.getX() + dim.getWidth(), + // pt.getY() + dim.getHeight()))) { + // return true; + // } + // if (contains(big, new Point2D.Double(pt.getX(), pt.getY() + + // dim.getHeight()))) { + // return true; + // } + // return false; + } + + // + // public boolean intersect(Positionable p) { + // return intersect(p.getPosition(), p.getSize()); + // } + static public Positionable addMargin(final Positionable pos, final double widthMargin, final double heightMargin) { return new Positionable() { @@ -86,4 +116,57 @@ public class PositionableUtils { return new Rectangle2D.Double(rect.getX() + dx, rect.getY() + dy, rect.getWidth(), rect.getHeight()); } + static public Point2D getCenter(Positionable p) { + final Point2D pt = p.getPosition(); + final Dimension2D dim = p.getSize(); + return new Point2D.Double(pt.getX() + dim.getWidth() / 2, pt.getY() + dim.getHeight() / 2); + } + + static public Positionable move(Positionable p, double deltaX, double deltaY) { + final Point2D pt = p.getPosition(); + final Dimension2D dim = p.getSize(); + return new PositionableImpl(pt.getX() + deltaX, pt.getY() + deltaY, dim); + + } + + public static Positionable moveAwayFrom(Positionable fixe, Positionable toMove) { + final Point2D centerFixe = getCenter(fixe); + final Point2D centerToMove = getCenter(toMove); + // final Point2D pt = toMove.getPosition(); + // return new PositionableImpl(pt.getX() + 20, pt.getY(), + // toMove.getSize()); + + final double deltaX = (centerToMove.getX() - centerFixe.getX()); + final double deltaY = (centerToMove.getY() - centerFixe.getY()); + + double min = 0.0; + if (doesIntersectWithThisCoef(fixe, toMove, deltaX, deltaY, min) == false) { + throw new IllegalArgumentException(); + } + double max = 0.1; + while (doesIntersectWithThisCoef(fixe, toMove, deltaX, deltaY, max)) { + max = max * 2; + } + for (int i = 0; i < 5; i++) { + assert doesIntersectWithThisCoef(fixe, toMove, deltaX, deltaY, min); + assert doesIntersectWithThisCoef(fixe, toMove, deltaX, deltaY, max) == false; + final double candidat = (min + max) / 2.0; + if (doesIntersectWithThisCoef(fixe, toMove, deltaX, deltaY, candidat)) { + min = candidat; + } else { + max = candidat; + } + // System.err.println("min=" + min + " max=" + max); + } + final double candidat = (min + max) / 2.0; + return move(toMove, deltaX * candidat, deltaY * candidat); + + } + + private static boolean doesIntersectWithThisCoef(Positionable fixe, Positionable toMove, double deltaX, + double deltaY, double c) { + final Positionable result = move(toMove, deltaX * c, deltaY * c); + return intersect(fixe, result); + } + } diff --git a/src/net/sourceforge/plantuml/postit/PostIt.java b/src/net/sourceforge/plantuml/postit/PostIt.java index a8879ee1a..adf62b756 100644 --- a/src/net/sourceforge/plantuml/postit/PostIt.java +++ b/src/net/sourceforge/plantuml/postit/PostIt.java @@ -104,7 +104,7 @@ public class PostIt { final HtmlColor noteBackgroundColor = HtmlColor.getColorIfValid("#FBFB77"); final HtmlColor borderColor = HtmlColor.getColorIfValid("#A80036"); - final SkinParam param = new SkinParam(); + final SkinParam param = new SkinParam(null); final UFont fontNote = param.getFont(FontParam.NOTE, null); final ComponentRoseNote note = new ComponentRoseNote(noteBackgroundColor, borderColor, HtmlColor.BLACK, fontNote, text); diff --git a/src/net/sourceforge/plantuml/postit/PostItDiagram.java b/src/net/sourceforge/plantuml/postit/PostItDiagram.java index 98f535900..06c2fc96c 100644 --- a/src/net/sourceforge/plantuml/postit/PostItDiagram.java +++ b/src/net/sourceforge/plantuml/postit/PostItDiagram.java @@ -63,7 +63,7 @@ public class PostItDiagram extends UmlDiagram { @Override public UmlDiagramType getUmlDiagramType() { - throw new UnsupportedOperationException(); + return null; } @Override diff --git a/src/net/sourceforge/plantuml/printskin/PrintSkin.java b/src/net/sourceforge/plantuml/printskin/PrintSkin.java index 487646e58..ea4e77858 100644 --- a/src/net/sourceforge/plantuml/printskin/PrintSkin.java +++ b/src/net/sourceforge/plantuml/printskin/PrintSkin.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6591 $ + * Revision $Revision: 7173 $ * */ package net.sourceforge.plantuml.printskin; @@ -47,6 +47,7 @@ import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.EmptyImageBuilder; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.SkinParam; +import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HorizontalAlignement; import net.sourceforge.plantuml.graphic.HtmlColor; @@ -113,7 +114,7 @@ class PrintSkin extends AbstractPSystem { private void printComponent(ComponentType type) { println(type.name()); - final Component comp = skin.createComponent(type, new SkinParam(), toPrint); + final Component comp = skin.createComponent(type, new SkinParam(null), toPrint); if (comp == null) { println("null"); return; diff --git a/src/net/sourceforge/plantuml/salt/Cell.java b/src/net/sourceforge/plantuml/salt/Cell.java new file mode 100644 index 000000000..e18b1285b --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/Cell.java @@ -0,0 +1,94 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.util.Collection; +import java.util.HashSet; + +public class Cell { + + // private Collection positions = new HashSet(); + + private int minRow; + private int maxRow; + private int minCol; + private int maxCol; + + public Cell(int row, int col) { + // positions.add(p); + minRow = row; + maxRow = row; + minCol = col; + maxCol = col; + } + + public void mergeLeft() { + maxCol++; + } + + +// public Collection getPositions() { +// return positions; +// } + + public int getMinRow() { + return minRow; + } + + public int getMaxRow() { + return maxRow; + } + + public int getMinCol() { + return minCol; + } + + public int getMaxCol() { + return maxCol; + } + + public int getNbRows() { + return maxRow - minRow + 1; + } + + public int getNbCols() { + return maxCol - minCol + 1; + } + + @Override + public String toString() { + return "(" + minRow + "," + minCol + ")-(" + maxRow + "," + maxCol + ")"; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/DataSource.java b/src/net/sourceforge/plantuml/salt/DataSource.java new file mode 100644 index 000000000..3d4415315 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/DataSource.java @@ -0,0 +1,41 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.util.Iterator; + +public interface DataSource extends Iterator> { + + Terminated peek(int i); +} diff --git a/src/net/sourceforge/plantuml/salt/DataSourceImpl.java b/src/net/sourceforge/plantuml/salt/DataSourceImpl.java new file mode 100644 index 000000000..c74ebf499 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/DataSourceImpl.java @@ -0,0 +1,111 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DataSourceImpl implements DataSource { + + private int i = 0; + private final List> data = new ArrayList>(); + + public DataSourceImpl(List data) { + final Pattern p = Pattern.compile("\\{[-+#!*/]?"); + for (String s : data) { + final StringTokenizer st = new StringTokenizer(s, "|}", true); + while (st.hasMoreTokens()) { + final String token = st.nextToken().trim(); + if (token.equals("|")) { + continue; + } + final Terminator terminator = st.hasMoreTokens() ? Terminator.NEWCOL : Terminator.NEWLINE; + final Matcher m = p.matcher(token); + final boolean found = m.find(); + if (found == false) { + addInternal(token, terminator); + continue; + } + int lastStart = 0; + int end = 0; + do { + final int start = m.start(); + if (start > lastStart) { + addInternal(token.substring(lastStart, start), Terminator.NEWCOL); + } + end = m.end(); + final Terminator t = end == token.length() ? terminator : Terminator.NEWCOL; + addInternal(token.substring(start, end), t); + lastStart = end; + } while (m.find()); + if (end < token.length()) { + addInternal(token.substring(end), terminator); + } + } + } + } + + private void addInternal(String s, Terminator t) { + s = s.trim(); + if (s.length() > 0) { + data.add(new Terminated(s, t)); + } + } + + public Terminated peek(int nb) { + return data.get(i + nb); + } + + public boolean hasNext() { + return i < data.size(); + } + + public Terminated next() { + final Terminated result = data.get(i); + i++; + return result; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public String toString() { + return super.toString() + " " + (hasNext() ? peek(0) : "$$$"); + } + +} diff --git a/src/net/sourceforge/plantuml/salt/Dictionary.java b/src/net/sourceforge/plantuml/salt/Dictionary.java new file mode 100644 index 000000000..5d55dc46f --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/Dictionary.java @@ -0,0 +1,57 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.util.HashMap; +import java.util.Map; + +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.WrappedElement; + +public class Dictionary { + + private final Map data = new HashMap(); + + public void put(String name, Element element) { + data.put(name, element); + } + + public Element get(String name) { + final Element result = data.get(name); + if (result == null) { + throw new IllegalArgumentException(); + } + return new WrappedElement(result); + } +} diff --git a/src/net/sourceforge/plantuml/salt/PSystemSalt.java b/src/net/sourceforge/plantuml/salt/PSystemSalt.java new file mode 100644 index 000000000..89f45104f --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/PSystemSalt.java @@ -0,0 +1,96 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 4041 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.Dimension2D; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import javax.imageio.ImageIO; + +import net.sourceforge.plantuml.AbstractPSystem; +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.EmptyImageBuilder; +import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.g2d.UGraphicG2d; + +public class PSystemSalt extends AbstractPSystem { + + private final List data; + + public PSystemSalt(List data) { + this.data = data; + } + + public void exportDiagram(OutputStream os, StringBuilder cmap, int index, FileFormatOption fileFormat) + throws IOException { + + final Element salt = SaltUtils.createElement(data); + + EmptyImageBuilder builder = new EmptyImageBuilder(10, 10, Color.WHITE); + Graphics2D g2d = builder.getGraphics2D(); + + final Dimension2D size = salt.getPreferredDimension(new UGraphicG2d(new ColorMapperIdentity(), g2d, null, 1.0) + .getStringBounder(), 0, 0); + g2d.dispose(); + + builder = new EmptyImageBuilder(size.getWidth() + 6, size.getHeight() + 6, Color.WHITE); + final BufferedImage im = builder.getBufferedImage(); + g2d = builder.getGraphics2D(); + g2d.translate(3, 3); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + final UGraphic ug = new UGraphicG2d(new ColorMapperIdentity(), g2d, null, 1.0); + ug.getParam().setColor(HtmlColor.BLACK); + salt.drawU(ug, 0, 0, 0, new Dimension2DDouble(size.getWidth(), size.getHeight())); + salt.drawU(ug, 0, 0, 1, new Dimension2DDouble(size.getWidth(), size.getHeight())); + g2d.dispose(); + + // Writes the off-screen image into a PNG file + ImageIO.write(im, "png", os); + } + + public String getDescription() { + return "(Salt)"; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/PSystemSaltFactory.java b/src/net/sourceforge/plantuml/salt/PSystemSaltFactory.java new file mode 100644 index 000000000..4f6195e42 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/PSystemSaltFactory.java @@ -0,0 +1,87 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3837 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.DiagramType; +import net.sourceforge.plantuml.PSystemBasicFactory; + +public class PSystemSaltFactory implements PSystemBasicFactory { + + private List data2; + private boolean first; + + private final DiagramType diagramType; + + public PSystemSaltFactory(DiagramType diagramType) { + this.diagramType = diagramType; + } + + public void init(String startLine) { + this.data2 = null; + if (diagramType == DiagramType.UML) { + first = true; + } else if (diagramType == DiagramType.SALT) { + first = false; + data2 = new ArrayList(); + } else { + throw new IllegalStateException(diagramType.name()); + } + + } + + public PSystemSalt getSystem() { + return new PSystemSalt(data2); + } + + public boolean executeLine(String line) { + if (first && line.equals("salt")) { + data2 = new ArrayList(); + return true; + } + first = false; + if (data2 == null) { + return false; + } + data2.add(line.trim()); + return true; + } + + public DiagramType getDiagramType() { + return diagramType; + } + +} diff --git a/src/net/sourceforge/plantuml/swing/SimpleLine.java b/src/net/sourceforge/plantuml/salt/Position.java similarity index 59% rename from src/net/sourceforge/plantuml/swing/SimpleLine.java rename to src/net/sourceforge/plantuml/salt/Position.java index 4085307e6..26582959f 100644 --- a/src/net/sourceforge/plantuml/swing/SimpleLine.java +++ b/src/net/sourceforge/plantuml/salt/Position.java @@ -28,50 +28,38 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 3837 $ + * Revision $Revision: 3835 $ * */ -package net.sourceforge.plantuml.swing; +package net.sourceforge.plantuml.salt; -import net.sourceforge.plantuml.GeneratedImage; +public class Position { -class SimpleLine implements Comparable { + final private int row; + final private int col; - private final GeneratedImage generatedImage; - - public SimpleLine(GeneratedImage generatedImage) { - this.generatedImage = generatedImage; + public Position(int row, int col) { + this.row = row; + this.col = col; } - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(generatedImage.getPngFile().getName()); - sb.append(" "); - sb.append(generatedImage.getDescription()); - return sb.toString(); + public int getRow() { + return row; + } + + public int getCol() { + return col; } @Override public int hashCode() { - return generatedImage.hashCode(); + return row * 49 + col; } @Override public boolean equals(Object obj) { - final SimpleLine this2 = (SimpleLine) obj; - return this2.generatedImage.equals(this.generatedImage); - } - - public boolean exists() { - return generatedImage.getPngFile().exists(); - } - - public int compareTo(SimpleLine this2) { - return this.generatedImage.compareTo(this2.generatedImage); - } - - public GeneratedImage getGeneratedImage() { - return generatedImage; + final Position other = (Position) obj; + return row == other.row && col == other.col; } } diff --git a/src/net/sourceforge/plantuml/salt/Positionner.java b/src/net/sourceforge/plantuml/salt/Positionner.java new file mode 100644 index 000000000..50c0695f8 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/Positionner.java @@ -0,0 +1,85 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import net.sourceforge.plantuml.salt.element.Element; + +public class Positionner { + + private int row; + private int col; + + private int maxRow; + private int maxCol; + + private final Map positions = new LinkedHashMap(); + + public void add(Terminated element) { + positions.put(element.getElement(), new Position(row, col)); + updateMax(); + final Terminator terminator = element.getTerminator(); + if (terminator == Terminator.NEWCOL) { + col++; + } else { + row++; + col = 0; + } + } + + private void updateMax() { + if (row > maxRow) { + maxRow = row; + } + if (col > maxCol) { + maxCol = col; + } + } + + public Map getAll() { + return Collections.unmodifiableMap(positions); + } + + public final int getNbRows() { + return maxRow + 1; + } + + public final int getNbCols() { + return maxCol + 1; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/Positionner2.java b/src/net/sourceforge/plantuml/salt/Positionner2.java new file mode 100644 index 000000000..84fd254d6 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/Positionner2.java @@ -0,0 +1,99 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import net.sourceforge.plantuml.salt.element.Element; + +public class Positionner2 { + + private int row; + private int col; + + private int maxRow; + private int maxCol; + + private final Map positions = new LinkedHashMap(); + + private Cell last; + + public void add(Terminated element) { + last = new Cell(row, col); + positions.put(element.getElement(), last); + updateMax(); + final Terminator terminator = element.getTerminator(); + if (terminator == Terminator.NEWCOL) { + col++; + } else { + row++; + col = 0; + } + } + + public void mergeLeft(Terminator terminator) { + updateMax(); + if (terminator == Terminator.NEWCOL) { + col++; + } else { + row++; + col = 0; + } + last.mergeLeft(); + } + + private void updateMax() { + if (row > maxRow) { + maxRow = row; + } + if (col > maxCol) { + maxCol = col; + } + } + + public Map getAll() { + return Collections.unmodifiableMap(positions); + } + + public final int getNbRows() { + return maxRow + 1; + } + + public final int getNbCols() { + return maxCol + 1; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/SaltUtils.java b/src/net/sourceforge/plantuml/salt/SaltUtils.java new file mode 100644 index 000000000..ccc779475 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/SaltUtils.java @@ -0,0 +1,110 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.factory.AbstractElementFactoryComplex; +import net.sourceforge.plantuml.salt.factory.ElementFactory; +import net.sourceforge.plantuml.salt.factory.ElementFactoryBorder; +import net.sourceforge.plantuml.salt.factory.ElementFactoryButton; +import net.sourceforge.plantuml.salt.factory.ElementFactoryCheckboxOff; +import net.sourceforge.plantuml.salt.factory.ElementFactoryCheckboxOn; +import net.sourceforge.plantuml.salt.factory.ElementFactoryDroplist; +import net.sourceforge.plantuml.salt.factory.ElementFactoryImage; +import net.sourceforge.plantuml.salt.factory.ElementFactoryLine; +import net.sourceforge.plantuml.salt.factory.ElementFactoryMenu; +import net.sourceforge.plantuml.salt.factory.ElementFactoryPyramid; +import net.sourceforge.plantuml.salt.factory.ElementFactoryPyramid2; +import net.sourceforge.plantuml.salt.factory.ElementFactoryRadioOff; +import net.sourceforge.plantuml.salt.factory.ElementFactoryRadioOn; +import net.sourceforge.plantuml.salt.factory.ElementFactoryRetrieveFromDictonnary; +import net.sourceforge.plantuml.salt.factory.ElementFactoryTab; +import net.sourceforge.plantuml.salt.factory.ElementFactoryText; +import net.sourceforge.plantuml.salt.factory.ElementFactoryTextField; + +public class SaltUtils { + + public static Element createElement(List data) { + final DataSourceImpl source = new DataSourceImpl(data); + + final Collection cpx = new ArrayList(); + + final Dictionary dictionnary = new Dictionary(); + + // cpx.add(new ElementFactorySimpleFrame(source, dictionnary)); + cpx.add(new ElementFactoryPyramid2(source, dictionnary)); + cpx.add(new ElementFactoryBorder(source, dictionnary)); + + for (AbstractElementFactoryComplex f : cpx) { + addSimpleFactory(f, source, dictionnary); + } + for (AbstractElementFactoryComplex f1 : cpx) { + for (AbstractElementFactoryComplex f2 : cpx) { + f1.addFactory(f2); + } + } + + for (ElementFactory f : cpx) { + if (f.ready()) { + return f.create().getElement(); + } + } + + System.err.println("data="+data); + throw new IllegalArgumentException(); + + } + + private static void addSimpleFactory(final AbstractElementFactoryComplex cpxFactory, final DataSource source, + Dictionary dictionnary) { + cpxFactory.addFactory(new ElementFactoryMenu(source, dictionnary)); + cpxFactory.addFactory(new ElementFactoryTab(source, dictionnary)); + cpxFactory.addFactory(new ElementFactoryLine(source)); + cpxFactory.addFactory(new ElementFactoryTextField(source)); + cpxFactory.addFactory(new ElementFactoryButton(source)); + cpxFactory.addFactory(new ElementFactoryDroplist(source)); + cpxFactory.addFactory(new ElementFactoryRadioOn(source)); + cpxFactory.addFactory(new ElementFactoryRadioOff(source)); + cpxFactory.addFactory(new ElementFactoryCheckboxOn(source)); + cpxFactory.addFactory(new ElementFactoryCheckboxOff(source)); + cpxFactory.addFactory(new ElementFactoryImage(source, dictionnary)); + cpxFactory.addFactory(new ElementFactoryRetrieveFromDictonnary(source, dictionnary)); + cpxFactory.addFactory(new ElementFactoryText(source)); + } + +} diff --git a/src/net/sourceforge/plantuml/salt/Terminated.java b/src/net/sourceforge/plantuml/salt/Terminated.java new file mode 100644 index 000000000..bd7ca3bf1 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/Terminated.java @@ -0,0 +1,61 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +public class Terminated { + + private final O element; + private final Terminator terminator; + + public Terminated(O element, Terminator terminator) { + if (terminator == null) { + throw new IllegalArgumentException(); + } + this.element = element; + this.terminator = terminator; + } + + public O getElement() { + return element; + } + + public Terminator getTerminator() { + return terminator; + } + + public String toString() { + return element.toString() + " " + terminator; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/Terminator.java b/src/net/sourceforge/plantuml/salt/Terminator.java new file mode 100644 index 000000000..fd48ec6fd --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/Terminator.java @@ -0,0 +1,38 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt; + +public enum Terminator { + NEWLINE, NEWCOL +} diff --git a/src/net/sourceforge/plantuml/salt/element/AbstractElementText.java b/src/net/sourceforge/plantuml/salt/element/AbstractElementText.java new file mode 100644 index 000000000..f6d273600 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/AbstractElementText.java @@ -0,0 +1,102 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.Arrays; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignement; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +abstract class AbstractElementText implements Element { + + private final TextBlock block; + private final FontConfiguration config; + private final int charLength; + + public AbstractElementText(String text, UFont font, boolean manageLength) { + config = new FontConfiguration(font, HtmlColor.BLACK); + if (manageLength) { + this.charLength = text.length(); + text = text.trim(); + } else { + this.charLength = 0; + } + this.block = TextBlockUtils.create(Arrays.asList(text), config, HorizontalAlignement.LEFT); + } + + protected void drawText(UGraphic ug, double x, double y) { + block.drawU(ug, x, y); + } + + protected Dimension2D getPureTextDimension(StringBounder stringBounder) { + return block.calculateDimension(stringBounder); + } + + protected Dimension2D getTextDimensionAt(StringBounder stringBounder, double x) { + final Dimension2D result = block.calculateDimension(stringBounder); + if (charLength == 0) { + return result; + } + final double dimSpace = getSingleSpace(stringBounder); + // final double endx = x + result.getWidth(); + // final double mod = endx % CHAR_SIZE; + // final double delta = charLength * CHAR_SIZE - mod; + // return Dimension2DDouble.delta(result, delta, 0); + return new Dimension2DDouble(Math.max(result.getWidth(), charLength * dimSpace), result.getHeight()); + } + + private double getSingleSpace(StringBounder stringBounder) { +// double max = 0; +// for (int i = 32; i < 127; i++) { +// final char c = (char) i; +// final double w = TextBlockUtils.create(Arrays.asList("" + c), config, HorizontalAlignement.LEFT) +// .calculateDimension(stringBounder).getWidth(); +// if (w > max) { +// System.err.println("c="+c+" "+max); +// max = w; +// } +// } +// return max; + return 8; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/Element.java b/src/net/sourceforge/plantuml/salt/element/Element.java new file mode 100644 index 000000000..6304ed55a --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/Element.java @@ -0,0 +1,48 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UGraphic; + + +public interface Element { + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y); + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse); + +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementBorder.java b/src/net/sourceforge/plantuml/salt/element/ElementBorder.java new file mode 100644 index 000000000..c858128ac --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementBorder.java @@ -0,0 +1,104 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.awt.geom.Point2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.MathUtils; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class ElementBorder implements Element { + + private Element north = new ElementEmpty(); + private Element south = new ElementEmpty(); + private Element east = new ElementEmpty(); + private Element west = new ElementEmpty(); + private Element center = new ElementEmpty(); + + public final void setNorth(Element north) { + this.north = north; + } + + public final void setSouth(Element south) { + this.south = south; + } + + public final void setEast(Element east) { + this.east = east; + } + + public final void setWest(Element west) { + this.west = west; + } + + public final void setCenter(Element center) { + this.center = center; + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + final StringBounder stringBounder = ug.getStringBounder(); + final Dimension2D dimNorth = north.getPreferredDimension(stringBounder, x, y); + final Dimension2D dimSouth = south.getPreferredDimension(stringBounder, x, y); + final Dimension2D dimEast = east.getPreferredDimension(stringBounder, x, y); + final Dimension2D dimWest = west.getPreferredDimension(stringBounder, x, y); + final Point2D pA = new Point2D.Double(dimWest.getWidth(), dimNorth.getHeight()); + final Point2D pB = new Point2D.Double(dimToUse.getWidth() - dimEast.getWidth(), dimNorth.getHeight()); + final Point2D pC = new Point2D.Double(dimWest.getWidth(), dimToUse.getHeight() - dimSouth.getHeight()); + final Point2D pD = new Point2D.Double(dimToUse.getWidth() - dimEast.getWidth(), dimToUse.getHeight() + - dimSouth.getHeight()); + + north.drawU(ug, x, y, zIndex, dimToUse); + south.drawU(ug, x, y + pC.getY(), zIndex, dimToUse); + west.drawU(ug, x, y + pA.getY(), zIndex, dimToUse); + east.drawU(ug, x + pB.getX(), y + pB.getY(), zIndex, dimToUse); + center.drawU(ug, x + pA.getX(), y + pA.getY(), zIndex, dimToUse); + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + final Dimension2D dimNorth = north.getPreferredDimension(stringBounder, x, y); + final Dimension2D dimSouth = south.getPreferredDimension(stringBounder, x, y); + final Dimension2D dimEast = east.getPreferredDimension(stringBounder, x, y); + final Dimension2D dimWest = west.getPreferredDimension(stringBounder, x, y); + final Dimension2D dimCenter = center.getPreferredDimension(stringBounder, x, y); + final double width = MathUtils.max(dimNorth.getWidth(), dimSouth.getWidth(), dimWest.getWidth() + + dimCenter.getWidth() + dimEast.getWidth()); + final double height = dimNorth.getHeight() + + MathUtils.max(dimWest.getHeight(), dimCenter.getHeight(), dimEast.getHeight()) + dimSouth.getHeight(); + return new Dimension2DDouble(width, height); + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementButton.java b/src/net/sourceforge/plantuml/salt/element/ElementButton.java new file mode 100644 index 000000000..850916d5b --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementButton.java @@ -0,0 +1,73 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UStroke; + +public class ElementButton extends AbstractElementText implements Element { + + private final double stroke = 2.5; + private final double marginX = 2; + private final double marginY = 2; + + public ElementButton(String text, UFont font) { + super(text, font, true); + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + Dimension2D dim = getTextDimensionAt(stringBounder, x + stroke + marginX); + dim = Dimension2DDouble.delta(dim, 2 * marginX, 2 * marginY); + return Dimension2DDouble.delta(dim, 2 * stroke); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 0) { + return; + } + final Dimension2D dim = getPreferredDimension(ug.getStringBounder(), x, y); + final Dimension2D dimPureText = getPureTextDimension(ug.getStringBounder()); + drawText(ug, x + (dim.getWidth() - dimPureText.getWidth()) / 2, y + stroke + marginY); + ug.getParam().setStroke(new UStroke(stroke)); + ug.draw(x + stroke, y + stroke, new URectangle(dim.getWidth() - 2 * stroke, dim.getHeight() - 2 * stroke, 10, + 10)); + ug.getParam().setStroke(new UStroke()); + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementDroplist.java b/src/net/sourceforge/plantuml/salt/element/ElementDroplist.java new file mode 100644 index 000000000..b7821eb24 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementDroplist.java @@ -0,0 +1,79 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.UPolygon; +import net.sourceforge.plantuml.ugraphic.URectangle; + +public class ElementDroplist extends AbstractElementText implements Element { + + private final int box = 12; + + public ElementDroplist(String text, UFont font) { + super(text, font, true); + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + final Dimension2D dim = getTextDimensionAt(stringBounder, x + 2); + return Dimension2DDouble.delta(dim, 4 + box, 4); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 0) { + return; + } + drawText(ug, x + 2, y + 2); + final Dimension2D dim = getPreferredDimension(ug.getStringBounder(), 0, 0); + ug.draw(x, y, new URectangle(dim.getWidth() - 1, dim.getHeight() - 1)); + final double xline = dim.getWidth() - box; + ug.draw(x + xline, y, new ULine(0, dim.getHeight() - 1)); + + final UPolygon poly = new UPolygon(); + poly.addPoint(0, 0); + poly.addPoint(box - 6, 0); + final Dimension2D dimText = getPureTextDimension(ug.getStringBounder()); + poly.addPoint((box - 6) / 2, dimText.getHeight() - 8); + ug.getParam().setBackcolor(ug.getParam().getColor()); + + ug.draw(x + xline + 3, y + 6, poly); + ug.getParam().setBackcolor(null); + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementEmpty.java b/src/net/sourceforge/plantuml/salt/element/ElementEmpty.java new file mode 100644 index 000000000..1254a5f9b --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementEmpty.java @@ -0,0 +1,50 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class ElementEmpty implements Element { + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + return new Dimension2DDouble(1, 1); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementImage.java b/src/net/sourceforge/plantuml/salt/element/ElementImage.java new file mode 100644 index 000000000..d16fed67c --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementImage.java @@ -0,0 +1,71 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.List; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UPixel; + +public class ElementImage implements Element { + + private final List img; + + public ElementImage(List img) { + this.img = img; + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + return new Dimension2DDouble(img.get(0).length(), img.size()); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 0) { + return; + } + final int w = img.get(0).length(); + final int h = img.size(); + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + final char c = img.get(j).charAt(i); + if (c == 'X') { + ug.draw(x + i, y + j, new UPixel()); + } + } + } + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementLine.java b/src/net/sourceforge/plantuml/salt/element/ElementLine.java new file mode 100644 index 000000000..7581b7d37 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementLine.java @@ -0,0 +1,59 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; + +public class ElementLine implements Element { + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + return new Dimension2DDouble(10, 8); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 0) { + return; + } + final HtmlColor old = ug.getParam().getColor(); + ug.getParam().setColor(HtmlColor.getColorIfValid("#AAAAAA")); + ug.draw(x, y, new ULine(dimToUse.getWidth(), 0)); + ug.getParam().setColor(old); + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementMenuBar.java b/src/net/sourceforge/plantuml/salt/element/ElementMenuBar.java new file mode 100644 index 000000000..01382619c --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementMenuBar.java @@ -0,0 +1,128 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.URectangle; + +public class ElementMenuBar implements Element { + + private final Collection entries = new ArrayList(); + private final Map popups = new HashMap(); + private final UFont font; + + public ElementMenuBar(UFont font) { + this.font = font; + } + + public void addEntry(String s) { + entries.add(new ElementMenuEntry(s, font)); + } + + public void addSubEntry(String s, String sub) { + final ElementMenuPopup popup = getPopup(getElementMenuEntry(s)); + popup.addEntry(sub); + } + + private ElementMenuPopup getPopup(ElementMenuEntry s) { + ElementMenuPopup popup = popups.get(s); + if (popup == null) { + popup = new ElementMenuPopup(font); + popups.put(s, popup); + } + return popup; + } + + private ElementMenuEntry getElementMenuEntry(String n) { + for (ElementMenuEntry entry : entries) { + if (entry.getText().equals(n)) { + return entry; + } + } + throw new IllegalArgumentException(); + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + double w = 0; + double h = 0; + for (ElementMenuEntry entry : entries) { + final Dimension2D dim = entry.getPreferredDimension(stringBounder, x, y); + w += dim.getWidth() + 10; + h = Math.max(h, dim.getHeight()); + } + return new Dimension2DDouble(w, h); + } + + public void drawU(UGraphic ug, final double x, final double y, int zIndex, Dimension2D dimToUse) { + final Dimension2D preferred = getPreferredDimension(ug.getStringBounder(), x, y); + + double x1 = x; + if (zIndex == 0) { + ug.getParam().setBackcolor(HtmlColor.getColorIfValid("#DDDDDD")); + ug.draw(x, y, new URectangle(dimToUse.getWidth(), dimToUse.getHeight())); + ug.getParam().setBackcolor(null); + for (ElementMenuEntry entry : entries) { + entry.drawU(ug, x1, y, zIndex, dimToUse); + final double w = entry.getPreferredDimension(ug.getStringBounder(), x1, y).getWidth(); + entry.setX(x1); + x1 += w + 10; + } + return; + } + + if (zIndex == 1) { + for (ElementMenuEntry entry : popups.keySet()) { + entry.setBackground(HtmlColor.getColorIfValid("#BBBBBB")); + } + + final double y1 = y + preferred.getHeight(); + for (Map.Entry ent : popups.entrySet()) { + final ElementMenuPopup p = ent.getValue(); + final double xpopup = ent.getKey().getX(); + p.drawU(ug, xpopup, y1, zIndex, p.getPreferredDimension(ug.getStringBounder(), xpopup, y1)); + } + } + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementMenuEntry.java b/src/net/sourceforge/plantuml/salt/element/ElementMenuEntry.java new file mode 100644 index 000000000..2a5f1581a --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementMenuEntry.java @@ -0,0 +1,99 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.Arrays; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignement; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.URectangle; + +public class ElementMenuEntry implements Element { + + private final TextBlock block; + private final String text; + private HtmlColor background; + private double x; + + public ElementMenuEntry(String text, UFont font) { + final FontConfiguration config = new FontConfiguration(font, HtmlColor.BLACK); + this.block = TextBlockUtils.create(Arrays.asList(text), config, HorizontalAlignement.LEFT); + this.text = text; + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + if (text.equals("-")) { + return new Dimension2DDouble(10, 5); + } + return block.calculateDimension(stringBounder); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (background!=null) { + final Dimension2D dim = getPreferredDimension(ug.getStringBounder(), x, y); + ug.getParam().setBackcolor(background); + ug.draw(x, y, new URectangle(dim.getWidth(), dim.getHeight())); + ug.getParam().setBackcolor(null); + } + block.drawU(ug, x, y); + } + + public double getX() { + return x; + } + + public void setX(double x) { + this.x = x; + } + + public String getText() { + return text; + } + + public HtmlColor getBackground() { + return background; + } + + public void setBackground(HtmlColor background) { + this.background = background; + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementMenuPopup.java b/src/net/sourceforge/plantuml/salt/element/ElementMenuPopup.java new file mode 100644 index 000000000..eee5b6ec1 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementMenuPopup.java @@ -0,0 +1,91 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.ArrayList; +import java.util.Collection; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.URectangle; + +public class ElementMenuPopup implements Element { + + private final Collection entries = new ArrayList(); + private final UFont font; + + public ElementMenuPopup(UFont font) { + this.font = font; + } + + public void addEntry(String s) { + entries.add(new ElementMenuEntry(s, font)); + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + double w = 0; + double h = 0; + for (ElementMenuEntry entry : entries) { + final Dimension2D dim = entry.getPreferredDimension(stringBounder, x, y); + w = Math.max(w, dim.getWidth()); + h += dim.getHeight(); + } + return new Dimension2DDouble(w, h); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 1) { + return; + } + ug.getParam().setBackcolor(HtmlColor.getColorIfValid("#DDDDDD")); + ug.draw(x, y, new URectangle(dimToUse.getWidth(), dimToUse.getHeight())); + ug.getParam().setBackcolor(null); + + for (ElementMenuEntry entry : entries) { + final double h = entry.getPreferredDimension(ug.getStringBounder(), x, y).getHeight(); + if (entry.getText().equals("-")) { + ug.draw(x, y + h / 2, new ULine(dimToUse.getWidth(), 0)); + } else { + entry.drawU(ug, x, y, zIndex, dimToUse); + } + y += h; + } + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementPyramid.java b/src/net/sourceforge/plantuml/salt/element/ElementPyramid.java new file mode 100644 index 000000000..4b4a4682c --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementPyramid.java @@ -0,0 +1,154 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.Map; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.salt.Position; +import net.sourceforge.plantuml.salt.Positionner; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.URectangle; + +public class ElementPyramid implements Element { + + private final Element elements[][]; + private final int rows; + private final int cols; + private final TableStrategy tableStrategy; + + public ElementPyramid(Positionner positionner, TableStrategy tableStrategy) { + this.rows = positionner.getNbRows(); + this.cols = positionner.getNbCols(); + this.tableStrategy = tableStrategy; + if (rows == 0) { + throw new IllegalArgumentException("rows=0"); + } + if (cols == 0) { + throw new IllegalArgumentException("cols=0"); + } + this.elements = new Element[rows][cols]; + for (int r = 0; r < rows; r++) { + for (int c = 0; c < cols; c++) { + this.getElements()[r][c] = new ElementEmpty(); + } + } + + for (Map.Entry ent : positionner.getAll().entrySet()) { + final int r = ent.getValue().getRow(); + final int c = ent.getValue().getCol(); + this.getElements()[r][c] = ent.getKey(); + } + } + + private double getRowHeight(StringBounder stringBounder, int row) { + double max = 0; + for (int c = 0; c < cols; c++) { + final Dimension2D dim = elements[row][c].getPreferredDimension(stringBounder, 0, 0); + if (dim.getHeight() > max) { + max = dim.getHeight(); + } + } + return max; + } + + private double getColWidth(StringBounder stringBounder, int col) { + double max = 0; + for (int r = 0; r < rows; r++) { + final Dimension2D dim = elements[r][col].getPreferredDimension(stringBounder, 0, 0); + if (dim.getWidth() > max) { + max = dim.getWidth(); + } + } + return max; + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + double width = 1; + for (int c = 0; c < cols; c++) { + width += getColWidth(stringBounder, c) + 3; + } + double height = 1; + for (int r = 0; r < rows; r++) { + height += getRowHeight(stringBounder, r) + 3; + } + return new Dimension2DDouble(width, height); + } + + public void drawU(UGraphic ug, final double x, final double y, int zIndex, Dimension2D dimToUse) { + double ytmp = y + 2; + final Dimension2D preferred = getPreferredDimension(ug.getStringBounder(), 0, 0); + if (tableStrategy == TableStrategy.DRAW_OUTSIDE || tableStrategy == TableStrategy.DRAW_ALL) { + ug.draw(x, y, new URectangle(preferred.getWidth() - 1, preferred.getHeight() - 1)); + } + for (int r = 0; r < rows; r++) { + double xtmp = x + 2; + final double rowHeight = getRowHeight(ug.getStringBounder(), r); + for (int c = 0; c < cols; c++) { + final double colWidth = getColWidth(ug.getStringBounder(), c); + this.elements[r][c].drawU(ug, xtmp, ytmp, zIndex, new Dimension2DDouble(colWidth, rowHeight)); + if (tableStrategy == TableStrategy.DRAW_ALL || tableStrategy == TableStrategy.DRAW_VERTICAL) { + ug.draw(xtmp - 2, y, new ULine(0, preferred.getHeight() - 1)); + } + xtmp += colWidth + 3; + } + if (tableStrategy == TableStrategy.DRAW_VERTICAL) { + ug.draw(xtmp - 2, y, new ULine(0, preferred.getHeight() - 1)); + } + if (tableStrategy == TableStrategy.DRAW_ALL || tableStrategy == TableStrategy.DRAW_HORIZONTAL) { + ug.draw(x, ytmp - 2, new ULine(preferred.getWidth() - 1, 0)); + } + ytmp += rowHeight + 3; + } + if (tableStrategy == TableStrategy.DRAW_HORIZONTAL) { + ug.draw(x, ytmp - 2, new ULine(preferred.getWidth() - 1, 0)); + } + } + + protected final Element[][] getElements() { + return elements; + } + +// public final int getRows() { +// return rows; +// } +// +// public final int getCols() { +// return cols; +// } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementPyramid2.java b/src/net/sourceforge/plantuml/salt/element/ElementPyramid2.java new file mode 100644 index 000000000..38b2de811 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementPyramid2.java @@ -0,0 +1,152 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.salt.Cell; +import net.sourceforge.plantuml.salt.Positionner2; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class ElementPyramid2 implements Element { + + private int rows; + private int cols; + private final TableStrategy tableStrategy; + private final Map positions1; + private final Map positions2 = new HashMap(); + + private double rowsStart[]; + private double colsStart[]; + + public ElementPyramid2(Positionner2 positionner, TableStrategy tableStrategy) { + positions1 = positionner.getAll(); + for (Map.Entry ent : positions1.entrySet()) { + positions2.put(ent.getValue(), ent.getKey()); + } + + this.rows = positionner.getNbRows(); + this.cols = positionner.getNbCols(); + this.tableStrategy = tableStrategy; + + for (Cell c : positions1.values()) { + rows = Math.max(rows, c.getMaxRow()); + cols = Math.max(cols, c.getMaxCol()); + } + + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + init(stringBounder); + return new Dimension2DDouble(colsStart[colsStart.length - 1], rowsStart[rowsStart.length - 1]); + } + + public void drawU(UGraphic ug, final double x, final double y, int zIndex, Dimension2D dimToUse) { + init(ug.getStringBounder()); + final Grid grid = new Grid(rowsStart, colsStart, tableStrategy); + for (Map.Entry ent : positions1.entrySet()) { + final Element elt = ent.getKey(); + final Cell cell = ent.getValue(); + final double xcell = colsStart[cell.getMinCol()]; + final double ycell = rowsStart[cell.getMinRow()]; + final double width = colsStart[cell.getMaxCol() + 1] - colsStart[cell.getMinCol()] - 1; + final double height = rowsStart[cell.getMaxRow() + 1] - rowsStart[cell.getMinRow()] - 1; + grid.addCell(cell); + // ug.draw(x + xcell, y + ycell, new ULine(width, 0)); + // ug.draw(x + xcell, y + ycell, new ULine(0, height)); + // ug.draw(x + xcell, y + ycell, new URectangle(width, height)); + elt.drawU(ug, x + xcell + 1, y + ycell + 1, zIndex, new Dimension2DDouble(width, height)); + } + if (zIndex == 0) { + grid.drawU(ug, x, y); + } + } + + private void init(StringBounder stringBounder) { + if (rowsStart != null) { + return; + } + rowsStart = new double[rows + 1]; + colsStart = new double[cols + 1]; + final List all = new ArrayList(positions1.values()); + Collections.sort(all, new LeftFirst()); + for (Cell cell : all) { + final Element elt = positions2.get(cell); + final Dimension2D dim = elt.getPreferredDimension(stringBounder, 0, 0); + ensureColWidth(cell.getMinCol(), cell.getMaxCol() + 1, dim.getWidth() + 2); + } + Collections.sort(all, new TopFirst()); + for (Cell cell : all) { + final Element elt = positions2.get(cell); + final Dimension2D dim = elt.getPreferredDimension(stringBounder, 0, 0); + ensureRowHeight(cell.getMinRow(), cell.getMaxRow() + 1, dim.getHeight() + 2); + } + } + + private void ensureColWidth(int first, int last, double width) { + final double actual = colsStart[last] - colsStart[first]; + final double missing = width - actual; + if (missing > 0) { + for (int i = last; i < colsStart.length; i++) { + colsStart[i] += missing; + } + } + } + + private void ensureRowHeight(int first, int last, double height) { + final double actual = rowsStart[last] - rowsStart[first]; + final double missing = height - actual; + if (missing > 0) { + for (int i = last; i < rowsStart.length; i++) { + rowsStart[i] += missing; + } + } + } + + public final int getNbRows() { + return rows + 1; + } + + public final int getNbCols() { + return cols + 1; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementRadioCheckbox.java b/src/net/sourceforge/plantuml/salt/element/ElementRadioCheckbox.java new file mode 100644 index 000000000..0849f032b --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementRadioCheckbox.java @@ -0,0 +1,117 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.List; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignement; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.ugraphic.UEllipse; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UPolygon; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UStroke; + +public class ElementRadioCheckbox implements Element { + + private static final int RECTANGLE = 10; + private static final int ELLIPSE = 10; + private static final int ELLIPSE2 = 4; + private final TextBlock block; + private final int margin = 20; + private final double stroke = 1.5; + private final boolean radio; + private final boolean checked; + + public ElementRadioCheckbox(List text, UFont font, boolean radio, boolean checked) { + final FontConfiguration config = new FontConfiguration(font, HtmlColor.BLACK); + this.block = TextBlockUtils.create(text, config, HorizontalAlignement.LEFT); + this.radio = radio; + this.checked = checked; + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + final Dimension2D dim = block.calculateDimension(stringBounder); + return Dimension2DDouble.delta(dim, margin, 0); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 0) { + return; + } + block.drawU(ug, x + margin, y); + + final Dimension2D dim = getPreferredDimension(ug.getStringBounder(), 0, 0); + final double height = dim.getHeight(); + + ug.getParam().setStroke(new UStroke(stroke)); + if (radio) { + ug.draw(x + 2, y + (height - ELLIPSE) / 2, new UEllipse(ELLIPSE, ELLIPSE)); + if (checked) { + ug.getParam().setBackcolor(ug.getParam().getColor()); + ug + .draw(x + 2 + (ELLIPSE - ELLIPSE2) / 2, y + (height - ELLIPSE2) / 2, new UEllipse(ELLIPSE2, + ELLIPSE2)); + ug.getParam().setBackcolor(null); + } + } else { + ug.draw(x + 2, y + (height - RECTANGLE) / 2, new URectangle(RECTANGLE, RECTANGLE)); + if (checked) { + ug.getParam().setBackcolor(ug.getParam().getColor()); + final UPolygon poly = new UPolygon(); + poly.addPoint(0, 0); + poly.addPoint(3, 3); + poly.addPoint(10, -6); + poly.addPoint(3, 1); + ug.draw(x + 3, y + 6, poly); + ug.getParam().setBackcolor(null); + } + } + ug.getParam().setStroke(new UStroke()); + + // ug.getParam().setColor(HtmlColor.BLACK); + // final Dimension2D dim = getDimension(ug.getStringBounder()); + // ug.getParam().setStroke(new UStroke(stroke)); + // ug.draw(x, y, new URectangle(dim.getWidth() - 2 * stroke, + // dim.getHeight() - 2 * stroke, 10, 10)); + // ug.getParam().setStroke(new UStroke()); + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementTabBar.java b/src/net/sourceforge/plantuml/salt/element/ElementTabBar.java new file mode 100644 index 000000000..99bce04bd --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementTabBar.java @@ -0,0 +1,146 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; + +public class ElementTabBar implements Element { + + private final Collection tabs = new ArrayList(); + private final UFont font; + + private final double margin1 = 2; + private final double margin2 = 3; + private final double margin3 = 10; + + private boolean vertical = false; + + public ElementTabBar(UFont font) { + this.font = font; + } + + public void addTab(String tab) { + final Element elt = new ElementText(Arrays.asList(tab), font); + tabs.add(elt); + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + if (vertical) { + return getPreferredDimensionVertical(stringBounder, x, y); + } + return getPreferredDimensionHorizontal(stringBounder, x, y); + + } + + private Dimension2D getPreferredDimensionHorizontal(StringBounder stringBounder, double x, double y) { + double w = 0; + double h = 0; + for (Element elt : tabs) { + final Dimension2D dim = elt.getPreferredDimension(stringBounder, x, y); + w += dim.getWidth() + margin1 + margin2 + margin3; + h = Math.max(h, dim.getHeight()); + } + return new Dimension2DDouble(w, h); + } + + public void drawU(UGraphic ug, final double x, final double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 0) { + return; + } + if (vertical) { + drawUVertical(ug, x, y, zIndex, dimToUse); + } else { + drawUHorizontal(ug, x, y, zIndex, dimToUse); + } + } + + private void drawUHorizontal(UGraphic ug, final double x, final double y, int zIndex, Dimension2D dimToUse) { + double x1 = x; + for (Element elt : tabs) { + elt.drawU(ug, x1 + margin1, y, zIndex, dimToUse); + final Dimension2D dimText = elt.getPreferredDimension(ug.getStringBounder(), x1, y); + final double w = dimText.getWidth(); + ug.draw(x1, y, new ULine(0, dimText.getHeight())); + ug.draw(x1, y, new ULine(w + margin1 + margin2, 0)); + ug.draw(x1 + w + margin1 + margin2, y, new ULine(0, dimText.getHeight())); + ug.draw(x1 + w + margin1 + margin2, y + dimText.getHeight(), new ULine(margin3, 0)); + x1 += w + margin1 + margin2 + margin3; + } + } + + private Dimension2D getPreferredDimensionVertical(StringBounder stringBounder, double x, double y) { + double w = 0; + double h = 0; + for (Element elt : tabs) { + final Dimension2D dim = elt.getPreferredDimension(stringBounder, x, y); + h += dim.getHeight() + margin1 + margin2 + margin3; + w = Math.max(w, dim.getWidth()); + } + return new Dimension2DDouble(w, h); + } + + private void drawUVertical(UGraphic ug, final double x, final double y, int zIndex, Dimension2D dimToUse) { + final Dimension2D preferred = getPreferredDimension(ug.getStringBounder(), x, y); + + double y1 = x; + for (Element elt : tabs) { + elt.drawU(ug, x, y1 + margin1, zIndex, dimToUse); + final Dimension2D dimText = elt.getPreferredDimension(ug.getStringBounder(), x, y1); + final double h = dimText.getHeight(); + ug.draw(x, y1, new ULine(preferred.getWidth(), 0)); + ug.draw(x, y1, new ULine(0, h + margin1 + margin2)); + ug.draw(x, y1 + h + margin1 + margin2, new ULine(preferred.getWidth(), 0)); + ug.draw(x + preferred.getWidth(), y1 + h + margin1 + margin2, new ULine(0, margin3)); + y1 += h + margin1 + margin2 + margin3; + } + } + + public boolean isVertical() { + return vertical; + } + + public void setVertical(boolean vertical) { + this.vertical = vertical; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementText.java b/src/net/sourceforge/plantuml/salt/element/ElementText.java new file mode 100644 index 000000000..d71e6bb78 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementText.java @@ -0,0 +1,78 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; +import java.util.List; + +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignement; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class ElementText implements Element { + + private final TextBlock block; + private final boolean show; + private final String text; + + public ElementText(List text, UFont font) { + final FontConfiguration config = new FontConfiguration(font, HtmlColor.BLACK); + this.block = TextBlockUtils.create(text, config, HorizontalAlignement.LEFT); + this.show = text.get(0).equals(".") == false; + this.text = text.get(0); + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + return block.calculateDimension(stringBounder); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 0) { + return; + } + if (show) { + block.drawU(ug, x, y); + } + } + + public final String getText() { + return text; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/ElementTextField.java b/src/net/sourceforge/plantuml/salt/element/ElementTextField.java new file mode 100644 index 000000000..2c80a9f77 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/ElementTextField.java @@ -0,0 +1,68 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; + +public class ElementTextField extends AbstractElementText implements Element { + + public ElementTextField(String text, UFont font) { + super(text, font, true); + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + final Dimension2D dim = getTextDimensionAt(stringBounder, x); + return Dimension2DDouble.delta(dim, 6, 2); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + if (zIndex != 0) { + return; + } + drawText(ug, x + 3, y); + final Dimension2D dim = getPreferredDimension(ug.getStringBounder(), 0, 0); + final Dimension2D textDim = getTextDimensionAt(ug.getStringBounder(), 0); + ug.draw(x + 1, y + textDim.getHeight(), new ULine(dim.getWidth() - 3, 0)); + final double y3 = y + textDim.getHeight() - 3; + ug.draw(x + 1, y3, new ULine(0, 2)); + ug.draw(x + 3 + textDim.getWidth() + 1, y3, new ULine(0, 2)); + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/Grid.java b/src/net/sourceforge/plantuml/salt/element/Grid.java new file mode 100644 index 000000000..dbfa22eea --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/Grid.java @@ -0,0 +1,116 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.util.HashSet; +import java.util.Set; + +import net.sourceforge.plantuml.salt.Cell; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; + +public class Grid { + + private final double[] rowsStart; + private final double[] colsStart; + private final TableStrategy strategy; + + private final Set horizontals = new HashSet(); + private final Set verticals = new HashSet(); + + public Grid(double[] rowsStart, double[] colsStart, TableStrategy strategy) { + this.rowsStart = rowsStart; + this.colsStart = colsStart; + this.strategy = strategy; + if (strategy == TableStrategy.DRAW_OUTSIDE || strategy == TableStrategy.DRAW_ALL) { + addOutside(); + } + } + + private void addOutside() { + final int nbRow = rowsStart.length; + final int nbCol = colsStart.length; + for (int c = 0; c < nbCol - 1; c++) { + horizontals.add(new Segment(0, c)); + horizontals.add(new Segment(nbRow - 1, c)); + } + for (int r = 0; r < nbRow - 1; r++) { + verticals.add(new Segment(r, 0)); + verticals.add(new Segment(r, nbCol - 1)); + } + + } + + public void drawU(UGraphic ug, double x, double y) { + // Hlines + for (Segment seg : horizontals) { + final int row1 = seg.getRow(); + final int col1 = seg.getCol(); + final double width = colsStart[col1 + 1] - colsStart[col1]; + ug.draw(x + colsStart[col1], y + rowsStart[row1], new ULine(width, 0)); + } + // Vlines + for (Segment seg : verticals) { + final int row1 = seg.getRow(); + final int col1 = seg.getCol(); + final double height = rowsStart[row1 + 1] - rowsStart[row1]; + ug.draw(x + colsStart[col1], y + rowsStart[row1], new ULine(0, height)); + } + } + + public void addCell(Cell cell) { + + if (strategy == TableStrategy.DRAW_NONE) { + return; + } + if (strategy == TableStrategy.DRAW_OUTSIDE) { + return; + } + + if (strategy == TableStrategy.DRAW_HORIZONTAL || strategy == TableStrategy.DRAW_ALL) { + // Hlines + for (int c = cell.getMinCol(); c <= cell.getMaxCol(); c++) { + horizontals.add(new Segment(cell.getMinRow(), c)); + horizontals.add(new Segment(cell.getMaxRow() + 1, c)); + } + } + if (strategy == TableStrategy.DRAW_VERTICAL || strategy == TableStrategy.DRAW_ALL) { + // Vlines + for (int r = cell.getMinRow(); r <= cell.getMaxRow(); r++) { + verticals.add(new Segment(r, cell.getMinCol())); + verticals.add(new Segment(r, cell.getMaxCol() + 1)); + } + } + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/LeftFirst.java b/src/net/sourceforge/plantuml/salt/element/LeftFirst.java new file mode 100644 index 000000000..7f0bfbf84 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/LeftFirst.java @@ -0,0 +1,51 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.util.Comparator; + +import net.sourceforge.plantuml.salt.Cell; + +class LeftFirst implements Comparator { + + public int compare(Cell c0, Cell c1) { + final int diffNb = c0.getNbCols() - c1.getNbCols(); + if (diffNb != 0) { + return diffNb; + } + final int diffPos = c0.getMinCol() - c1.getMinCol(); + return diffPos; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/Segment.java b/src/net/sourceforge/plantuml/salt/element/Segment.java new file mode 100644 index 000000000..f5b99fb65 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/Segment.java @@ -0,0 +1,65 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +public class Segment { + + private final int row; + private final int col; + + public Segment(int row, int col) { + this.row = row; + this.col = col; + } + + @Override + public int hashCode() { + return row * 47 + col; + } + + @Override + public boolean equals(Object obj) { + final Segment this2 = (Segment) obj; + return row == this2.row && col == this2.col; + } + + public final int getRow() { + return row; + } + + public final int getCol() { + return col; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/TableStrategy.java b/src/net/sourceforge/plantuml/salt/element/TableStrategy.java new file mode 100644 index 000000000..78df69509 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/TableStrategy.java @@ -0,0 +1,53 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +public enum TableStrategy { + DRAW_NONE(' '), DRAW_OUTSIDE('+'), DRAW_HORIZONTAL('-'), DRAW_VERTICAL('!'), DRAW_ALL('#'); + + private final char c; + + private TableStrategy(char c) { + this.c = c; + } + + public static TableStrategy fromChar(char c) { + for (TableStrategy t : TableStrategy.values()) { + if (c == t.c) { + return t; + } + } + throw new IllegalArgumentException(); + } +} diff --git a/src/net/sourceforge/plantuml/salt/element/TopFirst.java b/src/net/sourceforge/plantuml/salt/element/TopFirst.java new file mode 100644 index 000000000..7a012041d --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/TopFirst.java @@ -0,0 +1,51 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.util.Comparator; + +import net.sourceforge.plantuml.salt.Cell; + +class TopFirst implements Comparator { + + public int compare(Cell c0, Cell c1) { + final int diffNb = c0.getNbRows() - c1.getNbRows(); + if (diffNb != 0) { + return diffNb; + } + final int diffPos = c0.getMinRow() - c1.getMinRow(); + return diffPos; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/element/WrappedElement.java b/src/net/sourceforge/plantuml/salt/element/WrappedElement.java new file mode 100644 index 000000000..40eda645c --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/element/WrappedElement.java @@ -0,0 +1,57 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.element; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class WrappedElement implements Element { + + private final Element wrapped; + + public WrappedElement(Element element) { + this.wrapped = element; + } + + public Dimension2D getPreferredDimension(StringBounder stringBounder, double x, double y) { + return wrapped.getPreferredDimension(stringBounder, 0, 0); + } + + public void drawU(UGraphic ug, double x, double y, int zIndex, Dimension2D dimToUse) { + wrapped.drawU(ug, x, y, zIndex, dimToUse); + } + +} diff --git a/src/net/sourceforge/plantuml/salt/factory/AbstractElementFactoryComplex.java b/src/net/sourceforge/plantuml/salt/factory/AbstractElementFactoryComplex.java new file mode 100644 index 000000000..6dfb5a03e --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/AbstractElementFactoryComplex.java @@ -0,0 +1,73 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.util.ArrayList; +import java.util.Collection; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Dictionary; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; + +public abstract class AbstractElementFactoryComplex implements ElementFactory { + + final private DataSource dataSource; + final private Collection factories = new ArrayList(); + final private Dictionary dictionary; + + + public AbstractElementFactoryComplex(DataSource dataSource, Dictionary dictionary) { + this.dataSource = dataSource; + this.dictionary = dictionary; + } + + final public void addFactory(ElementFactory factory) { + factories.add(factory); + } + + protected Terminated getNextElement() { + for (ElementFactory factory : factories) { + if (factory.ready()) { + return factory.create(); + } + } + throw new IllegalStateException(dataSource.peek(0).getElement()); + } + + protected DataSource getDataSource() { + return dataSource; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactory.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactory.java new file mode 100644 index 000000000..f8c5dae71 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactory.java @@ -0,0 +1,45 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; + +public interface ElementFactory { + + Terminated create(); + + boolean ready(); + +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryBorder.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryBorder.java new file mode 100644 index 000000000..21b35e92e --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryBorder.java @@ -0,0 +1,101 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Dictionary; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementBorder; +import net.sourceforge.plantuml.salt.element.TableStrategy; + +public class ElementFactoryBorder extends AbstractElementFactoryComplex { + + public ElementFactoryBorder(DataSource dataSource, Dictionary dictionary) { + super(dataSource, dictionary); + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final String header = getDataSource().next().getElement(); + assert header.startsWith("{"); + + TableStrategy strategy = TableStrategy.DRAW_NONE; + if (header.length() == 2) { + strategy = TableStrategy.fromChar(header.charAt(1)); + } + + final ElementBorder result = new ElementBorder(); + + while (getDataSource().peek(0).getElement().equals("}") == false) { + final String pos = getDataSource().next().getElement(); + switch (pos.charAt(0)) { + case 'N': + result.setNorth(getNextElement().getElement()); + break; + case 'S': + result.setSouth(getNextElement().getElement()); + break; + case 'E': + result.setEast(getNextElement().getElement()); + break; + case 'W': + result.setWest(getNextElement().getElement()); + break; + case 'C': + result.setCenter(getNextElement().getElement()); + break; + default: + throw new IllegalStateException(); + + } + } + final Terminated next = getDataSource().next(); + return new Terminated(result, next.getTerminator()); + } + + public boolean ready() { + final String text = getDataSource().peek(0).getElement(); + if (text.equals("{") || text.equals("{+") || text.equals("{#") || text.equals("{!") || text.equals("{-")) { + final String text1 = getDataSource().peek(1).getElement(); + if (text1.matches("[NSEW]=")) { + return true; + } + return false; + } + return false; + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryButton.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryButton.java new file mode 100644 index 000000000..1a3f1b80f --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryButton.java @@ -0,0 +1,67 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementButton; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryButton implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryButton(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + final String text = next.getElement(); + final UFont font = new UFont("Default", Font.PLAIN, 12); + return new Terminated(new ElementButton(text.substring(1, text.length() - 1), font), + next.getTerminator()); + } + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.startsWith("[") && text.endsWith("]"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryCheckboxOff.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryCheckboxOff.java new file mode 100644 index 000000000..3b3dc121a --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryCheckboxOff.java @@ -0,0 +1,76 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; +import java.util.Arrays; +import java.util.List; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementRadioCheckbox; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryCheckboxOff implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryCheckboxOff(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + final String text = next.getElement(); + final UFont font = new UFont("Default", Font.PLAIN, 12); + return new Terminated(new ElementRadioCheckbox(extracted(text), font, false, + false), next.getTerminator()); + } + + private List extracted(final String text) { + final int x = text.indexOf(']'); + return Arrays.asList(text.substring(x+1).trim()); + } + + + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.startsWith("[]") || text.startsWith("[ ]"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryCheckboxOn.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryCheckboxOn.java new file mode 100644 index 000000000..9c5404016 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryCheckboxOn.java @@ -0,0 +1,76 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; +import java.util.Arrays; +import java.util.List; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementRadioCheckbox; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryCheckboxOn implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryCheckboxOn(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + final String text = next.getElement(); + final UFont font = new UFont("Default", Font.PLAIN, 12); + return new Terminated(new ElementRadioCheckbox(extracted(text), font, false, + true), next.getTerminator()); + } + + private List extracted(final String text) { + final int x = text.indexOf(']'); + return Arrays.asList(text.substring(x+1).trim()); + } + + + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.startsWith("[X]"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryDroplist.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryDroplist.java new file mode 100644 index 000000000..f474cf3e7 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryDroplist.java @@ -0,0 +1,67 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementDroplist; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryDroplist implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryDroplist(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + final String text = next.getElement(); + final UFont font = new UFont("Default", Font.PLAIN, 12); + return new Terminated(new ElementDroplist(text.substring(1, text.length() - 1), font), + next.getTerminator()); + } + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.startsWith("^") && text.endsWith("^"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryImage.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryImage.java new file mode 100644 index 000000000..82c6cae05 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryImage.java @@ -0,0 +1,77 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Dictionary; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementImage; + +public class ElementFactoryImage implements ElementFactory { + + final private DataSource dataSource; + final private Dictionary dictionary; + + public ElementFactoryImage(DataSource dataSource, Dictionary dictionary) { + this.dataSource = dataSource; + this.dictionary = dictionary; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final String header = dataSource.next().getElement(); + final String name = header.length() > 2 ? header.substring(2) : null; + final List img = new ArrayList(); + while (dataSource.peek(0).getElement().equals(">>") == false) { + img.add(dataSource.next().getElement()); + } + final Terminated next = dataSource.next(); + final ElementImage element = new ElementImage(img); + if (name != null) { + dictionary.put(name, element); + } + return new Terminated(element, next.getTerminator()); + } + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.equals("<<") || text.matches("\\<\\<\\w+"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryLine.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryLine.java new file mode 100644 index 000000000..781f44063 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryLine.java @@ -0,0 +1,61 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementLine; + +public class ElementFactoryLine implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryLine(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + return new Terminated(new ElementLine(), next.getTerminator()); + } + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.equals("--"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryMenu.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryMenu.java new file mode 100644 index 000000000..897c7629d --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryMenu.java @@ -0,0 +1,89 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Dictionary; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.Terminator; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementMenuBar; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryMenu extends AbstractElementFactoryComplex { + + public ElementFactoryMenu(DataSource dataSource, Dictionary dictionary) { + super(dataSource, dictionary); + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final String header = getDataSource().next().getElement(); + assert header.startsWith("{*"); + + final UFont font = new UFont("Default", Font.PLAIN, 12); + final ElementMenuBar result = new ElementMenuBar(font); + + String subentry = null; + + while (getDataSource().peek(0).getElement().equals("}") == false) { + final Terminated t = getDataSource().next(); + final String s = t.getElement(); + if (subentry == null) { + result.addEntry(s); + } else if (subentry.length() == 0) { + subentry = s; + } else { + result.addSubEntry(subentry, s); + } + if (t.getTerminator() == Terminator.NEWLINE) { + subentry = ""; + } + } + final Terminated next = getDataSource().next(); + return new Terminated(result, next.getTerminator()); + } + + public boolean ready() { + final String text = getDataSource().peek(0).getElement(); + if (text.equals("{*")) { + return true; + } + return false; + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryPyramid.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryPyramid.java new file mode 100644 index 000000000..5da75312a --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryPyramid.java @@ -0,0 +1,82 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Dictionary; +import net.sourceforge.plantuml.salt.Positionner; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementPyramid; +import net.sourceforge.plantuml.salt.element.TableStrategy; + +public class ElementFactoryPyramid extends AbstractElementFactoryComplex { + + public ElementFactoryPyramid(DataSource dataSource, Dictionary dictionary) { + super(dataSource, dictionary); + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final String header = getDataSource().next().getElement(); + assert header.startsWith("{"); + + TableStrategy strategy = TableStrategy.DRAW_NONE; + if (header.length() == 2) { + strategy = TableStrategy.fromChar(header.charAt(1)); + } + + final Positionner positionner = new Positionner(); + + while (getDataSource().peek(0).getElement().equals("}") == false) { + positionner.add(getNextElement()); + } + final Terminated next = getDataSource().next(); + return new Terminated(new ElementPyramid(positionner, strategy), next.getTerminator()); + } + + public boolean ready() { + final String text = getDataSource().peek(0).getElement(); + if (text.equals("{") || text.equals("{+") || text.equals("{#") || text.equals("{!") || text.equals("{-")) { + final String text1 = getDataSource().peek(1).getElement(); + if (text1.matches("[NSEW]=")) { + return false; + } + return true; + } + return false; + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryPyramid2.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryPyramid2.java new file mode 100644 index 000000000..1867f189a --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryPyramid2.java @@ -0,0 +1,95 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Dictionary; +import net.sourceforge.plantuml.salt.Positionner2; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementPyramid2; +import net.sourceforge.plantuml.salt.element.ElementText; +import net.sourceforge.plantuml.salt.element.TableStrategy; + +public class ElementFactoryPyramid2 extends AbstractElementFactoryComplex { + + public ElementFactoryPyramid2(DataSource dataSource, Dictionary dictionary) { + super(dataSource, dictionary); + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final String header = getDataSource().next().getElement(); + assert header.startsWith("{"); + + TableStrategy strategy = TableStrategy.DRAW_NONE; + if (header.length() == 2) { + strategy = TableStrategy.fromChar(header.charAt(1)); + } + + final Positionner2 positionner = new Positionner2(); + + while (getDataSource().peek(0).getElement().equals("}") == false) { + final Terminated next = getNextElement(); + if (isStar(next.getElement())) { + positionner.mergeLeft(next.getTerminator()); + } else { + positionner.add(next); + } + } + final Terminated next = getDataSource().next(); + return new Terminated(new ElementPyramid2(positionner, strategy), next.getTerminator()); + } + + private boolean isStar(Element element) { + if (element instanceof ElementText == false) { + return false; + } + return "*".equals(((ElementText) element).getText()); + } + + public boolean ready() { + final String text = getDataSource().peek(0).getElement(); + if (text.equals("{") || text.equals("{+") || text.equals("{#") || text.equals("{!") || text.equals("{-")) { + final String text1 = getDataSource().peek(1).getElement(); + if (text1.matches("[NSEW]=")) { + return false; + } + return true; + } + return false; + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRadioOff.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRadioOff.java new file mode 100644 index 000000000..647b1db02 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRadioOff.java @@ -0,0 +1,74 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; +import java.util.Arrays; +import java.util.List; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementRadioCheckbox; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryRadioOff implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryRadioOff(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + final String text = next.getElement(); + final UFont font = new UFont("Default", Font.PLAIN, 12); + return new Terminated(new ElementRadioCheckbox(extracted(text), font, true, + false), next.getTerminator()); + } + + private List extracted(final String text) { + final int x = text.indexOf(')'); + return Arrays.asList(text.substring(x+1).trim()); + } + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.startsWith("()") || text.startsWith("( )"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRadioOn.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRadioOn.java new file mode 100644 index 000000000..f3488ee06 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRadioOn.java @@ -0,0 +1,75 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; +import java.util.Arrays; +import java.util.List; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementRadioCheckbox; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryRadioOn implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryRadioOn(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + final String text = next.getElement(); + final UFont font = new UFont("Default", Font.PLAIN, 12); + return new Terminated(new ElementRadioCheckbox(extracted(text), font, true, + true), next.getTerminator()); + } + + private List extracted(final String text) { + final int x = text.indexOf(')'); + return Arrays.asList(text.substring(x+1).trim()); + } + + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.startsWith("(X)"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRetrieveFromDictonnary.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRetrieveFromDictonnary.java new file mode 100644 index 000000000..df66f2ed5 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryRetrieveFromDictonnary.java @@ -0,0 +1,71 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Dictionary; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; + +public class ElementFactoryRetrieveFromDictonnary implements ElementFactory { + + private final Dictionary dictionary; + private final DataSource dataSource; + + public ElementFactoryRetrieveFromDictonnary(DataSource dataSource, Dictionary dictionary) { + this.dataSource = dataSource; + this.dictionary = dictionary; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + + String name = next.getElement(); + name = name.substring(2, name.length() - 2); + final Element retrieve = dictionary.get(name); + if (retrieve == null) { + throw new IllegalArgumentException("Cannot retrieve " + name); + } + + return new Terminated(retrieve, next.getTerminator()); + } + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.matches("\\<\\<\\w+\\>\\>"); + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryTab.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryTab.java new file mode 100644 index 000000000..fb613b431 --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryTab.java @@ -0,0 +1,80 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Dictionary; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.Terminator; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementTabBar; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryTab extends AbstractElementFactoryComplex { + + public ElementFactoryTab(DataSource dataSource, Dictionary dictionary) { + super(dataSource, dictionary); + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final String header = getDataSource().next().getElement(); + assert header.startsWith("{/"); + + final UFont font = new UFont("Default", Font.PLAIN, 12); + final ElementTabBar result = new ElementTabBar(font); + + while (getDataSource().peek(0).getElement().equals("}") == false) { + final Terminated t = getDataSource().next(); + result.addTab(t.getElement()); + if (t.getTerminator() == Terminator.NEWLINE) { + result.setVertical(true); + } + } + final Terminated next = getDataSource().next(); + return new Terminated(result, next.getTerminator()); + } + + public boolean ready() { + final String text = getDataSource().peek(0).getElement(); + if (text.equals("{/")) { + return true; + } + return false; + } +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryText.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryText.java new file mode 100644 index 000000000..467b1f06e --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryText.java @@ -0,0 +1,73 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; +import java.util.Arrays; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementText; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryText implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryText(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + final String text = next.getElement(); + final UFont font = new UFont("Default", Font.PLAIN, 12); + return new Terminated(new ElementText(Arrays.asList(text), font), next + .getTerminator()); + } + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + // return text.startsWith("\"") && text.endsWith("\""); + if (text.startsWith("{") || text.startsWith("}")) { + return false; + } + return text.trim().length() > 0; + } + +} diff --git a/src/net/sourceforge/plantuml/salt/factory/ElementFactoryTextField.java b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryTextField.java new file mode 100644 index 000000000..c2351f42a --- /dev/null +++ b/src/net/sourceforge/plantuml/salt/factory/ElementFactoryTextField.java @@ -0,0 +1,68 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 3835 $ + * + */ +package net.sourceforge.plantuml.salt.factory; + +import java.awt.Font; + +import net.sourceforge.plantuml.salt.DataSource; +import net.sourceforge.plantuml.salt.Terminated; +import net.sourceforge.plantuml.salt.element.Element; +import net.sourceforge.plantuml.salt.element.ElementTextField; +import net.sourceforge.plantuml.ugraphic.UFont; + +public class ElementFactoryTextField implements ElementFactory { + + final private DataSource dataSource; + + public ElementFactoryTextField(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Terminated create() { + if (ready() == false) { + throw new IllegalStateException(); + } + final Terminated next = dataSource.next(); + final String text = next.getElement(); + final UFont font = new UFont("Default", Font.PLAIN, 12); + return new Terminated(new ElementTextField(text.substring(1, text.length() - 1), font), + next.getTerminator()); + } + + public boolean ready() { + final String text = dataSource.peek(0).getElement(); + return text.startsWith("\"") && text.endsWith("\""); + } + +} diff --git a/src/net/sourceforge/plantuml/sequencediagram/Note.java b/src/net/sourceforge/plantuml/sequencediagram/Note.java index 59c3888d0..28e52ec4b 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/Note.java +++ b/src/net/sourceforge/plantuml/sequencediagram/Note.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6575 $ + * Revision $Revision: 7111 $ * */ package net.sourceforge.plantuml.sequencediagram; @@ -49,6 +49,7 @@ public class Note implements Event, SpecificBackcolorable { private final List strings; private final NotePosition position; + private NoteStyle style = NoteStyle.NORMAL; private final Url url; @@ -120,4 +121,12 @@ public class Note implements Event, SpecificBackcolorable { return url; } + public final NoteStyle getStyle() { + return style; + } + + public final void setStyle(NoteStyle style) { + this.style = style; + } + } diff --git a/src/net/sourceforge/plantuml/sequencediagram/NoteStyle.java b/src/net/sourceforge/plantuml/sequencediagram/NoteStyle.java new file mode 100644 index 000000000..46d1c6364 --- /dev/null +++ b/src/net/sourceforge/plantuml/sequencediagram/NoteStyle.java @@ -0,0 +1,49 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6575 $ + * + */ +package net.sourceforge.plantuml.sequencediagram; + +public enum NoteStyle { + + NORMAL, HEXAGONAL, BOX; + + public static NoteStyle getNoteStyle(String s) { + if (s.equalsIgnoreCase("hnote")) { + return NoteStyle.HEXAGONAL; + } else if (s.equalsIgnoreCase("rnote")) { + return NoteStyle.BOX; + } + return NoteStyle.NORMAL; + } + +} diff --git a/src/net/sourceforge/plantuml/sequencediagram/command/CommandMultilinesNote.java b/src/net/sourceforge/plantuml/sequencediagram/command/CommandMultilinesNote.java index 81f9aca56..b6313b29b 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/command/CommandMultilinesNote.java +++ b/src/net/sourceforge/plantuml/sequencediagram/command/CommandMultilinesNote.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6575 $ + * Revision $Revision: 7113 $ * */ package net.sourceforge.plantuml.sequencediagram.command; @@ -41,25 +41,27 @@ import net.sourceforge.plantuml.command.CommandMultilines; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.sequencediagram.Note; import net.sourceforge.plantuml.sequencediagram.NotePosition; +import net.sourceforge.plantuml.sequencediagram.NoteStyle; import net.sourceforge.plantuml.sequencediagram.Participant; import net.sourceforge.plantuml.sequencediagram.SequenceDiagram; public class CommandMultilinesNote extends CommandMultilines { public CommandMultilinesNote(final SequenceDiagram sequenceDiagram) { - super(sequenceDiagram, "(?i)^note\\s+(right|left|over)\\s+(?:of\\s+)?([\\p{L}0-9_.]+|\"[^\"]+\")\\s*(#\\w+)?$", "(?i)^end ?note$"); + super(sequenceDiagram, "(?i)^(note|hnote|rnote)\\s+(right|left|over)\\s+(?:of\\s+)?([\\p{L}0-9_.]+|\"[^\"]+\")\\s*(#\\w+)?$", "(?i)^end ?(note|hnote|rnote)$"); } public CommandExecutionResult execute(List lines) { final List line0 = StringUtils.getSplit(getStartingPattern(), lines.get(0).trim()); - final Participant p = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(line0.get(1))); + final Participant p = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(line0.get(2))); - final NotePosition position = NotePosition.valueOf(line0.get(0).toUpperCase()); + final NotePosition position = NotePosition.valueOf(line0.get(1).toUpperCase()); final List strings = StringUtils.removeEmptyColumns(lines.subList(1, lines.size() - 1)); if (strings.size() > 0) { final Note note = new Note(p, position, strings); - note.setSpecificBackcolor(HtmlColor.getColorIfValid(line0.get(2))); + note.setSpecificBackcolor(HtmlColor.getColorIfValid(line0.get(3))); + note.setStyle(NoteStyle.getNoteStyle(line0.get(0))); getSystem().addNote(note); } diff --git a/src/net/sourceforge/plantuml/sequencediagram/command/CommandMultilinesNoteOverSeveral.java b/src/net/sourceforge/plantuml/sequencediagram/command/CommandMultilinesNoteOverSeveral.java index ae1270bae..72b25dd12 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/command/CommandMultilinesNoteOverSeveral.java +++ b/src/net/sourceforge/plantuml/sequencediagram/command/CommandMultilinesNoteOverSeveral.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6575 $ + * Revision $Revision: 7113 $ * */ package net.sourceforge.plantuml.sequencediagram.command; @@ -40,25 +40,27 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.CommandMultilines; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.sequencediagram.Note; +import net.sourceforge.plantuml.sequencediagram.NoteStyle; import net.sourceforge.plantuml.sequencediagram.Participant; import net.sourceforge.plantuml.sequencediagram.SequenceDiagram; public class CommandMultilinesNoteOverSeveral extends CommandMultilines { public CommandMultilinesNoteOverSeveral(final SequenceDiagram sequenceDiagram) { - super(sequenceDiagram, "(?i)^note\\s+over\\s+([\\p{L}0-9_.]+|\"[^\"]+\")\\s*\\,\\s*([\\p{L}0-9_.]+|\"[^\"]+\")\\s*(#\\w+)?$", "(?i)^end ?note$"); + super(sequenceDiagram, "(?i)^(note|hnote|rnote)\\s+over\\s+([\\p{L}0-9_.]+|\"[^\"]+\")\\s*\\,\\s*([\\p{L}0-9_.]+|\"[^\"]+\")\\s*(#\\w+)?$", "(?i)^end ?(note|hnote|rnote)$"); } public CommandExecutionResult execute(List lines) { final List line0 = StringUtils.getSplit(getStartingPattern(), lines.get(0).trim()); - final Participant p1 = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(line0.get(0))); - final Participant p2 = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(line0.get(1))); + final Participant p1 = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(line0.get(1))); + final Participant p2 = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(line0.get(2))); final List strings = StringUtils.removeEmptyColumns(lines.subList(1, lines.size() - 1)); if (strings.size() > 0) { final Note note = new Note(p1, p2, strings); - note.setSpecificBackcolor(HtmlColor.getColorIfValid(line0.get(2))); + note.setSpecificBackcolor(HtmlColor.getColorIfValid(line0.get(3))); + note.setStyle(NoteStyle.getNoteStyle(line0.get(0))); getSystem().addNote(note); } return CommandExecutionResult.ok(); diff --git a/src/net/sourceforge/plantuml/sequencediagram/command/CommandNoteOverSeveral.java b/src/net/sourceforge/plantuml/sequencediagram/command/CommandNoteOverSeveral.java index 6d3f1e77d..014cef9ab 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/command/CommandNoteOverSeveral.java +++ b/src/net/sourceforge/plantuml/sequencediagram/command/CommandNoteOverSeveral.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6575 $ + * Revision $Revision: 7113 $ * */ package net.sourceforge.plantuml.sequencediagram.command; @@ -40,23 +40,29 @@ import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.command.SingleLineCommand; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.sequencediagram.Note; +import net.sourceforge.plantuml.sequencediagram.NoteStyle; import net.sourceforge.plantuml.sequencediagram.Participant; import net.sourceforge.plantuml.sequencediagram.SequenceDiagram; public class CommandNoteOverSeveral extends SingleLineCommand { public CommandNoteOverSeveral(SequenceDiagram sequenceDiagram) { - super(sequenceDiagram, "(?i)^note\\s+over\\s+([\\p{L}0-9_.]+|\"[^\"]+\")\\s*\\,\\s*([\\p{L}0-9_.]+|\"[^\"]+\")\\s*(#\\w+)?\\s*:\\s*(.*)$"); + super( + sequenceDiagram, + "(?i)^(note|hnote|rnote)\\s+over\\s+([\\p{L}0-9_.]+|\"[^\"]+\")\\s*\\,\\s*([\\p{L}0-9_.]+|\"[^\"]+\")\\s*(#\\w+)?\\s*:\\s*(.*)$"); } @Override protected CommandExecutionResult executeArg(List arg) { - final Participant p1 = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.get(0))); - final Participant p2 = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.get(1))); - final List strings = StringUtils.getWithNewlines(arg.get(3)); + final Participant p1 = getSystem().getOrCreateParticipant( + StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.get(1))); + final Participant p2 = getSystem().getOrCreateParticipant( + StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.get(2))); + final List strings = StringUtils.getWithNewlines(arg.get(4)); final Note note = new Note(p1, p2, strings); - note.setSpecificBackcolor(HtmlColor.getColorIfValid(arg.get(2))); + note.setSpecificBackcolor(HtmlColor.getColorIfValid(arg.get(3))); getSystem().addNote(note); + note.setStyle(NoteStyle.getNoteStyle(arg.get(0))); return CommandExecutionResult.ok(); } diff --git a/src/net/sourceforge/plantuml/sequencediagram/command/CommandNoteSequence.java b/src/net/sourceforge/plantuml/sequencediagram/command/CommandNoteSequence.java index e7c32cbeb..29a17d045 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/command/CommandNoteSequence.java +++ b/src/net/sourceforge/plantuml/sequencediagram/command/CommandNoteSequence.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6575 $ + * Revision $Revision: 7113 $ * */ package net.sourceforge.plantuml.sequencediagram.command; @@ -41,24 +41,28 @@ import net.sourceforge.plantuml.command.SingleLineCommand; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.sequencediagram.Note; import net.sourceforge.plantuml.sequencediagram.NotePosition; +import net.sourceforge.plantuml.sequencediagram.NoteStyle; import net.sourceforge.plantuml.sequencediagram.Participant; import net.sourceforge.plantuml.sequencediagram.SequenceDiagram; public class CommandNoteSequence extends SingleLineCommand { public CommandNoteSequence(SequenceDiagram sequenceDiagram) { - super(sequenceDiagram, "(?i)^note\\s+(right|left|over)\\s+(?:of\\s+)?([\\p{L}0-9_.]+|\"[^\"]+\")\\s*(#\\w+)?\\s*:\\s*(.*)$"); + super(sequenceDiagram, + "(?i)^(note|hnote|rnote)\\s+(right|left|over)\\s+(?:of\\s+)?([\\p{L}0-9_.]+|\"[^\"]+\")\\s*(#\\w+)?\\s*:\\s*(.*)$"); } @Override protected CommandExecutionResult executeArg(List arg) { - final Participant p = getSystem().getOrCreateParticipant(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.get(1))); + final Participant p = getSystem().getOrCreateParticipant( + StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.get(2))); - final NotePosition position = NotePosition.valueOf(arg.get(0).toUpperCase()); + final NotePosition position = NotePosition.valueOf(arg.get(1).toUpperCase()); - final List strings = StringUtils.getWithNewlines(arg.get(3)); + final List strings = StringUtils.getWithNewlines(arg.get(4)); final Note note = new Note(p, position, strings); - note.setSpecificBackcolor(HtmlColor.getColorIfValid(arg.get(2))); + note.setSpecificBackcolor(HtmlColor.getColorIfValid(arg.get(3))); + note.setStyle(NoteStyle.getNoteStyle(arg.get(0))); getSystem().addNote(note); return CommandExecutionResult.ok(); } diff --git a/src/net/sourceforge/plantuml/sequencediagram/graphic/DrawableSetInitializer.java b/src/net/sourceforge/plantuml/sequencediagram/graphic/DrawableSetInitializer.java index 7779d2813..1453d5bbf 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/graphic/DrawableSetInitializer.java +++ b/src/net/sourceforge/plantuml/sequencediagram/graphic/DrawableSetInitializer.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6665 $ + * Revision $Revision: 7112 $ * */ package net.sourceforge.plantuml.sequencediagram.graphic; @@ -49,7 +49,6 @@ import net.sourceforge.plantuml.sequencediagram.Event; import net.sourceforge.plantuml.sequencediagram.GroupingLeaf; import net.sourceforge.plantuml.sequencediagram.GroupingStart; import net.sourceforge.plantuml.sequencediagram.GroupingType; -import net.sourceforge.plantuml.sequencediagram.InGroupable; import net.sourceforge.plantuml.sequencediagram.InGroupableList; import net.sourceforge.plantuml.sequencediagram.LifeEvent; import net.sourceforge.plantuml.sequencediagram.LifeEventType; @@ -57,6 +56,7 @@ import net.sourceforge.plantuml.sequencediagram.Message; import net.sourceforge.plantuml.sequencediagram.MessageExo; import net.sourceforge.plantuml.sequencediagram.Newpage; import net.sourceforge.plantuml.sequencediagram.Note; +import net.sourceforge.plantuml.sequencediagram.NoteStyle; import net.sourceforge.plantuml.sequencediagram.Participant; import net.sourceforge.plantuml.sequencediagram.ParticipantEnglober; import net.sourceforge.plantuml.sequencediagram.ParticipantEngloberContexted; @@ -399,7 +399,8 @@ class DrawableSetInitializer { } } final ISkinParam skinParam = new SkinParamBackcolored(drawableSet.getSkinParam(), n.getSpecificBackColor()); - final NoteBox noteBox = new NoteBox(freeY, drawableSet.getSkin().createComponent(ComponentType.NOTE, skinParam, + final ComponentType type = getNoteComponentType(n.getStyle()); + final NoteBox noteBox = new NoteBox(freeY, drawableSet.getSkin().createComponent(type, skinParam, n.getStrings()), p1, p2, n.getPosition(), n.getUrl()); for (InGroupableList groupingStructure : inGroupableLists) { @@ -410,6 +411,16 @@ class DrawableSetInitializer { freeY += noteBox.getPreferredHeight(stringBounder); } + private ComponentType getNoteComponentType(NoteStyle noteStyle) { + if (noteStyle == NoteStyle.HEXAGONAL) { + return ComponentType.NOTE_HEXAGONAL; + } + if (noteStyle == NoteStyle.BOX) { + return ComponentType.NOTE_BOX; + } + return ComponentType.NOTE; + } + private void prepareLiveEvent(StringBounder stringBounder, LifeEvent lifeEvent) { if (lifeEvent.getType() != LifeEventType.DESTROY && lifeEvent.getType() != LifeEventType.CREATE) { throw new IllegalStateException(); diff --git a/src/net/sourceforge/plantuml/skin/AbstractComponent.java b/src/net/sourceforge/plantuml/skin/AbstractComponent.java index 71c296c66..69f4fa39c 100644 --- a/src/net/sourceforge/plantuml/skin/AbstractComponent.java +++ b/src/net/sourceforge/plantuml/skin/AbstractComponent.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 5939 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin; @@ -60,7 +60,7 @@ public abstract class AbstractComponent implements Component { stroke(ug, dashVisible, dashSpace, 1); } - abstract protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse); + abstract protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow); protected void drawBackgroundInternalU(UGraphic ug, Dimension2D dimensionToUse) { } @@ -72,7 +72,7 @@ public abstract class AbstractComponent implements Component { if (context.isBackground()) { drawBackgroundInternalU(ug, dimensionToUse); } else { - drawInternalU(ug, dimensionToUse); + drawInternalU(ug, dimensionToUse, context.withShadow()); } ug.setTranslate(dx, dy); } diff --git a/src/net/sourceforge/plantuml/skin/ComponentType.java b/src/net/sourceforge/plantuml/skin/ComponentType.java index 38ed6a4ef..9c09c61fe 100644 --- a/src/net/sourceforge/plantuml/skin/ComponentType.java +++ b/src/net/sourceforge/plantuml/skin/ComponentType.java @@ -69,6 +69,8 @@ public class ComponentType { // static public final ComponentType NEWPAGE = new ComponentType("NEWPAGE"); static public final ComponentType NOTE = new ComponentType("NOTE"); + static public final ComponentType NOTE_HEXAGONAL = new ComponentType("NOTE_HEXAGONAL"); + static public final ComponentType NOTE_BOX = new ComponentType("NOTE_BOX"); static public final ComponentType DIVIDER = new ComponentType("DIVIDER"); static public final ComponentType REFERENCE = new ComponentType("REFERENCE"); static public final ComponentType ENGLOBER = new ComponentType("ENGLOBER"); diff --git a/src/net/sourceforge/plantuml/skin/Context2D.java b/src/net/sourceforge/plantuml/skin/Context2D.java index e38e12188..d64ed5bdf 100644 --- a/src/net/sourceforge/plantuml/skin/Context2D.java +++ b/src/net/sourceforge/plantuml/skin/Context2D.java @@ -28,11 +28,12 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 3836 $ + * Revision $Revision: 7169 $ * */ package net.sourceforge.plantuml.skin; public interface Context2D { boolean isBackground(); + boolean withShadow(); } diff --git a/src/net/sourceforge/plantuml/skin/GrayComponent.java b/src/net/sourceforge/plantuml/skin/GrayComponent.java index 297057067..dfc467d68 100644 --- a/src/net/sourceforge/plantuml/skin/GrayComponent.java +++ b/src/net/sourceforge/plantuml/skin/GrayComponent.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6591 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin; @@ -59,7 +59,7 @@ class GrayComponent extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); ug.getParam().setBackcolor(HtmlColor.LIGHT_GRAY); ug.getParam().setColor(HtmlColor.BLACK); diff --git a/src/net/sourceforge/plantuml/skin/SimpleContext2D.java b/src/net/sourceforge/plantuml/skin/SimpleContext2D.java index a7841497c..26adac5ac 100644 --- a/src/net/sourceforge/plantuml/skin/SimpleContext2D.java +++ b/src/net/sourceforge/plantuml/skin/SimpleContext2D.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 3836 $ + * Revision $Revision: 7169 $ * */ package net.sourceforge.plantuml.skin; @@ -36,13 +36,23 @@ package net.sourceforge.plantuml.skin; public class SimpleContext2D implements Context2D { private final boolean isBackground; + private final boolean withShadow; public SimpleContext2D(boolean isBackground) { + this(isBackground, false); + } + + public SimpleContext2D(boolean isBackground, boolean withShadow) { this.isBackground = isBackground; + this.withShadow = withShadow; } public boolean isBackground() { return isBackground; } + public boolean withShadow() { + return withShadow; + } + } diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernActiveLine.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernActiveLine.java index 5e9a9cf4a..4d2e44b63 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernActiveLine.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernActiveLine.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -51,7 +51,7 @@ public class ComponentBlueModernActiveLine extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final int x = (int) (dimensionToUse.getWidth() - getPreferredWidth(stringBounder)) / 2; final ShadowShape shadowShape = new ShadowShape(getPreferredWidth(stringBounder), dimensionToUse.getHeight() diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernActor.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernActor.java index 9fc612c8e..f95491b5c 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernActor.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernActor.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -58,7 +58,7 @@ public class ComponentBlueModernActor extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setColor(getFontColor()); final TextBlock textBlock = getTextBlock(); final StringBounder stringBounder = ug.getStringBounder(); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernArrow.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernArrow.java index f8c92a3af..f78cdaead 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernArrow.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernArrow.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -55,7 +55,7 @@ public class ComponentBlueModernArrow extends AbstractComponentBlueModernArrow { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final int textHeight = (int) getTextHeight(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDelayLine.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDelayLine.java index fde26c9b4..82814796c 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDelayLine.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDelayLine.java @@ -51,7 +51,7 @@ public class ComponentBlueModernDelayLine extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setColor(color); ug.getParam().setBackcolor(color); stroke(ug, 1, 4); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDelayText.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDelayText.java index 055d13f53..edf770755 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDelayText.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDelayText.java @@ -51,7 +51,7 @@ public class ComponentBlueModernDelayText extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final TextBlock textBlock = getTextBlock(); final StringBounder stringBounder = ug.getStringBounder(); final double textWidth = getTextWidth(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDivider.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDivider.java index ddd024621..a64cafb70 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDivider.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernDivider.java @@ -62,7 +62,7 @@ public class ComponentBlueModernDivider extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final TextBlock textBlock = getTextBlock(); final StringBounder stringBounder = ug.getStringBounder(); final double textWidth = getTextWidth(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernEnglober.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernEnglober.java index fd1ea95e3..c43251cb9 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernEnglober.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernEnglober.java @@ -69,7 +69,7 @@ public class ComponentBlueModernEnglober extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { // ug.getParam().setColor(Color.RED); // ug.getParam().setBackcolor(Color.YELLOW); // ug.draw(0, 0, new URectangle(dimensionToUse.getWidth(), diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingBody.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingBody.java index 2226326e2..7a90fc603 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingBody.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingBody.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -61,7 +61,7 @@ public class ComponentBlueModernGroupingBody extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setStroke(new UStroke(2)); ug.getParam().setColor(foregroundColor); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingHeader.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingHeader.java index 2c730cfe1..61c496532 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingHeader.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingHeader.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -108,7 +108,7 @@ public class ComponentBlueModernGroupingHeader extends AbstractTextualComponent } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final int textWidth = (int) getTextWidth(stringBounder); final int textHeight = (int) getTextHeight(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingTail.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingTail.java index 3751ac580..e9d16ea59 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingTail.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernGroupingTail.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -51,7 +51,7 @@ public class ComponentBlueModernGroupingTail extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setStroke(new UStroke(2)); ug.getParam().setColor(foregroundColor); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernLine.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernLine.java index f151e27ec..4a5e99727 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernLine.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernLine.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -51,7 +51,7 @@ public class ComponentBlueModernLine extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setColor(color); ug.getParam().setBackcolor(color); final int x = (int) (dimensionToUse.getWidth() / 2); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernNewpage.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernNewpage.java index b94211af3..5e1f1bcfd 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernNewpage.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernNewpage.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -51,7 +51,7 @@ public class ComponentBlueModernNewpage extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { stroke(ug, 10, 2); ug.getParam().setColor(foregroundColor); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernNote.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernNote.java index 64fe9c934..7a8ccdb15 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernNote.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernNote.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -81,7 +81,7 @@ final public class ComponentBlueModernNote extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final double textHeight = getTextHeight(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernParticipant.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernParticipant.java index 068d882f3..71a393543 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernParticipant.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernParticipant.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -57,7 +57,7 @@ public class ComponentBlueModernParticipant extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final ShadowShape shadowShape = new ShadowShape(getTextWidth(stringBounder), getTextHeight(stringBounder), 10); diff --git a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernSelfArrow.java b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernSelfArrow.java index 21e314cdf..ac5ef44ec 100644 --- a/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernSelfArrow.java +++ b/src/net/sourceforge/plantuml/skin/bluemodern/ComponentBlueModernSelfArrow.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.bluemodern; @@ -56,7 +56,7 @@ public class ComponentBlueModernSelfArrow extends AbstractComponentBlueModernArr } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final int textHeight = (int) getTextHeight(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseActiveLine.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseActiveLine.java index a0adda978..22558e2b2 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseActiveLine.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseActiveLine.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -56,7 +56,7 @@ public class ComponentRoseActiveLine extends AbstractComponent { this.closeDown = closeDown; } - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final int x = (int) (dimensionToUse.getWidth() - getPreferredWidth(stringBounder)) / 2; diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseActor.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseActor.java index 005868770..bae42f8c5 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseActor.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseActor.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -58,7 +58,7 @@ public class ComponentRoseActor extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setColor(getFontColor()); final TextBlock textBlock = getTextBlock(); final StringBounder stringBounder = ug.getStringBounder(); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseArrow.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseArrow.java index f5ab985ee..335c59dab 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseArrow.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseArrow.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -60,7 +60,7 @@ public class ComponentRoseArrow extends AbstractComponentRoseArrow { } @Override - public void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + public void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final int textHeight = (int) getTextHeight(stringBounder); ug.getParam().setColor(getForegroundColor()); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDelayLine.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDelayLine.java index aec812fc7..3c2ed05c3 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDelayLine.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDelayLine.java @@ -51,7 +51,7 @@ public class ComponentRoseDelayLine extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setColor(color); // stroke(ug, 0.4, 2.5); stroke(ug, 1, 4); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDelayText.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDelayText.java index 233254680..d4dfa3b3c 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDelayText.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDelayText.java @@ -51,7 +51,7 @@ public class ComponentRoseDelayText extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final TextBlock textBlock = getTextBlock(); final StringBounder stringBounder = ug.getStringBounder(); final double textWidth = getTextWidth(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDestroy.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDestroy.java index 8f34ef953..9b07ae41d 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDestroy.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDestroy.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -53,7 +53,7 @@ public class ComponentRoseDestroy extends AbstractComponent { private final int crossSize = 9; @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setStroke(new UStroke(2)); ug.getParam().setColor(foregroundColor); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDivider.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDivider.java index 52aed2a1b..456ba2200 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDivider.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDivider.java @@ -59,7 +59,7 @@ public class ComponentRoseDivider extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final TextBlock textBlock = getTextBlock(); final StringBounder stringBounder = ug.getStringBounder(); final double textWidth = getTextWidth(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseEnglober.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseEnglober.java index 4d1cb48ca..a0472043b 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseEnglober.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseEnglober.java @@ -65,7 +65,7 @@ public class ComponentRoseEnglober extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { // ug.getParam().setColor(Color.RED); // ug.getParam().setBackcolor(Color.YELLOW); // ug.draw(0, 0, new URectangle(dimensionToUse.getWidth(), diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingBody.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingBody.java index ca5598e3f..26934daa9 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingBody.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingBody.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -67,7 +67,7 @@ public class ComponentRoseGroupingBody extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setStroke(new UStroke(2)); ug.getParam().setColor(foregroundColor); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingElse.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingElse.java index 5e6e49970..ecebc906f 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingElse.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingElse.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -54,7 +54,7 @@ public class ComponentRoseGroupingElse extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { stroke(ug, 2, 2); ug.getParam().setColor(groupBorder); ug.draw(0, 1, new ULine(dimensionToUse.getWidth(), 0)); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingHeader.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingHeader.java index 058b2a8e4..4f6dce5ab 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingHeader.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingHeader.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -110,7 +110,7 @@ public class ComponentRoseGroupingHeader extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final int textWidth = (int) getTextWidth(stringBounder); final int textHeight = (int) getTextHeight(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingTail.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingTail.java index c4236595b..9dc826601 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingTail.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseGroupingTail.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -54,7 +54,7 @@ public class ComponentRoseGroupingTail extends AbstractComponent { @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setStroke(new UStroke(2)); ug.getParam().setColor(groupBorder); ug.draw(0, dimensionToUse.getHeight(), new ULine(dimensionToUse.getWidth(), 0)); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseLine.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseLine.java index 1f7483bb7..906f70c97 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseLine.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseLine.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -54,7 +54,7 @@ public class ComponentRoseLine extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { ug.getParam().setColor(color); if (continueLine) { ug.getParam().setStroke(new UStroke()); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNewpage.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNewpage.java index 10ba53626..c025b7ffe 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNewpage.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNewpage.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -51,7 +51,7 @@ public class ComponentRoseNewpage extends AbstractComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { stroke(ug, 2, 2); ug.getParam().setColor(foregroundColor); ug.draw(0, 0, new ULine(dimensionToUse.getWidth(), 0)); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNote.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNote.java index d2590cb4c..7553c7a66 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNote.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNote.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7171 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -80,7 +80,8 @@ final public class ComponentRoseNote extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { + final StringBounder stringBounder = ug.getStringBounder(); final int textHeight = (int) getTextHeight(stringBounder); @@ -93,6 +94,9 @@ final public class ComponentRoseNote extends AbstractTextualComponent { polygon.addPoint(x2, cornersize); polygon.addPoint(x2 - cornersize, 0); polygon.addPoint(0, 0); + if (withShadow) { + polygon.setDeltaShadow(4); + } ug.getParam().setColor(foregroundColor); ug.getParam().setBackcolor(back); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNoteBox.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNoteBox.java new file mode 100644 index 000000000..a5ba80ea3 --- /dev/null +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNoteBox.java @@ -0,0 +1,95 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6590 $ + * + */ +package net.sourceforge.plantuml.skin.rose; + +import java.awt.geom.Dimension2D; +import java.util.List; + +import net.sourceforge.plantuml.graphic.HorizontalAlignement; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.skin.AbstractTextualComponent; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.URectangle; + +final public class ComponentRoseNoteBox extends AbstractTextualComponent { + + private final HtmlColor back; + private final HtmlColor foregroundColor; + + public ComponentRoseNoteBox(HtmlColor back, HtmlColor foregroundColor, HtmlColor fontColor, UFont font, + List strings) { + super(strings, fontColor, font, HorizontalAlignement.LEFT, 4, 4, 4); + this.back = back; + this.foregroundColor = foregroundColor; + } + + @Override + final public double getPreferredWidth(StringBounder stringBounder) { + final double result = getTextWidth(stringBounder) + 2 * getPaddingX(); + return result; + } + + @Override + final public double getPreferredHeight(StringBounder stringBounder) { + return getTextHeight(stringBounder) + 2 * getPaddingY(); + } + + @Override + public double getPaddingX() { + return 5; + } + + @Override + public double getPaddingY() { + return 5; + } + + @Override + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { + final StringBounder stringBounder = ug.getStringBounder(); + final int textHeight = (int) getTextHeight(stringBounder); + + final int x2 = (int) getTextWidth(stringBounder); + + + ug.getParam().setColor(foregroundColor); + ug.getParam().setBackcolor(back); + ug.draw(0, 0, new URectangle(x2, textHeight)); + + getTextBlock().drawU(ug, getMarginX1(), getMarginY()); + + } +} diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNoteHexagonal.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNoteHexagonal.java new file mode 100644 index 000000000..c52e52ffa --- /dev/null +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseNoteHexagonal.java @@ -0,0 +1,105 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6590 $ + * + */ +package net.sourceforge.plantuml.skin.rose; + +import java.awt.geom.Dimension2D; +import java.util.List; + +import net.sourceforge.plantuml.graphic.HorizontalAlignement; +import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.skin.AbstractTextualComponent; +import net.sourceforge.plantuml.ugraphic.UFont; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UPolygon; + +final public class ComponentRoseNoteHexagonal extends AbstractTextualComponent { + + private final int cornersize = 10; + private final HtmlColor back; + private final HtmlColor foregroundColor; + + public ComponentRoseNoteHexagonal(HtmlColor back, HtmlColor foregroundColor, HtmlColor fontColor, UFont font, + List strings) { + super(strings, fontColor, font, HorizontalAlignement.LEFT, 12, 12, 4); + this.back = back; + this.foregroundColor = foregroundColor; + } + + @Override + final public double getPreferredWidth(StringBounder stringBounder) { + final double result = getTextWidth(stringBounder) + 2 * getPaddingX(); + return result; + } + + @Override + final public double getPreferredHeight(StringBounder stringBounder) { + return getTextHeight(stringBounder) + 2 * getPaddingY(); + } + + @Override + public double getPaddingX() { + return 5; + } + + @Override + public double getPaddingY() { + return 5; + } + + @Override + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { + final StringBounder stringBounder = ug.getStringBounder(); + final int textHeight = (int) getTextHeight(stringBounder); + + final int x2 = (int) getTextWidth(stringBounder); + + final UPolygon polygon = new UPolygon(); + polygon.addPoint(cornersize, 0); + polygon.addPoint(x2 - cornersize, 0); + polygon.addPoint(x2, textHeight / 2); + polygon.addPoint(x2 - cornersize, textHeight); + polygon.addPoint(cornersize, textHeight); + polygon.addPoint(0, textHeight / 2); + polygon.addPoint(cornersize, 0); + + ug.getParam().setColor(foregroundColor); + ug.getParam().setBackcolor(back); + ug.draw(0, 0, polygon); + + getTextBlock().drawU(ug, getMarginX1(), getMarginY()); + + } + +} diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseParticipant.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseParticipant.java index a0ef60519..f58817f32 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseParticipant.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseParticipant.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -58,7 +58,7 @@ public class ComponentRoseParticipant extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); ug.getParam().setColor(foregroundColor); ug.getParam().setBackcolor(back); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseReference.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseReference.java index b4694a664..8a8b8e307 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseReference.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseReference.java @@ -75,7 +75,7 @@ public class ComponentRoseReference extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final int textHeaderWidth = (int) (getHeaderWidth(stringBounder)); final int textHeaderHeight = (int) (getHeaderHeight(stringBounder)); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseSelfArrow.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseSelfArrow.java index 94db6297f..ca7e9afd6 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseSelfArrow.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseSelfArrow.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -57,7 +57,7 @@ public class ComponentRoseSelfArrow extends AbstractComponentRoseArrow { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final StringBounder stringBounder = ug.getStringBounder(); final double textHeight = getTextHeight(stringBounder); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseTitle.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseTitle.java index 85be3d983..dc651ab0d 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseTitle.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseTitle.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7170 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -53,7 +53,7 @@ public class ComponentRoseTitle extends AbstractTextualComponent { } @Override - protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse) { + protected void drawInternalU(UGraphic ug, Dimension2D dimensionToUse, boolean withShadow) { final TextBlock textBlock = getTextBlock(); textBlock.drawU(ug, outMargin + getMarginX1(), getMarginY()); } diff --git a/src/net/sourceforge/plantuml/skin/rose/Rose.java b/src/net/sourceforge/plantuml/skin/rose/Rose.java index 3deb6e38c..de3645719 100644 --- a/src/net/sourceforge/plantuml/skin/rose/Rose.java +++ b/src/net/sourceforge/plantuml/skin/rose/Rose.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6602 $ + * Revision $Revision: 7112 $ * */ package net.sourceforge.plantuml.skin.rose; @@ -210,6 +210,20 @@ public class Rose implements Skin { return new ComponentRoseNote(noteBackgroundColor, borderColor, getFontColor(param, FontParam.NOTE), fontNote, stringsToDisplay); } + if (type == ComponentType.NOTE_HEXAGONAL) { + final HtmlColor noteBackgroundColor = getHtmlColor(param, ColorParam.noteBackground); + final HtmlColor borderColor = getHtmlColor(param, ColorParam.noteBorder); + final UFont fontNote = param.getFont(FontParam.NOTE, null); + return new ComponentRoseNoteHexagonal(noteBackgroundColor, borderColor, getFontColor(param, FontParam.NOTE), + fontNote, stringsToDisplay); + } + if (type == ComponentType.NOTE_BOX) { + final HtmlColor noteBackgroundColor = getHtmlColor(param, ColorParam.noteBackground); + final HtmlColor borderColor = getHtmlColor(param, ColorParam.noteBorder); + final UFont fontNote = param.getFont(FontParam.NOTE, null); + return new ComponentRoseNoteBox(noteBackgroundColor, borderColor, getFontColor(param, FontParam.NOTE), + fontNote, stringsToDisplay); + } if (type == ComponentType.GROUPING_HEADER) { final UFont fontGroupingHeader = param.getFont(FontParam.SEQUENCE_GROUP_HEADER, null); return new ComponentRoseGroupingHeader(getFontColor(param, FontParam.SEQUENCE_GROUP_HEADER), background, diff --git a/src/net/sourceforge/plantuml/svek/Cluster.java b/src/net/sourceforge/plantuml/svek/Cluster.java index 8402a2ac5..23727cd58 100644 --- a/src/net/sourceforge/plantuml/svek/Cluster.java +++ b/src/net/sourceforge/plantuml/svek/Cluster.java @@ -234,7 +234,7 @@ public class Cluster { } public void printCluster(StringBuilder sb, Collection lines) { - System.err.println("Cluster::printCluster " + this); + // System.err.println("Cluster::printCluster " + this); final Set rankSame = new HashSet(); for (Line l : lines) { diff --git a/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java b/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java index 3b6b55815..ed1a5c3a4 100644 --- a/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java +++ b/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java @@ -41,7 +41,6 @@ import java.io.IOException; import java.io.OutputStream; import java.util.List; -import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.EmptyImageBuilder; import net.sourceforge.plantuml.FileFormat; import net.sourceforge.plantuml.FileFormatOption; @@ -49,7 +48,9 @@ import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.UmlDiagramType; +import net.sourceforge.plantuml.Url; import net.sourceforge.plantuml.cucadiagram.CucaDiagram; +import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.dot.CucaDiagramSimplifier2; import net.sourceforge.plantuml.cucadiagram.dot.DotData; import net.sourceforge.plantuml.cucadiagram.dot.ICucaDiagramFileMaker; @@ -61,7 +62,6 @@ import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.StringBounderUtils; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; -import net.sourceforge.plantuml.graphic.VerticalPosition; import net.sourceforge.plantuml.png.PngIO; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UGraphic; @@ -88,35 +88,38 @@ public final class CucaDiagramFileMakerSvek implements ICucaDiagramFileMaker { public String createFile(OutputStream os, List dotStrings, FileFormatOption fileFormatOption) throws IOException { - try { - createFileInternal(os, dotStrings, fileFormatOption); + return createFileInternal(os, dotStrings, fileFormatOption); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } - - return "svek"; + return null; } - private void createFileInternal(OutputStream os, List dotStrings, FileFormatOption fileFormatOption) + private String createFileInternal(OutputStream os, List dotStrings, FileFormatOption fileFormatOption) throws IOException, InterruptedException { if (diagram.getUmlDiagramType() == UmlDiagramType.STATE || diagram.getUmlDiagramType() == UmlDiagramType.ACTIVITY) { new CucaDiagramSimplifier2(diagram, dotStrings); } + double deltaX = 0; + double deltaY = 0; + final DotData dotData = new DotData(null, diagram.getLinks(), diagram.entities(), diagram.getUmlDiagramType(), diagram.getSkinParam(), diagram.getRankdir(), diagram, diagram, diagram.getColorMapper()); - final CucaDiagramFileMakerSvek2 skek2 = new CucaDiagramFileMakerSvek2(dotData); + final CucaDiagramFileMakerSvek2 svek2 = new CucaDiagramFileMakerSvek2(dotData); - IEntityImage result = skek2.createFile(((CucaDiagram) diagram).getDotStringSkek()); + IEntityImage result = svek2.createFile(((CucaDiagram) diagram).getDotStringSkek()); result = addTitle(result); result = addHeaderAndFooter(result); - final Dimension2D dim = Dimension2DDouble.delta(result.getDimension(stringBounder), 10); + // final Dimension2D dim = + // Dimension2DDouble.delta(result.getDimension(stringBounder), 10); + final Dimension2D dim = result.getDimension(stringBounder); final FileFormat fileFormat = fileFormatOption.getFileFormat(); if (fileFormat == FileFormat.PNG) { @@ -128,7 +131,45 @@ public final class CucaDiagramFileMakerSvek implements ICucaDiagramFileMaker { } else { throw new UnsupportedOperationException(fileFormat.toString()); } + + if (result instanceof DecorateEntityImage) { + deltaX += ((DecorateEntityImage) result).getDeltaX(); + deltaY += ((DecorateEntityImage) result).getDeltaY(); + } + + if (diagram.hasUrl()) { + return cmapString(svek2, deltaX, deltaY); + } + return null; + + } + + private String cmapString(CucaDiagramFileMakerSvek2 svek2, double deltaX, double deltaY) { + final StringBuilder sb = new StringBuilder(); + sb.append("\n"); + for (IEntity ent : diagram.entities().values()) { + final Url url = ent.getUrl(); + if (url == null) { + continue; + } + sb.append("\"\""); + + sb.append("\n"); + } + sb.append("\n"); + return sb.toString(); } private IEntityImage addHeaderAndFooter(IEntityImage original) { diff --git a/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek2.java b/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek2.java index 138d1a929..449b3b896 100644 --- a/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek2.java +++ b/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek2.java @@ -141,6 +141,9 @@ public final class CucaDiagramFileMakerSvek2 { if (ent.getType() == EntityType.EMPTY_PACKAGE) { return new EntityImageEmptyPackage(ent, dotData.getSkinParam()); } + if (ent.getType() == EntityType.ASSOCIATION) { + return new EntityImageAssociation(ent, dotData.getSkinParam()); + } throw new UnsupportedOperationException(ent.getType().toString()); } @@ -159,7 +162,15 @@ public final class CucaDiagramFileMakerSvek2 { return "za" + ent.getParent().getUid2(); } } - return result.getUid(); + String uid = result.getUid(); + if (result.isShielded()) { + uid = uid + ":h"; + } + return uid; + } + + public Shape getShape(IEntity ent) { + return shapeMap.get(ent); } public IEntityImage createFile(String... dotStrings) throws IOException, InterruptedException { @@ -263,7 +274,8 @@ public final class CucaDiagramFileMakerSvek2 { image = ent.getSvekImage(); } final Dimension2D dim = image.getDimension(stringBounder); - final Shape shape = new Shape(image.getShapeType(), dim.getWidth(), dim.getHeight(), colorSequence, ent.isTop()); + final Shape shape = new Shape(image.getShapeType(), dim.getWidth(), dim.getHeight(), colorSequence, + ent.isTop(), image.getShield()); dotStringFactory.addShape(shape); shape.setImage(image); shapeMap.put(ent, shape); diff --git a/src/net/sourceforge/plantuml/svek/DecorateEntityImage.java b/src/net/sourceforge/plantuml/svek/DecorateEntityImage.java index 519e4937f..ffc9bfe40 100644 --- a/src/net/sourceforge/plantuml/svek/DecorateEntityImage.java +++ b/src/net/sourceforge/plantuml/svek/DecorateEntityImage.java @@ -50,6 +50,9 @@ public class DecorateEntityImage implements IEntityImage { private final HorizontalAlignement horizontal2; private final TextBlock text2; + private double deltaX; + private double deltaY; + public DecorateEntityImage(IEntityImage original, TextBlock text, HorizontalAlignement horizontal) { this(original, text, horizontal, null, null); } @@ -81,6 +84,8 @@ public class DecorateEntityImage implements IEntityImage { text1.drawU(ug, xText1, yText1); } original.drawU(ug, xImage, yImage); + deltaX = xImage; + deltaY = yImage; if (text2 != null) { final double xText2 = getTextX(dimText2, dimTotal, horizontal2); text2.drawU(ug, xText2, yText2); @@ -121,4 +126,22 @@ public class DecorateEntityImage implements IEntityImage { return ShapeType.RECTANGLE; } + public int getShield() { + return 0; + } + + public final double getDeltaX() { + if (original instanceof DecorateEntityImage) { + return deltaX + ((DecorateEntityImage) original).deltaX; + } + return deltaX; + } + + public final double getDeltaY() { + if (original instanceof DecorateEntityImage) { + return deltaY + ((DecorateEntityImage) original).deltaY; + } + return deltaY; + } + } \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/svek/DotStringFactory.java b/src/net/sourceforge/plantuml/svek/DotStringFactory.java index 0c34d80a2..68f6c78a9 100644 --- a/src/net/sourceforge/plantuml/svek/DotStringFactory.java +++ b/src/net/sourceforge/plantuml/svek/DotStringFactory.java @@ -47,6 +47,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.Log; +import net.sourceforge.plantuml.OptionFlags; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.cucadiagram.Group; @@ -126,13 +128,13 @@ public class DotStringFactory { nodesep = getMinNodeSep(); } final String nodesepInches = SvekUtils.pixelToInches(nodesep); - System.err.println("nodesep=" + nodesepInches); + // System.err.println("nodesep=" + nodesepInches); double ranksep = getVerticalDzeta(); if (ranksep < getMinRankSep()) { ranksep = getMinRankSep(); } final String ranksepInches = SvekUtils.pixelToInches(ranksep); - System.err.println("ranksep=" + ranksepInches); + // System.err.println("ranksep=" + ranksepInches); sb.append("digraph unix {"); SvekUtils.println(sb); @@ -182,7 +184,7 @@ public class DotStringFactory { String getSVG(String... dotStrings) throws IOException, InterruptedException { final String dotString = createDotString(dotStrings); - System.err.println("dotString=" + dotString); + // System.err.println("dotString=" + dotString); final Graphviz graphviz = GraphvizUtils.create(dotString, "svg"); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -191,7 +193,10 @@ public class DotStringFactory { final byte[] result = baos.toByteArray(); final String s = new String(result, "UTF-8"); - SvekUtils.traceSvgString(s); + if (OptionFlags.getInstance().isKeepTmpFiles()) { + Log.info("Creating temporary file svek.svg"); + SvekUtils.traceSvgString(s); + } return s; } @@ -281,12 +286,11 @@ public class DotStringFactory { for (Line line : lines) { line.solveLine(svg, fullHeight); } - + for (Line line : lines) { line.manageCollision(allShapes); } - return new Dimension2DDouble(fullWidth, fullHeight); } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageActivity.java b/src/net/sourceforge/plantuml/svek/EntityImageActivity.java index 819ccdf5b..791a10e0d 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageActivity.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageActivity.java @@ -39,7 +39,6 @@ import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; -import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.Stereotype; import net.sourceforge.plantuml.graphic.FontConfiguration; @@ -48,6 +47,7 @@ import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UStroke; @@ -62,9 +62,8 @@ public class EntityImageActivity extends AbstractEntityImage { super(entity, skinParam); final Stereotype stereotype = entity.getStereotype(); - this.desc = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration( - getFont(FontParam.ACTIVITY, stereotype), getFontColor(FontParam.ACTIVITY, stereotype)), - HorizontalAlignement.CENTER); + this.desc = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration(getFont(FontParam.ACTIVITY, + stereotype), getFontColor(FontParam.ACTIVITY, stereotype)), HorizontalAlignement.CENTER); } @Override @@ -79,7 +78,8 @@ public class EntityImageActivity extends AbstractEntityImage { final double widthTotal = dimTotal.getWidth(); final double heightTotal = dimTotal.getHeight(); - final URectangle rect = new URectangle(widthTotal, heightTotal, CORNER, CORNER); + final Shadowable rect = new URectangle(widthTotal, heightTotal, CORNER, CORNER); + rect.setDeltaShadow(4); ug.getParam().setStroke(new UStroke(1.5)); ug.getParam().setColor(getColor(ColorParam.activityBorder, getStereo())); @@ -101,4 +101,9 @@ public class EntityImageActivity extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.ROUND_RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageActor.java b/src/net/sourceforge/plantuml/svek/EntityImageActor.java index fd6929144..59a4aa679 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageActor.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageActor.java @@ -119,4 +119,9 @@ public class EntityImageActor extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageAssociation.java b/src/net/sourceforge/plantuml/svek/EntityImageAssociation.java new file mode 100644 index 000000000..aa5de424b --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/EntityImageAssociation.java @@ -0,0 +1,90 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 5183 $ + * + */ +package net.sourceforge.plantuml.svek; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.ColorParam; +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.cucadiagram.IEntity; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UPolygon; +import net.sourceforge.plantuml.ugraphic.UStroke; + +public class EntityImageAssociation extends AbstractEntityImage { + + final private static int SIZE = 12; + + public EntityImageAssociation(IEntity entity, ISkinParam skinParam) { + super(entity, skinParam); + } + + @Override + public Dimension2D getDimension(StringBounder stringBounder) { + return new Dimension2DDouble(SIZE * 2, SIZE * 2); + } + + public void drawU(UGraphic ug, double xTheoricalPosition, double yTheoricalPosition) { + // final StringBounder stringBounder = ug.getStringBounder(); + // final Dimension2D dimTotal = getDimension(stringBounder); + // + // final double widthTotal = dimTotal.getWidth(); + // final double heightTotal = dimTotal.getHeight(); + + final UPolygon diams = new UPolygon(); + diams.setDeltaShadow(5); + diams.addPoint(SIZE, 0); + diams.addPoint(SIZE * 2, SIZE); + diams.addPoint(SIZE, SIZE * 2); + diams.addPoint(0, SIZE); + diams.addPoint(SIZE, 0); + + ug.getParam().setStroke(new UStroke(1.5)); + ug.getParam().setColor(getColor(ColorParam.classBorder, getStereo())); + ug.getParam().setBackcolor(getColor(ColorParam.classBackground, getStereo())); + ug.draw(xTheoricalPosition, yTheoricalPosition, diams); + ug.getParam().setStroke(new UStroke()); + } + + public ShapeType getShapeType() { + return ShapeType.DIAMOND; + } + + public int getShield() { + return 0; + } + +} diff --git a/src/net/sourceforge/plantuml/svek/EntityImageAssociationPoint.java b/src/net/sourceforge/plantuml/svek/EntityImageAssociationPoint.java index d5b4680a4..7fc3b9e3b 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageAssociationPoint.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageAssociationPoint.java @@ -67,5 +67,10 @@ public class EntityImageAssociationPoint extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.CIRCLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageBranch.java b/src/net/sourceforge/plantuml/svek/EntityImageBranch.java index da92e7843..709f546ff 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageBranch.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageBranch.java @@ -65,6 +65,7 @@ public class EntityImageBranch extends AbstractEntityImage { // final double heightTotal = dimTotal.getHeight(); final UPolygon diams = new UPolygon(); + diams.setDeltaShadow(5); diams.addPoint(SIZE, 0); diams.addPoint(SIZE * 2, SIZE); diams.addPoint(SIZE, SIZE * 2); @@ -81,4 +82,9 @@ public class EntityImageBranch extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.DIAMOND; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageCircleEnd.java b/src/net/sourceforge/plantuml/svek/EntityImageCircleEnd.java index e3cdf64c2..7f540a6de 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageCircleEnd.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageCircleEnd.java @@ -59,7 +59,8 @@ public class EntityImageCircleEnd extends AbstractEntityImage { } public void drawU(UGraphic ug, double xTheoricalPosition, double yTheoricalPosition) { - final UShape circle = new UEllipse(SIZE, SIZE); + final UEllipse circle = new UEllipse(SIZE, SIZE); + circle.setDeltaShadow(3); ug.getParam().setStroke(new UStroke()); ug.getParam().setBackcolor(null); ug.getParam().setColor(getColor(ColorParam.activityEnd, getStereo())); @@ -77,5 +78,10 @@ public class EntityImageCircleEnd extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.CIRCLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageCircleInterface.java b/src/net/sourceforge/plantuml/svek/EntityImageCircleInterface.java index 67bac2b9d..fccd3da52 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageCircleInterface.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageCircleInterface.java @@ -123,5 +123,10 @@ public class EntityImageCircleInterface extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageCircleStart.java b/src/net/sourceforge/plantuml/svek/EntityImageCircleStart.java index 4a8b87acd..1a96e3157 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageCircleStart.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageCircleStart.java @@ -42,7 +42,6 @@ import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UGraphic; -import net.sourceforge.plantuml.ugraphic.UShape; public class EntityImageCircleStart extends AbstractEntityImage { @@ -58,7 +57,8 @@ public class EntityImageCircleStart extends AbstractEntityImage { } public void drawU(UGraphic ug, double xTheoricalPosition, double yTheoricalPosition) { - final UShape circle = new UEllipse(SIZE, SIZE); + final UEllipse circle = new UEllipse(SIZE, SIZE); + circle.setDeltaShadow(3); ug.getParam().setColor(null); ug.getParam().setBackcolor(getColor(ColorParam.activityStart, getStereo())); ug.draw(xTheoricalPosition, yTheoricalPosition, circle); @@ -68,4 +68,8 @@ public class EntityImageCircleStart extends AbstractEntityImage { return ShapeType.CIRCLE; } + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageClass.java b/src/net/sourceforge/plantuml/svek/EntityImageClass.java index cfa8312f1..7f984bd66 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageClass.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageClass.java @@ -40,7 +40,6 @@ import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.MathUtils; -import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.cucadiagram.EntityPortion; import net.sourceforge.plantuml.cucadiagram.EntityType; import net.sourceforge.plantuml.cucadiagram.IEntity; @@ -56,6 +55,7 @@ import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.ugraphic.PlacementStrategyX1Y2Y3; import net.sourceforge.plantuml.ugraphic.PlacementStrategyY1Y2; +import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGroup; @@ -67,13 +67,16 @@ public class EntityImageClass extends AbstractEntityImage { final private TextBlock name; final private TextBlock stereo; - final private MethodsOrFieldsArea2 methods; - final private MethodsOrFieldsArea2 fields; + final private TextBlock methods; + final private TextBlock fields; final private CircledCharacter circledCharacter; + final private int shield; public EntityImageClass(IEntity entity, ISkinParam skinParam, PortionShower portionShower) { super(entity, skinParam); + this.shield = entity.hasNearDecoration() ? 16 : 0; + final boolean italic = entity.getType() == EntityType.ABSTRACT_CLASS || entity.getType() == EntityType.INTERFACE; @@ -83,30 +86,31 @@ public class EntityImageClass extends AbstractEntityImage { if (italic) { fontConfigurationName = fontConfigurationName.italic(); } - this.name = TextBlockUtils.create(entity.getDisplay2(), fontConfigurationName, - HorizontalAlignement.CENTER); + this.name = TextBlockUtils.create(entity.getDisplay2(), fontConfigurationName, HorizontalAlignement.CENTER); if (stereotype == null || stereotype.getLabel() == null || portionShower.showPortion(EntityPortion.STEREOTYPE, entity) == false) { this.stereo = null; } else { - this.stereo = TextBlockUtils.create(StringUtils.getWithNewlines(stereotype.getLabel()), - new FontConfiguration(getFont(FontParam.CLASS_STEREOTYPE, stereotype), getFontColor( - FontParam.CLASS_STEREOTYPE, stereotype)), HorizontalAlignement.CENTER); + this.stereo = TextBlockUtils.create(stereotype.getLabels(), new FontConfiguration(getFont( + FontParam.CLASS_STEREOTYPE, stereotype), getFontColor(FontParam.CLASS_STEREOTYPE, stereotype)), + HorizontalAlignement.CENTER); } // see LabelBuilderHtmlHeaderTableForObjectOrClass for colors final boolean showMethods = portionShower.showPortion(EntityPortion.METHOD, getEntity()); if (showMethods) { - this.methods = new MethodsOrFieldsArea2(entity.getMethodsToDisplay(), FontParam.CLASS_ATTRIBUTE, skinParam); + this.methods = TextBlockUtils.withMargin(new MethodsOrFieldsArea2(entity.getMethodsToDisplay(), + FontParam.CLASS_ATTRIBUTE, skinParam), 6, 4); } else { this.methods = null; } final boolean showFields = portionShower.showPortion(EntityPortion.FIELD, getEntity()); if (showFields) { - this.fields = new MethodsOrFieldsArea2(entity.getFieldsToDisplay(), FontParam.CLASS_ATTRIBUTE, skinParam); + this.fields = TextBlockUtils.withMargin(new MethodsOrFieldsArea2(entity.getFieldsToDisplay(), + FontParam.CLASS_ATTRIBUTE, skinParam), 6, 4); } else { this.fields = null; } @@ -150,7 +154,6 @@ public class EntityImageClass extends AbstractEntityImage { return null; } - private int xMarginFieldsOrMethod = 5; private int marginEmptyFieldsOrMethod = 13; @Override @@ -160,8 +163,8 @@ public class EntityImageClass extends AbstractEntityImage { .calculateDimension(stringBounder); final Dimension2D dimFields = fields == null ? new Dimension2DDouble(0, 0) : fields .calculateDimension(stringBounder); - final double width = MathUtils.max(dimMethods.getWidth() + 2 * xMarginFieldsOrMethod, dimFields.getWidth() + 2 - * xMarginFieldsOrMethod, dimTitle.getWidth() + 2 * xMarginCircle); + final double width = MathUtils.max(dimMethods.getWidth(), dimFields.getWidth(), dimTitle.getWidth() + 2 + * xMarginCircle); final double height = getMethodOrFieldHeight(dimMethods, EntityPortion.METHOD) + getMethodOrFieldHeight(dimFields, EntityPortion.FIELD) + dimTitle.getHeight(); return new Dimension2DDouble(width, height); @@ -214,7 +217,9 @@ public class EntityImageClass extends AbstractEntityImage { final double widthTotal = dimTotal.getWidth(); final double heightTotal = dimTotal.getHeight(); - final URectangle rect = new URectangle(widthTotal, heightTotal); + // final URectangle rect = new URectangle(widthTotal, heightTotal); + final Shadowable rect = new URectangle(widthTotal, heightTotal); + rect.setDeltaShadow(4); ug.getParam().setColor(getColor(ColorParam.classBorder, getStereo())); ug.getParam().setBackcolor(getColor(ColorParam.classBackground, getStereo())); @@ -246,7 +251,7 @@ public class EntityImageClass extends AbstractEntityImage { ug.getParam().setStroke(new UStroke(1.5)); ug.draw(x, y, new ULine(widthTotal, 0)); ug.getParam().setStroke(new UStroke()); - fields.draw(ug, x + xMarginFieldsOrMethod, y); + fields.drawU(ug, x, y); y += getMethodOrFieldHeight(fields.calculateDimension(stringBounder), EntityPortion.FIELD); } @@ -255,7 +260,7 @@ public class EntityImageClass extends AbstractEntityImage { ug.getParam().setStroke(new UStroke(1.5)); ug.draw(x, y, new ULine(widthTotal, 0)); ug.getParam().setStroke(new UStroke()); - methods.draw(ug, x + xMarginFieldsOrMethod, y); + methods.drawU(ug, x, y); } } @@ -263,4 +268,8 @@ public class EntityImageClass extends AbstractEntityImage { return ShapeType.RECTANGLE; } + public int getShield() { + return shield; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageComponent.java b/src/net/sourceforge/plantuml/svek/EntityImageComponent.java index 9e30dbf44..0ae36bfb3 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageComponent.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageComponent.java @@ -123,4 +123,9 @@ public class EntityImageComponent extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageEmptyPackage.java b/src/net/sourceforge/plantuml/svek/EntityImageEmptyPackage.java index a3a3f761a..f3490e876 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageEmptyPackage.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageEmptyPackage.java @@ -39,7 +39,6 @@ import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; -import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.Stereotype; import net.sourceforge.plantuml.graphic.FontConfiguration; @@ -47,6 +46,7 @@ import net.sourceforge.plantuml.graphic.HorizontalAlignement; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UShape; @@ -60,9 +60,8 @@ public class EntityImageEmptyPackage extends AbstractEntityImage { public EntityImageEmptyPackage(IEntity entity, ISkinParam skinParam) { super(entity, skinParam); final Stereotype stereotype = entity.getStereotype(); - this.desc = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration( - getFont(FontParam.PACKAGE, stereotype), getFontColor(FontParam.PACKAGE, stereotype)), - HorizontalAlignement.CENTER); + this.desc = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration(getFont(FontParam.PACKAGE, + stereotype), getFontColor(FontParam.PACKAGE, stereotype)), HorizontalAlignement.CENTER); } @Override @@ -77,7 +76,8 @@ public class EntityImageEmptyPackage extends AbstractEntityImage { final double widthTotal = dimTotal.getWidth(); final double heightTotal = dimTotal.getHeight(); - final UShape form = new URectangle(widthTotal, heightTotal); + final Shadowable form = new URectangle(widthTotal, heightTotal); + form.setDeltaShadow(4); final UShape small = new URectangle(15, 5); @@ -97,4 +97,9 @@ public class EntityImageEmptyPackage extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageGroup.java b/src/net/sourceforge/plantuml/svek/EntityImageGroup.java index 14888b75b..440614f3f 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageGroup.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageGroup.java @@ -83,4 +83,9 @@ public class EntityImageGroup extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageLollipopInterface.java b/src/net/sourceforge/plantuml/svek/EntityImageLollipopInterface.java index b7158f159..ebe810f41 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageLollipopInterface.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageLollipopInterface.java @@ -72,7 +72,8 @@ public class EntityImageLollipopInterface extends AbstractEntityImage { } public void drawU(UGraphic ug, double xTheoricalPosition, double yTheoricalPosition) { - final UShape circle = new UEllipse(SIZE, SIZE); + final UEllipse circle = new UEllipse(SIZE, SIZE); + circle.setDeltaShadow(4); ug.getParam().setStroke(new UStroke(1.5)); ug.getParam().setColor(getColor(ColorParam.classBorder, getStereo())); ug.getParam().setBackcolor(getColor(ColorParam.classBackground, getStereo())); @@ -91,5 +92,10 @@ public class EntityImageLollipopInterface extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.CIRCLE_IN_RECT; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageNote.java b/src/net/sourceforge/plantuml/svek/EntityImageNote.java index c77daf87c..276f98378 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageNote.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageNote.java @@ -39,7 +39,6 @@ import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.SkinParamBackcolored; -import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.Stereotype; import net.sourceforge.plantuml.graphic.HtmlColor; @@ -93,7 +92,7 @@ public class EntityImageNote extends AbstractEntityImage { final double dx = ug.getTranslateX(); final double dy = ug.getTranslateY(); ug.translate(xTheoricalPosition, yTheoricalPosition); - comp.drawU(ug, getDimension(ug.getStringBounder()), new SimpleContext2D(false)); + comp.drawU(ug, getDimension(ug.getStringBounder()), new SimpleContext2D(false, true)); ug.setTranslate(dx, dy); } @@ -101,5 +100,10 @@ public class EntityImageNote extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageNoteLink.java b/src/net/sourceforge/plantuml/svek/EntityImageNoteLink.java index d58273767..47fec8644 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageNoteLink.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageNoteLink.java @@ -65,7 +65,7 @@ public class EntityImageNoteLink implements IEntityImage { final double dx = ug.getTranslateX(); final double dy = ug.getTranslateY(); ug.translate(xTheoricalPosition, yTheoricalPosition); - comp.drawU(ug, getDimension(ug.getStringBounder()), new SimpleContext2D(false)); + comp.drawU(ug, getDimension(ug.getStringBounder()), new SimpleContext2D(false, true)); ug.setTranslate(dx, dy); } @@ -77,5 +77,10 @@ public class EntityImageNoteLink implements IEntityImage { public HtmlColor getBackcolor() { return null; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageObject.java b/src/net/sourceforge/plantuml/svek/EntityImageObject.java index 120394e0d..461a36f13 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageObject.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageObject.java @@ -49,6 +49,7 @@ import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.ugraphic.PlacementStrategyY1Y2; +import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGroup; import net.sourceforge.plantuml.ugraphic.ULine; @@ -65,9 +66,8 @@ public class EntityImageObject extends AbstractEntityImage { public EntityImageObject(IEntity entity, ISkinParam skinParam) { super(entity, skinParam); final Stereotype stereotype = entity.getStereotype(); - this.name = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration( - getFont(FontParam.OBJECT, stereotype), getFontColor(FontParam.OBJECT, stereotype)), - HorizontalAlignement.CENTER); + this.name = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration(getFont(FontParam.OBJECT, + stereotype), getFontColor(FontParam.OBJECT, stereotype)), HorizontalAlignement.CENTER); if (stereotype == null || stereotype.getLabel() == null) { this.stereo = null; } else { @@ -125,7 +125,8 @@ public class EntityImageObject extends AbstractEntityImage { final double widthTotal = dimTotal.getWidth(); final double heightTotal = dimTotal.getHeight(); - final URectangle rect = new URectangle(widthTotal, heightTotal); + final Shadowable rect = new URectangle(widthTotal, heightTotal); + rect.setDeltaShadow(4); ug.getParam().setColor(getColor(ColorParam.objectBorder, getStereo())); ug.getParam().setBackcolor(getColor(ColorParam.objectBackground, getStereo())); @@ -150,12 +151,17 @@ public class EntityImageObject extends AbstractEntityImage { ug.getParam().setStroke(new UStroke(1.5)); ug.draw(x, y, new ULine(widthTotal, 0)); ug.getParam().setStroke(new UStroke()); - fields.draw(ug, x + xMarginFieldsOrMethod, y); + fields.drawU(ug, x + xMarginFieldsOrMethod, y); } public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageState.java b/src/net/sourceforge/plantuml/svek/EntityImageState.java index 7e988df0b..8aee739b6 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageState.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageState.java @@ -41,7 +41,6 @@ import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; -import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.Member; import net.sourceforge.plantuml.cucadiagram.Stereotype; @@ -51,6 +50,7 @@ import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.URectangle; @@ -71,9 +71,8 @@ public class EntityImageState extends AbstractEntityImage { super(entity, skinParam); final Stereotype stereotype = entity.getStereotype(); - this.desc = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration( - getFont(FontParam.STATE, stereotype), getFontColor(FontParam.STATE, stereotype)), - HorizontalAlignement.CENTER); + this.desc = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration(getFont(FontParam.STATE, + stereotype), getFontColor(FontParam.STATE, stereotype)), HorizontalAlignement.CENTER); final List list = new ArrayList(); for (Member att : entity.getFieldsToDisplay()) { @@ -100,7 +99,8 @@ public class EntityImageState extends AbstractEntityImage { final double widthTotal = dimTotal.getWidth(); final double heightTotal = dimTotal.getHeight(); - final URectangle rect = new URectangle(widthTotal, heightTotal, CORNER, CORNER); + final Shadowable rect = new URectangle(widthTotal, heightTotal, CORNER, CORNER); + rect.setDeltaShadow(4); ug.getParam().setStroke(new UStroke(1.5)); ug.getParam().setColor(getColor(ColorParam.stateBorder, getStereo())); @@ -130,4 +130,9 @@ public class EntityImageState extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.ROUND_RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageSynchroBar.java b/src/net/sourceforge/plantuml/svek/EntityImageSynchroBar.java index 80b1b94b6..9ddefb36b 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageSynchroBar.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageSynchroBar.java @@ -40,9 +40,9 @@ import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.URectangle; -import net.sourceforge.plantuml.ugraphic.UShape; public class EntityImageSynchroBar extends AbstractEntityImage { @@ -57,7 +57,8 @@ public class EntityImageSynchroBar extends AbstractEntityImage { public void drawU(UGraphic ug, double xTheoricalPosition, double yTheoricalPosition) { final Dimension2D dim = getDimension(ug.getStringBounder()); - final UShape rect = new URectangle(dim.getWidth(), dim.getHeight()); + final Shadowable rect = new URectangle(dim.getWidth(), dim.getHeight()); + rect.setDeltaShadow(4); ug.getParam().setColor(null); ug.getParam().setBackcolor(getColor(ColorParam.activityBar, getStereo())); ug.draw(xTheoricalPosition, yTheoricalPosition, rect); @@ -66,5 +67,10 @@ public class EntityImageSynchroBar extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/EntityImageUseCase.java b/src/net/sourceforge/plantuml/svek/EntityImageUseCase.java index 280f33f3c..bed7f2cbd 100644 --- a/src/net/sourceforge/plantuml/svek/EntityImageUseCase.java +++ b/src/net/sourceforge/plantuml/svek/EntityImageUseCase.java @@ -61,8 +61,8 @@ public class EntityImageUseCase extends AbstractEntityImage { super(entity, skinParam); final Stereotype stereotype = entity.getStereotype(); - this.desc = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration( - getFont(FontParam.USECASE, stereotype), getFontColor(FontParam.USECASE, stereotype)), HorizontalAlignement.CENTER); + this.desc = TextBlockUtils.create(entity.getDisplay2(), new FontConfiguration(getFont(FontParam.USECASE, + stereotype), getFontColor(FontParam.USECASE, stereotype)), HorizontalAlignement.CENTER); if (stereotype == null || stereotype.getLabel() == null) { this.stereo = null; @@ -97,6 +97,7 @@ public class EntityImageUseCase extends AbstractEntityImage { final double widthTotal = dimTotal.getWidth(); final double heightTotal = dimTotal.getHeight(); final UEllipse ellipse = new UEllipse(widthTotal, heightTotal); + ellipse.setDeltaShadow(3); ug.getParam().setStroke(new UStroke(1.5)); ug.getParam().setColor(getColor(ColorParam.usecaseBorder, getStereo())); @@ -118,4 +119,9 @@ public class EntityImageUseCase extends AbstractEntityImage { public ShapeType getShapeType() { return ShapeType.OVAL; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/IEntityImage.java b/src/net/sourceforge/plantuml/svek/IEntityImage.java index 1cd617a1e..dc886a5f0 100644 --- a/src/net/sourceforge/plantuml/svek/IEntityImage.java +++ b/src/net/sourceforge/plantuml/svek/IEntityImage.java @@ -48,5 +48,7 @@ public interface IEntityImage { ShapeType getShapeType(); HtmlColor getBackcolor(); + + int getShield(); } \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/svek/InnerActivity.java b/src/net/sourceforge/plantuml/svek/InnerActivity.java index 58c91da17..242b548ec 100644 --- a/src/net/sourceforge/plantuml/svek/InnerActivity.java +++ b/src/net/sourceforge/plantuml/svek/InnerActivity.java @@ -77,5 +77,10 @@ public final class InnerActivity implements IEntityImage { public ShapeType getShapeType() { return ShapeType.ROUND_RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/InnerStateAutonom.java b/src/net/sourceforge/plantuml/svek/InnerStateAutonom.java index c9e5d8d32..b0cec0abd 100644 --- a/src/net/sourceforge/plantuml/svek/InnerStateAutonom.java +++ b/src/net/sourceforge/plantuml/svek/InnerStateAutonom.java @@ -90,5 +90,10 @@ public final class InnerStateAutonom implements IEntityImage { public ShapeType getShapeType() { return ShapeType.ROUND_RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/InnerStateConcurrent.java b/src/net/sourceforge/plantuml/svek/InnerStateConcurrent.java index 40ddf16fb..35116f52e 100644 --- a/src/net/sourceforge/plantuml/svek/InnerStateConcurrent.java +++ b/src/net/sourceforge/plantuml/svek/InnerStateConcurrent.java @@ -79,5 +79,10 @@ public final class InnerStateConcurrent implements IEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/svek/Line.java b/src/net/sourceforge/plantuml/svek/Line.java index d3f2c810a..2bd15f9f1 100644 --- a/src/net/sourceforge/plantuml/svek/Line.java +++ b/src/net/sourceforge/plantuml/svek/Line.java @@ -33,12 +33,14 @@ */ package net.sourceforge.plantuml.svek; +import java.awt.geom.AffineTransform; import java.awt.geom.Dimension2D; import java.awt.geom.Point2D; import java.util.List; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.StringUtils; +import net.sourceforge.plantuml.command.Position; import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.LinkDecor; import net.sourceforge.plantuml.graphic.FontConfiguration; @@ -47,11 +49,15 @@ import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; +import net.sourceforge.plantuml.graphic.UDrawable3; import net.sourceforge.plantuml.posimo.BezierUtils; import net.sourceforge.plantuml.posimo.DotPath; import net.sourceforge.plantuml.posimo.Positionable; +import net.sourceforge.plantuml.posimo.PositionableUtils; import net.sourceforge.plantuml.svek.SvekUtils.PointListIterator; +import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UPolygon; import net.sourceforge.plantuml.ugraphic.UShape; import net.sourceforge.plantuml.ugraphic.UStroke; @@ -67,24 +73,21 @@ public class Line { private final String startUid; private final String endUid; - private final TextBlock labelText; private final TextBlock startTailText; private final TextBlock endHeadText; - private final IEntityImage note; + private final TextBlock noteLabelText; private final int lineColor; - private final int labelColor; + private final int noteLabelColor; private final int startTailColor; private final int endHeadColor; - private final int noteColor; - private Point2D.Double labelXY; - private Point2D.Double startTailLabelXY; - private Point2D.Double endHeadLabelXY; - private Point2D.Double noteXY; + private Positionable startTailLabelXY; + private Positionable endHeadLabelXY; + private Positionable noteLabelXY; - private List endHead; - private List startTail; + private UDrawable3 endHead; + private UDrawable3 startTail; private final StringBounder stringBounder; @@ -101,18 +104,43 @@ public class Line { this.lhead = lhead; this.lineColor = colorSequence.getValue(); - this.labelColor = colorSequence.getValue(); + this.noteLabelColor = colorSequence.getValue(); this.startTailColor = colorSequence.getValue(); this.endHeadColor = colorSequence.getValue(); - this.noteColor = colorSequence.getValue(); + final TextBlock labelOnly; if (link.getLabel() == null) { - labelText = null; + labelOnly = null; } else { - labelText = TextBlockUtils.create(StringUtils.getWithNewlines(link.getLabel()), labelFont, + labelOnly = TextBlockUtils.create(StringUtils.getWithNewlines(link.getLabel()), labelFont, HorizontalAlignement.CENTER); } + final TextBlock noteOnly; + if (link.getNote() == null) { + noteOnly = null; + } else { + noteOnly = TextBlockUtils.fromIEntityImage(new EntityImageNoteLink(link.getNote(), skinParam)); + } + + if (labelOnly != null && noteOnly != null) { + if (link.getNotePosition() == Position.LEFT) { + noteLabelText = TextBlockUtils.mergeLR(noteOnly, labelOnly); + } else if (link.getNotePosition() == Position.RIGHT) { + noteLabelText = TextBlockUtils.mergeLR(labelOnly, noteOnly); + } else if (link.getNotePosition() == Position.TOP) { + noteLabelText = TextBlockUtils.mergeTB(noteOnly, labelOnly); + } else { + noteLabelText = TextBlockUtils.mergeTB(labelOnly, noteOnly); + } + } else if (labelOnly != null) { + noteLabelText = labelOnly; + } else if (noteOnly != null) { + noteLabelText = noteOnly; + } else { + noteLabelText = null; + } + if (link.getQualifier1() == null) { startTailText = null; } else { @@ -127,12 +155,6 @@ public class Line { HorizontalAlignement.CENTER); } - if (link.getNote() == null) { - note = null; - } else { - note = new EntityImageNoteLink(link.getNote(), skinParam); - } - } public void appendLine(StringBuilder sb) { @@ -140,7 +162,7 @@ public class Line { sb.append("->"); sb.append(endUid); sb.append("["); - String decoration = link.getType().getSpecificDecoration(); + String decoration = link.getType().getSpecificDecorationSvek(); if (decoration.endsWith(",") == false) { decoration += ","; } @@ -151,15 +173,10 @@ public class Line { sb.append(","); } sb.append("color=\"" + StringUtils.getAsHtml(lineColor) + "\""); - if (labelText != null) { + if (noteLabelText != null) { sb.append(","); sb.append("label=<"); - appendTable(sb, labelText.calculateDimension(stringBounder), labelColor); - sb.append(">"); - } else if (note != null) { - sb.append(","); - sb.append("label=<"); - appendTable(sb, note.getDimension(stringBounder), noteColor); + appendTable(sb, noteLabelText.calculateDimension(stringBounder), noteLabelColor); sb.append(">"); } @@ -196,7 +213,7 @@ public class Line { public String rankSame() { if (link.getLength() == 1) { - return "{rank=same; " + startUid + "; " + endUid + "}"; + return "{rank=same; " + getStartUid() + "; " + getEndUid() + "}"; } return null; } @@ -223,10 +240,16 @@ public class Line { } public final String getStartUid() { + if (startUid.endsWith(":h")) { + return startUid.substring(0, startUid.length() - 2); + } return startUid; } public final String getEndUid() { + if (endUid.endsWith(":h")) { + return endUid.substring(0, endUid.length() - 2); + } return endUid; } @@ -249,28 +272,51 @@ public class Line { final PointListIterator pointListIterator = new PointListIterator(svg.substring(end), fullHeight); - if (link.getType().getDecor2() != LinkDecor.NONE) { - this.endHead = pointListIterator.next(); + if (link.getType().getDecor2() == LinkDecor.PLUS) { + final List points = pointListIterator.next(); + final Point2D p0 = points.get(0); + final Point2D p1 = points.get(1); + final Point2D p2 = points.get(2); + final Point2D pc = new Point2D.Double((p0.getX() + p2.getX()) / 2, (p0.getY() + p2.getY()) / 2); + this.endHead = new Plus(p1, pc); + } else if (link.getType().getDecor2() != LinkDecor.NONE) { + final UShape sh = new UPolygon(pointListIterator.next()); + this.endHead = new UDrawable3() { + public void drawU(UGraphic ug, double x, double y) { + ug.draw(x, y, sh); + } + }; } - if (link.getType().getDecor1() != LinkDecor.NONE) { - this.startTail = pointListIterator.next(); + if (link.getType().getDecor1() == LinkDecor.PLUS) { + final List points = pointListIterator.next(); + final Point2D p0 = points.get(0); + final Point2D p1 = points.get(1); + final Point2D p2 = points.get(2); + final Point2D pc = new Point2D.Double((p0.getX() + p2.getX()) / 2, (p0.getY() + p2.getY()) / 2); + this.startTail = new Plus(p1, pc); + } else if (link.getType().getDecor1() != LinkDecor.NONE) { + final UShape sh = new UPolygon(pointListIterator.next()); + this.startTail = new UDrawable3() { + public void drawU(UGraphic ug, double x, double y) { + ug.draw(x, y, sh); + } + }; } - if (this.labelText != null) { - this.labelXY = getXY(svg, this.labelColor, fullHeight); + if (this.noteLabelText != null) { + this.noteLabelXY = TextBlockUtils.asPositionable(noteLabelText, stringBounder, getXY(svg, + this.noteLabelColor, fullHeight)); } if (this.startTailText != null) { - this.startTailLabelXY = getXY(svg, this.startTailColor, fullHeight); + this.startTailLabelXY = TextBlockUtils.asPositionable(startTailText, stringBounder, getXY(svg, + this.startTailColor, fullHeight)); } if (this.endHeadText != null) { - this.endHeadLabelXY = getXY(svg, this.endHeadColor, fullHeight); - } - - if (this.note != null) { - this.noteXY = getXY(svg, this.noteColor, fullHeight); + this.endHeadLabelXY = TextBlockUtils.asPositionable(endHeadText, stringBounder, getXY(svg, + this.endHeadColor, fullHeight)); } } @@ -298,37 +344,34 @@ public class Line { ug.getParam().setStroke(new UStroke()); if (this.startTail != null) { - final UShape shape = new UPolygon(this.startTail); ug.getParam().setColor(color); if (this.link.getType().getDecor1().isFill()) { ug.getParam().setBackcolor(color); } else { ug.getParam().setBackcolor(null); } - ug.draw(x, y, shape); + this.startTail.drawU(ug, x, y); } if (this.endHead != null) { - final UShape shape = new UPolygon(this.endHead); ug.getParam().setColor(color); if (this.link.getType().getDecor2().isFill()) { ug.getParam().setBackcolor(color); } else { ug.getParam().setBackcolor(null); } - ug.draw(x, y, shape); + this.endHead.drawU(ug, x, y); } - if (this.labelText != null) { - this.labelText.drawU(ug, x + this.labelXY.x, y + this.labelXY.y); + if (this.noteLabelText != null) { + this.noteLabelText.drawU(ug, x + this.noteLabelXY.getPosition().getX(), y + + this.noteLabelXY.getPosition().getY()); } if (this.startTailText != null) { - this.startTailText.drawU(ug, x + this.startTailLabelXY.x, y + this.startTailLabelXY.y); + this.startTailText.drawU(ug, x + this.startTailLabelXY.getPosition().getX(), y + + this.startTailLabelXY.getPosition().getY()); } if (this.endHeadText != null) { - this.endHeadText.drawU(ug, x + this.endHeadLabelXY.x, y + this.endHeadLabelXY.y); - } - - if (this.note != null) { - this.note.drawU(ug, x + this.noteXY.x, y + this.noteXY.y); + this.endHeadText.drawU(ug, x + this.endHeadLabelXY.getPosition().getX(), y + + this.endHeadLabelXY.getPosition().getY()); } } @@ -352,8 +395,8 @@ public class Line { } else { return 0; } - if (labelText != null) { - strategy.eat(labelText.calculateDimension(stringBounder).getWidth()); + if (noteLabelText != null) { + strategy.eat(noteLabelText.calculateDimension(stringBounder).getWidth()); } if (startTailText != null) { strategy.eat(startTailText.calculateDimension(stringBounder).getWidth()); @@ -378,8 +421,8 @@ public class Line { } else { strategy = new ArithmeticStrategySum(); } - if (labelText != null) { - strategy.eat(labelText.calculateDimension(stringBounder).getHeight()); + if (noteLabelText != null) { + strategy.eat(noteLabelText.calculateDimension(stringBounder).getHeight()); } if (startTailText != null) { strategy.eat(startTailText.calculateDimension(stringBounder).getHeight()); @@ -390,54 +433,65 @@ public class Line { return strategy.getResult() + getDecorDzeta(); } - private Positionable getStartTailPositionnable() { - if (startTailText == null) { - return null; - } - return new Positionable() { - public Point2D getPosition() { - return startTailLabelXY; - } - - public Dimension2D getSize() { - return startTailText.calculateDimension(stringBounder); - } - }; - } - - private Positionable getEndHeadPositionnable() { - if (endHeadText == null) { - return null; - } - return new Positionable() { - public Point2D getPosition() { - return endHeadLabelXY; - } - - public Dimension2D getSize() { - return endHeadText.calculateDimension(stringBounder); - } - }; - } + // private Positionable getStartTailPositionnable() { + // if (startTailText == null) { + // return null; + // } + // return new Positionable() { + // public Point2D getPosition() { + // return startTailLabelXY.; + // } + // + // public Dimension2D getSize() { + // return startTailText.calculateDimension(stringBounder); + // } + // }; + // } + // + // private Positionable getEndHeadPositionnable() { + // if (endHeadText == null) { + // return null; + // } + // return new Positionable() { + // public Point2D getPosition() { + // return endHeadLabelXY; + // } + // + // public Dimension2D getSize() { + // return endHeadText.calculateDimension(stringBounder); + // } + // }; + // } public void manageCollision(List allShapes) { -// final Positionable start = getStartTailPositionnable(); -// if (start != null) { -// for (Shape sh : allShapes) { -// if (cut(start, sh)) { -// avoid(startTailLabelXY, start, sh); -// } -// } -// } -// -// final Positionable end = getEndHeadPositionnable(); -// if (end != null) { -// for (Shape sh : allShapes) { -// if (cut(end, sh)) { -// avoid(endHeadLabelXY, end, sh); -// } -// } -// } + + for (Shape sh : allShapes) { + final Positionable cl = PositionableUtils.addMargin(sh, 8, 8); + if (startTailText != null && PositionableUtils.intersect(cl, startTailLabelXY)) { + startTailLabelXY = PositionableUtils.moveAwayFrom(cl, startTailLabelXY); + } + if (endHeadText != null && PositionableUtils.intersect(cl, endHeadLabelXY)) { + endHeadLabelXY = PositionableUtils.moveAwayFrom(cl, endHeadLabelXY); + } + } + + // final Positionable start = getStartTailPositionnable(); + // if (start != null) { + // for (Shape sh : allShapes) { + // if (cut(start, sh)) { + // avoid(startTailLabelXY, start, sh); + // } + // } + // } + // + // final Positionable end = getEndHeadPositionnable(); + // if (end != null) { + // for (Shape sh : allShapes) { + // if (cut(end, sh)) { + // avoid(endHeadLabelXY, end, sh); + // } + // } + // } } @@ -461,4 +515,58 @@ public class Line { return dist < (dim.getWidth() / 2 + 2) || dist < (dim.getHeight() / 2 + 2); } + static class Plus implements UDrawable3 { + + private final AffineTransform at; + private final AffineTransform at2; + private int radius; + private final Point2D center; + private final Point2D p1; + private final Point2D p2; + private Point2D p3; + private Point2D p4; + + public Plus(Point2D p1, Point2D p2) { + this.center = new Point2D.Double((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2); + at = AffineTransform.getTranslateInstance(-center.getX(), -center.getY()); + at2 = AffineTransform.getTranslateInstance(center.getX(), center.getY()); + radius = (int) (p1.distance(p2) / 2); + if (radius % 2 == 0) { + radius--; + } + this.p1 = putOnCircle(p1); + this.p2 = putOnCircle(p2); + + this.p3 = at.transform(this.p1, null); + this.p3 = new Point2D.Double(p3.getY(), -p3.getX()); + this.p3 = at2.transform(p3, null); + + this.p4 = at.transform(this.p2, null); + this.p4 = new Point2D.Double(p4.getY(), -p4.getX()); + this.p4 = at2.transform(p4, null); + } + + private Point2D putOnCircle(Point2D p) { + p = at.transform(p, null); + final double coef = p.distance(new Point2D.Double()) / radius; + p = new Point2D.Double(p.getX() / coef, p.getY() / coef); + return at2.transform(p, null); + } + + public void drawU(UGraphic ug, double x, double y) { + final UShape circle = new UEllipse(radius * 2, radius * 2); + ug.draw(x + center.getX() - radius, y + center.getY() - radius, circle); + drawLine(ug, x, y, p1, p2); + drawLine(ug, x, y, p3, p4); + } + + static private void drawLine(UGraphic ug, double x, double y, Point2D p1, Point2D p2) { + final double dx = p2.getX() - p1.getX(); + final double dy = p2.getY() - p1.getY(); + ug.draw(x + p1.getX(), y + p1.getY(), new ULine(dx, dy)); + + } + + } + } diff --git a/src/net/sourceforge/plantuml/svek/Shape.java b/src/net/sourceforge/plantuml/svek/Shape.java index 32a584195..0e0b9d8b4 100644 --- a/src/net/sourceforge/plantuml/svek/Shape.java +++ b/src/net/sourceforge/plantuml/svek/Shape.java @@ -51,6 +51,7 @@ public class Shape implements Positionable { private double minX; private double minY; + private final int shield; private Cluster cluster; @@ -64,13 +65,17 @@ public class Shape implements Positionable { this.cluster = cluster; } - public Shape(ShapeType type, double width, double height, ColorSequence colorSequence, boolean top) { + public Shape(ShapeType type, double width, double height, ColorSequence colorSequence, boolean top, int shield) { this.top = top; this.type = type; this.width = width; this.height = height; this.color = colorSequence.getValue(); this.uid = String.format("sh%04d", color); + this.shield = shield; + if (shield > 0 && type != ShapeType.RECTANGLE) { + throw new IllegalArgumentException(); + } } public final ShapeType getType() { @@ -86,6 +91,10 @@ public class Shape implements Positionable { } public void appendShape(StringBuilder sb) { + if (type == ShapeType.RECTANGLE && shield > 0) { + appendHtml(sb); + return; + } // if (type == ShapeType.CIRCLE_IN_RECT) { // sb.append("subgraph clusterlol" + uid + " {"); // DotStringFactory.println(sb); @@ -110,8 +119,58 @@ public class Shape implements Positionable { } + private void appendHtml(StringBuilder sb) { + sb.append(uid); + sb.append(" ["); + sb.append("shape=plaintext,"); + sb.append("label=<"); + appendLabelHtml(sb); + sb.append(">"); + sb.append("];"); + SvekUtils.println(sb); + + } + + private void appendLabelHtml(StringBuilder sb) { + // System.err.println("shield=" + shield); + sb.append(""); + sb.append(""); + appendTd(sb); + appendTd(sb, shield, shield); + appendTd(sb); + sb.append(""); + sb.append(""); + appendTd(sb, shield, shield); + sb.append(""); + appendTd(sb, shield, shield); + sb.append(""); + sb.append(""); + appendTd(sb); + appendTd(sb, shield, shield); + appendTd(sb); + sb.append(""); + sb.append("
"); + sb.append("
"); + } + + private void appendTd(StringBuilder sb, int w, int h) { + sb.append(""); + sb.append(""); + } + + private void appendTd(StringBuilder sb) { + sb.append(""); + sb.append(""); + } + private void appendShapeInternal(StringBuilder sb) { - if (type == ShapeType.RECTANGLE) { + if (type == ShapeType.RECTANGLE && shield > 0) { + throw new UnsupportedOperationException(); + } else if (type == ShapeType.RECTANGLE) { sb.append("shape=rect"); } else if (type == ShapeType.DIAMOND) { sb.append("shape=diamond"); @@ -140,6 +199,9 @@ public class Shape implements Positionable { } public final void setMinX(double minX) { + if (minX < 0) { + minX = 0; + } this.minX = minX; } @@ -148,6 +210,9 @@ public class Shape implements Positionable { } public final void setMinY(double minY) { + if (minY < 0) { + minY = 0; + } this.minY = minY; } @@ -173,4 +238,44 @@ public class Shape implements Positionable { return new Dimension2DDouble(width, height); } + // public boolean contains(Point2D pt) { + // return pt.getX() >= minX && pt.getX() <= minX + width && pt.getY() >= + // minY && pt.getY() <= minY + height; + // } + // + // public boolean intersect(Point2D pt, Dimension2D dim) { + // if (contains(pt)) { + // return true; + // } + // if (contains(new Point2D.Double(pt.getX() + dim.getWidth(), pt.getY()))) + // { + // return true; + // } + // if (contains(new Point2D.Double(pt.getX() + dim.getWidth(), pt.getY() + + // dim.getHeight()))) { + // return true; + // } + // if (contains(new Point2D.Double(pt.getX(), pt.getY() + dim.getHeight()))) + // { + // return true; + // } + // return false; + // } + // + // public boolean intersect(Positionable p) { + // return intersect(p.getPosition(), p.getSize()); + // } + + public boolean isShielded() { + return shield > 0; + } + + public String getCoords(double deltaX, double deltaY) { + final int x1 = (int) (getMinX() + deltaX); + final int y1 = (int) (getMinY() + deltaY); + final int x2 = (int) (getMinX() + getWidth() + deltaX); + final int y2 = (int) (getMinY() + getHeight() + deltaY); + return "" + x1 + "," + y1 + "," + x2 + "," + y2; + } + } diff --git a/src/net/sourceforge/plantuml/svek/SvekResult.java b/src/net/sourceforge/plantuml/svek/SvekResult.java index 1ec64df11..ee752701e 100644 --- a/src/net/sourceforge/plantuml/svek/SvekResult.java +++ b/src/net/sourceforge/plantuml/svek/SvekResult.java @@ -40,7 +40,6 @@ import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.cucadiagram.dot.DotData; import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.StringBounder; -import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.skin.rose.Rose; import net.sourceforge.plantuml.ugraphic.UGraphic; @@ -64,7 +63,7 @@ public final class SvekResult implements IEntityImage { for (Cluster cluster : dotStringFactory.getAllSubCluster()) { cluster.drawU(ug, x, y, clusterBorder, dotData); } - + for (Shape shape : dotStringFactory.getShapes()) { final double minX = shape.getMinX(); final double minY = shape.getMinY(); @@ -106,5 +105,10 @@ public final class SvekResult implements IEntityImage { public ShapeType getShapeType() { return ShapeType.RECTANGLE; } + + public int getShield() { + return 0; + } + } diff --git a/src/net/sourceforge/plantuml/swing/ImageWindow.java b/src/net/sourceforge/plantuml/swing/ImageWindow.java deleted file mode 100644 index c7b04196c..000000000 --- a/src/net/sourceforge/plantuml/swing/ImageWindow.java +++ /dev/null @@ -1,148 +0,0 @@ -/* ======================================================================== - * PlantUML : a free UML diagram generator - * ======================================================================== - * - * (C) Copyright 2009, Arnaud Roques - * - * Project Info: http://plantuml.sourceforge.net - * - * This file is part of PlantUML. - * - * PlantUML is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * PlantUML 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. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - * - * [Java is a trademark or registered trademark of Sun Microsystems, Inc. - * in the United States and other countries.] - * - * Original Author: Arnaud Roques - * - * Revision $Revision: 5885 $ - * - */ -package net.sourceforge.plantuml.swing; - -import java.awt.BorderLayout; -import java.awt.Image; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.File; - -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.ListModel; -import javax.swing.WindowConstants; - -class ImageWindow extends JFrame { - - private SimpleLine simpleLine; - final private JScrollPane scrollPane; - private final JButton next = new JButton("Next"); - private final JButton previous = new JButton("Previous"); - private final ListModel listModel; - private int index; - - public ImageWindow(SimpleLine simpleLine, final MainWindow main, ListModel listModel, int index) { - super(simpleLine.toString()); - this.simpleLine = simpleLine; - this.listModel = listModel; - this.index = index; - - final JPanel north = new JPanel(); - north.add(previous); - north.add(next); - next.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ae) { - next(); - } - }); - previous.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ae) { - previous(); - } - }); - - scrollPane = new JScrollPane(buildScrollablePicture()); - getContentPane().add(north, BorderLayout.NORTH); - getContentPane().add(scrollPane, BorderLayout.CENTER); - setSize(640, 400); - setVisible(true); - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - this.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - super.windowClosing(e); - main.closing(ImageWindow.this); - } - }); - } - - private void next() { - index++; - updateSimpleLine(); - } - - private void previous() { - index--; - updateSimpleLine(); - } - - private void updateSimpleLine() { - if (index < 0) { - index = 0; - } - if (index > listModel.getSize() - 1) { - index = listModel.getSize() - 1; - } - simpleLine = (SimpleLine) listModel.getElementAt(index); - setTitle(simpleLine.toString()); - refreshImage(); - } - - private ScrollablePicture buildScrollablePicture() { - final File png = simpleLine.getGeneratedImage().getPngFile(); - final Image image = Toolkit.getDefaultToolkit().createImage(png.getAbsolutePath()); - final ImageIcon imageIcon = new ImageIcon(image, simpleLine.toString()); - final ScrollablePicture scrollablePicture = new ScrollablePicture(imageIcon, 1); - return scrollablePicture; - } - - public SimpleLine getSimpleLine() { - return simpleLine; - } - - public void refreshImage() { - scrollPane.setViewportView(buildScrollablePicture()); - force(); - } - - private void force() { - // setVisible(true); - repaint(); - // validate(); - // getContentPane().validate(); - // getContentPane().setVisible(true); - // getContentPane().repaint(); - // scrollPane.validate(); - // scrollPane.setVisible(true); - // scrollPane.repaint(); - } - -} diff --git a/src/net/sourceforge/plantuml/swing/MainWindow.java b/src/net/sourceforge/plantuml/swing/MainWindow.java deleted file mode 100644 index 0eec83f4d..000000000 --- a/src/net/sourceforge/plantuml/swing/MainWindow.java +++ /dev/null @@ -1,334 +0,0 @@ -/* ======================================================================== - * PlantUML : a free UML diagram generator - * ======================================================================== - * - * (C) Copyright 2009, Arnaud Roques - * - * Project Info: http://plantuml.sourceforge.net - * - * This file is part of PlantUML. - * - * PlantUML is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * PlantUML 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. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - * - * [Java is a trademark or registered trademark of Sun Microsystems, Inc. - * in the United States and other countries.] - * - * Original Author: Arnaud Roques - * - * Revision $Revision: 6533 $ - * - */ -package net.sourceforge.plantuml.swing; - -import java.awt.BorderLayout; -import java.awt.Frame; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.Vector; -import java.util.prefs.Preferences; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextField; -import javax.swing.ListModel; -import javax.swing.SwingUtilities; -import javax.swing.Timer; - -import net.sourceforge.plantuml.DirWatcher; -import net.sourceforge.plantuml.GeneratedImage; -import net.sourceforge.plantuml.Log; -import net.sourceforge.plantuml.Option; - -public class MainWindow extends JFrame { - - final private static Preferences prefs = Preferences.userNodeForPackage(MainWindow.class); - final private static String KEY_DIR = "cur"; - final private static String KEY_PATTERN = "pat"; - - private final JList jList1 = new JList(); - private final JScrollPane scrollPane; - private final JButton changeDirButton = new JButton("Change Directory"); - private final JTextField extensions = new JTextField(); - - final private List currentDirectoryListing = new ArrayList(); - final private Set openWindows = new HashSet(); - final private Option option; - - private DirWatcher dirWatcher; - - public MainWindow(Option option) { - this(new File(prefs.get(KEY_DIR, ".")), option); - - } - - private String getExtensions() { - return prefs.get(KEY_PATTERN, getDefaultFileExtensions()); - } - - private String getDefaultFileExtensions() { - return "txt, tex, java, htm, html, c, h, cpp, apt"; - } - - private void changeExtensions(String ext) { - if (ext.equals(getExtensions())) { - return; - } - final Pattern p = Pattern.compile("\\w+"); - final Matcher m = p.matcher(ext); - final StringBuilder sb = new StringBuilder(); - - while (m.find()) { - final String value = m.group(); - if (sb.length() > 0) { - sb.append(", "); - } - sb.append(value); - - } - ext = sb.toString(); - if (ext.length() == 0) { - ext = getDefaultFileExtensions(); - } - extensions.setText(ext); - prefs.put(KEY_PATTERN, ext); - changeDir(dirWatcher.getDir()); - } - - private String getRegexpPattern(String ext) { - final Pattern p = Pattern.compile("\\w+"); - final Matcher m = p.matcher(ext); - final StringBuilder filePattern = new StringBuilder("(?i)^.*\\.("); - - while (m.find()) { - final String value = m.group(); - if (filePattern.toString().endsWith("(") == false) { - filePattern.append("|"); - } - filePattern.append(value); - } - if (filePattern.toString().endsWith("(") == false) { - filePattern.append(")$"); - return filePattern.toString(); - } - return Option.getPattern(); - } - - private MainWindow(File dir, Option option) { - super(dir.getAbsolutePath()); - this.option = option; - dirWatcher = new DirWatcher(dir, option, getRegexpPattern(getExtensions())); - - Log.info("Showing MainWindow"); - scrollPane = new JScrollPane(jList1); - - final JPanel south = new JPanel(new BorderLayout()); - final JLabel labelFileExtensions = new JLabel("File extensions: "); - extensions.setText(getExtensions()); - - labelFileExtensions.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); - south.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3), BorderFactory - .createEtchedBorder())); - south.add(labelFileExtensions, BorderLayout.WEST); - south.add(extensions, BorderLayout.CENTER); - - south.add(changeDirButton, BorderLayout.SOUTH); - - getContentPane().add(south, BorderLayout.SOUTH); - getContentPane().add(scrollPane, BorderLayout.CENTER); - setSize(320, 200); - setVisible(true); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - final MouseListener mouseListener = new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - final int index = jList1.locationToIndex(e.getPoint()); - doubleClick((SimpleLine) jList1.getModel().getElementAt(index), jList1.getModel(), index); - } - } - }; - jList1.addMouseListener(mouseListener); - changeDirButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - System.err.println("Opening Directory Window"); - displayDialogChangeDir(); - } - }); - - extensions.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - changeExtensions(extensions.getText()); - } - }); - extensions.addFocusListener(new FocusListener() { - - public void focusGained(FocusEvent e) { - } - - public void focusLost(FocusEvent e) { - changeExtensions(extensions.getText()); - } - }); - - startTimer(); - } - - private void startTimer() { - Log.info("Init done"); - final Timer timer = new Timer(3000, new ActionListener() { - public void actionPerformed(ActionEvent e) { - tick(); - } - }); - timer.setInitialDelay(0); - timer.start(); - Log.info("Timer started"); - } - - private void displayDialogChangeDir() { - final JFileChooser chooser = new JFileChooser(); - chooser.setDialogType(JFileChooser.CUSTOM_DIALOG); - chooser.setDialogTitle("Directory to watch:"); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - final String currentPath = prefs.get(KEY_DIR, "."); - chooser.setCurrentDirectory(new File(currentPath)); - Log.info("Showing OpenDialog"); - final int returnVal = chooser.showOpenDialog(this); - Log.info("Closing OpenDialog"); - if (returnVal == JFileChooser.APPROVE_OPTION) { - final File dir = chooser.getSelectedFile(); - changeDir(dir); - } - - } - - private void changeDir(File dir) { - prefs.put(KEY_DIR, dir.getAbsolutePath()); - dirWatcher = new DirWatcher(dir, option, getRegexpPattern(getExtensions())); - setTitle(dir.getAbsolutePath()); - Log.info("Creating DirWatcher"); - currentDirectoryListing.clear(); - jList1.setListData(new Vector(currentDirectoryListing)); - jList1.setVisible(true); - } - - private void doubleClick(SimpleLine simpleLine, ListModel listModel, int index) { - for (ImageWindow win : openWindows) { - if (win.getSimpleLine().equals(simpleLine)) { - win.setVisible(true); - win.setExtendedState(Frame.NORMAL); - return; - } - } - openWindows.add(new ImageWindow(simpleLine, this, listModel, index)); - } - - private void tick() { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - try { - final boolean changed = refreshDir(); - if (changed) { - jList1.setListData(new Vector(currentDirectoryListing)); - jList1.setVisible(true); - } - } catch (IOException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }); - } - - private boolean refreshDir() throws IOException, InterruptedException { - final Collection createdFiles2 = dirWatcher.buildCreatedFiles(); - - boolean changed = false; - - for (GeneratedImage g : createdFiles2) { - final SimpleLine simpleLine = new SimpleLine(g); - mayRefreshImageWindow(g.getPngFile()); - if (currentDirectoryListing.contains(simpleLine) == false) { - removeAllThatUseThisFile(g.getPngFile()); - currentDirectoryListing.add(simpleLine); - changed = true; - } - } - for (final Iterator it = currentDirectoryListing.iterator(); it.hasNext();) { - final SimpleLine s = it.next(); - if (s.exists() == false) { - it.remove(); - changed = true; - } - - } - Collections.sort(currentDirectoryListing); - return changed; - } - - private void removeAllThatUseThisFile(File pngFile) { - for (final Iterator it = currentDirectoryListing.iterator(); it.hasNext();) { - final SimpleLine line = it.next(); - if (line.getGeneratedImage().getPngFile().equals(pngFile)) { - it.remove(); - } - - } - - } - - private void mayRefreshImageWindow(File pngFile) { - for (ImageWindow win : openWindows) { - if (pngFile.equals(win.getSimpleLine().getGeneratedImage().getPngFile())) { - win.refreshImage(); - } - } - - } - - public void closing(ImageWindow imageWindow) { - final boolean ok = openWindows.remove(imageWindow); - if (ok == false) { - throw new IllegalStateException(); - } - } - -} diff --git a/src/net/sourceforge/plantuml/swing/MainWindow2.java b/src/net/sourceforge/plantuml/swing/MainWindow2.java index 0ea9e0f45..c9ed2a045 100644 --- a/src/net/sourceforge/plantuml/swing/MainWindow2.java +++ b/src/net/sourceforge/plantuml/swing/MainWindow2.java @@ -39,6 +39,9 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; @@ -192,6 +195,16 @@ public class MainWindow2 extends JFrame { displayDialogChangeDir(); } }); + jList1.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + final int index = jList1.getSelectedIndex(); + doubleClick((SimpleLine2) jList1.getModel().getElementAt(index), jList1.getModel(), index); + } + } + + }); extensions.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -260,7 +273,9 @@ public class MainWindow2 extends JFrame { return; } } - openWindows2.add(new ImageWindow2(simpleLine, this, listModel, index)); + if (simpleLine.getGeneratedImage() != null) { + openWindows2.add(new ImageWindow2(simpleLine, this, listModel, index)); + } } private void tick() { @@ -323,6 +338,9 @@ public class MainWindow2 extends JFrame { private void mayRefreshImageWindow(File pngFile) { for (ImageWindow2 win : openWindows2) { + if (win.getSimpleLine().getGeneratedImage() == null) { + continue; + } if (pngFile.equals(win.getSimpleLine().getGeneratedImage().getPngFile())) { win.refreshImage(); } diff --git a/src/net/sourceforge/plantuml/swing/SimpleLine2.java b/src/net/sourceforge/plantuml/swing/SimpleLine2.java index fb45b91ce..bfab8be11 100644 --- a/src/net/sourceforge/plantuml/swing/SimpleLine2.java +++ b/src/net/sourceforge/plantuml/swing/SimpleLine2.java @@ -62,21 +62,6 @@ class SimpleLine2 implements Comparable { return generatedImage == null && future.isDone(); } - public List getFutureTerminated() throws InterruptedException, ExecutionException { - if (future == null) { - throw new IllegalStateException(); - } - final List list = future.get(); - if (list == null) { - return null; - } - final List result = new ArrayList(); - for (GeneratedImage im : list) { - result.add(new SimpleLine2(file, im, null)); - } - return Collections.unmodifiableList(result); - } - @Override public String toString() { if (generatedImage == null) { diff --git a/src/net/sourceforge/plantuml/ugraphic/AbstractShadowable.java b/src/net/sourceforge/plantuml/ugraphic/AbstractShadowable.java new file mode 100644 index 000000000..9bc22f4f8 --- /dev/null +++ b/src/net/sourceforge/plantuml/ugraphic/AbstractShadowable.java @@ -0,0 +1,48 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 4901 $ + * + */ +package net.sourceforge.plantuml.ugraphic; + +abstract class AbstractShadowable implements Shadowable { + + private double deltaShadow; + + public double getDeltaShadow() { + return deltaShadow; + } + + public void setDeltaShadow(double deltaShadow) { + this.deltaShadow = deltaShadow; + } + +} diff --git a/src/net/sourceforge/plantuml/ugraphic/Shadowable.java b/src/net/sourceforge/plantuml/ugraphic/Shadowable.java new file mode 100644 index 000000000..5804681e2 --- /dev/null +++ b/src/net/sourceforge/plantuml/ugraphic/Shadowable.java @@ -0,0 +1,40 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + */ +package net.sourceforge.plantuml.ugraphic; + +public interface Shadowable extends UShape { + + public void setDeltaShadow(double deltaShadow); + + public double getDeltaShadow(); + +} diff --git a/src/net/sourceforge/plantuml/ugraphic/UEllipse.java b/src/net/sourceforge/plantuml/ugraphic/UEllipse.java index 2303af747..3fd5af96a 100644 --- a/src/net/sourceforge/plantuml/ugraphic/UEllipse.java +++ b/src/net/sourceforge/plantuml/ugraphic/UEllipse.java @@ -28,12 +28,12 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 4901 $ + * Revision $Revision: 7143 $ * */ package net.sourceforge.plantuml.ugraphic; -public class UEllipse implements UShape { +public class UEllipse extends AbstractShadowable { private final double width; private final double height; diff --git a/src/net/sourceforge/plantuml/ugraphic/UFont.java b/src/net/sourceforge/plantuml/ugraphic/UFont.java index 0c12e1c9f..9606b6707 100644 --- a/src/net/sourceforge/plantuml/ugraphic/UFont.java +++ b/src/net/sourceforge/plantuml/ugraphic/UFont.java @@ -35,7 +35,6 @@ package net.sourceforge.plantuml.ugraphic; import java.awt.Font; import java.awt.Graphics2D; -import java.util.Locale; public class UFont { diff --git a/src/net/sourceforge/plantuml/ugraphic/UPixel.java b/src/net/sourceforge/plantuml/ugraphic/UPixel.java new file mode 100644 index 000000000..00254693b --- /dev/null +++ b/src/net/sourceforge/plantuml/ugraphic/UPixel.java @@ -0,0 +1,37 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 4681 $ + * + */ +package net.sourceforge.plantuml.ugraphic; + +public class UPixel implements UShape { +} diff --git a/src/net/sourceforge/plantuml/ugraphic/UPolygon.java b/src/net/sourceforge/plantuml/ugraphic/UPolygon.java index b25bea040..2562b357a 100644 --- a/src/net/sourceforge/plantuml/ugraphic/UPolygon.java +++ b/src/net/sourceforge/plantuml/ugraphic/UPolygon.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6743 $ + * Revision $Revision: 7143 $ * */ package net.sourceforge.plantuml.ugraphic; @@ -38,7 +38,7 @@ import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; -public class UPolygon implements UShape { +public class UPolygon extends AbstractShadowable { private final List all = new ArrayList(); diff --git a/src/net/sourceforge/plantuml/ugraphic/URectangle.java b/src/net/sourceforge/plantuml/ugraphic/URectangle.java index 08f439690..11d1e97fd 100644 --- a/src/net/sourceforge/plantuml/ugraphic/URectangle.java +++ b/src/net/sourceforge/plantuml/ugraphic/URectangle.java @@ -31,7 +31,7 @@ */ package net.sourceforge.plantuml.ugraphic; -public class URectangle implements UShape { +public class URectangle extends AbstractShadowable { private final double width; private final double height; diff --git a/src/net/sourceforge/plantuml/ugraphic/eps/UGraphicEps.java b/src/net/sourceforge/plantuml/ugraphic/eps/UGraphicEps.java index 634fd42a8..680045080 100644 --- a/src/net/sourceforge/plantuml/ugraphic/eps/UGraphicEps.java +++ b/src/net/sourceforge/plantuml/ugraphic/eps/UGraphicEps.java @@ -95,13 +95,13 @@ public class UGraphicEps extends AbstractUGraphic implements ClipCo public StringBounder getStringBounder() { return stringBounder; } - + public void drawEps(String eps, double x, double y) { this.getGraphicObject().drawEps(eps, x, y); } public void setClip(UClip clip) { - this.clip = clip; + this.clip = clip == null ? null : clip.translate(getTranslateX(), getTranslateY()); } public UClip getClip() { @@ -121,7 +121,8 @@ public class UGraphicEps extends AbstractUGraphic implements ClipCo } - static public String getEpsString(ColorMapper colorMapper, EpsStrategy epsStrategy, UDrawable udrawable) throws IOException { + static public String getEpsString(ColorMapper colorMapper, EpsStrategy epsStrategy, UDrawable udrawable) + throws IOException { final UGraphicEps ug = new UGraphicEps(colorMapper, epsStrategy); udrawable.drawU(ug); return ug.getEPSCode(); diff --git a/src/net/sourceforge/plantuml/ugraphic/g2d/DriverEllipseG2d.java b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverEllipseG2d.java index 488e2a6c3..947532cec 100644 --- a/src/net/sourceforge/plantuml/ugraphic/g2d/DriverEllipseG2d.java +++ b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverEllipseG2d.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7143 $ * */ package net.sourceforge.plantuml.ugraphic.g2d; @@ -45,7 +45,7 @@ import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UParam; import net.sourceforge.plantuml.ugraphic.UShape; -public class DriverEllipseG2d implements UDriver { +public class DriverEllipseG2d extends DriverShadowedG2d implements UDriver { public void draw(UShape ushape, double x, double y, ColorMapper mapper, UParam param, Graphics2D g2d) { final UEllipse shape = (UEllipse) ushape; @@ -53,6 +53,11 @@ public class DriverEllipseG2d implements UDriver { if (shape.getStart() == 0 && shape.getExtend() == 0) { final Shape ellipse = new Ellipse2D.Double(x, y, shape.getWidth(), shape.getHeight()); + // Shadow + if (shape.getDeltaShadow() != 0) { + drawShadow(g2d, ellipse, x, y, shape.getDeltaShadow()); + } + if (param.getBackcolor() != null) { g2d.setColor(mapper.getMappedColor(param.getBackcolor())); g2d.fill(ellipse); diff --git a/src/net/sourceforge/plantuml/ugraphic/g2d/DriverPixelG2d.java b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverPixelG2d.java new file mode 100644 index 000000000..a06ee9790 --- /dev/null +++ b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverPixelG2d.java @@ -0,0 +1,50 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6576 $ + * + */ +package net.sourceforge.plantuml.ugraphic.g2d; + +import java.awt.Graphics2D; + +import net.sourceforge.plantuml.ugraphic.ColorMapper; +import net.sourceforge.plantuml.ugraphic.UDriver; +import net.sourceforge.plantuml.ugraphic.UParam; +import net.sourceforge.plantuml.ugraphic.UShape; + +public class DriverPixelG2d implements UDriver { + + public void draw(UShape ushape, double x, double y, ColorMapper mapper, UParam param, Graphics2D g2d) { + g2d.setColor(mapper.getMappedColor(param.getColor())); + g2d.fillRect((int) x, (int) y, 1, 1); + } + +} diff --git a/src/net/sourceforge/plantuml/ugraphic/g2d/DriverPolygonG2d.java b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverPolygonG2d.java index 10963664e..42af5ab36 100644 --- a/src/net/sourceforge/plantuml/ugraphic/g2d/DriverPolygonG2d.java +++ b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverPolygonG2d.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6576 $ + * Revision $Revision: 7143 $ * */ package net.sourceforge.plantuml.ugraphic.g2d; @@ -44,7 +44,7 @@ import net.sourceforge.plantuml.ugraphic.UParam; import net.sourceforge.plantuml.ugraphic.UPolygon; import net.sourceforge.plantuml.ugraphic.UShape; -public class DriverPolygonG2d implements UDriver { +public class DriverPolygonG2d extends DriverShadowedG2d implements UDriver { public void draw(UShape ushape, double x, double y, ColorMapper mapper, UParam param, Graphics2D g2d) { final UPolygon shape = (UPolygon) ushape; @@ -56,6 +56,10 @@ public class DriverPolygonG2d implements UDriver { polygon.addPoint((int) (pt.getX() + x), (int) (pt.getY() + y)); } + if (shape.getDeltaShadow() != 0) { + drawShadow(g2d, polygon, x, y, shape.getDeltaShadow()); + } + if (param.getBackcolor() != null) { g2d.setColor(mapper.getMappedColor(param.getBackcolor())); g2d.fill(polygon); diff --git a/src/net/sourceforge/plantuml/ugraphic/g2d/DriverRectangleG2d.java b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverRectangleG2d.java index fb90c440e..297beb7d4 100644 --- a/src/net/sourceforge/plantuml/ugraphic/g2d/DriverRectangleG2d.java +++ b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverRectangleG2d.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6859 $ + * Revision $Revision: 7143 $ * */ package net.sourceforge.plantuml.ugraphic.g2d; @@ -47,7 +47,7 @@ import net.sourceforge.plantuml.ugraphic.UParam; import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UShape; -public class DriverRectangleG2d implements UDriver { +public class DriverRectangleG2d extends DriverShadowedG2d implements UDriver { public void draw(UShape ushape, double x, double y, ColorMapper mapper, UParam param, Graphics2D g2d) { g2d.setStroke(new BasicStroke((float) param.getStroke().getThickness())); @@ -60,6 +60,12 @@ public class DriverRectangleG2d implements UDriver { } else { rect = new RoundRectangle2D.Double(x, y, shape.getWidth(), shape.getHeight(), rx, ry); } + + // Shadow + if (shape.getDeltaShadow() != 0) { + drawShadow(g2d, rect, x, y, shape.getDeltaShadow()); + } + final UGradient gr = param.getGradient(); if (gr == null) { if (param.getBackcolor() != null) { diff --git a/src/net/sourceforge/plantuml/ugraphic/g2d/DriverShadowedG2d.java b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverShadowedG2d.java new file mode 100644 index 000000000..8ac39485f --- /dev/null +++ b/src/net/sourceforge/plantuml/ugraphic/g2d/DriverShadowedG2d.java @@ -0,0 +1,84 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009, Arnaud Roques + * + * Project Info: http://plantuml.sourceforge.net + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML 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. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * [Java is a trademark or registered trademark of Sun Microsystems, Inc. + * in the United States and other countries.] + * + * Original Author: Arnaud Roques + * + * Revision $Revision: 6859 $ + * + */ +package net.sourceforge.plantuml.ugraphic.g2d; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ConvolveOp; +import java.awt.image.Kernel; + +public class DriverShadowedG2d { + + private final static ConvolveOp convolveOp; + + static { + final int blurRadius = 6; + final int blurRadius2 = blurRadius * blurRadius; + final float blurRadius2F = blurRadius2; + final float weight = 1.0f / blurRadius2F; + final float[] elements = new float[blurRadius2]; + for (int k = 0; k < blurRadius2; k++) { + elements[k] = weight; + } + final Kernel myKernel = new Kernel(blurRadius, blurRadius, elements); + + // if EDGE_NO_OP is not selected, EDGE_ZERO_FILL is the default which + // creates a black border + convolveOp = new ConvolveOp(myKernel, ConvolveOp.EDGE_NO_OP, null); + } + + private final Color color = new Color(170, 170, 170); + + protected void drawShadow(Graphics2D g2d, Shape shape, double x, double y, double deltaShadow) { + // Shadow + final Rectangle2D bounds = shape.getBounds2D(); + BufferedImage destination = new BufferedImage((int) (bounds.getWidth() + deltaShadow * 2 + 6), (int) (bounds + .getHeight() + + deltaShadow * 2 + 6), BufferedImage.TYPE_INT_ARGB); + final Graphics2D gg = destination.createGraphics(); + gg.setColor(color); + gg.translate(deltaShadow - x, deltaShadow - y); + gg.fill(shape); + gg.dispose(); + final ConvolveOp simpleBlur = convolveOp; + destination = simpleBlur.filter(destination, null); + g2d.drawImage(destination, (int) x, (int) y, null); + // Shadow + + } + +} diff --git a/src/net/sourceforge/plantuml/ugraphic/g2d/UGraphicG2d.java b/src/net/sourceforge/plantuml/ugraphic/g2d/UGraphicG2d.java index 1b0e61825..3de714d0c 100644 --- a/src/net/sourceforge/plantuml/ugraphic/g2d/UGraphicG2d.java +++ b/src/net/sourceforge/plantuml/ugraphic/g2d/UGraphicG2d.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6590 $ + * Revision $Revision: 7143 $ * */ package net.sourceforge.plantuml.ugraphic.g2d; @@ -54,6 +54,7 @@ import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UImage; import net.sourceforge.plantuml.ugraphic.ULine; +import net.sourceforge.plantuml.ugraphic.UPixel; import net.sourceforge.plantuml.ugraphic.UPolygon; import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UText; @@ -77,6 +78,7 @@ public class UGraphicG2d extends AbstractUGraphic { registerDriver(URectangle.class, new DriverRectangleG2d()); registerDriver(UText.class, new DriverTextG2d()); registerDriver(ULine.class, new DriverLineG2d()); + registerDriver(UPixel.class, new DriverPixelG2d()); registerDriver(UPolygon.class, new DriverPolygonG2d()); registerDriver(UEllipse.class, new DriverEllipseG2d()); registerDriver(UImage.class, new DriverImageG2d()); diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index fd57597e8..d55c8c083 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -28,7 +28,7 @@ * * Original Author: Arnaud Roques * - * Revision $Revision: 6940 $ + * Revision $Revision: 7178 $ * */ package net.sourceforge.plantuml.version; @@ -36,11 +36,11 @@ package net.sourceforge.plantuml.version; public class Version { public static int version() { - return 6939; + return 7177; } public static long compileTime() { - return 1312823992421L; + return 1314897125765L; } }