version 1.2020.6

This commit is contained in:
Arnaud Roques 2020-04-05 17:13:04 +02:00
parent ce8d9045b5
commit 85ad30b381
172 changed files with 10466 additions and 675 deletions

View File

@ -0,0 +1,228 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import jcckit.graphic.GraphicalElement;
import jcckit.graphic.Renderer;
import jcckit.plot.Plot;
import jcckit.plot.PlotCanvas;
import jcckit.renderer.Graphics2DRenderer;
import jcckit.renderer.Transformation;
import jcckit.util.ConfigParameters;
import jcckit.util.Factory;
/**
* Class which handles plotting into a <tt>Graphics</tt> context based on the
* {@link jcckit.renderer.GraphicsRenderer}. This class is not a subclass of
* <tt>java.awt.Component</tt>. The actual AWT component presenting the plot
* is an innerclass. Its instance wrapped by <tt>GraphicsPlotCanvas</tt> can
* be obtained with {@link #getGraphicsCanvas}.
* <p>
* The plot is painted by using double-buffering and pre-rendered view of the
* coordinate system. That is, the coordinate system is drawn into an off-screen
* image. It will be redrawn only if the size of the embedding AWT component is
* changed.
*
* @author Franz-Josef Elmer
*/
public class GraphicsPlotCanvas extends PlotCanvas {
/** Key of a configuration parameter. */
public static final String BACKGROUND_KEY = "background";
public static final String FOREGROUND_KEY = "foreground";
public static final String DOUBLE_BUFFERING_KEY = "doubleBuffering";
/**
* Class which does the actual painting. Needs the <tt>Component</tt> into
* which the plot is painted for some resources like size, background color,
* etc.
*
* @author Franz-Josef Elmer
*/
private final BufferedImage img3;
private final Graphics2D g3;
private Transformation _transformation;
private String _renderer = "jcckit.renderer.GraphicsRenderer";
private GraphicalElement _marker;
/**
* Creates an instance from the specified configuration parameters. <table
* border=1 cellpadding=5>
* <tr>
* <th>Key &amp; Default Value</th>
* <th>Type</th>
* <th>Mandatory</th>
* <th>Description</th>
* </tr>
* <tr>
* <td><tt>background = </tt><i>default background color of the wrapped
* AWT component</i></td>
* <td><tt>Color</tt></td>
* <td>no</td>
* <td>Background color of the wrapped AWT component.</td>
* </tr>
* <tr>
* <td><tt>foreground = </tt><i>default foreground color of the wrapped
* AWT component</i></td>
* <td><tt>Color</tt></td>
* <td>no</td>
* <td>Foreground color of the wrapped AWT component.</td>
* </tr>
* <tr>
* <td><tt>doubleBuffering = true</td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> the plot will be painted by using
* double-buffering and pre-rendered view of the coordinate system.
* </td></tr>
* </table>
* In addition the configuration parameters of the
* <a href="plot/PlotCanvas.html#PlotCanvas(jcckit.util.ConfigParameters)">
* constructor</a> of the superclass {@link jcckit.plot.PlotCanvas} apply.
*/
public GraphicsPlotCanvas(ConfigParameters config, BufferedImage img3) {
super(config);
this.img3 = img3;
setRenderer("jcckit.renderer.Graphics2DRenderer");
g3 = img3.createGraphics();
g3.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// _doubleBuffering = config.getBoolean(DOUBLE_BUFFERING_KEY, true);
background = config.getColor(BACKGROUND_KEY, Color.WHITE);
foreground = config.getColor(FOREGROUND_KEY, Color.BLACK);
}
private final Color background;
private final Color foreground;
/**
* Paints the plot. If {@link GraphicsPlotCanvas#_doubleBuffering} is set
* double-buffering and pre-rendered view of the coordinate system is used.
*/
public void paint() {
Dimension size = new Dimension(img3.getWidth(), img3.getHeight());
g3.setColor(background);
g3.fillRect(0, 0, size.width + 1, size.height + 1);
init(size);
_transformation.apply(g3);
Plot plot = getPlot();
drawCoordinateSystem(size, plot);
drawPlot(plot);
if (_marker != null) {
_marker.renderWith(createRenderer());
}
}
private void drawPlot(Plot plot) {
prepare();
Renderer renderer = createRenderer();
GraphicalElement[] curves = plot.getCurves();
for (int i = 0; i < curves.length; i++) {
curves[i].renderWith(renderer);
}
GraphicalElement annotation = plot.getAnnotation();
if (annotation != null) {
annotation.renderWith(renderer);
}
if (plot.isLegendVisible()) {
plot.getLegend().renderWith(renderer);
}
}
private void init(Dimension size) {
calculateTransformation(size);
}
private void drawCoordinateSystem(Dimension size, Plot plot) {
g3.setColor(foreground);
plot.getCoordinateSystem().renderWith(createRenderer());
}
/**
* Prepare graphics context before drawing the pre-rendered view of the
* coordinate system. Does nothing but will be used in subclasses.
*/
protected void prepare() {
}
/**
* Calculate the transformation form device-independent coordinates into
* device-dependent coordinates according to the specified canvas size.
*/
protected void calculateTransformation(Dimension size) {
_transformation = new Transformation(size.width, size.height, getPaper(), getHorizontalAnchor(),
getVerticalAnchor());
}
/**
* Creates an appropriated {@link Renderer} for the specified
* <tt>Graphics</tt> context.
*/
protected Renderer createRenderer() {
return ((Graphics2DRenderer) Factory.create(_renderer)).init(g3);
// return ((GraphicsRenderer) Factory.create(_renderer)).init(g, null,
// _transformation);
}
/**
* Sets the renderer used to render the plot. The default value is
* {@link GraphicsRenderer}.
*
* @param className
* Fully qualified name of the renderer class.
*/
public void setRenderer(String className) {
_renderer = className;
}
// /**
// * Maps the cursor position onto a point in device-independent
// coordinates.
// *
// * @param x
// * X-coordinate of the cursor.
// * @param y
// * Y-coordinate of the cursor.
// */
// public GraphPoint mapCursorPosition(int x, int y) {
// return _transformation.transformBack(x, y);
// }
/**
* Defines a graphical marker which will be drawn on top of the plot. To
* remove the marker call this method with argument <tt>null</tt>.
*
* @param marker
* Marker element. Can be <tt>null</tt>.
*/
public void setMarker(GraphicalElement marker) {
_marker = marker;
}
}

View File

@ -0,0 +1,182 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.data;
import java.text.MessageFormat;
import java.util.Vector;
/**
* Abstract superclass of all data containers. A data container holds an
* ordered list of {@link DataElement DataElements} of the same type.
* <p>
* Data elements can be added, inserted, removed, or replaced.
* Such an action leads to a {@link DataEvent} which will be delivered to
* all {@link DataListener DataListeners} observing this
* <code>DataContainer</code>. If this data container also implements
* {@link DataEvent} (as {@link DataCurve} does) also the listeners
* registrated at the data container containg this container will be notified.
* As a consequence a <tt>DataListener</tt> must only be registered at the
* {@link DataPlot} instance and it will automatically also received events
* caused by manipulating one of its <tt>DataCurves</tt>.
* <p>
* Concrete subclasses have to implement {@link #isValid} which
* checks whether the added or inserted <tt>DataElement</tt> is of the right
* type. This is an application of the Template Method Design Pattern.
*
* @author Franz-Josef Elmer
*/
public abstract class DataContainer {
private final static String TEMPLATE
= "Invalid operation: {0}, Element: {1}, Container: {2}";
final static String ADD = "add",
REPLACE = "replace",
INSERT = "insert";
private final Vector _listeners = new Vector();
private final Vector _container = new Vector();
/** Adds a {@link DataListener}. Does nothing if already added. */
public void addDataListener(DataListener listener) {
if (!_listeners.contains(listener)) {
_listeners.addElement(listener);
}
}
/** Removes a {@link DataListener}. Does nothing if already removed. */
public void removeDataListener(DataListener listener) {
_listeners.removeElement(listener);
}
private void notifyListeners(DataEvent event) {
for (int i = 0, n = _listeners.size(); i < n; i++) {
((DataListener) _listeners.elementAt(i)).dataChanged(event);
}
// Notifies also parent container
if (this instanceof DataElement) {
DataContainer container = ((DataElement) this).getContainer();
if (container != null) {
container.notifyListeners(event);
}
}
}
/** Returns the number of elements of this container. */
public int getNumberOfElements() {
return _container.size();
}
/** Returns the element for the specified index. */
public DataElement getElement(int index) {
return (DataElement) _container.elementAt(index);
}
/**
* Returns the index of the specified element.
* @param element Element to be looked for.
* @return -1 if not found.
*/
public int getIndexOf(DataElement element) {
return _container.indexOf(element);
}
/**
* Adds a {@link DataElement}. After the element has been successfully
* added all {@link DataListener DataListeners} will be informed.
* @param element DataElement to be added.
* @throws IllegalArgumentException if <tt>element</tt> is not of the correct
* type which will be checked by the method {@link #isValid}.
*/
public void addElement(DataElement element) {
if (isValid(element)) {
_container.addElement(element);
element.setContainer(this);
notifyListeners(DataEvent.createAddEvent(this));
} else {
throwException(ADD, element);
}
}
/**
* Inserts a {@link DataElement} at the specified index.
* After the element has been successfully inserted
* all {@link DataListener DataListeners} will be informed.
* @param index Index at which <tt>element</tt> will be inserted.
* All elements with an index &gt;= <tt>index</tt> will be shifted.
* @param element DataElement to be added.
* @throws IllegalArgumentException if <tt>element</tt> is not of the correct
* type which will be checked by the method {@link #isValid}.
*/
public void insertElementAt(int index, DataElement element) {
if (isValid(element)) {
_container.insertElementAt(element, index);
element.setContainer(this);
notifyListeners(DataEvent.createInsertEvent(this, index));
} else {
throwException(INSERT, element);
}
}
/**
* Removes a {@link DataElement} at the specified index.
* After the element has been successfully removed
* all {@link DataListener DataListeners} will be informed.
* @param index Index of the element which will be removed.
* All elements with an index &gt; <tt>index</tt> will be shifted.
*/
public void removeElementAt(int index) {
DataElement element = (DataElement) _container.elementAt(index);
element.setContainer(null);
_container.removeElementAt(index);
notifyListeners(DataEvent.createRemoveEvent(this, index, element));
}
/**
* Replaces the {@link DataElement} at the specified index.
* After the element has been successfully replaced
* all {@link DataListener DataListeners} will be informed.
* @param index Index of the element which will be replaced by
* <tt>element</tt>.
* @param element The new <tt>DataElement</tt>.
* @throws IllegalArgumentException if <tt>element</tt> is not of the correct
* type which will be checked by the method {@link #isValid}.
*/
public void replaceElementAt(int index, DataElement element) {
if (isValid(element)) {
DataElement oldElement = (DataElement) _container.elementAt(index);
oldElement.setContainer(null);
_container.setElementAt(element, index);
element.setContainer(this);
notifyListeners(DataEvent.createReplaceEvent(this, index, oldElement));
} else {
throwException(REPLACE, element);
}
}
private void throwException(String operation, DataElement element) {
throw new IllegalArgumentException(MessageFormat.format(TEMPLATE,
new Object[] {operation, element, this.getClass().getName()}));
}
/**
* Returns <tt>true</tt> if the specified {@link DataElement} has the
* correct type. Concrete subclasses have to implement this method.
* @param element <tt>DataElement</tt> to be checked.
*/
protected abstract boolean isValid(DataElement element);
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.data;
import jcckit.util.ConfigParameters;
/**
* A curve is a {@link DataContainer} of {@link DataPoint DataPoints}.
*
* @author Franz-Josef Elmer
*/
public class DataCurve extends DataContainer implements DataElement {
/** Config parameter key. */
public static final String X_KEY = "x",
Y_KEY = "y",
TITLE_KEY = "title";
private final String _title;
private DataContainer _container;
/** Creates an empty instance with the specified title. */
public DataCurve(String title) {
_title = title;
}
/**
* Creates an instance from the specified config parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>title = </tt><i>empty string</i></td>
* <td><tt>String</tt></td><td>no</td>
* <td>Curve title.</td></tr>
* <tr><td><tt>x</tt></td><td><tt>double[]</tt></td><td>yes</td>
* <td>x-coordinates of the curve points.</td></tr>
* <tr><td><tt>y</tt></td><td><tt>double[]</tt></td><td>yes</td>
* <td>y-coordinates of the curve points.</td></tr>
* </table>
*/
public DataCurve(ConfigParameters config) {
this(config.get(TITLE_KEY, ""));
double[] xPoints = config.getDoubleArray(X_KEY);
double[] yPoints = config.getDoubleArray(Y_KEY);
int n = Math.min(xPoints.length, yPoints.length);
for (int i = 0; i < n; i++) {
addElement(new DataPoint(xPoints[i], yPoints[i]));
}
}
/**
* Returns the {@link DataPlot} containing this curve.
*/
public DataContainer getContainer() {
return _container;
}
/**
* Sets the {@link DataPlot} where this is a curve of.
*/
public void setContainer(DataContainer container) {
_container = container;
}
/** Returns the title of this curve. */
public String getTitle() {
return _title;
}
/**
* Returns <tt>true</tt> if <tt>element</tt> is an instance of
* {@link DataPoint}.
*/
protected boolean isValid(DataElement element) {
return element instanceof DataPoint;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.data;
/**
* Interface for all kinds of data elements.
*
* @author Franz-Josef Elmer
*/
public interface DataElement {
/**
* Returns the container containing this element.
* @return <tt>null</tt> if this element is not an element of a container.
*/
public DataContainer getContainer();
/**
* Sets the container which should contain this element.
* This method should <b>not</b> used outside {@link DataContainer}..
* @param container Container which should contains this element. Cann be
* <tt>null</tt> if this element does not belong to a container.
*/
public void setContainer(DataContainer container);
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.data;
/**
* Event to be sent to a {@link DataListener}.
*
* @author Franz-Josef Elmer
*/
public class DataEvent {
private final DataContainer _container;
private final DataEventType _type;
private final int _index;
private final DataElement _deletedElement;
/**
* Creates an instance for the specified parameters.
* @param container The container which has been changed.
* @param type Type of change.
* @param index Index of the element which has been added, inserted,
* replaced, or removed.
* @param deletedElement Element which has been replaced or removed.
*/
private DataEvent(DataContainer container, DataEventType type, int index,
DataElement deletedElement) {
_container = container;
_type = type;
_index = index;
_deletedElement = deletedElement;
}
/**
* Creates an event of type {@link DataEventType#ELEMENT_ADDED} for the
* specified container.
* @param container Container where an element has been added.
* @return <tt>ELEMENT_ADDED</tt> event.
*/
public static final DataEvent createAddEvent(DataContainer container) {
return new DataEvent(container, DataEventType.ELEMENT_ADDED,
container.getNumberOfElements() - 1, null);
}
/**
* Creates an event of type {@link DataEventType#ELEMENT_INSERTED} for the
* specified container.
* @param container Container where an element has been inserted.
* @param index Index at which an element has been inserted.
* @return <tt>ELEMENT_INSERTED</tt> event.
*/
public static final DataEvent createInsertEvent(DataContainer container,
int index) {
return new DataEvent(container, DataEventType.ELEMENT_INSERTED, index,
null);
}
/**
* Creates an event of type {@link DataEventType#ELEMENT_REPLACED} for the
* specified container.
* @param container Container where an element has been replaced.
* @param index Index of the replaced element.
* @param replacedElement The previous element at <tt>index</tt>.
* @return <tt>ELEMENT_REPLACED</tt> event.
*/
public static final DataEvent createReplaceEvent(DataContainer container,
int index, DataElement replacedElement) {
return new DataEvent(container, DataEventType.ELEMENT_REPLACED, index,
replacedElement);
}
/**
* Creates an event of type {@link DataEventType#ELEMENT_REMOVED} for the
* specified container.
* @param container Container where an element has been removed.
* @param index Index of the removed element.
* @param removedElement The previous element at <tt>index</tt>.
* @return <tt>ELEMENT_REMOVED</tt> event.
*/
public static final DataEvent createRemoveEvent(DataContainer container,
int index, DataElement removedElement) {
return new DataEvent(container, DataEventType.ELEMENT_REMOVED, index,
removedElement);
}
/** Returns the container. */
public DataContainer getContainer() {
return _container;
}
/**
* Returns the event type. Will be one of the constants
* {@link DataEventType#ELEMENT_ADDED},
* {@link DataEventType#ELEMENT_INSERTED},
* {@link DataEventType#ELEMENT_REMOVED}, or
* {@link DataEventType#ELEMENT_REPLACED}.
*/
public DataEventType getType() {
return _type;
}
/** Returns the index. */
public int getIndex() {
return _index;
}
/**
* Returns the deleted element.
* @return <tt>null</tt> if either an element has been added or inserted.
*/
public DataElement getDeletedElement() {
return _deletedElement;
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.data;
/**
* Type of a {@link DataEvent}. Implements the typesafe enumeration pattern.
*
* @author Franz-Josef Elmer
*/
public class DataEventType {
private DataEventType() {}
/** Event type. */
public static final DataEventType ELEMENT_ADDED = new DataEventType(),
ELEMENT_INSERTED = new DataEventType(),
ELEMENT_REPLACED = new DataEventType(),
ELEMENT_REMOVED = new DataEventType();
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.data;
/**
* An interface all observers of {@link DataEvent DataEvents}
* have to implement.
*
* @author Franz-Josef Elmer
*/
public interface DataListener {
/**
* Sends the specified data event to this object.
* @param event Data event informing where and what happened.
*/
public void dataChanged(DataEvent event);
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.data;
import java.util.StringTokenizer;
import jcckit.util.ConfigParameters;
/**
* A plot is a {@link DataContainer} of {@link DataCurve DataCurves}.
*
* @author Franz-Josef Elmer
*/
public class DataPlot extends DataContainer {
/** Config parameter key. */
public static final String CURVES_KEY = "curves",
DATA_KEY = "data";
/** Creates an empty instance. */
public DataPlot() {}
/**
* Creates an instance from the specified config parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>curves</tt></td><td><tt>String[]</tt></td><td>yes</td>
* <td>List of keys denoting data curves. Each key refers to
* config parameters used in the
* <a href="DataCurve.html#DataCurve(jcckit.util.ConfigParameters)">
* constructor</a> of {@link DataCurve}.</td></tr>
* </table>
*/
public DataPlot(ConfigParameters config) {
StringTokenizer tokenizer = new StringTokenizer(config.get(CURVES_KEY));
while (tokenizer.hasMoreTokens()) {
addElement(new DataCurve(config.getNode(tokenizer.nextToken())));
}
}
/**
* Convenient method to create a <tt>DataPlot</tt> based on the specified
* config parameters. It is a short-cut of
* <tt>new DataPlot(config.getNode("data"))</tt>.
*/
public static DataPlot create(ConfigParameters config) {
return new DataPlot(config.getNode(DATA_KEY));
}
/**
* Returns <tt>true</tt> if <tt>element</tt> is an instance of
* {@link DataCurve}.
*/
protected boolean isValid(DataElement element) {
return element instanceof DataCurve;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.data;
import jcckit.util.Point;
/**
* Immutable two-dimensional point in data coordinates.
*
* @author Franz-Josef Elmer
*/
public class DataPoint extends Point implements DataElement {
public DataPoint(double x, double y) {
super(x, y);
}
/** Returns always <tt>null</tt>. */
public DataContainer getContainer() {
return null;
}
/** Does nothing. */
public void setContainer(DataContainer container) {}
}

View File

@ -0,0 +1,129 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import jcckit.util.ConfigParameters;
import jcckit.util.FactoryException;
/**
* Anchor of a graphical element. There exist only the three
* instances {@link #LEFT_BOTTOM}, {@link #CENTER}, and
* {@link #RIGHT_TOP}.
* <p>
* The anchor factor can be used in a position formular. Its value
* for the three instances reads:
* <p>
* <center>
* <table border=1 cellpadding=5>
* <tr><th>Instance</th><th>Factor</th></tr>
* <tr><td><tt>LEFT_BOTTOM</tt></td><td>0</td></tr>
* <tr><td><tt>CENTER</tt></td><td>1</td></tr>
* <tr><td><tt>RIGHT_TOP</tt></td><td>2</td></tr>
* </table>
* </center>
*
* @author Franz-Josef Elmer
*/
public class Anchor {
/** Anchor constant. */
public static final Anchor LEFT_BOTTOM = new Anchor(0),
CENTER = new Anchor(1),
RIGHT_TOP = new Anchor(2);
private static final String LEFT_VALUE = "left",
RIGHT_VALUE = "right",
CENTER_VALUE = "center",
TOP_VALUE = "top",
BOTTOM_VALUE = "bottom";
/**
* Returns form the specified configuration parameters the
* horizontal anchor defined by the specified key or the
* specified default value.
* @param config Configuration parameters.
* @param key The key of the anchor. <tt>null</tt> is not allowed.
* @param defaultValue The default value.
* @return one of the three instances of <tt>Anchor</tt>.
* @throws FactoryException if the value of <tt>key</tt> is
* neither <tt>left</tt>, <tt>center</tt>,
* nor <tt>right</tt>.
* Note, that {@link FactoryException#getClassName()}
* returns the invalid value.
*/
public static Anchor getHorizontalAnchor(ConfigParameters config, String key,
Anchor defaultValue) {
Anchor result = defaultValue;
String anchor = config.get(key, null);
if (anchor != null) {
if (anchor.equals(LEFT_VALUE)) {
result = Anchor.LEFT_BOTTOM;
} else if (anchor.equals(CENTER_VALUE)) {
result = Anchor.CENTER;
} else if (anchor.equals(RIGHT_VALUE)) {
result = Anchor.RIGHT_TOP;
} else {
throw new FactoryException(config, key, "Invalid horizontal anchor.");
}
}
return result;
}
/**
* Returns form the specified configuration parameters the
* vertical anchor defined by the specified key or the
* specified default value.
* @param config Configuration parameters.
* @param key The key of the anchor. <tt>null</tt> is not allowed.
* @param defaultValue The default value.
* @return one of the three instances of <tt>Anchor</tt>.
* @throws FactoryException if the value of <tt>key</tt> is
* neither <tt>top</tt>, <tt>center</tt>,
* nor <tt>bottom</tt>.
* Note, that {@link FactoryException#getClassName()}
* returns the invalid value.
*/
public static Anchor getVerticalAnchor(ConfigParameters config, String key,
Anchor defaultValue) {
Anchor result = defaultValue;
String anchor = config.get(key, null);
if (anchor != null) {
if (anchor.equals(BOTTOM_VALUE)) {
result = Anchor.LEFT_BOTTOM;
} else if (anchor.equals(CENTER_VALUE)) {
result = Anchor.CENTER;
} else if (anchor.equals(TOP_VALUE)) {
result = Anchor.RIGHT_TOP;
} else {
throw new FactoryException(config, key, "Invalid vertcal anchor.");
}
}
return result;
}
private final int _factor;
private Anchor(int factor) {
_factor = factor;
}
/** Returns the factor. */
public int getFactor() {
return _factor;
}
}

View File

@ -0,0 +1,202 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import java.awt.Color;
import jcckit.util.ConfigParameters;
/**
* The basic attributes of any {@link BasicGraphicalElement}. This is an
* extension of {@link ShapeAttributes} implementing {@link TextAttributes}.
*
* @author Franz-Josef Elmer
*/
public class BasicGraphicAttributes extends ShapeAttributes
implements TextAttributes {
/** Configuration parameter key. */
public static final String TEXT_COLOR_KEY = "textColor",
FONT_NAME_KEY = "fontName",
FONT_STYLE_KEY = "fontStyle",
FONT_SIZE_KEY = "fontSize",
HORIZONTAL_ANCHOR_KEY = "horizontalAnchor",
VERTICAL_ANCHOR_KEY = "verticalAnchor",
ORIENTATION_ANGLE_KEY = "orientationAngle";
private final Color _textColor;
private final String _fontName;
private final FontStyle _fontStyle;
private final double _fontSize;
private final double _orientationAngle;
private final Anchor _horizontalAnchor;
private final Anchor _verticalAnchor;
/**
* Creates a new instance based on the specified configuration
* parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>textColor = </tt><i>default foreground color of the
* renderer</i></td><td><tt>Color</tt></td><td>no</td>
* <td>The text color.</td></tr>
* <tr><td><tt>fontName = </tt><i>default font name of the
* renderer</i></td><td><tt>String</tt></td><td>no</td>
* <td>The name of the text font. The standard Java font name
* "Serif", "SansSerif", and "Monospaced" can be used.
* Other font names depend on the actual {@link Renderer}
* rendering the corresponding {@link BasicGraphicalElement}.
* </td></tr>
* <tr><td><tt>fontStyle = normal</tt></td><td><tt>String</tt>
* </td><td>no</td>
* <td>The font style. Possible values are:
* <ul><li><tt>normal</tt><li><tt>bold</tt><li><tt>italic</tt>
* <li><tt>bold italic</tt></ul>
* </td></tr>
* <tr><td><tt>fontSize = </tt><i>default font size of the
* renderer</i></td><td><tt>double</tt></td><td>no</td>
* <td>The font size in units of the device-independent
* coordinates.</td></tr>
* <tr><td><tt>orientationAngle = 0</tt></td><td><tt>double</tt></td>
* <td>no</td>
* <td>The orientation angle of the text (in degree).
* Zero means normal orientation whereas a positive value means
* a rotation in counter-clockweise direction.</td></tr>
* <tr><td><tt>horizontalAnchor = left</tt></td><td><tt>String</tt>
* </td><td>no</td>
* <td>Anchor for horizontal text position. Possible values are
* <tt>left</tt>, <tt>center</tt>, and <tt>right</tt>.</td></tr>
* <tr><td><tt>verticalAnchor = center</tt></td><td><tt>String</tt>
* </td><td>no</td>
* <td>Anchor for vertical text position. Possible values are
* <tt>top</tt>, <tt>center</tt>, and <tt>bottom</tt>.</td></tr>
* </table>
* Additional configuration parameters are explained in the
* {@link ShapeAttributes#ShapeAttributes constructor}
* of the superclass {@link ShapeAttributes}.
*/
public BasicGraphicAttributes(ConfigParameters config) {
super(config);
_textColor = config.getColor(TEXT_COLOR_KEY, null);
_fontName = config.get(FONT_NAME_KEY, null);
_fontStyle = FontStyle.getFontStyle(config, FONT_STYLE_KEY,
FontStyle.NORMAL);
_fontSize = config.getDouble(FONT_SIZE_KEY, 0);
_orientationAngle = config.getDouble(ORIENTATION_ANGLE_KEY, 0);
_horizontalAnchor = Anchor.getHorizontalAnchor(config,
HORIZONTAL_ANCHOR_KEY, Anchor.LEFT_BOTTOM);
_verticalAnchor = Anchor.getVerticalAnchor(config,
VERTICAL_ANCHOR_KEY, Anchor.CENTER);
}
/**
* Creates a new instance.
* @param fillColor The fill color. May be <tt>null</tt>.
* @param lineColor The line color. May be <tt>null</tt>.
* @param lineThickness Thickness of the line.
* Negative numbers will be trimmed to zero.
* @param linePattern Line pattern. May be <tt>null</tt>.
* @param textColor The text color. May be <tt>null</tt>.
* @param fontName The font name. May be <tt>null</tt>.
* @param fontStyle The font style. May be <tt>null</tt>.
* @param fontSize The font size in units of the device-independent
* coordinates. May be <tt>null</tt>.
* @param orientationAngle Orientation angle of the text.
* @param horizontalAnchor Horizontal text anchor.
* @param verticalAnchor Vertical text anchor.
*/
public BasicGraphicAttributes(Color fillColor, Color lineColor,
double lineThickness,
double[] linePattern, Color textColor,
String fontName, FontStyle fontStyle,
double fontSize, double orientationAngle,
Anchor horizontalAnchor,
Anchor verticalAnchor) {
super(fillColor, lineColor, lineThickness, linePattern);
_textColor = textColor;
_fontName = fontName;
_fontStyle = fontStyle;
_fontSize = fontSize;
_orientationAngle = orientationAngle;
_horizontalAnchor = horizontalAnchor;
_verticalAnchor = verticalAnchor;
}
/**
* Returns the text color.
* @return <tt>null</tt> means default color of the renderer.
*/
public Color getTextColor() {
return _textColor;
}
/**
* Returns the font name.
* @return <tt>null</tt> means default font name of the renderer.
*/
public String getFontName() {
return _fontName;
}
/**
* Returns the font style.
* @return <tt>null</tt> means default font style of the renderer.
*/
public FontStyle getFontStyle() {
return _fontStyle;
}
/**
* Returns the font size in units of the device-independent coordinates.
*/
public double getFontSize() {
return _fontSize;
}
/**
* Returns the orientation angle in degree. Zero means
* normal text orientation. Any positive angle means a
* counter-clockwise rotation of the text.
*/
public double getOrientationAngle() {
return _orientationAngle;
}
/**
* Returns the anchor for horizontal position of the text.
* Note, that the anchor is related to the text <em>before</em>
* it is rotated by the orientation angle.
* @return one of the three instances of <tt>Anchor</tt>.
*/
public Anchor getHorizontalAnchor() {
return _horizontalAnchor;
}
/**
* Returns the anchor for vertical position of the text.
* Note, that the anchor is related to the text <em>before</em>
* it is rotated by the orientation angle.
* @return one of the three instances of <tt>Anchor</tt>.
*/
public Anchor getVerticalAnchor() {
return _verticalAnchor;
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Abstract superclass of all basic {@link GraphicalElement
* GraphicalElements}. Concrete subclasses have to implement
* the method {@link GraphicalElement#renderWith}.
*
* @author Franz-Josef Elmer
*/
public abstract class BasicGraphicalElement implements GraphicalElement {
private final GraphicAttributes _attributes;
/**
* Creates an instance with the specified drawing attributes.
* Note, that a {@link Renderer} should use default attributes
* in the case no attributes are defined.
* @param attributes Drawing attributes or <tt>null</tt> if undefined.
*/
public BasicGraphicalElement(GraphicAttributes attributes) {
_attributes = attributes;
}
/**
* Returns the drawing attributes.
* @return <tt>null</tt> if undefined.
*/
public GraphicAttributes getGraphicAttributes() {
return _attributes;
}
/**
* Returns whether this basic graphical element has a closed shape
* or not. By default always <tt>true</tt>. Subclasses may override
* this behaviour.
* @return <tt>true</tt> if the shape is closed.
*/
public boolean isClosed() {
return true;
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Immutable class of a rectangular clipping area.
*
* @author Franz-Josef Elmer
*/
public class ClippingRectangle implements ClippingShape {
private final double _minX, _minY, _maxX, _maxY;
/**
* Creates an instance for the specified coordinates of
* two opposite corner points.
*/
public ClippingRectangle(double x1, double y1, double x2, double y2) {
_minX = Math.min(x1, x2);
_minY = Math.min(y1, y2);
_maxX = Math.max(x1, x2);
_maxY = Math.max(y1, y2);
}
/**
* Returns <tt>true</tt> if the specified point is inside this
* rectangle.
*/
public boolean isInside(GraphPoint point) {
double x = point.getX();
double y = point.getY();
return _minX <= x && x <= _maxX && _minY <= y && y <= _maxY;
}
/** Returns the minimum x value. */
public double getMinX() {
return _minX;
}
/** Returns the maximum x value. */
public double getMaxX() {
return _maxX;
}
/** Returns the minimum y value. */
public double getMinY() {
return _minY;
}
/** Returns the maximum y value. */
public double getMaxY() {
return _maxY;
}
/** Returns this instance. */
public ClippingRectangle getBoundingBox() {
return this;
}
/** Returns a {@link Rectangle}. */
public BasicGraphicalElement getGraphicalElement() {
return new Rectangle(new GraphPoint(0.5 * (_minX + _maxX),
0.5 * (_minY + _maxY)),
_maxX - _minX, _maxY - _minY, null);
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Defining a clipping shape applied to all {@link GraphicalElement
* GraphicalElements} of a {@link GraphicalComposite}.
*
* @author Franz-Josef Elmer
*/
public interface ClippingShape {
/**
* Returns <tt>true</tt> if the specified point is inside this
* clipping shape.
*/
public boolean isInside(GraphPoint point);
/**
* Returns the bounding box of this clipping shape.
* This method will be used by renderers who supports only
* rectangular clipping shapes.
*/
public ClippingRectangle getBoundingBox();
/**
* Returns a basic graphical element (such as {@link Rectangle}
* or {@link Polygon}) which may be used by renderers to
* define the clipping shape for the output device.
*/
public BasicGraphicalElement getGraphicalElement();
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import java.awt.Color;
/**
* Interface for fill attributes.
*
* @author Franz-Josef Elmer
*/
public interface FillAttributes extends GraphicAttributes {
/**
* Returns the fill color.
* @return <tt>null</tt> means no filling.
*/
public Color getFillColor();
}

View File

@ -0,0 +1,82 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import java.util.Hashtable;
import jcckit.util.ConfigParameters;
import jcckit.util.FactoryException;
/**
* Font style constants.
* This class is based on the typesafe enumeration pattern.
*
* @author Franz-Josef Elmer
*/
public class FontStyle {
private static final Hashtable REPOSITORY = new Hashtable();
static final String NORMAL_TXT = "normal",
BOLD_TXT = "bold",
ITALIC_TXT = "italic",
BOLD_ITALIC_TXT = "bold italic";
/** Font style constant. */
public static final FontStyle NORMAL = new FontStyle(NORMAL_TXT),
BOLD = new FontStyle(BOLD_TXT),
ITALIC = new FontStyle(ITALIC_TXT),
BOLD_ITALIC = new FontStyle(BOLD_ITALIC_TXT);
private final String _description;
/** Non-public constructor to control the number of instances. */
private FontStyle(String description) {
_description = description;
REPOSITORY.put(description, this);
}
/**
* Returns from the specified configuration parameters the font style
* defined by the specified key or the specified default value.
* @param config Configuration parameters.
* @param key The key of the font style.
* @param defaultValue The default value.
* @return one of the four instances of <tt>FontStyle</tt>.
* @throws FactoryException if the value of the key-value pair denoted
* by <tt>key</tt> is neither <tt>normal</tt>, <tt>bold</tt>,
* <tt>italic</tt>, nor <tt>bold italic</tt>,
* Note, that {@link FactoryException#getClassName()}
* returns the invalid value.
*/
public static FontStyle getFontStyle(ConfigParameters config, String key,
FontStyle defaultValue) {
FontStyle result = defaultValue;
String value = config.get(key, null);
if (value != null) {
result = (FontStyle) REPOSITORY.get(value);
if (result == null) {
throw new FactoryException(config, key, "Invalid font style.");
}
}
return result;
}
/** Returns a human readable description for pretty printing. */
public String toString() {
return _description;
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import jcckit.util.Point;
/**
* Immutable class of a two-dimensional point in the device-independent
* coordinate system.
*
* @author Franz-Josef Elmer
*/
public class GraphPoint extends Point {
/**
* Creates an instance for the specified vector.
* If <tt>vector</tt> is <tt>null</tt> or not long enough the
* default value 0 will be used instead.
*/
public GraphPoint(double[] vector) {
super(vector);
}
/** Creates an instance for the specified coordinates. */
public GraphPoint(double x, double y) {
super(x, y);
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Marker interface for all types of graphic attributes
* of a {@link BasicGraphicalElement}. Graphic attributes are only
* hints for {@link Renderer Renderers} how to render a
* <tt>BasicGraphicalElement</tt>. Whether they are used and how
* they are interpreted depends on the concrete <tt>Renderer</tt>.
* <p>
* This is only a marker interface. There are several subinterfaces
* specifying various attributes grouped by the type of element to
* be rendered.
*
* @author Franz-Josef Elmer
*/
public interface GraphicAttributes {
}

View File

@ -0,0 +1,106 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import java.util.Vector;
/**
* Container for {@link GraphicalElement GraphicalElements}.
*
* @author Franz-Josef Elmer
*/
public class GraphicalComposite implements GraphicalElement {
private final Vector _elements = new Vector();
private final ClippingShape _clippingShape;
/**
* Creates an instance with the specified clipping shape.
* @param clippingShape Clipping shape or <tt>null</tt> if no clipping.
*/
public GraphicalComposite(ClippingShape clippingShape) {
_clippingShape = clippingShape;
}
/**
* Returns the clipping shape.
* @return <tt>null</tt> if no clipping should be applied.
*/
public ClippingShape getClippingShape() {
return _clippingShape;
}
/**
* Adds the specified element at the end of the list of elements.
* @param element Element to be added. <tt>null</tt> is not allowed.
* @throws NullPointerException if <tt>element == null</tt>
*/
public void addElement(GraphicalElement element) {
if (element == null) {
throwNullPointerException();
} else {
_elements.addElement(element);
}
}
/** Remove all elements. */
public void removeAllElements() {
_elements.removeAllElements();
}
/**
* Replaces the specified element at the specified index of
* the list of elements.
* @param element New element. <tt>null</tt> is not allowed.
* @throws NullPointerException if <tt>element == null</tt>
*/
public void replaceElementAt(int index, GraphicalElement element) {
if (element == null) {
throwNullPointerException();
} else {
_elements.setElementAt(element, index);
}
}
private void throwNullPointerException() {
throw new NullPointerException(
"A null as an GraphicalElement is not allowed");
}
/**
* Renders all {@link GraphicalElement GraphicalElements} in the sequence
* they have been added.
* @param renderer Renderer which implements all renderer interfaces
* necessary to render the child elements.
* @throws IllegalArgumentException if <tt>renderer</tt> is not
* an instance of <tt>GraphicalCompositeRenderer</tt>.
*/
public void renderWith(Renderer renderer) {
if (renderer instanceof GraphicalCompositeRenderer) {
GraphicalCompositeRenderer r = (GraphicalCompositeRenderer) renderer;
r.startRendering(this);
for (int i = 0, n = _elements.size(); i < n; i++) {
((GraphicalElement) _elements.elementAt(i)).renderWith(r);
}
r.finishRendering(this);
} else {
throw new IllegalArgumentException(renderer
+ " does not implements GraphicalCompositeRenderer.");
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Interface of all {@link Renderer Renderers} who render a
* {@link GraphicalComposite}. Note, that a
* <tt>GraphicalCompositeRenderer</tt> does <em>not</em>
* render the element of a <tt>GraphicalComposite</tt>
*
* @author Franz-Josef Elmer
*/
public interface GraphicalCompositeRenderer extends Renderer {
/**
* Starts rendering of the specified composite before its
* elements are rendererd. Implementations of this method
* usually obtain the {@link ClippingShape} from
* <tt>composite</tt>.
*/
public void startRendering(GraphicalComposite composite);
/** Finishes rendering of the specified composite. */
public void finishRendering(GraphicalComposite composite);
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Interface all graphical elements have to implement.
* Together with the marker interface {@link Renderer} it
* realizes the Anticyclic Visitor Pattern, a variant of the
* GoF Visitor Pattern. This allows not only to extend JCCKit with
* new renderers but also with new types of <tt>GraphicalElements</tt>
* without touching existing code.
*
* @author Franz-Josef Elmer
*/
public interface GraphicalElement {
/**
* Renders this element according to the type of renderer.
* Concrete <tt>GraphicalElements</tt> who are not instances of
* {@link GraphicalComposite} dynamically cast <tt>renderer</tt>.
* If it does not implement the type of renderer specific for
* the concrete <tt>GraphicalElement</tt> it should throw an
* <tt>IllegalArgumentException</tt>.
*/
public abstract void renderWith(Renderer renderer);
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import java.awt.Color;
/**
* Interface for line attributes.
*
* @author Franz-Josef Elmer
*/
public interface LineAttributes extends GraphicAttributes {
/**
* Returns the line color.
* @return <tt>null</tt> means default color of the renderer.
*/
public Color getLineColor();
/**
* Returns the line tickness. 0 means that the line thickness is
* chosen as thin as possible.
* Implementations have to guarantee that the returned value is
* never negative.
*/
public double getLineThickness();
/**
* Returns the line pattern. This is a sequence of length where the
* pen is down or up. The first element is the length where the
* pen is down. The next element is the length where the pen is up.
* The pattern is cyclically repeated.
* @return <tt>null</tt> means solid line.
*/
public double[] getLinePattern();
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* An oval (i.e.&nbsp;an ellipse).
*
* @author Franz-Josef Elmer
*/
public class Oval extends Rectangle {
/**
* Creates a new instance.
* @param center The position of the center of this element.
* @param width The width.
* @param height The height.
* @param attributes Drawing attributes. Can be <tt>null</tt>.
*/
public Oval(GraphPoint center, double width, double height,
GraphicAttributes attributes) {
super(center, width, height, attributes);
}
/**
* Renders this oval with the specified {@link Renderer}.
* @param renderer An instance of {@link OvalRenderer}.
* @throws IllegalArgumentException if <tt>renderer</tt> is not
* an instance of <tt>OvalRenderer</tt>.
*/
public void renderWith(Renderer renderer) {
if (renderer instanceof OvalRenderer) {
((OvalRenderer) renderer).render(this);
} else {
throw new IllegalArgumentException(renderer
+ " does not implements OvalRenderer.");
}
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Interface of all {@link Renderer Renderers} who render a
* {@link Oval}.
*
* @author Franz-Josef Elmer
*/
public interface OvalRenderer extends Renderer {
/** Renders the specified oval. */
public void render(Oval oval);
}

View File

@ -0,0 +1,85 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import java.util.Vector;
/**
* A polygon or polyline.
*
* @author Franz-Josef Elmer
*/
public class Polygon extends BasicGraphicalElement {
private final Vector _points = new Vector();
private final boolean _closed;
/**
* Creates an instance of the specified graphic attributes.
* @param closed <tt>true</tt> if this polygon is closed.
*/
public Polygon(GraphicAttributes attributes, boolean closed) {
super(attributes);
_closed = closed;
}
/** Returns <tt>true</tt> if this polygon is closed. */
public boolean isClosed() {
return _closed;
}
/** Returns the number points. */
public int getNumberOfPoints() {
return _points.size();
}
/** Returns the point for the specified index. */
public GraphPoint getPoint(int index) {
return (GraphPoint) _points.elementAt(index);
}
/** Adds a new point to the end of the list of points. */
public void addPoint(GraphPoint point) {
_points.addElement(point);
}
/** Removes all points. */
public void removeAllPoints() {
_points.removeAllElements();
}
/** Replaces the point at the specified index by a new one. */
public void replacePointAt(int index, GraphPoint point) {
_points.setElementAt(point, index);
}
/**
* Renders this line with the specified {@link Renderer}.
* @param renderer An instance of {@link PolygonRenderer}.
* @throws IllegalArgumentException if <tt>renderer</tt> is not
* an instance of <tt>PolygonRenderer</tt>.
*/
public void renderWith(Renderer renderer) {
if (renderer instanceof PolygonRenderer) {
((PolygonRenderer) renderer).render(this);
} else {
throw new IllegalArgumentException(renderer
+ " does not implements PolygonRenderer.");
}
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Interface of all {@link Renderer Renderers} who render an
* instance of {@link Polygon}.
*
* @author Franz-Josef Elmer
*/
public interface PolygonRenderer extends Renderer {
/** Renders the specified <tt>Polygon</tt> instance. */
public void render(Polygon polygon);
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* A rectangle.
*
* @author Franz-Josef Elmer
*/
public class Rectangle extends BasicGraphicalElement {
private final GraphPoint _center;
private final double _width;
private final double _height;
/**
* Creates a new instance.
* @param center The position of the center of this element.
* @param width The width.
* @param height The height.
* @param attributes Drawing attributes. Can be <tt>null</tt>.
*/
public Rectangle(GraphPoint center, double width, double height,
GraphicAttributes attributes) {
super(attributes);
_center = center;
_width = width;
_height = height;
}
/** Returns the center of this element. */
public GraphPoint getCenter() {
return _center;
}
/** Returns the width of this element. */
public double getWidth() {
return _width;
}
/** Returns the height of this element. */
public double getHeight() {
return _height;
}
/**
* Renders this rectangle with the specified {@link Renderer}.
* @param renderer An instance of {@link RectangleRenderer}.
* @throws IllegalArgumentException if <tt>renderer</tt> is not
* an instance of <tt>RectangleRenderer</tt>.
*/
public void renderWith(Renderer renderer) {
if (renderer instanceof RectangleRenderer) {
((RectangleRenderer) renderer).render(this);
} else {
throw new IllegalArgumentException(renderer
+ " does not implements RectangleRenderer.");
}
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Interface of all {@link Renderer Renderers} who render a
* {@link Rectangle}.
*
* @author Franz-Josef Elmer
*/
public interface RectangleRenderer extends Renderer {
/** Renders the specified rectangle. */
public void render(Rectangle rectangle);
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Marker interface. Each subclass is an interface for a specific
* type of {@link GraphicalElement}.
*
* @author Franz-Josef Elmer
*/
public interface Renderer {}

View File

@ -0,0 +1,104 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import java.awt.Color;
import jcckit.util.ConfigParameters;
/**
* Basic attributes for shapes.
*
* @author Franz-Josef Elmer
*/
public class ShapeAttributes implements LineAttributes, FillAttributes {
/** Configuration parameter key. */
public static final String FILL_COLOR_KEY = "fillColor",
LINE_COLOR_KEY = "lineColor",
LINE_THICKNESS_KEY = "lineThickness",
LINE_PATTERN_KEY = "linePattern";
private final Color _fillColor;
private final Color _lineColor;
private final double _lineThickness;
private final double[] _linePattern;
/**
* Creates a new instance based on the specified configuration
* parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>fillColor = <i>no filling</i></tt></td><td><tt>Color</tt></td>
* <td>no</td><td>The fill color of the shape.</td></tr>
* <tr><td><tt>lineColor = <i>no line<i></tt></td><td><tt>Color</tt></td>
* <td>no</td><td>The color of a line, a polygon, or the border of a shape.</td></tr>
* <tr><td><tt>lineThickness = 0</tt></td><td><tt>double</tt></td>
* <td>no</td>
* <td>The thickness of a line. A thickness of zero means that
* the renderer will draw the thinest line possible.</td></tr>
* <tr><td><tt>linePattern = </tt><i>solid line</i></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>A sequence of lengths where the pen is alternatively
* down or up. For example, <tt>0.1 0.1</tt> will lead to a dashed
* line whereas <tt>0.02 0.02</tt> is the pattern of a dotted
* line and <tt>0.02 0.02 0.1 0.02</tt> of a dashed-dotted
* line.</td></tr>
* </table>
*/
public ShapeAttributes(ConfigParameters config) {
this(config.getColor(FILL_COLOR_KEY, null),
config.getColor(LINE_COLOR_KEY, null),
config.getDouble(LINE_THICKNESS_KEY, 0),
config.getDoubleArray(LINE_PATTERN_KEY, null));
}
/**
* Creates a new instance.
* @param fillColor The fill color. May be <tt>null</tt>.
* @param lineColor The line color. May be <tt>null</tt>.
* @param lineThickness Thickness of the line.
* Negative numbers will be trimmed to zero.
* @param linePattern Line pattern. May be <tt>null</tt>.
*/
public ShapeAttributes(Color fillColor, Color lineColor,
double lineThickness, double[] linePattern) {
_fillColor = fillColor;
_lineColor = lineColor;
_lineThickness = Math.max(0, lineThickness);
_linePattern = linePattern;
}
public Color getFillColor() {
return _fillColor;
}
public Color getLineColor() {
return _lineColor;
}
public double getLineThickness() {
return _lineThickness;
}
public double[] getLinePattern() {
return _linePattern;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* A single line of text.
*
* @author Franz-Josef Elmer
*/
public class Text extends BasicGraphicalElement {
private final GraphPoint _position;
private final String _text;
/**
* Creates an instance with the specified parameters.
* @param position Position of the text.
* @param text Text.
* @param attributes Drawing attributes. Can be <tt>null</tt>.
*/
public Text(GraphPoint position, String text, GraphicAttributes attributes) {
super(attributes);
_position = position;
_text = text;
}
/** Returns the position. */
public GraphPoint getPosition() {
return _position;
}
/** Returns the text string. */
public String getText() {
return _text;
}
/**
* Renders this line with the specified {@link Renderer}.
* @param renderer An instance of {@link TextRenderer}.
* @throws IllegalArgumentException if <tt>renderer</tt> is not
* an instance of <tt>TextRenderer</tt>.
*/
public void renderWith(Renderer renderer) {
if (renderer instanceof TextRenderer) {
((TextRenderer) renderer).render(this);
} else {
throw new IllegalArgumentException(renderer
+ " does not implements TextRenderer.");
}
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
import java.awt.Color;
/**
* Interface for text attributes.
*
* @author Franz-Josef Elmer
*/
public interface TextAttributes extends GraphicAttributes {
/**
* Returns the text color.
* @return <tt>null</tt> means default color of the renderer.
*/
public Color getTextColor();
/**
* Returns the font name.
* @return <tt>null</tt> means default font name of the renderer.
*/
public String getFontName();
/**
* Returns the font style.
* @return <tt>null</tt> means default font style of the renderer.
*/
public FontStyle getFontStyle();
/**
* Returns the font size in units of the device-independent coordinates.
*/
public double getFontSize();
/**
* Returns the orientation angle in degree. Zero means
* normal text orientation. Any positive angle means a
* counter-clockwise rotation of the text.
*/
public double getOrientationAngle();
/**
* Returns the anchor for horizontal position of the text.
* Note, that the anchor is related to the text <em>before</em>
* it is rotated by the orientation angle.
* @return one of the three instances of <tt>Anchor</tt>.
*/
public Anchor getHorizontalAnchor();
/**
* Returns the anchor for vertical position of the text.
* Note, that the anchor is related to the text <em>before</em>
* it is rotated by the orientation angle.
* @return one of the three instances of <tt>Anchor</tt>.
*/
public Anchor getVerticalAnchor();
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.graphic;
/**
* Interface of all {@link Renderer Renderers} who render an
* instance of {@link Text}.
*
* @author Franz-Josef Elmer
*/
public interface TextRenderer extends Renderer {
/** Renders the specified <tt>Text</tt> instance. */
public void render(Text text);
}

View File

@ -0,0 +1,120 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicAttributes;
import jcckit.graphic.GraphicalElement;
import jcckit.util.ConfigParameters;
import jcckit.util.Factory;
/**
* Abstract superclass of all {@link SymbolFactory SymbolFactories}.
* Subclasses have to implement {@link #createPlainSymbol createPlainSymbol()}.
*
* @author Franz-Josef Elmer
*/
public abstract class AbstractSymbolFactory implements SymbolFactory {
/** Size of all symbols. */
protected final double _size;
/** Attributes of all symbols. */
protected final GraphicAttributes _attributes;
/**
* Creates an instance from the specified configuration parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>size = </tt>0.01</td>
* <td><tt>double</tt></td><td>no</td>
* <td>Size of the symbol in device-independent units.</td></tr>
* <tr><td><tt>attributes</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Configuration parameters for the attributes of the symbol.
* <tt>className</tt> has to be a class which is an instance of
* {@link GraphicAttributes}.</td></tr>
* </table>
*/
public AbstractSymbolFactory(ConfigParameters config) {
_size = config.getDouble(SIZE_KEY, DEFAULT_SIZE);
_attributes = (GraphicAttributes) Factory.createOrGet(
config.getNode(ATTRIBUTES_KEY), null);
}
/**
* Creates a symbol.
* Evaluate <tt>hintFromPreviousPoint</tt> if it is a {@link AttributesHint}.
* Calls {@link #createSymbol(GraphPoint, GraphicAttributes, Hint, Hint)}.
* @param point Symbol position.
* @param hintFromPreviousPoint Hint from the previous point.
* @param hintFromPreviousCurve Hint from the previous curve.
*/
public Symbol createSymbol(GraphPoint point, Hint hintFromPreviousPoint,
Hint hintFromPreviousCurve) {
GraphicAttributes attributes = _attributes;
Hint hintForNextPoint = hintFromPreviousPoint;
if (hintFromPreviousPoint instanceof AttributesHint) {
attributes = ((AttributesHint) hintFromPreviousPoint).getAttributes();
hintForNextPoint
= ((AttributesHint) hintFromPreviousPoint).getNextHint();
}
return createSymbol(point, attributes, hintForNextPoint,
hintFromPreviousCurve);
}
/**
* Creates a symbol.
* Uses {@link #createPlainSymbol createPlainSymbol()}.
* @param point Symbol position.
* @param attributes Symbol attributes.
* @param hintForNextPoint Hint for the next point. Will be delivered
* unchanged in the return <tt>Symbol</tt> object.
* @param hintFromPreviousCurve Hint from the previous curve.
* Will be delivered unchanged in the return <tt>Symbol</tt> object.
* Subclasses may override this behavior.
*/
protected Symbol createSymbol(GraphPoint point, GraphicAttributes attributes,
Hint hintForNextPoint,
Hint hintFromPreviousCurve) {
return new Symbol(createPlainSymbol(point, _size, attributes),
hintForNextPoint, hintFromPreviousCurve);
}
/**
* Creates a symbol for the legend at the specified position.
* Uses {@link #createPlainSymbol createPlainSymbol()}
* @param centerPosition Center position of the symbol.
* @param size The size of the symbol. Will be ignored because the value
* given in the constructor will be used.
*/
public GraphicalElement createLegendSymbol(GraphPoint centerPosition,
double size) {
return createPlainSymbol(centerPosition, _size, _attributes);
}
/**
* Creates the graphical element of the plain symbol.
* @param centerPosition Center position of the symbol.
* @param size The size of the symbol.
* @param attributes The attributes of the symbol.
*/
protected abstract GraphicalElement createPlainSymbol(
GraphPoint centerPosition, double size, GraphicAttributes attributes);
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.graphic.GraphicAttributes;
/**
* A {@link Hint} which wraps a {@link GraphicAttributes} instance.
* In addition the method {@link #getNextHint()} creates a new instance
* with different attributes derivated from the wrapped attributes.
*
* @author Franz-Josef Elmer
*/
public interface AttributesHint extends Hint {
/**
* Returns the hint for the next {@link Symbol} of a {@link Curve}.
* The new hint has a different {@link GraphicAttributes}.
*/
public AttributesHint getNextHint();
/** Returns the attributes value. */
public GraphicAttributes getAttributes();
}

View File

@ -0,0 +1,496 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import java.util.Properties;
import jcckit.graphic.BasicGraphicAttributes;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.LineAttributes;
import jcckit.graphic.ShapeAttributes;
import jcckit.graphic.TextAttributes;
import jcckit.util.ConfigData;
import jcckit.util.ConfigParameters;
import jcckit.util.ConfigParametersBasedConfigData;
import jcckit.util.Factory;
import jcckit.util.Format;
import jcckit.util.PropertiesBasedConfigData;
import jcckit.util.TicLabelFormat;
import jcckit.util.Util;
/**
* Helper class with various parameters defining an axis.
* This helper class is used by {@link CartesianCoordinateSystem}
* to set up a coordinate systems.
* <p>
* This class holds more than a dozen parameters. There are two factory
* methods creating instances for x- and y-axis based on
* {@link ConfigParameters}. They differ in their default parameters for
* those axes.
* <p>
* Note, that there is a direct access of these parameters without getters
* and setters but only for classes in the package <tt>jcckit.plot</tt>.
*
* @author Franz-Josef Elmer
*/
public class AxisParameters {
/** Configuration parameter key. */
public static final String LOG_SCALE_KEY = "logScale",
MINIMUM_KEY = "minimum",
MAXIMUM_KEY = "maximum",
AXIS_LENGTH_KEY = "axisLength",
AXIS_ATTRIBUTES_KEY = "axisAttributes",
AXIS_LABEL_KEY = "axisLabel",
AXIS_LABEL_POSITION_KEY = "axisLabelPosition",
AXIS_LABEL_ATTRIBUTES_KEY = "axisLabelAttributes",
AUTOMATIC_TIC_CALCULATION_KEY
= "automaticTicCalculation",
MINIMUM_TIC_KEY = "minimumTic",
MAXIMUM_TIC_KEY = "maximumTic",
NUMBER_OF_TICS_KEY = "numberOfTics",
TIC_LENGTH_KEY = "ticLength",
TIC_ATTRIBUTES_KEY = "ticAttributes",
TIC_LABEL_FORMAT_KEY = "ticLabelFormat",
TIC_LABEL_POSITION_KEY = "ticLabelPosition",
TIC_LABEL_ATTRIBUTES_KEY = "ticLabelAttributes",
GRID_KEY = "grid",
GRID_ATTRIBUTES_KEY = "gridAttributes";
private static final double LN10 = Math.log(10);
/** If <tt>true</tt> the scale is logarithmic otherwise linear. */
boolean logScale;
/** Minimum data value represented by the axis. */
double minimum;
/** Maximum data value represented by the axis. */
double maximum;
/** Length of the axis in device-independent graphical units. */
double axisLength;
/**
* Line attributes of the axis.
* Can be <tt>null</tt> which means default attributes.
*/
LineAttributes axisAttributes;
boolean automaticTicCalculation;
double minimumTic;
double maximumTic;
int numberOfTics;
/**
* Length of the tics in device-independent graphical units.
* If 0 no tics and tics label will be drawn.
*/
double ticLength;
/**
* Attributes of the tics.
* Can be <tt>null</tt> which means default attributes.
*/
LineAttributes ticAttributes;
/** Tic label formatter. */
TicLabelFormat ticLabelFormat;
/** Position of the tic label relative to the tic. */
GraphPoint ticLabelPosition;
/** Text attributes of the tic labels. */
TextAttributes ticLabelAttributes;
/** If <tt>true</tt> grid lines are drawn. */
boolean grid;
/**
* Attributes of the grid lines.
* Can be <tt>null</tt> which means default attributes.
*/
LineAttributes gridAttributes;
/** Axis label. */
String axisLabel;
/** Position of the axis label relative to the center of the axis. */
GraphPoint axisLabelPosition;
/** Text attributes of the axis label. */
TextAttributes axisLabelAttributes;
/**
* Calculate the tics based on <tt>minimumTic</tt>, <tt>maximumTic</tt>,
* and <tt>numberOfTics</tt>. If <tt>automaticTicCalculation == true</tt>
* appropriated values for these fields are calculated.
*/
double[] calculateTics() {
if (automaticTicCalculation) {
calculateTicsParameters();
}
double[] result = new double[numberOfTics];
if (numberOfTics > 0) {
double b = Util.log(minimumTic, logScale);
double a = Util.log(maximumTic, logScale);
a = numberOfTics > 1 ? (a - b) / (numberOfTics - 1) : 0;
for (int i = 0; i < result.length; i++) {
result[i] = Util.exp(a * i + b, logScale);
}
result[0] = adjust(minimum, result[0]);
result[numberOfTics - 1] = adjust(maximum, result[numberOfTics - 1]);
}
return result;
}
private void calculateTicsParameters() {
double min = Math.min(minimum, maximum);
double max = Math.max(minimum, maximum);
if (logScale) {
int minExponent = (int) (199.9999 + Math.log(min) / LN10) - 199;
int maxExponent = (int) (200.0001 + Math.log(max) / LN10) - 200;
minimumTic = Math.exp(LN10 * minExponent);
maximumTic = Math.exp(LN10 * maxExponent);
numberOfTics = maxExponent - minExponent + 1;
} else {
int baseExponent = (int) (199.69 + Math.log(max - min) / LN10) - 200;
double base = 0.2 * Math.exp(LN10 * baseExponent);
do
{
base *= 5;
int minInt = (int) (999999.999999 + min / base) - 999999;
int maxInt = (int) (1000000.000001 + max / base) - 1000000;
minimumTic = minInt * base;
maximumTic = maxInt * base;
numberOfTics = maxInt - minInt + 1;
} while (numberOfTics > 11);
}
}
/**
* Returns <tt>adjustingValue</tt> if <tt>value</tt> is very close
* to <tt>adjustingValue</tt>. Otherwise <tt>value</tt> is returned.
*/
private static double adjust(double adjustingValue, double value) {
return value != 0 && Math.abs(adjustingValue / value - 1) < 1e-11
? adjustingValue : value;
}
/**
* Returns a <tt>Properties</tt> object with those default parameters
* which are common for x- and y-axis.
*/
private static Properties createDefaultAxisProperties() {
Properties p = new Properties();
p.put(LOG_SCALE_KEY, "false");
p.put(MINIMUM_KEY, "0");
p.put(MAXIMUM_KEY, "1");
p.put(AXIS_LENGTH_KEY, "0.8");
p.put(AXIS_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
ShapeAttributes.class.getName());
p.put(AXIS_LABEL_KEY, "x");
p.put(AXIS_LABEL_POSITION_KEY, "0 -0.05");
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
BasicGraphicAttributes.class.getName());
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "center");
p.put(AUTOMATIC_TIC_CALCULATION_KEY, "true");
p.put(TIC_LENGTH_KEY, "0.01");
p.put(TIC_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
ShapeAttributes.class.getName());
p.put(TIC_LABEL_POSITION_KEY, "0 -0.01");
p.put(TIC_LABEL_FORMAT_KEY, "%1.1f");
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
BasicGraphicAttributes.class.getName());
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "center");
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "top");
p.put(GRID_KEY, "false");
p.put(GRID_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
ShapeAttributes.class.getName());
return p;
}
/**
* Returns a <tt>Properties</tt> object of the default parameters for
* an x-axis.
*/
private static Properties createDefaultXAxisProperties() {
Properties p = createDefaultAxisProperties();
p.put(AXIS_LABEL_KEY, "x");
p.put(AXIS_LABEL_POSITION_KEY, "0 -0.05");
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "top");
p.put(TIC_LABEL_POSITION_KEY, "0 -0.01");
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "center");
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "top");
return p;
}
/**
* Creates an x axis based on the specified configuration parameters.
* All numbers (lengths, fontsizes, linethicknesses, etc.) are in
* device-independent units.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>automaticTicCalculation = true</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>Has to be <tt>true</tt> if the tics should be calculated
* automatically.</td></tr>
* <tr><td><tt>axisAttributes = </tt>default values of
* {@link ShapeAttributes}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Attributes of the axis box.</td></tr>
* <tr><td><tt>axisLabel = x</tt></td>
* <td><tt>String</tt></td><td>no</td>
* <td>Axis label.</td></tr>
* <tr><td><tt>axisLabelAttributes = </tt>default values of
* {@link BasicGraphicAttributes} with a text anchor CENTER
* TOP.</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Text attributes of axis label.</td></tr>
* <tr><td><tt>axisLabelPosition = 0 -0.05</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Position of the anchor of the axis
* label relative to the center of the x-axis line.</td></tr>
* <tr><td><tt>axisLength = 0.8</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Length of the x-axis.</td></tr>
* <tr><td><tt>grid = false</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> grid lines will be drawn through the axis
* tics.</td></tr>
* <tr><td><tt>gridAttributes = </tt>default values of
* {@link ShapeAttributes}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Attributes of the grid lines.</td></tr>
* <tr><td><tt>logScale = false</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> the axis will be logarithmic. Otherwise
* the axis is linear.</td></tr>
* <tr><td><tt>maximum = 1</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>The corresponding data value of one end of the axis.</td></tr>
* <tr><td><tt>maximumTic = </tt>result from automatic calculation</td>
* <td><tt>double</tt></td><td>no</td>
* <td>The corresponding data value of the tic nearest the maximum end
* of the axis.</td></tr>
* <tr><td><tt>minimum = 0</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>The corresponding data value of one end of the axis.</td></tr>
* <tr><td><tt>minimumTic = </tt>result from automatic calculation</td>
* <td><tt>double</tt></td><td>no</td>
* <td>The corresponding data value of the tic nearest the minimum end
* of the axis.</td></tr>
* <tr><td><tt>numberOfTics = </tt>result from automatic calculation</td>
* <td><tt>int</tt></td><td>no</td>
* <td>Number of tics. The tics between the minimum and maximum tic
* are spaced equidistantly.</td></tr>
* <tr><td><tt>ticAttributes = </tt>default values of
* {@link ShapeAttributes}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Attributes of the tics.</td></tr>
* <tr><td><tt>ticLabelAttributes = </tt>default values of
* {@link BasicGraphicAttributes} with a text anchor CENTER
* TOP.</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Text attributes of tic labels.</td></tr>
* <tr><td><tt>ticLabelFormat = %1.1f</tt></td>
* <td><tt>String</tt> or <tt>ConfigParameters</tt></td><td>no</td>
* <td>Defines rendering of the tic label. By default a
* <tt>printf</tt>-like format string is given (see {@link Format}).
* Note, that an empty string means that tic labels are dropped.
* <p>
* For non-numerical rendering an implementation of a
* {@link TicLabelFormat} can be specified (e.g.
* {@link TicLabelMap}). Note, that a configuration sub tree with
* a <tt>className</tt> key-value pair overwrites any string
* definition.</td></tr>
* <tr><td><tt>ticLabelPosition = 0 -0.01</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Position of the anchor of the tic label relative to the
* tic position on the axis.</td></tr>
* <tr><td><tt>ticLength = 0.01</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Length of the tics. Negative/positive values mean tics
* inside/outside the box.</td></tr>
* </table>
*/
public static AxisParameters createXAxis(ConfigParameters config) {
return createAxis(config, createDefaultXAxisProperties());
}
/**
* Returns a <tt>Properties</tt> object of the default parameters for
* an x-axis.
*/
private static Properties createDefaultYAxisProperties() {
Properties p = createDefaultAxisProperties();
p.put(AXIS_LENGTH_KEY, "0.45");
p.put(AXIS_LABEL_KEY, "y");
p.put(AXIS_LABEL_POSITION_KEY, "-0.1 0");
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "bottom");
p.put(AXIS_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.ORIENTATION_ANGLE_KEY, "90");
p.put(TIC_LABEL_POSITION_KEY, "-0.01 0");
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "right");
p.put(TIC_LABEL_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "center");
return p;
}
/**
* Creates an y axis based on the specified configuration parameters.
* All numbers (lengths, fontsizes, linethicknesses, etc.) are in
* device-independent units.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>automaticTicCalculation = true</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>Has to be <tt>true</tt> if the tics should be calculated
* automatically.</td></tr>
* <tr><td><tt>axisAttributes = </tt>default values of
* {@link ShapeAttributes}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Attributes of the axis box.</td></tr>
* <tr><td><tt>axisLabel = y</tt></td>
* <td><tt>String</tt></td><td>no</td>
* <td>Axis label.</td></tr>
* <tr><td><tt>axisLabelAttributes = </tt>default values of
* {@link BasicGraphicAttributes} with a text anchor CENTER
* BOTTOM and the text rotated by 90 degree.</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Text attributes of axis label.</td></tr>
* <tr><td><tt>axisLabelPosition = -0.1 0</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Position of the anchor of the axis
* label relative to the center of the y-axis line.</td></tr>
* <tr><td><tt>axisLength = 0.45</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Length of the y-axis.</td></tr>
* <tr><td><tt>grid = false</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> grid lines will be drawn through the axis
* tics.</td></tr>
* <tr><td><tt>gridAttributes = </tt>default values of
* {@link ShapeAttributes}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Attributes of the grid lines.</td></tr>
* <tr><td><tt>logScale = false</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> the axis will be logarithmic. Otherwise
* the axis is linear.</td></tr>
* <tr><td><tt>maximum = 1</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>The corresponding data value of one end of the axis.</td></tr>
* <tr><td><tt>maximumTic = </tt>result from automatic calculation</td>
* <td><tt>double</tt></td><td>no</td>
* <td>The corresponding data value of the tic nearest the maximum end
* of the axis.</td></tr>
* <tr><td><tt>minimum = 0</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>The corresponding data value of one end of the axis.</td></tr>
* <tr><td><tt>minimumTic = </tt>result from automatic calculation</td>
* <td><tt>double</tt></td><td>no</td>
* <td>The corresponding data value of the tic nearest the minimum end
* of the axis.</td></tr>
* <tr><td><tt>numberOfTics = </tt>result from automatic calculation</td>
* <td><tt>int</tt></td><td>no</td>
* <td>Number of tics. The tics between the minimum and maximum tic
* are spaced equidistantly.</td></tr>
* <tr><td><tt>ticAttributes = </tt>default values of
* {@link ShapeAttributes}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Attributes of the tics.</td></tr>
* <tr><td><tt>ticLabelAttributes = </tt>default values of
* {@link BasicGraphicAttributes} with a text anchor RIGHT CENTER.
* </td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Text attributes of tic labels.</td></tr>
* <tr><td><tt>ticLabelFormat = %1.1f</tt></td>
* <td><tt>String</tt></td><td>no</td>
* <td>Defines rendering of the tic label. By default a
* <tt>printf</tt>-like format string is given (see {@link Format}).
* Note, that an empty string means that tic labels are dropped.
* <p>
* For non-numerical rendering an implementation of a
* {@link TicLabelFormat} can be specified (e.g.
* {@link TicLabelMap}). Note, that a configuration sub tree with
* a <tt>className</tt> key-value pair overwrites any string
* definition.</td></tr>
* <tr><td><tt>ticLabelPosition = -0.01 0</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Position of the anchor of the tic label relative to the
* tic position on the axis.</td></tr>
* <tr><td><tt>ticLength = 0.01</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Length of the tics. Negative/positive values mean tics
* inside/outside the box.</td></tr>
* </table>
*/
public static AxisParameters createYAxis(ConfigParameters config) {
return createAxis(config, createDefaultYAxisProperties());
}
private static AxisParameters createAxis(ConfigParameters config,
Properties p) {
ConfigData cd = new PropertiesBasedConfigData(p);
ConfigParameters c = new ConfigParameters(cd);
cd = new ConfigParametersBasedConfigData(config, c);
c = new ConfigParameters(cd);
AxisParameters a = new AxisParameters();
a.logScale = c.getBoolean(LOG_SCALE_KEY);
a.minimum = c.getDouble(MINIMUM_KEY);
a.maximum = c.getDouble(MAXIMUM_KEY);
a.axisLength = c.getDouble(AXIS_LENGTH_KEY);
a.axisAttributes
= (LineAttributes) Factory.create(c.getNode(AXIS_ATTRIBUTES_KEY));
a.axisLabel = c.get(AXIS_LABEL_KEY);
a.axisLabelPosition
= new GraphPoint(c.getDoubleArray(AXIS_LABEL_POSITION_KEY));
a.axisLabelAttributes = (TextAttributes) Factory.create(
c.getNode(AXIS_LABEL_ATTRIBUTES_KEY));
a.ticLength = c.getDouble(TIC_LENGTH_KEY);
a.automaticTicCalculation
= c.getBoolean(AUTOMATIC_TIC_CALCULATION_KEY);
if (!a.automaticTicCalculation) {
a.calculateTicsParameters(); // calculate default parameters
a.minimumTic = c.getDouble(MINIMUM_TIC_KEY, a.minimumTic);
a.maximumTic = c.getDouble(MAXIMUM_TIC_KEY, a.maximumTic);
a.numberOfTics = c.getInt(NUMBER_OF_TICS_KEY, a.numberOfTics);
}
a.ticAttributes
= (LineAttributes) Factory.create(c.getNode(TIC_ATTRIBUTES_KEY));
a.ticLabelFormat = createTicLabelFormat(c);
a.ticLabelPosition
= new GraphPoint(c.getDoubleArray(TIC_LABEL_POSITION_KEY));
a.ticLabelAttributes = (TextAttributes) Factory.create(
c.getNode(TIC_LABEL_ATTRIBUTES_KEY));
a.grid = c.getBoolean(GRID_KEY);
a.gridAttributes
= (LineAttributes) Factory.create(c.getNode(GRID_ATTRIBUTES_KEY));
return a;
}
private static TicLabelFormat createTicLabelFormat(ConfigParameters c)
{
TicLabelFormat result = Format.create(c, TIC_LABEL_FORMAT_KEY);
ConfigParameters node = c.getNode(TIC_LABEL_FORMAT_KEY);
if (node.get(Factory.CLASS_NAME_KEY, null) != null) {
result = (TicLabelFormat) Factory.create(node);
}
return result;
}
}

View File

@ -0,0 +1,131 @@
/*
* 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;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicAttributes;
import jcckit.graphic.GraphicalElement;
import jcckit.graphic.Rectangle;
import jcckit.util.ConfigParameters;
/**
* A factory of bars. The bars are {@link Rectangle Rectangles}.
* Depending on the configuration parameters the bars can be
* horizontal or vertical. Bars of several curves can be side by side or
* stacked. The bar length is determined by the x or y value of the
* curve point in device-independent coordinates. If the value is negative
* the bar goes into the negative direction. For stacked bars the values
* should always be positive.
* <p>
* When used inside a {@link SimpleCurve} soft clipping should always be
* switched off (see
* {@link SimpleCurve#SimpleCurve(ConfigParameters, int, int, ClippingShape, Legend)}).
*
* @author Franz-Josef Elmer
*/
public class BarFactory extends AbstractSymbolFactory {
/** Configuration parameter key. */
public static final String STACKED_KEY = "stacked",
HORIZONTAL_BARS_KEY = "horizontalBars";
private final boolean _stacked;
private final boolean _horizontalBars;
/**
* Creates an instance from the specified configuration parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>horizontalBars = false</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> horizontal bars will be drawn. Otherwise
* vertical bars are drawn.</td></tr>
* <tr><td><tt>stacked = false</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> the bars of several curves will be
* stacked.</td></tr>
* </table>
* In addition the configuration parameters of the
* <a href="AbstractSymbolFactory.html#AbstractSymbolFactory(jcckit.util.ConfigParameters)">
* constructor</a> of the superclass {@link AbstractSymbolFactory} apply.
*/
public BarFactory(ConfigParameters config) {
super(config);
_horizontalBars = config.getBoolean(HORIZONTAL_BARS_KEY, false);
_stacked = config.getBoolean(STACKED_KEY, false);
}
/**
* Creates a bar at the specified point.
* If <tt>hintFromPreviousCurve</tt>
* is not an instance of {@link PositionHint} the values of
* origin and position will be (0,0).
* @param hintFromPreviousCurve Hint from previous curve. Will be used
* to calculate symbol shape and hint for the next curve.
*/
protected Symbol createSymbol(GraphPoint point, GraphicAttributes attributes,
Hint hintForNextPoint,
Hint hintFromPreviousCurve) {
GraphPoint origin = new GraphPoint(null);
GraphPoint position = origin;
if (hintFromPreviousCurve instanceof PositionHint) {
origin = ((PositionHint) hintFromPreviousCurve).getOrigin();
position = ((PositionHint) hintFromPreviousCurve).getPosition();
}
double px = position.getX();
double py = position.getY();
double x = point.getX() - origin.getX();
double y = point.getY() - origin.getY();
if (_horizontalBars) {
y = _size;
position = new GraphPoint(px + 0.5 * x, point.getY() + py);
px += _stacked ? x : 0;
py += _stacked ? 0 : _size;
} else {
x = _size;
position = new GraphPoint(point.getX() + px, py + 0.5 * y);
px += _stacked ? 0 : _size;
py += _stacked ? y : 0;
}
Hint hintForNextCurve = new PositionHint(origin, new GraphPoint(px, py));
return new Symbol(new Rectangle(position, Math.abs(x), Math.abs(y),
attributes),
hintForNextPoint, hintForNextCurve);
}
/**
* Creates a symbol for the legend at the specified position.
* @param centerPosition Center position of the symbol.
* @param size The size of the symbol.
*/
public GraphicalElement createLegendSymbol(GraphPoint centerPosition,
double size) {
return new Rectangle(centerPosition, size, size, _attributes);
}
/**
* Returns <tt>null</tt> because this method isn't needed but has to be
* implemented.
*/
protected GraphicalElement createPlainSymbol(
GraphPoint centerPosition, double size, GraphicAttributes attributes) {
return null;
}
}

View File

@ -0,0 +1,206 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.data.DataPoint;
import jcckit.graphic.ClippingRectangle;
import jcckit.graphic.ClippingShape;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicAttributes;
import jcckit.graphic.GraphicalComposite;
import jcckit.graphic.GraphicalElement;
import jcckit.graphic.LineAttributes;
import jcckit.graphic.Polygon;
import jcckit.graphic.Text;
import jcckit.transformation.CartesianTransformation;
import jcckit.transformation.Transformation;
import jcckit.util.ConfigParameters;
/**
* A Cartesian coordinate system. One or both axes can be logarithmic.
*
* @author Franz-Josef Elmer
*/
public class CartesianCoordinateSystem implements CoordinateSystem {
/** Configuration parameter key. */
public static final String ORIGIN_KEY = "origin",
X_AXIS_KEY = "xAxis",
Y_AXIS_KEY = "yAxis";
private final CartesianTransformation _transformation;
private final GraphicalComposite _view;
private final ClippingRectangle _clippingRectangle;
/**
* Creates an instance from the specified configuration parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>origin = 0.15,&nbsp;0.1</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Position (in device-independent coordinates) of the lower-left
* corner of the axis box.</td></tr>
* <tr><td><tt>xAxis</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Parameters defining the x-axis. For definitions and default
* values see {@link AxisParameters#createXAxis
* AxisParameters.createXAxis()}.</td></tr>
* <tr><td><tt>yAxis</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Parameters defining the y-axis. For definitions and default
* values see {@link AxisParameters#createYAxis
* AxisParameters.createYAxis()}.</td></tr>
* </table>
*/
public CartesianCoordinateSystem(ConfigParameters config) {
this(new GraphPoint(config.getDoubleArray(ORIGIN_KEY,
new double[] {0.15, 0.1})),
AxisParameters.createXAxis(config.getNode(X_AXIS_KEY)),
AxisParameters.createYAxis(config.getNode(Y_AXIS_KEY)));
}
/**
* Creates an instance for the specified origin and parameters
* of both axes.
* @param origin Position (in device-independent coordinates) of the
* lower-left corner of the axis box.
* @param xAxisParameters Parameters of the x-axis.
* @param yAxisParameters Parameters of the y-axis.
*/
public CartesianCoordinateSystem(GraphPoint origin,
AxisParameters xAxisParameters,
AxisParameters yAxisParameters) {
double x = origin.getX();
double y = origin.getY();
_transformation = new CartesianTransformation(xAxisParameters.logScale,
yAxisParameters.logScale,
new DataPoint(xAxisParameters.minimum, yAxisParameters.minimum),
new GraphPoint(x, y),
new DataPoint(xAxisParameters.maximum, yAxisParameters.maximum),
new GraphPoint(x + xAxisParameters.axisLength,
y + yAxisParameters.axisLength));
_clippingRectangle = new ClippingRectangle(x, y,
x + xAxisParameters.axisLength,
y + yAxisParameters.axisLength);
_view = new GraphicalComposite(null);
createView(origin, xAxisParameters, yAxisParameters);
}
/** Creates the graphical representation of this coordinate system. */
private void createView(GraphPoint origin,
AxisParameters xAxisParameters,
AxisParameters yAxisParameters) {
double x0 = origin.getX();
double x1 = x0 + xAxisParameters.axisLength;
double y0 = origin.getY();
double y1 = y0 + yAxisParameters.axisLength;
GraphPoint lowerLeftCorner = new GraphPoint(x0, y0);
GraphPoint upperLeftCorner = new GraphPoint(x0, y1);
GraphPoint lowerRightCorner = new GraphPoint(x1, y0);
GraphPoint upperRightCorner = new GraphPoint(x1, y1);
LineAttributes xLineAttributes = xAxisParameters.axisAttributes;
LineAttributes yLineAttributes = yAxisParameters.axisAttributes;
createTicsAndGrid(true, y0, y1, xAxisParameters);
createTicsAndGrid(false, x0, x1, yAxisParameters);
addLine(lowerLeftCorner, lowerRightCorner, xLineAttributes);
addLine(lowerLeftCorner, upperLeftCorner, yLineAttributes);
addLine(upperLeftCorner, upperRightCorner, xLineAttributes);
addLine(lowerRightCorner, upperRightCorner, yLineAttributes);
createLabel(0.5 * (x0 + x1), y0, xAxisParameters);
createLabel(x0, 0.5 * (y0 + y1), yAxisParameters);
}
private void createLabel(double x, double y, AxisParameters parameters) {
if (parameters.axisLabel.length() > 0) {
_view.addElement(new Text(
new GraphPoint(x + parameters.axisLabelPosition.getX(),
y + parameters.axisLabelPosition.getY()),
parameters.axisLabel, parameters.axisLabelAttributes));
}
}
private void createTicsAndGrid(boolean isXAxis, double low, double high,
AxisParameters parameters) {
double[] tics = parameters.calculateTics();
int offIndex = isXAxis ? 1 : 0;
double[] point = new double[2]; // helper array
for (int i = 0; i < tics.length; i++) {
point[1 - offIndex] = tics[i];
point[offIndex] = 1;
GraphPoint gPoint1 =
_transformation.transformToGraph(new DataPoint(point[0], point[1]));
point[0] = gPoint1.getX();
point[1] = gPoint1.getY();
point[offIndex] = high;
gPoint1 = new GraphPoint(point[0], point[1]);
point[offIndex] += parameters.ticLength;
addLine(gPoint1, new GraphPoint(point[0], point[1]),
parameters.ticAttributes);
point[offIndex] = low;
GraphPoint gPoint2 = new GraphPoint(point[0], point[1]);
if (parameters.grid) {
addLine(gPoint1, gPoint2, parameters.gridAttributes);
}
point[offIndex] -= parameters.ticLength;
addLine(gPoint2, new GraphPoint(point[0], point[1]),
parameters.ticAttributes);
if (parameters.ticLabelFormat != null) {
point[offIndex] += parameters.ticLength;
point[0] += parameters.ticLabelPosition.getX();
point[1] += parameters.ticLabelPosition.getY();
_view.addElement(new Text(new GraphPoint(point[0], point[1]),
parameters.ticLabelFormat.form(tics[i]),
parameters.ticLabelAttributes));
}
}
}
private void addLine(GraphPoint point1, GraphPoint point2,
GraphicAttributes attributes) {
Polygon line = new Polygon(attributes, false);
line.addPoint(point1);
line.addPoint(point2);
_view.addElement(line);
}
/**
* Returns the graphical representation of the coordinate system.
* In each call the same instance is returned.
*/
public GraphicalElement getView() {
return _view;
}
/**
* Returns the clipping rectangle of specified by the axis.
* In each call the same instance is returned.
*/
public ClippingShape getClippingShape() {
return _clippingRectangle;
}
/**
* Returns the transformation of data coordinates into the device-independent
* coordinates of the axis box.
* In each call the same instance is returned.
*/
public Transformation getTransformation() {
return _transformation;
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicAttributes;
import jcckit.graphic.GraphicalElement;
import jcckit.graphic.Oval;
import jcckit.util.ConfigParameters;
/**
* A factory of circle symbols.
*
* @author Franz-Josef Elmer
*/
public class CircleSymbolFactory extends AbstractSymbolFactory {
/**
* Creates an instance from the specified configuration parameters.
* For the configuration parameters see the
* <a href="AbstractSymbolFactory.html#AbstractSymbolFactory(jcckit.util.ConfigParameters)">
* constructor</a> of the superclass {@link AbstractSymbolFactory}.
*/
public CircleSymbolFactory(ConfigParameters config) {
super(config);
}
/**
* Creates a circle.
* @param centerPosition Position of the center of the circle.
* @param size Diameter of the circle.
* @param attributes Circle attributes.
*/
protected GraphicalElement createPlainSymbol(GraphPoint centerPosition,
double size,
GraphicAttributes attributes) {
return new Oval(centerPosition, size, size, attributes);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.graphic.ClippingShape;
import jcckit.graphic.GraphicalElement;
import jcckit.transformation.Transformation;
/**
* Interface for all generators of coordinate systems. A
* <tt>CoordinateSystem</tt> creates a
* {@link jcckit.graphic.GraphicalComposite} which contains all the
* {@link GraphicalElement GraphicalElements} defining axes, labels, grid, etc.
*
* @author Franz-Josef Elmer
*/
public interface CoordinateSystem {
/**
* Returns the graphical representation of a coordinate
* system. Different invocations of this method may return
* different coordinate systems, e.g., due to changes in the
* transformation or clipping shapes.
*/
public GraphicalElement getView();
/**
* Returns the clipping chape of {@link Curve Curves} drawn on top
* of the coordinates system. Different invocations of
* this method may return different clipping shapes.
*/
public ClippingShape getClippingShape();
/**
* Returns the transformation between data coordinates and
* device-independent graphcial coordinates. Different invocations
* of this method may return different transformations.
*/
public Transformation getTransformation();
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicalElement;
/**
* A curve is defined by a sequence of points in device-independent
* coordinates. The points can be decorated by symbols and/or
* connected by lines.{@link Hint Hints} are used to determine additional
* properties of the symbol. This is especially important for
* charts with bars.
* <p>
* In accordance with the Factory Method Pattern
* the symbols are created by a {@link SymbolFactory}.
*
* @author Franz-Josef Elmer
*/
public interface Curve {
/**
* Returns the graphical representation of a curve.
* Different invocations of this method might return
* different instances.
* This is especially true after adding, inserting, removing, or
* repplacing a point of the curve.
*/
public GraphicalElement getView();
/**
* Returns a symbol which can be used to create the legend for the curve.
* For example, it should return a horizontal line with the symbol
* in the middle if the curve is a line with points decorated by symbols.
*/
public GraphicalElement getLegendSymbol();
/**
* Appends a new point to the curve.
* @param point Position in device-independent coordinates.
* @param hintFromPreviousCurve Hint which may be used to calculate
* the corresponding {@link GraphicalElement}.
* @return hint for next curve.
*/
public Hint addPoint(GraphPoint point, Hint hintFromPreviousCurve);
/** Removes all points from the curve. */
public void removeAllPoints();
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.graphic.ClippingShape;
/**
* Interface of a curve factory. A curve factory creates a new instance
* of a {@link Curve}.
*
* @author Franz-Josef Elmer
*/
public interface CurveFactory {
/**
* Creates a new curve instance.
* @param curveIndex The index of the curve in the {@link Plot} to which
* it should belong.
* @param numberOfCurves Number of curves. Will be needed to calculate the
* y-coordinate of the legend symbol.
* @param clippingShape Clipping shape applied to the curve.
* @param legend The legend which will show the curve symbol.
* @return an empty instance.
*/
public Curve create(int curveIndex, int numberOfCurves,
ClippingShape clippingShape, Legend legend);
}

View File

@ -0,0 +1,136 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicAttributes;
import jcckit.graphic.GraphicalComposite;
import jcckit.graphic.GraphicalElement;
import jcckit.graphic.Rectangle;
import jcckit.util.ConfigParameters;
import jcckit.util.Factory;
/**
* Symbol factory for creating symbols with error bars. It wraps
* a {@link SymbolFactory} for creating the symbol. The error bars
* are {@link Rectangle Rectangles}.
* <p>
* Curves with error bars are based on <em>two</em>
* {@link jcckit.data.DataCurve DataCurves}:
* <ol><li>The plain curve.
* <li>An instance which stores the errors in <i>x</i> and <i>y</i>.
* It is assumed that the errors are positive values defining
* the error symmetrically around the curve points.
* </ol>
* <p>
* The <tt>ErrorBarFactory</tt> needs an instance of {@link PositionHint}
* as initial {@link Hint} for the next curve. Its origin must be
* the origin of the data coordinate system in device-independent coordinates.
* The position of <tt>PositionHint</tt> must be undefined.
*
* @author Franz-Josef Elmer
*/
public class ErrorBarFactory implements SymbolFactory {
/** Configuration parameter key. */
public static final String SYMBOL_FACTORY_KEY = "symbolFactory";
private final SymbolFactory _symbolFactory;
private final GraphicAttributes _attributes;
private final double _size;
/**
* Creates an instance from the specified configuration parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>symbolFactory = null</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Definition of the wrapped {@link SymbolFactory} which generates
* the curve symbol without bars. By default an empty
* {@link GraphicalComposite} will be created.</td></tr>
* <tr><td><tt>size = 0</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Width of the error bars.</td></tr>
* <tr><td><tt>attributes = null</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Definition of the {@link GraphicAttributes} of the error
* bars.</td></tr>
* </table>
*/
public ErrorBarFactory(ConfigParameters config) {
_symbolFactory = (SymbolFactory) Factory.createOrGet(
config.getNode(SYMBOL_FACTORY_KEY), null);
_size = config.getDouble(SIZE_KEY, 0);
_attributes = (GraphicAttributes) Factory.createOrGet(
config.getNode(ATTRIBUTES_KEY), null);
}
/**
* Creates the legend symbol. Calls the wrapped {@link SymbolFactory}
* or returns an empty instance of {@link GraphicalComposite} if undefined.
*/
public GraphicalElement createLegendSymbol(GraphPoint centerPosition,
double size) {
return _symbolFactory == null ? new GraphicalComposite(null)
: _symbolFactory.createLegendSymbol(centerPosition, size);
}
/**
* Creates either the curve symbol or the error bars. Error bars are
* created when <tt>hintFromPreviousCurve</tt> is an instance of
* {@link PositionHint} and its position attribute is not <tt>null</tt>.
* Otherwise the curve symbol is created. The position attributes stores
* the curve point (in device-independent coordinates). The origin is
* always as set in the initial <tt>PositionHint</tt>. The hint for
* the next curve wrapped by the returned <tt>Symbol</tt> is always
* a <tt>PositionHint</tt>.
*/
public Symbol createSymbol(GraphPoint point, Hint hintFromPreviousPoint,
Hint hintFromPreviousCurve) {
GraphPoint origin = new GraphPoint(null);
GraphPoint position = null;
if (hintFromPreviousCurve instanceof PositionHint) {
origin = ((PositionHint) hintFromPreviousCurve).getOrigin();
position = ((PositionHint) hintFromPreviousCurve).getPosition();
}
if (position == null) {
if (_symbolFactory == null) {
return new Symbol(new GraphicalComposite(null), hintFromPreviousPoint,
new PositionHint(origin, point));
} else {
return _symbolFactory.createSymbol(point, hintFromPreviousPoint,
new PositionHint(origin, point));
}
} else {
double xError = point.getX() - origin.getX();
double yError = point.getY() - origin.getY();
GraphicalComposite errorBars = new GraphicalComposite(null);
if (xError > 0) {
errorBars.addElement(new Rectangle(position, 2 * xError, _size,
_attributes));
}
if (yError > 0) {
errorBars.addElement(new Rectangle(position, _size, 2 * yError,
_attributes));
}
return new Symbol(errorBars, hintFromPreviousPoint,
new PositionHint(origin, null));
}
}
}

32
src/jcckit/plot/Hint.java Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
/**
* Marker interface of all types of hints. Hints are used to calculate
* {@link jcckit.graphic.GraphicalElement} representing a point in a {@link
* Curve}. For example, in a chart with stacked
* bars the data determines the height of a bar but the foot of
* a bar is determined by the height of the bar below. Its value will be
* stored in a {@link PositionHint}.
*
* @author Franz-Josef Elmer
*/
public interface Hint {}

250
src/jcckit/plot/Legend.java Normal file
View File

@ -0,0 +1,250 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import java.util.Properties;
import jcckit.graphic.BasicGraphicAttributes;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicAttributes;
import jcckit.graphic.GraphicalComposite;
import jcckit.graphic.GraphicalElement;
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;
/**
* Helper class for creating the legend of a {@link Plot}.
*
* @author Franz-Josef Elmer
*/
public class Legend {
/** Configuration parameter key. */
public static final String UPPER_RIGHT_CORNER_KEY = "upperRightCorner",
BOX_WIDTH_KEY = "boxWidth",
BOX_HEIGHT_KEY = "boxHeight",
BOX_ATTRIBUTES_KEY = "boxAttributes",
TITLE_KEY = "title",
TITLE_DISTANCE_KEY = "titleDistance",
TITLE_ATTRIBUTES_KEY = "titleAttributes",
LEFT_DISTANCE_KEY = "leftDistance",
BOTTOM_DISTANCE_KEY = "bottomDistance",
TOP_DISTANCE_KEY = "topDistance",
LINE_LENGTH_KEY = "lineLength",
SYMBOL_SIZE_KEY = "symbolSize",
CURVE_TITLE_DISTANCE_KEY = "curveTitleDistance",
CURVE_TITLE_ATTRIBUTES_KEY
= "curveTitleAttributes";
private final GraphicalComposite _box;
private final TextAttributes _curveTitleAttributes;
private final double _xSymbol;
private final double _xText;
private final double _yBase;
private final double _yLastRow;
private final double _length;
private final double _size;
/**
* Creates an instance from the specified configuration parameters.
* All numbers (lengths, fontsizes, linethicknesses, etc.) are in
* device-independent units.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>bottomDistance = 0.02</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Distance between the last row and the bottom of the legend box.
* </td></tr>
* <tr><td><tt>boxAttributes = </tt>default values of
* {@link ShapeAttributes} with a white fill color.</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Attributes of the legend box.</td></tr>
* <tr><td><tt>boxHeight = 0.1</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Height of the legend box.</td></tr>
* <tr><td><tt>boxWidth = 0.2</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Width of the legend box.</td></tr>
* <tr><td><tt>curveTitleAttributes = </tt>default values of
* {@link BasicGraphicAttributes}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Text attributes of curve titles printed in the legend.</td></tr>
* <tr><td><tt>curveTitleDistance = 0.005</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Horizontal distance between the line part of the legend symbol
* and the curve title.</td></tr>
* <tr><td><tt>leftDistance = 0.01</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Horizontal distance between the line part of the legend symbol
* and the left border of the legend box.</td></tr>
* <tr><td><tt>lineLength = 0.035</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Length of the line part of the legend symbol.</td></tr>
* <tr><td><tt>symbolSize = 0.01</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Size of the symbol part of the legend symbol. Will be the
* <tt>size</tt> argument of {@link SymbolFactory#createLegendSymbol
* createLegendSymbol} in a {@link SymbolFactory}.</td></tr>
* <tr><td><tt>titleAttributes = </tt>default values of
* {@link BasicGraphicAttributes} with a text anchor CENTER
* TOP.</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Text attributes of the title of the legend box.</td></tr>
* <tr><td><tt>title = Legend</tt></td>
* <td><tt>String</tt></td><td>no</td>
* <td>Title of the legend box.</td></tr>
* <tr><td><tt>titleDistance = 0.005</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Distance between the center of the upper line of the legend box
* and the anchor of the legend title.</td></tr>
* <tr><td><tt>topDistance = 0.04</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Distance between the first row and the top of the legend box.
* </td></tr>
* <tr><td><tt>upperRightCorner = 0.94,&nbsp;0.54</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Position of the upper-right corner of the legend box.</td></tr>
* </table>
*/
public Legend(ConfigParameters config) {
config = mergeWithDefaultConfig(config);
GraphPoint corner
= new GraphPoint(config.getDoubleArray(UPPER_RIGHT_CORNER_KEY,
new double[] {0.94, 0.54}));
double width = config.getDouble(BOX_WIDTH_KEY, 0.2);
double height = config.getDouble(BOX_HEIGHT_KEY, 0.1);
_curveTitleAttributes = (TextAttributes) Factory.create(
config.getNode(CURVE_TITLE_ATTRIBUTES_KEY));
_xSymbol = corner.getX() - width
+ config.getDouble(LEFT_DISTANCE_KEY, 0.01);
_yBase = corner.getY() - config.getDouble(TOP_DISTANCE_KEY, 0.04);
_yLastRow = corner.getY() - height
+ config.getDouble(BOTTOM_DISTANCE_KEY, 0.02);
_length = config.getDouble(LINE_LENGTH_KEY, 0.035);
_size = config.getDouble(SYMBOL_SIZE_KEY, 0.01);
_xText = _xSymbol + _length
+ config.getDouble(CURVE_TITLE_DISTANCE_KEY, 0.005);
_box = new GraphicalComposite(null);
double xCenter = corner.getX() - width / 2;
_box.addElement(new Rectangle(
new GraphPoint(xCenter, corner.getY() - height / 2), width, height,
(GraphicAttributes) Factory.create(
config.getNode(BOX_ATTRIBUTES_KEY))));
_box.addElement(new Text(
new GraphPoint(xCenter, corner.getY()
- config.getDouble(TITLE_DISTANCE_KEY, 0.005)),
config.get(TITLE_KEY, "Legend"),
(TextAttributes) Factory.create(
config.getNode(TITLE_ATTRIBUTES_KEY))));
}
private ConfigParameters mergeWithDefaultConfig(ConfigParameters config) {
Properties p = new Properties();
p.put(BOX_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
ShapeAttributes.class.getName());
p.put(BOX_ATTRIBUTES_KEY + '/'
+ ShapeAttributes.FILL_COLOR_KEY, "0xffffff");
p.put(BOX_ATTRIBUTES_KEY + '/'
+ ShapeAttributes.LINE_COLOR_KEY, "0");
p.put(TITLE_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
BasicGraphicAttributes.class.getName());
p.put(TITLE_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.HORIZONTAL_ANCHOR_KEY, "center");
p.put(TITLE_ATTRIBUTES_KEY + '/'
+ BasicGraphicAttributes.VERTICAL_ANCHOR_KEY, "top");
p.put(CURVE_TITLE_ATTRIBUTES_KEY + '/' + Factory.CLASS_NAME_KEY,
BasicGraphicAttributes.class.getName());
ConfigData cd = new PropertiesBasedConfigData(p);
cd = new ConfigParametersBasedConfigData(config, new ConfigParameters(cd));
return new ConfigParameters(cd);
}
/**
* Returns the legend box with title but without legend symbols and curve
* titles.
*/
public GraphicalElement getBox() {
return _box;
}
/**
* Creates the symbol part of a legend symbol.
* @param curveIndex Index of the curve. Will be needed to calculate the
* y-coordinate of the symbol.
* @param numberOfCurves Number of curves. Will be needed to calculate the
* y-coordinate of the symbol.
* @param factory Factory for the symbol part of the legend symbol.
* Can be <tt>null</tt>.
* @param withLine <tt>true</tt> if the line part of the legend symbol
* should be created.
* @param lineAttributes Attributes of the line part.
*/
public GraphicalElement createSymbol(int curveIndex, int numberOfCurves,
SymbolFactory factory,
boolean withLine,
GraphicAttributes lineAttributes) {
GraphicalComposite result = new GraphicalComposite(null);
double y = calculateBaseLine(curveIndex, numberOfCurves);
if (withLine) {
Polygon line = new Polygon(lineAttributes, false);
line.addPoint(new GraphPoint(_xSymbol, y));
line.addPoint(new GraphPoint(_xSymbol + _length, y));
result.addElement(line);
}
if (factory != null) {
result.addElement(factory.createLegendSymbol(
new GraphPoint(_xSymbol + _length / 2, y), _size));
}
return result;
}
private double calculateBaseLine(int curveIndex, int numberOfCurves) {
if (numberOfCurves > 1) {
return _yBase + ((_yLastRow - _yBase) / (numberOfCurves - 1))
* curveIndex;
} else {
return 0.5 * (_yBase + _yLastRow);
}
}
/**
* Creates the title part of a legend symbol.
* @param curveIndex Index of the curve. Will be needed to calculate the
* y-coordinate of the title.
* @param numberOfCurves Number of curves. Will be needed to calculate the
* y-coordinate of the symbol.
* @param title Title text.
*/
public GraphicalElement createCurveTitle(int curveIndex, int numberOfCurves,
String title) {
return new Text(new GraphPoint(_xText, calculateBaseLine(curveIndex,
numberOfCurves)),
title, _curveTitleAttributes);
}
}

377
src/jcckit/plot/Plot.java Normal file
View File

@ -0,0 +1,377 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import java.util.Vector;
import jcckit.data.DataCurve;
import jcckit.data.DataEvent;
import jcckit.data.DataListener;
import jcckit.data.DataPlot;
import jcckit.data.DataPoint;
import jcckit.graphic.ClippingShape;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicalComposite;
import jcckit.graphic.GraphicalElement;
import jcckit.transformation.Transformation;
import jcckit.util.ConfigParameters;
import jcckit.util.Factory;
/**
* A plot is determined by a {@link CoordinateSystem}, {@link Curve Curves},
* an optional annotation layer and an optional {@link Legend}. When rendered
* these components are draw in this order.
* <p>
* Registrated {@link PlotListener PlotListeners} will be informed
* when the plot changes.
* <p>
* A {@link DataPlot} can be connected with a <tt>Plot</tt> instance.
* This is done with the method {@link #connect connect()} which registrates
* this <tt>Plot</tt> instance as
* a {@link DataListener} at the connected <tt>DataPlot</tt>.
* After an received {@link DataEvent DataEvents} has been handled
* the registrated <tt>PlotListeners</tt> will receive a
* {@link PlotEvent} of the type {@link PlotEventType#DATA_PLOT_CHANGED}.
*
* @author Franz-Josef Elmer
*/
public class Plot implements DataListener {
/** Configuration parameter key. */
public static final String COORDINATE_SYSTEM_KEY = "coordinateSystem",
CURVE_FACTORY_KEY = "curveFactory",
LEGEND_VISIBLE_KEY = "legendVisible",
LEGEND_KEY = "legend",
INITIAL_HINT_FOR_NEXT_CURVE_KEY
= "initialHintForNextCurve";
private final Vector _plotListeners = new Vector();
private DataPlot _dataPlot;
private final CurveFactory _curveFactory;
private final Vector _curves = new Vector();
private final Vector _nextCurveHints = new Vector();
private final Hint _initialHintForNextCurve;
private final Legend _legend;
private final boolean _legendVisibility;
private GraphicalElement _coordinateSystemView;
private ClippingShape _clippingShape;
private Transformation _transformation;
private GraphicalElement _annotation;
private GraphicalComposite _legendView = new GraphicalComposite(null);
/**
* Creates an instance from the specified configuration parameters.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>coordinateSystem = </tt>{@link CartesianCoordinateSystem}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Definition of the {@link CoordinateSystem}.</td></tr>
* <tr><td><tt>curveFactory = </tt>{@link SimpleCurveFactory}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Definition of the {@link CurveFactory}.</td></tr>
* <tr><td><tt>initialHintForNextCurve = null</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Definition of the initial {@link Hint} which is needed by some
* {@link SymbolFactory SymbolFactories} like {@link BarFactory}.
* </td></tr>
* <tr><td><tt>legend = </tt>default values of {@link Legend}</td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Configuration parameters of a {@link Legend}.</td></tr>
* <tr><td><tt>legendVisible = true</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> the {@link Legend} will be created.</td></tr>
* </table>
*/
public Plot(ConfigParameters config) {
CoordinateSystem coordinateSystem = (CoordinateSystem) Factory.create(
config.getNode(COORDINATE_SYSTEM_KEY),
CartesianCoordinateSystem.class.getName());
setCoordinateSystem(coordinateSystem);
_curveFactory = (CurveFactory) Factory.create(
config.getNode(CURVE_FACTORY_KEY),
SimpleCurveFactory.class.getName());
_initialHintForNextCurve = (Hint) Factory.createOrGet(
config.getNode(INITIAL_HINT_FOR_NEXT_CURVE_KEY), null);
_legend = new Legend(config.getNode(LEGEND_KEY));
_legendVisibility = config.getBoolean(LEGEND_VISIBLE_KEY, true);
}
/**
* Sets the coordinate system. All curves will be regenerated and a
* {@link PlotEvent} of type {@link PlotEventType#COODINATE_SYSTEM_CHANGED}
* will be fired.
*
* @param coordinateSystem New coordinate system.
*/
public void setCoordinateSystem(CoordinateSystem coordinateSystem)
{
_coordinateSystemView = coordinateSystem.getView();
_clippingShape = coordinateSystem.getClippingShape();
_transformation = coordinateSystem.getTransformation();
if (_dataPlot != null)
{
generateCurves(_dataPlot);
}
notifyListeners(
new PlotEvent(this, PlotEventType.COODINATE_SYSTEM_CHANGED, null));
}
/**
* Adds the specified {@link PlotListener}. Does nothing if
* already added.
*/
public void addPlotListener(PlotListener listener) {
if (!_plotListeners.contains(listener)) {
_plotListeners.addElement(listener);
}
}
/**
* Removes the specfied {@link PlotListener}. Does nothing if
* already removed.
*/
public void removePlotListener(PlotListener listener) {
_plotListeners.removeElement(listener);
}
/**
* Sends all registrated {@link PlotListener PlotListeners}
* the specified event.
*/
protected void notifyListeners(PlotEvent event) {
for (int i = 0, n = _plotListeners.size(); i < n; i++) {
((PlotListener) _plotListeners.elementAt(i)).plotChanged(event);
}
}
/**
* Connect the specified {@link DataPlot} with this instance.
* <p>
* If this <tt>Plot</tt> instance is already connected with a
* <tt>DataPlot</tt> the connection will be released and a
* {@link PlotEvent} of the type {@link PlotEventType#DATA_PLOT_DISCONNECTED}
* will be sent to all registrated {@link PlotListener PlotListeners}.
* <p>
* It registers itself at <tt>dataPlot</tt> and
* all its {@link DataCurve DataCurves}.
* <p>
* Finally all curves will be generated and a <tt>PlotEvent</tt>
* of the type {@link PlotEventType#DATA_PLOT_CONNECTED} will be transmitted.
* @param dataPlot Data to be connected with this plot instance.
* Can be <tt>null</tt> in order to disconnect this instance from
* any <tt>DataPlot</tt>.
*/
public void connect(DataPlot dataPlot) {
if (_dataPlot != null) {
_dataPlot.removeDataListener(this);
notifyListeners(new PlotEvent(this, PlotEventType.DATA_PLOT_DISCONNECTED,
_dataPlot));
}
_dataPlot = dataPlot;
if (_dataPlot != null)
{
_dataPlot.addDataListener(this);
generateCurves(_dataPlot);
notifyListeners(new PlotEvent(this, PlotEventType.DATA_PLOT_CONNECTED,
_dataPlot));
}
}
/**
* Transforms a point from device-independent coordinates into
* data coordinates.
* @param point Point in device-independent coordinates.
* @return transform <tt>point</tt>.
*/
public DataPoint transform(GraphPoint point) {
return _transformation.transformToData(point);
}
/**
* Creates a graphical representation of the complete plot.
* @return <tt>GraphicalComposite</tt> containing the views of the
* coordinate system, the curves, and optionally the legend (in this order).
*/
public GraphicalComposite getCompletePlot() {
GraphicalComposite result = new GraphicalComposite(null);
result.addElement(_coordinateSystemView);
GraphicalElement[] curves = getCurves();
for (int i = 0; i < curves.length; i++) {
result.addElement(curves[i]);
}
if (_annotation != null) {
result.addElement(_annotation);
}
if (_legendVisibility) {
result.addElement(getLegend());
}
return result;
}
/** Returns the view of the coordinate system. */
public GraphicalElement getCoordinateSystem() {
return _coordinateSystemView;
}
/** Returns the graphical representations of all curves. */
public GraphicalElement[] getCurves() {
synchronized (_curves) {
GraphicalElement[] curves = new GraphicalElement[_curves.size()];
for (int i = 0; i < curves.length; i++) {
curves[i] = ((Curve) _curves.elementAt(i)).getView();
}
return curves;
}
}
/**
* Returns the annotation layer.
* @return <tt>null</tt> if no annotation layer.
*/
public GraphicalElement getAnnotation()
{
return _annotation;
}
/**
* Sets the annotation layer.
* @param annotation Any kind of graphics which will be drawn on the
* top of the curves but may be covered by the legend.
* Can be <tt>null</tt>.
*/
public void setAnnotation(GraphicalElement annotation)
{
_annotation = annotation;
}
/** Returns <tt>true</tt> if the legend is visible. */
public boolean isLegendVisible() {
return _legendVisibility;
}
/** Returns the graphical representations of the legend. */
public GraphicalElement getLegend() {
return _legendView;
}
/**
* Handles the received {@link DataEvent} and notifies
* {@link PlotListener PlotListeners} by an event of the type
* {@link PlotEventType#DATA_CURVE_CHANGED} or
* {@link PlotEventType#DATA_PLOT_CHANGED}. The following table shows what
* this method does:
* <table border=1 cellpadding=5>
* <tr><th>Source of <tt>event</tt></th>
* <th>All hints for the next curve are <tt>null</tt>?</th>
* <th>Action</th><th>Type of sent {@link PlotEvent}</th></tr>
* <tr><td>{@link DataCurve}</td><td>Yes</td><td>Recreate changed curve.<td>
* <td><tt>DATA_CURVE_CHANGED</tt></td></tr>
* <tr><td>{@link DataCurve}</td><td>No</td><td>Recreate changed curve
* and all curves with large curve index.<td>
* <td><tt>DATA_PLOT_CHANGED</tt></td></tr>
* <tr><td>{@link DataPlot}</td><td>-</td><td>Recreate all curves
* and {@link Legend} view.<td>
* <td><tt>DATA_PLOT_CHANGED</tt></td></tr>
* </table>
*/
public void dataChanged(DataEvent event) {
Integer index = new Integer(0);
PlotEventType type = PlotEventType.DATA_PLOT_CHANGED;
synchronized (_curves) {
int numberOfCurves = _curves.size();
if (event.getContainer() instanceof DataCurve
&& numberOfCurves == _dataPlot.getNumberOfElements()) {
DataCurve curve = (DataCurve) event.getContainer();
index = new Integer(curve.getContainer().getIndexOf(curve));
type = PlotEventType.DATA_CURVE_CHANGED;
fillCurve(index.intValue(), curve);
if (index.intValue() < numberOfCurves - 1) {
Vector curveHints
= (Vector) _nextCurveHints.elementAt(index.intValue());
for (int i = 0, n = curveHints.size(); i < n; i++) {
if (curveHints.elementAt(i) != null) {
type = PlotEventType.DATA_PLOT_CHANGED;
for (int j = index.intValue()+1; j < numberOfCurves; j++) {
fillCurve(j, (DataCurve) _dataPlot.getElement(j));
}
break;
}
}
}
} else {
generateCurves(_dataPlot);
}
}
notifyListeners(new PlotEvent(Plot.this, type, index));
}
/**
* Generates all curves based on the specified data.
* In addition the legend view is created.
*/
private void generateCurves(DataPlot dataPlot) {
synchronized (_curves) {
_legendView = new GraphicalComposite(null);
_legendView.addElement(_legend.getBox());
_curves.setSize(0);
_nextCurveHints.setSize(0);
for (int i = 0, n = dataPlot.getNumberOfElements(); i < n; i++) {
Curve curve = _curveFactory.create(i, n, _clippingShape, _legend);
_curves.addElement(curve);
_nextCurveHints.addElement(new Vector());
DataCurve dataCurve = (DataCurve) dataPlot.getElement(i);
_legendView.addElement(curve.getLegendSymbol());
_legendView.addElement(
_legend.createCurveTitle(i, n, dataCurve.getTitle()));
fillCurve(i, dataCurve);
}
}
}
private void fillCurve(int curveIndex, DataCurve dataCurve) {
Vector curveHints = (Vector) _nextCurveHints.elementAt(curveIndex);
Curve curve = (Curve) _curves.elementAt(curveIndex);
curve.removeAllPoints();
for (int i = 0, n = dataCurve.getNumberOfElements(); i < n; i++) {
setHintForNextCurve(curveHints, i,
curve.addPoint(_transformation.transformToGraph(
(DataPoint) dataCurve.getElement(i)),
getHintForNextCurve(curveIndex - 1, i)));
}
}
private Hint getHintForNextCurve(int curveIndex, int pointIndex) {
Hint result = _initialHintForNextCurve;
if (curveIndex >= 0) {
Vector curveHints = (Vector) _nextCurveHints.elementAt(curveIndex);
result = pointIndex < curveHints.size() ?
(Hint) curveHints.elementAt(pointIndex)
: getHintForNextCurve(curveIndex - 1, pointIndex);
}
return result;
}
private void setHintForNextCurve(Vector curveHints, int pointIndex,
Hint hint) {
while (curveHints.size() <= pointIndex) {
curveHints.addElement(_initialHintForNextCurve);
}
curveHints.setElementAt(hint, pointIndex);
}
}

View File

@ -0,0 +1,135 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.data.DataPlot;
import jcckit.graphic.Anchor;
import jcckit.graphic.ClippingRectangle;
import jcckit.util.ConfigParameters;
/**
* An abstract canvas containg a single {@link Plot}. The canvas is specified
* by a {@link ClippingRectangle}, called <em>paper</em>. A horizontal and
* vertical {@link Anchor} determine the position of the paper on the actual
* device.
*
* @author Franz-Josef Elmer
*/
public class PlotCanvas implements PlotListener {
/** Configuration parameter key. */
public static final String PAPER_KEY = "paper", HORIZONTAL_ANCHOR_KEY = "horizontalAnchor",
VERTICAL_ANCHOR_KEY = "verticalAnchor", PLOT_KEY = "plot";
private final ClippingRectangle _paper;
private final Anchor _horizontalAnchor;
private final Anchor _verticalAnchor;
private final Plot _plot;
/**
* Creates an instance from the specified configuration parameters. <table
* border=1 cellpadding=5>
* <tr>
* <th>Key &amp; Default Value</th>
* <th>Type</th>
* <th>Mandatory</th>
* <th>Description</th>
* </tr>
* <tr>
* <td><tt>horizontalAnchor = center</tt></td>
* <td><tt>String</tt></td>
* <td>no</td>
* <td>Horizontal position of the paper relative to the device border.
* Possible values are <tt>left</tt>, <tt>center</tt>, and
* <tt>right</tt>.</td>
* </tr>
* <tr>
* <td><tt>paper = 0,&nbsp;0,&nbsp;1,&nbsp;0.6</tt></td>
* <td><tt>double[]</tt></td>
* <td>no</td>
* <td>Rectangle defining the paper. The first two values determine the x-
* and y- coordinates (in device-independent units) of the lower-left
* corner. The last two values determine the upper-right corner.</td>
* </tr>
* <tr>
* <td><tt>plot = </tt>default values of {@link Plot}</td>
* <td><tt>ConfigParameters</tt></td>
* <td>no</td>
* <td>Definition of the {@link Plot}.</td>
* </tr>
* <tr>
* <td><tt>verticalAnchor = center</tt></td>
* <td><tt>String</tt></td>
* <td>no</td>
* <td>Vertical position of the paper relative to the device border.
* Possible values are <tt>top</tt>, <tt>center</tt>, and
* <tt>bottom</tt>.</td>
* </tr>
* </table>
* <p>
* Note, that this instance registers itself at the wrapped {@link Plot}
* instance.
*/
public PlotCanvas(ConfigParameters config) {
double[] paper = config.getDoubleArray(PAPER_KEY, new double[] { 0, 0, 1, 0.6 });
_paper = new ClippingRectangle(paper[0], paper[1], paper[2], paper[3]);
_horizontalAnchor = Anchor.getHorizontalAnchor(config, HORIZONTAL_ANCHOR_KEY, Anchor.CENTER);
_verticalAnchor = Anchor.getVerticalAnchor(config, VERTICAL_ANCHOR_KEY, Anchor.CENTER);
_plot = new Plot(config.getNode(PLOT_KEY));
_plot.addPlotListener(this);
}
/** Returns the paper definition. */
public ClippingRectangle getPaper() {
return _paper;
}
/** Returns the horizontal anchor. */
public Anchor getHorizontalAnchor() {
return _horizontalAnchor;
}
/** Returns the vertical anchor. */
public Anchor getVerticalAnchor() {
return _verticalAnchor;
}
/** Returns the plot. */
public Plot getPlot() {
return _plot;
}
/**
* Connects the wrapped {@link Plot} instance with the specified
* {@link DataPlot}.
*
* @param dataPlot
* Data to be connected with this plot canvas. Can be
* <tt>null</tt> in order to disconnect this instance from a
* <tt>DataPlot</tt>.
*/
public void connect(DataPlot dataPlot) {
_plot.connect(dataPlot);
}
/**
* Handles the spcified event. Here nothing is done. But subclass may
* override this method.
*/
public void plotChanged(PlotEvent event) {
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
/**
* A plot event signales some changes of a {@link Plot}.
* It has three attributes:
* <ul><li><b>source</b>: Indicates the <tt>Plot</tt> instance responsible
* for this event.
* <li><b>type</b>: The type of event.
* <li><b>message</b>: The message object. Its meaning depends on the
* type of event:
* <table border=1 cellpadding=5>
* <tr><th>Type</th><th>Meaning of the message object</th></tr>
* <tr><td>{@link PlotEventType#DATA_PLOT_CONNECTED},
* {@link PlotEventType#DATA_PLOT_DISCONNECTED}</td>
* <td>The {@link jcckit.data.DataPlot} (dis)connected with the
* {@link Plot} instance specified by the source.</td>
* <tr><td>{@link PlotEventType#DATA_PLOT_CHANGED}</td>
* <td>An <tt>Integer</tt> indicating the lowest index of
* those curves which have been changed.</td>
* <tr><td>{@link PlotEventType#DATA_CURVE_CHANGED}</td>
* <td>An <tt>Integer</tt> indicating the index of the curve
* which has been changed.</td>
* </table>
* </ul>
*
*
* @author Franz-Josef Elmer
*/
public class PlotEvent {
private final Plot _source;
private final PlotEventType _type;
private final Object _message;
/**
* Creates a new event for the specified source, type, and message.
* @param source Plot causing this event.
* @param type Type of the event. Possible values are
* {@link PlotEventType#DATA_PLOT_CHANGED},
* {@link PlotEventType#DATA_CURVE_CHANGED},
* {@link PlotEventType#DATA_PLOT_CONNECTED}, and
* {@link PlotEventType#DATA_PLOT_DISCONNECTED}.
* @param message Message object. Can be <tt>null</tt>
*/
public PlotEvent(Plot source, PlotEventType type, Object message) {
_source = source;
_type = type;
_message = message;
}
/** Returns the source of this event. */
public Plot getSource() {
return _source;
}
/**
* Returns the event type.
* @return either {@link PlotEventType#DATA_PLOT_CHANGED},
* {@link PlotEventType#DATA_CURVE_CHANGED},
* {@link PlotEventType#DATA_PLOT_CONNECTED}, or
* {@link PlotEventType#DATA_PLOT_DISCONNECTED}.
*/
public PlotEventType getType() {
return _type;
}
/** Returns the message object. */
public Object getMessage() {
return _message;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
/**
* Types of {@link PlotEvent PlotEvents}. Using the typesafe enumeration
* pattern.
*
* @author Franz-Josef Elmer
*/
public class PlotEventType {
/** Event type. */
public static final PlotEventType DATA_PLOT_CONNECTED = new PlotEventType(),
DATA_PLOT_DISCONNECTED = new PlotEventType(),
COODINATE_SYSTEM_CHANGED = new PlotEventType(),
DATA_CURVE_CHANGED = new PlotEventType(),
DATA_PLOT_CHANGED = new PlotEventType();
private PlotEventType() {}
}

View File

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

View File

@ -0,0 +1,75 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.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.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>position = null</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Definition of position.</td></tr>
* <tr><td><tt>origin = position</tt> or (0,0) if <tt>position</tt>
* undefined</td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Definition of origin.</td></tr>
* </table>
*/
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;
}
}

View File

@ -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
* <tt>ShapeAttributes</tt> 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.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>initialAttributes = </tt><i>default values of
* {@link ShapeAttributes}</i></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Initial values of shape attributes. Note, that default
* fill and line colors are undefined (they depend on the
* <tt>Renderer</tt>). In this case color increments have no effects.
* </td></tr>
* <tr><td><tt>fillColorHSBIncrement = 0 0 0</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Hue, saturation, and brightness increments of the fill color.
* </td></tr>
* <tr><td><tt>lineColorHSBIncrement = 0 0 0</tt></td>
* <td><tt>double[]</tt></td><td>no</td>
* <td>Hue, saturation, and brightness increments of the line color.
* </td></tr>
* <tr><td><tt>lineThicknessIncrement = 0</tt></td>
* <td><tt>double</tt></td><td>no</td>
* <td>Line thickness increment.</td></tr>
* </table>
*/
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 <tt>ShapeAttributesHint</tt> 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);
}
}

View File

@ -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 <tt>config</tt> contains:
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>initialHintForNextPoint = null</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Definition of an initial {@link Hint} for the first curve point.
* </td></tr>
* <tr><td><tt>lineAttributes = </tt>a {@link ShapeAttributes}
* instances with default values and line colors based on
* the formula <tt>Color.getHSBColor(curveIndex/6,1,0.8)</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Configuration parameters of an instances of
* {@link jcckit.graphic.GraphicAttributes} for the
* {@link Polygon Polygons} connecting curve points.</td></tr>
* <tr><td><tt>symbolFactory = null</tt></td>
* <td><tt>ConfigParameters</tt></td><td>no</td>
* <td>Configuration parameters defining an instances of
* {@link SymbolFactory} for the {@link Symbol Symbols}
* decorating curve points.</td></tr>
* <tr><td><tt>softClipping = true</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> no explicit clipping takes
* place but the symbol is not drawn if the corresponding curve
* point is outside the axis box.<br>
* If <tt>false</tt> the symbol is
* drawn in any case but it may be clipped by the axis box.
* Soft-clipping should be set to <tt>false</tt> if the
* symbols are not located around the curve point (like for bars).
* </td></tr>
* <tr><td><tt>withLine = true</tt></td>
* <td><tt>boolean</tt></td><td>no</td>
* <td>If <tt>true</tt> curve points are connected by a
* {@link jcckit.graphic.Polygon}.</td></tr>
* </table>
* @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 <tt>null</tt>.
* @param legend Legend. Will be used to calculate the legend symbol.
* @throws IllegalArgumentException if <tt>symbolFactory == null</tt> and
* <tt>withLine == false</tt>.
*
*/
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;
}
}

View File

@ -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.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>definitions = </tt><i>one empty <tt>ConfigParameters<tt>
* instance</i></td>
* <td><tt>String[]</tt></td><td>no</td>
* <td>Keys of subtrees defining {@link ConfigParameters}
* used by the {@link SimpleCurve#SimpleCurve constructor} of
* {@link SimpleCurve}.</td></tr>
* </table>
*/
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);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicAttributes;
import jcckit.graphic.GraphicalElement;
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
* <a href="AbstractSymbolFactory.html#AbstractSymbolFactory(jcckit.util.ConfigParameters)">
* constructor</a> 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);
}
}

View File

@ -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;
}
}

View File

@ -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.GraphPoint;
import jcckit.graphic.GraphicalElement;
/**
* 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 <tt>null</tt>.
* @param hintFromPreviousCurve Hint from the previous
* {@link Curve} or <tt>null</tt>.
*/
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);
}

View File

@ -0,0 +1,136 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.plot;
import 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.
* <p>
* 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.
* <p>
* A condition description has one of the following forms:
* <pre><tt><i>&lt;label&gt;</i></tt></pre>
* <pre><tt><i>&lt;number&gt;</i>=<i>&lt;label&gt;</i></tt></pre>
* <pre><tt><i>&lt;number1&gt;</i>:<i>&lt;number2&gt;</i>=<i>&lt;label&gt;</i></tt></pre>
* <p>
* The first type of condition is always fulfilled. It will return
* <tt><i>&lt;label&gt;</i></tt>. This is a kind of else condtion
* which is put at the end of the condition list.
* <p>
* 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 <tt><i>&lt;number&gt;</i>.
* <p>
* The third form maps an interval onto a label. The condition reads
* <p>
* <tt><i>&lt;number1&gt;</i></tt>&nbsp;&lt;=&nbsp;tic&nbsp;label&nbsp;&lt;&nbsp;<tt><i>&lt;number2&gt;</i></tt>
* <p>
* Examples:
* <pre><tt>
* 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
* </tt></pre>
*
* @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.
* <table border=1 cellpadding=5>
* <tr><th>Key &amp; Default Value</th><th>Type</th><th>Mandatory</th>
* <th>Description</th></tr>
* <tr><td><tt>map</tt></td>
* <td><tt>String</tt></td><td>yes</td>
* <td>Map description as explained above.</td></tr>
* </table>
*/
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;
}
}

View File

@ -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 <tt>java.awt.Graphics2D</tt> context.
* <p>
* The default color for lines and texts is determined by the current color of
* the <tt>Graphics2D</tt> context when a new instance of
* <tt>Graphics2DRenderer</tt> is created.
* <p>
* The default font is <tt>SansSerif-12</tt>.
*
* @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
* <tt>composite</tt> has a {@link ClippingShape}. In this case the Clip
* of the <tt>Graphics2D</tt> context becomes the clipping rectangle
* determined by the bounding box of the <tt>ClippingShape</tt>.
*/
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
* <tt>composite</tt> has a {@link ClippingShape}. In this case the Clip
* of the <tt>Graphics2D</tt> context will be cleared.
*/
public void finishRendering(GraphicalComposite composite) {
_graphics.setClip(null);
}
/** Paints the specified polygon into the <tt>Graphics2D</tt> 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 <tt>Graphics</tt>
* 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 <tt>Graphics</tt> 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 <tt>Graphics</tt> context.
* <p>
* If the font size is zero the default font size will be used.
* <p>
* 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 <tt>Graphics</tt> 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);
}
}

View File

@ -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.ClippingRectangle;
import jcckit.graphic.GraphPoint;
/**
* 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);
}
}

View File

@ -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 <tt>true</tt> if logarithmic x axis.
* @param yLogScale <tt>true</tt> 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));
}
}

View File

@ -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 <tt>point</tt> 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 <tt>point</tt> tranformed into data coordinates.
*/
public DataPoint transformToData(GraphPoint point);
}

View File

@ -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
* <tt>java.applet.Applet</tt>.
*
* @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);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.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 <tt>ConfigData</tt> object.
* <p>
* 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. <tt>null</tt> 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. <tt>null</tt> is not allowed.
* @return the associated value. Will be <tt>null</tt> if no value exists
* for <tt>key</tt>.
*/
public String get(String key);
/**
* Returns the <tt>ConfigData</tt> object associated with this key.
* @param key The relative key. <tt>null</tt> is not allowed.
* @return the associated value. Will never return <tt>null</tt>.
* Instead an empty <tt>ConfigData</tt> is returned.
*/
public ConfigData getNode(String key);
}

View File

@ -0,0 +1,320 @@
/*
* 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.ugraphic.color.ColorMapperIdentity;
import net.sourceforge.plantuml.ugraphic.color.HColorSet;
/**
* Read-only class for hierarchically organized key-value pairs.
* The key is always a string. The following value types are
* supported:
* <ul><li><tt>String</tt>
* <li><tt>boolean</tt>
* <li><tt>int</tt>
* <li><tt>double</tt>
* <li><tt>double[]</tt>
* <li><tt>Color</tt>
* <li><tt>ConfigParameters</tt>
* </ul>
* <p>
* 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 <tt>ConfigData</tt> object. */
public ConfigParameters(ConfigData configData) {
_configData = configData;
}
/**
* Returns the full key.
* @return the path concatenated with <tt>key</tt>.
* @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. <tt>null</tt> is not allowed.
* @return the corresponding value. Will always be not <tt>null</tt>.
* @throws IllegalArgumentException if no value exists for <tt>key</tt>.
* 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
* <tt>defaultValue</tt> if undefined.
* @param key The (relative) key. <tt>null</tt> is not allowed.
* @param defaultValue The default value. Can be <tt>null</tt>.
* @return the corresponding value or <tt>defaultValue</tt>.
*/
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. <tt>null</tt> is not allowed.
* @return <tt>true</tt> if the value is "true" otherwise <tt>false</tt>.
* @throws IllegalArgumentException if no value exists for <tt>key</tt>.
* 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. <tt>null</tt> is not allowed.
* @param defaultValue The default value. Can be <tt>null</tt>.
* @return <tt>true</tt> if the value is "true" otherwise <tt>false</tt>.
* @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
* <ul><li>a decimal number (starting with a non-zero digit),
* <li>a hexadecimal number (starting with <tt>0x</tt>), or
* <li>an octal number (starting with zero).
* </ul>
* @param key The (relative) key. <tt>null</tt> is not allowed.
* @return the integer value.
* @throws IllegalArgumentException if no value exists for <tt>key</tt>.
* 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
* <tt>defaultValue</tt> if no key-value pair exists for the specified key.
* The value can be either
* <ul><li>a decimal number (starting with a non-zero digit),
* <li>a hexadecimal number (starting with <tt>0x</tt>), or
* <li>an octal number (starting with zero).
* </ul>
* @param key The (relative) key. <tt>null</tt> is not allowed.
* @param defaultValue The default value. Can be <tt>null</tt>.
* @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. <tt>null</tt> is not allowed.
* @return the double value.
* @throws IllegalArgumentException if no value exists for <tt>key</tt>.
* 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
* <tt>defaultValue</tt> if no key-value pair exists for the specified key.
* @param key The (relative) key. <tt>null</tt> is not allowed.
* @param defaultValue The default value. Can be <tt>null</tt>.
* @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. <tt>null</tt> is not allowed.
* @return the array of double values.
* @throws IllegalArgumentException if no value exists for <tt>key</tt>.
* 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 <tt>defaultValue</tt> if no key-value pair exists for
* the specified key. The numbers are separated by whitespaces.
* @param key The (relative) key. <tt>null</tt> is not allowed.
* @param defaultValue The default value. Can be <tt>null</tt>.
* @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
* <ul><li>a decimal number (starting with a non-zero digit),
* <li>a hexadecimal number (starting with <tt>0x</tt>), or
* <li>an octal number (starting with zero).
* </ul>
* @param key The (relative) key. <tt>null</tt> 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
* <ul><li>a decimal number (starting with a non-zero digit),
* <li>a hexadecimal number (starting with <tt>0x</tt>), or
* <li>an octal number (starting with zero).
* </ul>
* @param key The (relative) key. <tt>null</tt> is not allowed.
* @param defaultValue The default value. Can be <tt>null</tt>.
* @return the color or <tt>null</tt> 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);
}
}
static private HColorSet colors = HColorSet.instance();
private Color decodeInternal(String value) {
if (colors.getColorIfValid(value)!=null) {
return new ColorMapperIdentity().getMappedColor(colors.getColorIfValid(value));
}
return Color.decode(value);
}
/**
* Returns the child node associated with the specified key.
* This method returns in any case a non-<tt>null</tt> result.
* @param key The (relative) key. <tt>null</tt> is not allowed.
* @return the corresponding child node which may be empty.
*/
public ConfigParameters getNode(String key) {
return new ConfigParameters(_configData.getNode(key));
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.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. <tt>null</tt> 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. <tt>null</tt> is not allowed.
* @return the associated value. Will be <tt>null</tt> if no value exists
* for <tt>key</tt>.
*/
public String get(String key) {
String value = _config.get(key, null);
return value == null ? _defaultConfig.get(key, null) : value;
}
/**
* Returns the <tt>ConfigData</tt> object associated with this key.
* @param key The relative key. <tt>null</tt> is not allowed.
* @return the associated value. Will never return <tt>null</tt>.
* Instead an empty <tt>ConfigData</tt> is returned.
*/
public ConfigData getNode(String key) {
return new ConfigParametersBasedConfigData(_config.getNode(key),
_defaultConfig.getNode(key));
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.util;
import java.lang.reflect.Constructor;
/**
* 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 <tt>className</tt>. */
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
* <tt>ConfigParameter</tt> is invoked with the argument
* <tt>configParameters</tt>. 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 <tt>className</tt> 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
* <tt>configParameters</tt> <tt>defaultClassName</tt> 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 <tt>IllegalArgumentException</tt> if key <tt>className</tt>
* is missing. Instead <tt>defaultObject</tt> 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);
}
}
}

View File

@ -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.InvocationTargetException;
/**
* 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.
* <p>
* If <tt>reason</tt> is an instance of <tt>InvocationTargetException</tt>
* it will be replaced by the wrapped <tt>Throwable</tt>.
* @param configParameters Configuration parameters from which the
* <tt>className</tt> will be extracted (if it exists, otherwise
* <tt>null</tt> 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: <tt>jcckit.util.FactoryException:
* <i>full key</i> = <i>class name</i>: <i>reason</i></tt>.
*/
public String toString() {
return getClass().getName() + ": " + _fullKey + " = " + _className
+ ": " + _reason;
}
}

View File

@ -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 <tt>ConfigData</tt> 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.
* <p>
* In a flat representation of hierachically organized key-value
* pairs all key-value pairs are stored in a single <tt>Hashtable</tt>.
* Its key is the <em>full key</em> of the configuration data (i.e. the key
* including its path).
* <p>
* Example (using the notation for a <tt>.properties</tt> file):
* <pre>
* title = example
* symbolAttributes/className = jcckit.graphic.BasicDrawingAttributes
* symbolAttributes/fillColor = 0xcaffee
* symbolAttributes/lineColor = 0xff0000
* </pre>
* The following table shows the result of some method calls at a
* <tt>FlatConfigData</tt> instance prepared with
* this example:
* <p>
* <center>
* <table border=1 cellspacing=1 cellpadding=5>
* <tr><th>Method call</th><th>Result</th></tr>
* <tr><td>get(&quot;title&quot;)</td><td>example</td></tr>
* <tr><td>getNode(&quot;symbolAttributes&quot;).get(&quot;fillColor&quot;)
* </td><td>0xcaffee</td></tr>
* </table>
* </center>
* <p>
* In addition <tt>FlatConfigData</tt> implements <b>inheritance</b>
* 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.
* <p>
* The implementation of this kind of inheritance in a flat hashtable
* is done by an additional key-value pair of the form
* <pre>
* <i>extending-node</i><b>/</b> = <i>extended-node</i><b>/</b>
* </pre>
* Example:
* <pre>
* A/a/priority = high
* A/a/alpha/hello = universe
* A/a/alpha/answer = 42
* <b>A/b/1/ = A/a/</b>
* A/b/1/alpha/hello = world
* A/b/1/alpha/question = 6 * 7
* </pre>
* The following table shows the result of various method calls
* applied at the node <tt>A/b/1/</tt> of a <tt>FlatConfigData</tt>
* instance prepared with this example:
* <p>
* <center>
* <table border=1 cellspacing=1 cellpadding=5>
* <tr><th>Method call</th><th>Result</th><th>Comment</th></tr>
* <tr><td>get(&quot;priority&quot;)</td><td>high</td><td>inherited</td></tr>
* <tr><td>getNode(&quot;alpha&quot;).get(&quot;hello&quot;)
* </td><td>world</td><td>overridden</td></tr>
* <tr><td>getNode(&quot;alpha&quot;).get(&quot;question&quot;)
* </td><td>6 * 7</td><td>added</td></tr>
* <tr><td>getNode(&quot;alpha&quot;).get(&quot;answer&quot;)
* </td><td>42</td><td>inherited</td></tr>
* </table>
* </center>
*
* @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. <tt>null</tt> is not allowed.
* @return the path concatenated with <tt>key</tt> or <tt>key</tt>
* 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. <tt>null</tt> is not allowed.
* @return the associated value. Will be <tt>null</tt> if no value exists
* for <tt>key</tt>.
*/
public String get(String key) {
return get(_path, key, 0);
}
/**
* Obtains a value in accordance with hierarchy (<tt>path</tt>) 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 <tt>ConfigData</tt> object associated with this key.
* @param key The relative key.
* @return the associated value. Will never return <tt>null</tt>.
* Instead an empty <tt>ConfigData</tt> 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. <tt>null</tt> is not allowed.
* @return the value or <tt>null</tt> if not found.
*/
protected abstract String getValue(String fullKey);
/**
* Returns the <tt>FlatConfigData</tt> object for the specified full path.
* In general <tt>path</tt> 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);
}

208
src/jcckit/util/Format.java Normal file
View File

@ -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 <tt>printf</tt>-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 <tt>config</tt> containing
* the format string.
* @return <tt>null</tt> 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:
* <table border=0 cellpadding=5>
* <tr><td><tt>d</tt></td>
* <td>decimal integer</td></tr>
* <tr><td><tt>o</tt></td>
* <td>octal integer</td></tr>
* <tr><td><tt>x</tt></td>
* <td>hex integer</td></tr>
* <tr><td><tt>f</tt></td>
* <td>floating point number with a fixed decimal point</td></tr>
* <tr><td><tt>e,&nbsp;E</tt></td>
* <td>floating point number in logarithmic format</td></tr>
* <tr><td><tt>g,&nbsp;G</tt></td>
* <td>floating point number rendered either in fixed-decimal
* format of logarithmic format depending on the size of
* the mantissa.</td></tr>
* </table>
* The characters between '%' and the decriptor are optional.
* They can be grouped into
* <ul><li>modifier<br>
* it is
* <ul><li>'-' if the formated result should be flushed left
* <li>'+' if the sign should be always appear
* <li>'0' if the leading space should be filled with zeros
* </ul>
* <li>width<br>
* a decimal number given the minimum number of characters
* of the result
* <li>precision
* </ul>
* 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);
}
}

View File

@ -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 <tt>x^n</tt>.
*/
private static final double power(double x, int n) {
return n < 0 ? 1.0 / power2(x, -n) : power2(x, n);
}
/** Calculate <tt>x^n</tt> recursively assuming <tt>n > 0</tt>. */
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));
}
}

View File

@ -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 <tt>vector</tt> denotes the x/y value.
* If <tt>vector</tt> is <tt>null</tt> 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;
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.util;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
/**
* Implementation of {@link FlatConfigData} based on
* <tt>java.util.Properties</tt>.
*
* @author Franz-Josef Elmer
*/
public class PropertiesBasedConfigData extends FlatConfigData {
private final Properties _properties;
/**
* Creates an instance from the specified <tt>.properties</tt> file.
* @param fileName File name of the <tt>.properties</tt> file relative
* to the working directory or absolute.
* @throws IOException if the <tt>.properties</tt> 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 <tt>java.util.properties</tt> object.
* @param fullKey The full key including path. <tt>null</tt> is not allowed.
* @return the value or <tt>null</tt> if not found.
*/
protected String getValue(String fullKey) {
return _properties.getProperty(fullKey);
}
/**
* Returns a new instance of <tt>PropertiesBasedConfigData</tt>
* for the specified full path. The wrapped <tt>java.util.Properties</tt>
* 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);
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.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
* <tt>ticValue</tt> may be mapped onto a non-numerical one.
*/
public String form(double ticValue);
}

47
src/jcckit/util/Util.java Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.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
* <tt>logScale</tt> is true.
* @return <tt>x</tt> if <tt>logScale == false</tt>.
*/
public static double log(double x, boolean logScale) {
return logScale ? Math.log(x) : x;
}
/**
* Returns the exponential function of the specified number if
* <tt>logScale</tt> is true.
* @return <tt>x</tt> if <tt>logScale == false</tt>.
*/
public static double exp(double x, boolean logScale) {
return logScale ? Math.exp(x) : x;
}
}

View File

@ -44,6 +44,11 @@ public class LineBreakStrategy {
public LineBreakStrategy(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
public boolean isAuto() {
return "auto".equalsIgnoreCase(value);

View File

@ -68,6 +68,7 @@ import net.sourceforge.plantuml.error.PSystemErrorUtils;
import net.sourceforge.plantuml.flowdiagram.FlowDiagramFactory;
import net.sourceforge.plantuml.font.PSystemListFontsFactory;
import net.sourceforge.plantuml.help.HelpFactory;
import net.sourceforge.plantuml.jcckit.PSystemJcckitFactory;
import net.sourceforge.plantuml.math.PSystemLatexFactory;
import net.sourceforge.plantuml.math.PSystemMathFactory;
import net.sourceforge.plantuml.mindmap.MindMapDiagramFactory;
@ -79,8 +80,8 @@ import net.sourceforge.plantuml.project.GanttDiagramFactory;
import net.sourceforge.plantuml.salt.PSystemSaltFactory;
import net.sourceforge.plantuml.sequencediagram.SequenceDiagramFactory;
import net.sourceforge.plantuml.sprite.ListSpriteDiagramFactory;
import net.sourceforge.plantuml.sprite.StdlibDiagramFactory;
import net.sourceforge.plantuml.sprite.PSystemListInternalSpritesFactory;
import net.sourceforge.plantuml.sprite.StdlibDiagramFactory;
import net.sourceforge.plantuml.statediagram.StateDiagramFactory;
import net.sourceforge.plantuml.stats.StatsUtilsIncrement;
import net.sourceforge.plantuml.sudoku.PSystemSudokuFactory;
@ -109,9 +110,10 @@ public class PSystemBuilder {
// Dead code : should not append
Log.error("Preprocessor Error: " + s.getPreprocessorError());
final ErrorUml err = new ErrorUml(ErrorUmlType.SYNTAX_ERROR, s.getPreprocessorError(), /* cpt */
s.getLocation());
// return PSystemErrorUtils.buildV1(umlSource, err, Collections.<String> emptyList());
return PSystemErrorUtils.buildV2(umlSource, err, Collections.<String> emptyList(), strings2);
s.getLocation());
// return PSystemErrorUtils.buildV1(umlSource, err, Collections.<String>
// emptyList());
return PSystemErrorUtils.buildV2(umlSource, err, Collections.<String>emptyList(), strings2);
}
}
@ -173,8 +175,8 @@ public class PSystemBuilder {
factories.add(new PSystemDitaaFactory(DiagramType.DITAA));
factories.add(new PSystemDitaaFactory(DiagramType.UML));
if (License.getCurrent() == License.GPL || License.getCurrent() == License.GPLV2) {
// factories.add(new PSystemJcckitFactory(DiagramType.JCCKIT));
// factories.add(new PSystemJcckitFactory(DiagramType.UML));
factories.add(new PSystemJcckitFactory(DiagramType.JCCKIT));
factories.add(new PSystemJcckitFactory(DiagramType.UML));
// factories.add(new PSystemLogoFactory());
factories.add(new PSystemSudokuFactory());
}

View File

@ -62,7 +62,6 @@ import net.sourceforge.plantuml.code.TranscoderUtil;
import net.sourceforge.plantuml.command.UmlDiagramFactory;
import net.sourceforge.plantuml.descdiagram.DescriptionDiagramFactory;
import net.sourceforge.plantuml.ftp.FtpServer;
import net.sourceforge.plantuml.objectdiagram.ObjectDiagramFactory;
import net.sourceforge.plantuml.png.MetadataTag;
import net.sourceforge.plantuml.preproc.Stdlib;
import net.sourceforge.plantuml.sequencediagram.SequenceDiagramFactory;
@ -342,7 +341,7 @@ public class Run {
printPattern(new DescriptionDiagramFactory(null));
// printPattern(new ComponentDiagramFactory());
printPattern(new StateDiagramFactory(null));
printPattern(new ObjectDiagramFactory(null));
// printPattern(new ObjectDiagramFactory(null));
}
private static void printPattern(UmlDiagramFactory factory) {

View File

@ -49,6 +49,8 @@ import net.sourceforge.plantuml.UmlDiagram;
import net.sourceforge.plantuml.UmlDiagramType;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.activitydiagram3.ftile.BoxStyle;
import net.sourceforge.plantuml.activitydiagram3.ftile.ISwimlanesA;
import net.sourceforge.plantuml.activitydiagram3.ftile.SwimlanesAAA;
import net.sourceforge.plantuml.activitydiagram3.ftile.SwimlanesC;
import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.core.DiagramDescription;
@ -64,7 +66,7 @@ import net.sourceforge.plantuml.sequencediagram.NoteType;
import net.sourceforge.plantuml.ugraphic.ImageBuilder;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.comp.CompressionMode;
import net.sourceforge.plantuml.ugraphic.comp.TextBlockCompressedOnXorY;
import net.sourceforge.plantuml.ugraphic.comp.CompressionXorYBuilder;
public class ActivityDiagram3 extends UmlDiagram {
@ -74,7 +76,36 @@ public class ActivityDiagram3 extends UmlDiagram {
private SwimlaneStrategy swimlaneStrategy;
private final SwimlanesC swinlanes = new SwimlanesC(getSkinParam(), getPragma());
private final ISwimlanesA swinlanes = new SwimlanesAAA(getSkinParam(), getPragma());
// private final ISwimlanesA swinlanes = new SwimlanesC(getSkinParam(),
// getPragma());
private ImageData exportDiagramInternalAAA(OutputStream os, int index, FileFormatOption fileFormatOption)
throws IOException {
// BUG42
// COMPRESSION
swinlanes.computeSize(fileFormatOption.getDefaultStringBounder());
TextBlock result = swinlanes;
result = CompressionXorYBuilder.build(CompressionMode.ON_X, result, fileFormatOption.getDefaultStringBounder());
result = CompressionXorYBuilder.build(CompressionMode.ON_Y, result, fileFormatOption.getDefaultStringBounder());
result = new TextBlockRecentred(result);
final ISkinParam skinParam = getSkinParam();
result = new AnnotatedWorker(this, skinParam, fileFormatOption.getDefaultStringBounder()).addAdd(result);
final Dimension2D dim = result.getMinMax(fileFormatOption.getDefaultStringBounder()).getDimension();
final double margin = 10;
final double dpiFactor = getDpiFactor(fileFormatOption, Dimension2DDouble.delta(dim, 2 * margin, 0));
final ImageBuilder imageBuilder = new ImageBuilder(getSkinParam(), dpiFactor,
fileFormatOption.isWithMetadata() ? getMetadata() : null, getWarningOrError(), margin, margin,
getAnimation());
imageBuilder.setUDrawable(result);
return imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed(), os);
}
public ActivityDiagram3(ISkinSimple skinParam) {
super(skinParam);
@ -123,7 +154,8 @@ public class ActivityDiagram3 extends UmlDiagram {
}
public void addSpot(String spot, HColor color) {
final InstructionSpot ins = new InstructionSpot(spot, color, nextLinkRenderer(), swinlanes.getCurrentSwimlane());
final InstructionSpot ins = new InstructionSpot(spot, color, nextLinkRenderer(),
swinlanes.getCurrentSwimlane());
current().add(ins);
setNextLinkRendererInternal(LinkRendering.none());
manageSwimlaneStrategy();
@ -201,17 +233,21 @@ public class ActivityDiagram3 extends UmlDiagram {
@Override
protected ImageData exportDiagramInternal(OutputStream os, int index, FileFormatOption fileFormatOption)
throws IOException {
if (swinlanes instanceof SwimlanesC == false || swinlanes instanceof SwimlanesAAA) {
return exportDiagramInternalAAA(os, index, fileFormatOption);
}
// BUG42
// COMPRESSION
swinlanes.computeSize(fileFormatOption.getDefaultStringBounder());
TextBlock result = swinlanes;
// result = new TextBlockCompressedOnY(CompressionMode.ON_Y, result);
result = new TextBlockCompressedOnXorY(CompressionMode.ON_X, result);
result = new TextBlockCompressedOnXorY(CompressionMode.ON_Y, result);
result = CompressionXorYBuilder.build(CompressionMode.ON_X, result, fileFormatOption.getDefaultStringBounder());
result = CompressionXorYBuilder.build(CompressionMode.ON_Y, result, fileFormatOption.getDefaultStringBounder());
result = new TextBlockRecentred(result);
final ISkinParam skinParam = getSkinParam();
result = new AnnotatedWorker(this, skinParam, fileFormatOption.getDefaultStringBounder()).addAdd(result);
// final Dimension2D dim = TextBlockUtils.getMinMax(result, fileFormatOption.getDefaultStringBounder())
// .getDimension();
final Dimension2D dim = result.getMinMax(fileFormatOption.getDefaultStringBounder()).getDimension();
final double margin = 10;
final double dpiFactor = getDpiFactor(fileFormatOption, Dimension2DDouble.delta(dim, 2 * margin, 0));
@ -329,8 +365,8 @@ public class ActivityDiagram3 extends UmlDiagram {
public void startIf(Display test, Display whenThen, HColor color, Url url) {
manageSwimlaneStrategy();
final InstructionIf instructionIf = new InstructionIf(swinlanes.getCurrentSwimlane(), current(), test,
whenThen, nextLinkRenderer(), color, getSkinParam(), url);
final InstructionIf instructionIf = new InstructionIf(swinlanes.getCurrentSwimlane(), current(), test, whenThen,
nextLinkRenderer(), color, getSkinParam(), url);
current().add(instructionIf);
setNextLinkRendererInternal(LinkRendering.none());
setCurrent(instructionIf);
@ -396,12 +432,13 @@ public class ActivityDiagram3 extends UmlDiagram {
}
public CommandExecutionResult backwardWhile(Display label) {
public CommandExecutionResult backwardWhile(Display label, BoxStyle boxStyle) {
manageSwimlaneStrategy();
if (current() instanceof InstructionRepeat) {
final InstructionRepeat instructionRepeat = (InstructionRepeat) current();
// final LinkRendering back = new LinkRendering(linkColor).withDisplay(linkLabel);
instructionRepeat.setBackward(label, swinlanes.getCurrentSwimlane());
// final LinkRendering back = new
// LinkRendering(linkColor).withDisplay(linkLabel);
instructionRepeat.setBackward(label, swinlanes.getCurrentSwimlane(), boxStyle);
// setCurrent(instructionRepeat.getParent());
// this.setNextLinkRendererInternal(LinkRendering.none());
return CommandExecutionResult.ok();
@ -435,8 +472,8 @@ public class ActivityDiagram3 extends UmlDiagram {
return CommandExecutionResult.ok();
}
public void startGroup(Display name, HColor backColor, HColor titleColor, HColor borderColor,
USymbol type, double roundCorner) {
public void startGroup(Display name, HColor backColor, HColor titleColor, HColor borderColor, USymbol type,
double roundCorner) {
manageSwimlaneStrategy();
final InstructionGroup instructionGroup = new InstructionGroup(current(), name, backColor, titleColor,
swinlanes.getCurrentSwimlane(), borderColor, nextLinkRenderer(), type, roundCorner);

View File

@ -55,6 +55,7 @@ public class InstructionRepeat implements Instruction {
private final LinkRendering nextLinkRenderer;
private final Swimlane swimlane;
private Swimlane swimlaneOut;
private BoxStyle boxStyle;
// private final HtmlColor color;
private boolean killed = false;
private final BoxStyle boxStyleIn;
@ -93,9 +94,10 @@ public class InstructionRepeat implements Instruction {
return false;
}
public void setBackward(Display label, Swimlane swimlaneOut) {
public void setBackward(Display label, Swimlane swimlaneOut, BoxStyle boxStyle) {
this.backward = label;
this.swimlaneOut = swimlaneOut;
this.boxStyle = boxStyle;
}
public void add(Instruction ins) {
@ -104,7 +106,7 @@ public class InstructionRepeat implements Instruction {
public Ftile createFtile(FtileFactory factory) {
final Ftile back = Display.isNull(backward) ? null
: factory.activity(backward, swimlane, BoxStyle.PLAIN, Colors.empty());
: factory.activity(backward, swimlane, boxStyle, Colors.empty());
final Ftile decorateOut = factory.decorateOut(repeatList.createFtile(factory), endRepeatLinkRendering);
final Ftile result = factory.repeat(boxStyleIn, swimlane, swimlaneOut, startLabel, decorateOut, test, yes, out,
colors, backRepeatLinkRendering, back, isLastOfTheParent());

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.activitydiagram3.command;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.activitydiagram3.ActivityDiagram3;
import net.sourceforge.plantuml.activitydiagram3.ftile.BoxStyle;
import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.command.SingleLineCommand2;
import net.sourceforge.plantuml.command.regex.IRegex;
@ -57,14 +58,22 @@ public class CommandBackward3 extends SingleLineCommand2<ActivityDiagram3> {
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf(":"), //
new RegexLeaf("LABEL", "(.*)"), //
new RegexLeaf(";"), //
new RegexLeaf("STYLE", CommandActivity3.ENDING_GROUP), //
RegexLeaf.end());
}
@Override
protected CommandExecutionResult executeArg(ActivityDiagram3 diagram, LineLocation location, RegexResult arg) {
final BoxStyle boxStyle;
final String styleString = arg.get("STYLE", 0);
if (styleString == null) {
boxStyle = BoxStyle.PLAIN;
} else {
boxStyle = BoxStyle.fromChar(styleString.charAt(0));
}
final Display label = Display.getWithNewlines(arg.get("LABEL", 0));
return diagram.backwardWhile(label);
return diagram.backwardWhile(label, boxStyle);
}
}

View File

@ -0,0 +1,59 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* 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 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.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.activitydiagram3.ftile;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.ugraphic.UShape;
public class CenteredText implements UShape {
private final TextBlock text;
private final double totalWidth;
public CenteredText(TextBlock text, double totalWidth) {
this.text = text;
this.totalWidth = totalWidth;
}
public TextBlock getText() {
return text;
}
public double getTotalWidth() {
return totalWidth;
}
}

View File

@ -118,7 +118,7 @@ public class FtileFactoryDelegator implements FtileFactory {
} else {
fontConfiguration = new FontConfiguration(skinParam(), FontParam.ARROW, null);
}
return display.create(fontConfiguration, HorizontalAlignment.LEFT, skinParam(), CreoleMode.SIMPLE_LINE);
return display.create7(fontConfiguration, HorizontalAlignment.LEFT, skinParam(), CreoleMode.SIMPLE_LINE);
}
protected Display getInLinkRenderingDisplay(Ftile tile) {

View File

@ -0,0 +1,62 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* 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 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.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.activitydiagram3.ftile;
import net.sourceforge.plantuml.activitydiagram3.Instruction;
import net.sourceforge.plantuml.activitydiagram3.LinkRendering;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.style.Styleable;
import net.sourceforge.plantuml.ugraphic.color.HColor;
public interface ISwimlanesA extends TextBlock, Styleable {
public void computeSize(StringBounder stringBounder);
public void swimlane(String name, HColor color, Display label);
public void setCurrent(Instruction ins);
public Instruction getCurrent();
public LinkRendering nextLinkRenderer();
public Swimlane getCurrentSwimlane();
public void setNextLinkRenderer(LinkRendering link);
}

View File

@ -0,0 +1,123 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* 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 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.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.activitydiagram3.ftile;
import java.awt.geom.Dimension2D;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.SkinParam;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.style.SName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleSignature;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
import net.sourceforge.plantuml.ugraphic.UEmpty;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UStroke;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
public class LaneDivider extends AbstractTextBlock {
private final ISkinParam skinParam;;
private final double x1;
private final double x2;
private final double height;
private Style style;
public LaneDivider(ISkinParam skinParam, double x1, double x2, double height) {
this.skinParam = skinParam;
this.x1 = x1;
this.x2 = x2;
this.height = height;
}
public StyleSignature getDefaultStyleDefinition() {
return StyleSignature.of(SName.root, SName.element, SName.classDiagram, SName.swimlane);
}
private Style getStyle() {
if (style == null) {
this.style = getDefaultStyleDefinition().getMergedStyle(skinParam.getCurrentStyleBuilder());
}
return style;
}
public Dimension2D calculateDimension(StringBounder stringBounder) {
return new Dimension2DDouble(x1 + x2, height);
}
public void drawU(UGraphic ug) {
// final UShape back = new URectangle(x1 + x2, height).ignoreForCompressionOnY();
// ug.apply(new UChangeColor(HColorUtils.BLUE)).draw(back);
final UShape back = new UEmpty(x1 + x2, 1);
ug.draw(back);
HColor color = skinParam.getHtmlColor(ColorParam.swimlaneBorder, null, false);
if (color == null) {
color = ColorParam.swimlaneBorder.getDefaultValue();
}
UStroke thickness = Rose.getStroke(skinParam, LineParam.swimlaneBorder, 2);
if (SkinParam.USE_STYLES()) {
color = getStyle().value(PName.LineColor).asColor(skinParam.getIHtmlColorSet());
thickness = getStyle().getStroke();
}
ug.apply(UTranslate.dx(x1)).apply(thickness).apply(new UChangeColor(color)).draw(ULine.vline(height));
}
public double getWidth() {
return x1 + x2;
}
public final double getX1() {
return x1;
}
public final double getX2() {
return x2;
}
}

View File

@ -54,7 +54,7 @@ import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UPolygon;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.comp.CompressionTransform;
import net.sourceforge.plantuml.ugraphic.comp.PiecewiseAffineTransform;
public class Snake implements UShape {
@ -72,7 +72,7 @@ public class Snake implements UShape {
this.worm.setIgnoreForCompression();
}
public Snake transformX(CompressionTransform compressionTransform) {
public Snake transformX(PiecewiseAffineTransform compressionTransform) {
final Snake result = new Snake(startDecoration, horizontalAlignment, color, endDecoration);
result.textBlock = this.textBlock;
result.mergeable = this.mergeable;

View File

@ -79,8 +79,11 @@ public class Swimlane implements SpecificBackcolorable {
return translate;
}
public final void setTranslateAndWidth(UTranslate translate, double actualWidth) {
public final void setTranslate(UTranslate translate) {
this.translate = translate;
}
public final void setWidth(double actualWidth) {
this.actualWidth = actualWidth;
}

View File

@ -77,10 +77,12 @@ import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.comp.CompressionMode;
import net.sourceforge.plantuml.ugraphic.comp.SlotFinder;
import net.sourceforge.plantuml.ugraphic.comp.SlotSet;
import net.sourceforge.plantuml.utils.MathUtils;
public class SwimlanesA extends AbstractTextBlock implements TextBlock, Styleable {
public class SwimlanesA extends AbstractTextBlock implements ISwimlanesA, TextBlock, Styleable {
protected final ISkinParam skinParam;;
private final Pragma pragma;
@ -179,28 +181,33 @@ public class SwimlanesA extends AbstractTextBlock implements TextBlock, Styleabl
}
static protected final double separationMargin = 10;
protected double separationMargin() {
return 10;
}
private TextBlock full;
// private TextBlock full;
public void drawU(UGraphic ug) {
if (full == null) {
final FtileFactory factory = getFtileFactory(ug.getStringBounder());
full = root.createFtile(factory);
if (swimlanes.size() <= 1) {
// BUG42
full = new TextBlockInterceptorUDrawable(full);
}
public final void computeSize(StringBounder stringBounder) {
final SlotFinder ug = new SlotFinder(CompressionMode.ON_Y, stringBounder);
if (swimlanes.size() > 1) {
TextBlock full = root.createFtile(getFtileFactory(stringBounder));
computeSizeInternal(ug, full);
}
}
public final void drawU(UGraphic ug) {
TextBlock full = root.createFtile(getFtileFactory(ug.getStringBounder()));
ug = new UGraphicForSnake(ug);
if (swimlanes.size() <= 1) {
if (swimlanes.size() > 1) {
drawWhenSwimlanes(ug, full);
} else {
// BUG42
full = new TextBlockInterceptorUDrawable(full);
full.drawU(ug);
ug.flushUg();
return;
}
drawWhenSwimlanes(ug, full);
}
static private void printDebug(UGraphic ug, SlotSet slot, HColor col, TextBlock full) {
@ -213,30 +220,32 @@ public class SwimlanesA extends AbstractTextBlock implements TextBlock, Styleabl
final StringBounder stringBounder = ug.getStringBounder();
final Dimension2D dimensionFull = full.calculateDimension(stringBounder);
computeSize(ug, full);
final UTranslate titleHeightTranslate = getTitleHeightTranslate(stringBounder);
double x2 = 0;
for (Swimlane swimlane : swimlanes) {
final HColor back = swimlane.getColors(skinParam).getColor(ColorType.BACK);
if (back != null) {
final UGraphic background = ug.apply(new UChangeBackColor(back)).apply(new UChangeColor(back))
.apply(UTranslate.dx(x2));
final URectangle rectangle = new URectangle(swimlane.getActualWidth(), dimensionFull.getHeight()
+ titleHeightTranslate.getDy()).ignoreForCompression();
background.draw(rectangle);
UGraphic background = ug.apply(new UChangeBackColor(back)).apply(new UChangeColor(back));
background = background.apply(UTranslate.dx(x2));
drawBackColor(background, swimlane, dimensionFull);
}
full.drawU(new UGraphicInterceptorOneSwimlane(ug, swimlane).apply(swimlane.getTranslate()).apply(
titleHeightTranslate));
full.drawU(new UGraphicInterceptorOneSwimlane(ug, swimlane).apply(swimlane.getTranslate())
.apply(getTitleHeightTranslate(stringBounder)));
x2 += swimlane.getActualWidth();
}
final Cross cross = new Cross(ug.apply(titleHeightTranslate));
final Cross cross = new Cross(ug.apply(getTitleHeightTranslate(stringBounder)));
full.drawU(cross);
cross.flushUg();
}
protected void drawBackColor(UGraphic ug, Swimlane swimlane, Dimension2D dimensionFull) {
final StringBounder stringBounder = ug.getStringBounder();
final double height = dimensionFull.getHeight() + getTitleHeightTranslate(stringBounder).getDy();
final URectangle rectangle = new URectangle(swimlane.getActualWidth(), height).ignoreForCompressionOnX().ignoreForCompressionOnY();
ug.draw(rectangle);
}
protected UTranslate getTitleHeightTranslate(final StringBounder stringBounder) {
return new UTranslate();
}
@ -245,8 +254,8 @@ public class SwimlanesA extends AbstractTextBlock implements TextBlock, Styleabl
final StringBounder stringBounder = ug.getStringBounder();
for (Swimlane swimlane : swimlanes) {
final LimitFinder limitFinder = new LimitFinder(stringBounder, false);
final UGraphicInterceptorOneSwimlane interceptor = new UGraphicInterceptorOneSwimlane(new UGraphicForSnake(
limitFinder), swimlane);
final UGraphicInterceptorOneSwimlane interceptor = new UGraphicInterceptorOneSwimlane(
new UGraphicForSnake(limitFinder), swimlane);
full.drawU(interceptor);
interceptor.flushUg();
final MinMax minMax = limitFinder.getMinMax();
@ -254,7 +263,7 @@ public class SwimlanesA extends AbstractTextBlock implements TextBlock, Styleabl
}
}
private void computeSize(UGraphic ug, TextBlock full) {
private void computeSizeInternal(UGraphic ug, TextBlock full) {
computeDrawingWidths(ug, full);
double x1 = 0;
@ -269,9 +278,10 @@ public class SwimlanesA extends AbstractTextBlock implements TextBlock, Styleabl
for (Swimlane swimlane : swimlanes) {
final double swimlaneActualWidth = swimlaneActualWidth(ug.getStringBounder(), swimlaneWidth, swimlane);
final UTranslate translate = UTranslate.dx(x1 - swimlane.getMinMax().getMinX() + separationMargin
+ (swimlaneActualWidth - rawDrawingWidth(swimlane)) / 2.0);
swimlane.setTranslateAndWidth(translate, swimlaneActualWidth);
final UTranslate translate = UTranslate.dx(x1 - swimlane.getMinMax().getMinX() + separationMargin()
+ (swimlaneActualWidth - rawDrawingWidth(swimlane)) / 2.0);
swimlane.setTranslate(translate);
swimlane.setWidth(swimlaneActualWidth);
x1 += swimlaneActualWidth;
}
@ -282,7 +292,7 @@ public class SwimlanesA extends AbstractTextBlock implements TextBlock, Styleabl
}
private double rawDrawingWidth(Swimlane swimlane) {
return swimlane.getMinMax().getWidth() + 2 * separationMargin;
return swimlane.getMinMax().getWidth() + 2 * separationMargin();
}
public Dimension2D calculateDimension(StringBounder stringBounder) {

View File

@ -0,0 +1,436 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* 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 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.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.activitydiagram3.ftile;
import java.awt.geom.Dimension2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineBreakStrategy;
import net.sourceforge.plantuml.Pragma;
import net.sourceforge.plantuml.SkinParam;
import net.sourceforge.plantuml.activitydiagram3.Instruction;
import net.sourceforge.plantuml.activitydiagram3.InstructionList;
import net.sourceforge.plantuml.activitydiagram3.LinkRendering;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorAddNote;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorAddUrl;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorAssembly;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorCreateGroup;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorCreateParallel;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorIf;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorRepeat;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorSwitch;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorWhile;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.UGraphicInterceptorOneSwimlane;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.VCompactFactory;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.graphic.UGraphicDelegator;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.style.SName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleSignature;
import net.sourceforge.plantuml.style.Styleable;
import net.sourceforge.plantuml.svek.UGraphicForSnake;
import net.sourceforge.plantuml.ugraphic.LimitFinder;
import net.sourceforge.plantuml.ugraphic.MinMax;
import net.sourceforge.plantuml.ugraphic.UChange;
import net.sourceforge.plantuml.ugraphic.UChangeBackColor;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.comp.CompressionMode;
import net.sourceforge.plantuml.ugraphic.comp.SlotFinder;
import net.sourceforge.plantuml.utils.MathUtils;
public class SwimlanesAAA extends AbstractTextBlock implements ISwimlanesA, TextBlock, Styleable {
private final ISkinParam skinParam;;
private final Pragma pragma;
private final List<Swimlane> swimlanesRaw = new ArrayList<Swimlane>();
private final List<Swimlane> swimlanesSpecial = new ArrayList<Swimlane>();
private final List<LaneDivider> dividers = new ArrayList<LaneDivider>();
private Swimlane currentSwimlane = null;
private final Instruction root = new InstructionList();
private Instruction currentInstruction = root;
private LinkRendering nextLinkRenderer = LinkRendering.none();
private Style style;
private List<Swimlane> swimlanes() {
return Collections.unmodifiableList(swimlanesRaw);
}
private List<Swimlane> swimlanesSpecial() {
if (swimlanesSpecial.size() == 0) {
swimlanesSpecial.addAll(swimlanesRaw);
final Swimlane last = new Swimlane("");
last.setMinMax(MinMax.getEmpty(true));
swimlanesSpecial.add(last);
}
return Collections.unmodifiableList(swimlanesSpecial);
}
public StyleSignature getDefaultStyleDefinition() {
return StyleSignature.of(SName.root, SName.element, SName.classDiagram, SName.swimlane);
}
public SwimlanesAAA(ISkinParam skinParam, Pragma pragma) {
this.skinParam = skinParam;
this.pragma = pragma;
}
protected Style getStyle() {
if (style == null) {
this.style = getDefaultStyleDefinition().getMergedStyle(skinParam.getCurrentStyleBuilder());
}
return style;
}
private FtileFactory getFtileFactory(StringBounder stringBounder) {
FtileFactory factory = new VCompactFactory(skinParam, stringBounder);
factory = new FtileFactoryDelegatorAddUrl(factory);
factory = new FtileFactoryDelegatorAssembly(factory);
factory = new FtileFactoryDelegatorIf(factory, pragma);
factory = new FtileFactoryDelegatorSwitch(factory);
factory = new FtileFactoryDelegatorWhile(factory);
factory = new FtileFactoryDelegatorRepeat(factory);
factory = new FtileFactoryDelegatorCreateParallel(factory);
// factory = new FtileFactoryDelegatorCreateParallelAddingMargin(new
// FtileFactoryDelegatorCreateParallel1(factory));
factory = new FtileFactoryDelegatorAddNote(factory);
factory = new FtileFactoryDelegatorCreateGroup(factory);
return factory;
}
public void swimlane(String name, HColor color, Display label) {
currentSwimlane = getOrCreate(name);
if (color != null) {
currentSwimlane.setSpecificColorTOBEREMOVED(ColorType.BACK, color);
}
if (Display.isNull(label) == false) {
currentSwimlane.setDisplay(label);
}
}
private Swimlane getOrCreate(String name) {
for (Swimlane s : swimlanes()) {
if (s.getName().equals(name)) {
return s;
}
}
final Swimlane result = new Swimlane(name);
swimlanesRaw.add(result);
return result;
}
class Cross extends UGraphicDelegator {
private Cross(UGraphic ug) {
super(ug);
}
@Override
public void draw(UShape shape) {
if (shape instanceof Ftile) {
final Ftile tile = (Ftile) shape;
tile.drawU(this);
} else if (shape instanceof Connection) {
final Connection connection = (Connection) shape;
final Ftile tile1 = connection.getFtile1();
final Ftile tile2 = connection.getFtile2();
if (tile1 == null || tile2 == null) {
return;
}
if (tile1.getSwimlaneOut() != tile2.getSwimlaneIn()) {
final ConnectionCross connectionCross = new ConnectionCross(connection);
connectionCross.drawU(getUg());
}
}
}
public UGraphic apply(UChange change) {
return new Cross(getUg().apply(change));
}
}
public final void computeSize(StringBounder stringBounder) {
final SlotFinder ug = new SlotFinder(CompressionMode.ON_Y, stringBounder);
if (swimlanes().size() > 1) {
TextBlock full = root.createFtile(getFtileFactory(stringBounder));
computeSizeInternal(ug, full);
}
}
public final void drawU(UGraphic ug) {
TextBlock full = root.createFtile(getFtileFactory(ug.getStringBounder()));
ug = new UGraphicForSnake(ug);
if (swimlanes().size() > 1) {
drawWhenSwimlanes(ug, full);
} else {
// BUG42
full = new TextBlockInterceptorUDrawable(full);
full.drawU(ug);
ug.flushUg();
}
}
private TextBlock getTitle(Swimlane swimlane) {
final HorizontalAlignment horizontalAlignment = HorizontalAlignment.LEFT;
FontConfiguration fontConfiguration = new FontConfiguration(skinParam, FontParam.SWIMLANE_TITLE, null);
if (SkinParam.USE_STYLES()) {
fontConfiguration = getStyle().getFontConfiguration(skinParam.getIHtmlColorSet());
}
LineBreakStrategy wrap = getWrap();
if (wrap.isAuto()) {
wrap = new LineBreakStrategy("" + ((int) swimlane.getActualWidth()));
}
return swimlane.getDisplay().create9(fontConfiguration, horizontalAlignment, skinParam, wrap);
}
private LineBreakStrategy getWrap() {
LineBreakStrategy wrap = skinParam.swimlaneWrapTitleWidth();
if (wrap == LineBreakStrategy.NONE) {
wrap = skinParam.wrapWidth();
}
return wrap;
}
private UTranslate getTitleHeightTranslate(final StringBounder stringBounder) {
double titlesHeight = getTitlesHeight(stringBounder);
return UTranslate.dy(titlesHeight > 0 ? titlesHeight + 5 : 0);
}
private double getTitlesHeight(StringBounder stringBounder) {
double titlesHeight = 0;
for (Swimlane swimlane : swimlanes()) {
final TextBlock swTitle = getTitle(swimlane);
titlesHeight = Math.max(titlesHeight, swTitle.calculateDimension(stringBounder).getHeight());
}
return titlesHeight;
}
private void drawWhenSwimlanes(UGraphic ug, TextBlock full) {
final StringBounder stringBounder = ug.getStringBounder();
final UTranslate titleHeightTranslate = getTitleHeightTranslate(stringBounder);
drawTitlesBackground(ug);
final Dimension2D dimensionFull = full.calculateDimension(stringBounder);
int i = 0;
assert dividers.size() == swimlanes().size() + 1;
for (Swimlane swimlane : swimlanesSpecial()) {
final LaneDivider divider1 = dividers.get(i);
final double xpos = swimlane.getTranslate().getDx() + swimlane.getMinMax().getMinX();
final HColor back = swimlane.getColors(skinParam).getColor(ColorType.BACK);
if (back != null) {
final LaneDivider divider2 = dividers.get(i + 1);
final UGraphic background = ug.apply(new UChangeBackColor(back)).apply(new UChangeColor(back))
.apply(UTranslate.dx(xpos - divider1.getX2()));
final double width = swimlane.getActualWidth() + divider1.getX2() + divider2.getX1();
final double height = dimensionFull.getHeight() + titleHeightTranslate.getDy();
background.draw(new URectangle(width, height).ignoreForCompressionOnX().ignoreForCompressionOnY());
}
full.drawU(new UGraphicInterceptorOneSwimlane(ug, swimlane).apply(swimlane.getTranslate())
.apply(getTitleHeightTranslate(stringBounder)));
final double dividerWith = divider1.calculateDimension(stringBounder).getWidth();
divider1.drawU(ug.apply(UTranslate.dx(xpos - dividerWith)));
i++;
}
final Cross cross = new Cross(ug.apply(getTitleHeightTranslate(stringBounder)));
full.drawU(cross);
cross.flushUg();
drawTitles(ug);
}
private void drawTitlesBackground(UGraphic ug) {
HColor color = skinParam.getHtmlColor(ColorParam.swimlaneTitleBackground, null, false);
if (SkinParam.USE_STYLES()) {
color = getStyle().value(PName.BackGroundColor).asColor(skinParam.getIHtmlColorSet());
}
if (color != null) {
final double titleHeight = getTitlesHeight(ug.getStringBounder());
double fullWidth = swimlanesSpecial().get(swimlanesSpecial().size() - 1).getTranslate().getDx() - 2 * 5 - 1;
final URectangle back = new URectangle(fullWidth, titleHeight).ignoreForCompressionOnX()
.ignoreForCompressionOnY();
ug.apply(UTranslate.dx(5)).apply(new UChangeBackColor(color)).apply(new UChangeColor(color)).draw(back);
}
}
private void drawTitles(UGraphic ug) {
for (Swimlane swimlane : swimlanes()) {
final TextBlock swTitle = getTitle(swimlane);
final double x2 = swimlane.getTranslate().getDx() + swimlane.getMinMax().getMinX();
final CenteredText centeredText = new CenteredText(swTitle, getWidthWithoutTitle(swimlane));
ug.apply(UTranslate.dx(x2)).draw(centeredText);
}
}
private void computeDrawingWidths(UGraphic ug, TextBlock full) {
final StringBounder stringBounder = ug.getStringBounder();
for (Swimlane swimlane : swimlanes()) {
final LimitFinder limitFinder = new LimitFinder(stringBounder, false);
final UGraphicInterceptorOneSwimlane interceptor = new UGraphicInterceptorOneSwimlane(
new UGraphicForSnake(limitFinder), swimlane);
full.drawU(interceptor);
interceptor.flushUg();
final MinMax minMax = limitFinder.getMinMax();
swimlane.setMinMax(minMax);
}
}
private void computeSizeInternal(UGraphic ug, TextBlock full) {
computeDrawingWidths(ug, full);
double min = skinParam.swimlaneWidth();
if (min == ISkinParam.SWIMLANE_WIDTH_SAME) {
for (Swimlane swimlane : swimlanes()) {
min = Math.max(min, getWidthWithoutTitle(swimlane));
}
}
final StringBounder stringBounder = ug.getStringBounder();
for (int i = 0; i < swimlanesSpecial().size(); i++) {
final Swimlane swimlane = swimlanesSpecial().get(i);
final double swimlaneActualWidth = MathUtils.max(min, getWidthWithoutTitle(swimlane));
swimlane.setWidth(swimlaneActualWidth);
}
final UTranslate titleHeightTranslate = getTitleHeightTranslate(stringBounder);
final Dimension2D dimensionFull = full.calculateDimension(stringBounder);
dividers.clear();
double xpos = 0;
for (int i = 0; i < swimlanesSpecial().size(); i++) {
final Swimlane swimlane = swimlanesSpecial().get(i);
double x1 = getHalfMissingSpace(stringBounder, i, min);
double x2 = getHalfMissingSpace(stringBounder, i + 1, min);
final LaneDivider laneDivider = new LaneDivider(skinParam, x1, x2,
dimensionFull.getHeight() + titleHeightTranslate.getDy());
dividers.add(laneDivider);
final double xx = xpos + laneDivider.getWidth() - swimlane.getMinMax().getMinX()
+ (swimlane.getActualWidth() - getWidthWithoutTitle(swimlane)) / 2.0;
swimlane.setTranslate(UTranslate.dx(xx));
xpos += swimlane.getActualWidth() + laneDivider.getWidth();
}
assert dividers.size() == swimlanes().size() + 1;
}
public double getHalfMissingSpace(StringBounder stringBounder, int i, double min) {
if (i == 0 || i > swimlanesSpecial().size()) {
return 5;
}
final Swimlane swimlane = swimlanesSpecial().get(i - 1);
final double swimlaneActualWidth = Math.max(min, getWidthWithoutTitle(swimlane));
final double titleWidth = getTitle(swimlane).calculateDimension(stringBounder).getWidth();
if (titleWidth <= swimlaneActualWidth) {
return 5;
}
assert titleWidth > swimlaneActualWidth;
return Math.max(5, 5 + (titleWidth - swimlaneActualWidth) / 2);
}
private double getWidthWithoutTitle(Swimlane swimlane) {
return swimlane.getMinMax().getWidth();
}
public Dimension2D calculateDimension(StringBounder stringBounder) {
return getMinMax(stringBounder).getDimension();
}
public Instruction getCurrent() {
return currentInstruction;
}
public void setCurrent(Instruction current) {
this.currentInstruction = current;
}
public LinkRendering nextLinkRenderer() {
return nextLinkRenderer;
}
public void setNextLinkRenderer(LinkRendering link) {
if (link == null) {
throw new IllegalArgumentException();
}
this.nextLinkRenderer = link;
}
public Swimlane getCurrentSwimlane() {
return currentSwimlane;
}
private MinMax cachedMinMax;
@Override
public MinMax getMinMax(StringBounder stringBounder) {
if (cachedMinMax == null) {
cachedMinMax = TextBlockUtils.getMinMax(this, stringBounder);
}
return cachedMinMax;
}
}

View File

@ -73,7 +73,7 @@ public class SwimlanesB extends SwimlanesA {
}
if (color != null) {
final double titleHeight = getTitlesHeight(stringBounder);
final URectangle back = new URectangle(getTitlesWidth(stringBounder), titleHeight).ignoreForCompression();
final URectangle back = new URectangle(getTitlesWidth(stringBounder), titleHeight).ignoreForCompressionOnX().ignoreForCompressionOnY();
ug.apply(new UChangeBackColor(color)).apply(new UChangeColor(color)).draw(back);
}
for (Swimlane swimlane : swimlanes) {
@ -105,7 +105,7 @@ public class SwimlanesB extends SwimlanesA {
wrap = new LineBreakStrategy("" + ((int) swimlane.getActualWidth()));
}
return swimlane.getDisplay().create(fontConfiguration, horizontalAlignment, skinParam, wrap);
return swimlane.getDisplay().create9(fontConfiguration, horizontalAlignment, skinParam, wrap);
}
private LineBreakStrategy getWrap() {
@ -124,7 +124,7 @@ public class SwimlanesB extends SwimlanesA {
}
final double titleWidth = getTitle(swimlane).calculateDimension(stringBounder).getWidth();
return MathUtils.max(m1, titleWidth + 2 * separationMargin);
return MathUtils.max(m1, titleWidth + 2 * separationMargin());
}

View File

@ -91,5 +91,4 @@ public class SwimlanesC extends SwimlanesB {
}
ug.apply(thickness).apply(new UChangeColor(color)).draw(ULine.vline(height));
}
}

View File

@ -104,7 +104,7 @@ public class Worm implements Iterable<Point2D.Double> {
ug = ug.apply(new UStroke(1.5));
final Point2D start = points.get(0);
if (ignoreForCompression) {
startDecoration.setIgnoreForCompression(CompressionMode.ON_X);
startDecoration.setCompressionMode(CompressionMode.ON_X);
}
ug.apply(new UTranslate(start)).apply(new UStroke()).draw(startDecoration);
}
@ -112,7 +112,7 @@ public class Worm implements Iterable<Point2D.Double> {
ug = ug.apply(new UStroke(1.5));
final Point2D end = points.get(points.size() - 1);
if (ignoreForCompression) {
endDecoration.setIgnoreForCompression(CompressionMode.ON_X);
endDecoration.setCompressionMode(CompressionMode.ON_X);
}
ug.apply(new UTranslate(end)).apply(new UStroke()).draw(endDecoration);
}

View File

@ -119,7 +119,7 @@ public abstract class AbstractParallelFtilesBuilder {
} else {
fontConfiguration = new FontConfiguration(skinParam(), FontParam.ARROW, null);
}
return display.create(fontConfiguration, HorizontalAlignment.LEFT, skinParam(), CreoleMode.SIMPLE_LINE);
return display.create7(fontConfiguration, HorizontalAlignment.LEFT, skinParam(), CreoleMode.SIMPLE_LINE);
}
protected TextBlock getTextBlock(LinkRendering linkRendering) {

View File

@ -173,8 +173,8 @@ public class FtileGroup extends AbstractFtile {
final FtileGeometry orig = getInnerDimension(stringBounder);
final Dimension2D dimTitle = name.calculateDimension(stringBounder);
final Dimension2D dimHeaderNote = headerNote.calculateDimension(stringBounder);
final double suppWidth = MathUtils
.max(orig.getWidth(), dimTitle.getWidth() + 20, dimHeaderNote.getWidth() + 20) - orig.getWidth();
final double suppWidth = MathUtils.max(orig.getWidth(), dimTitle.getWidth() + 20, dimHeaderNote.getWidth() + 20)
- orig.getWidth();
return suppWidth;
}
@ -207,11 +207,11 @@ public class FtileGroup extends AbstractFtile {
+ headerNoteHeight(stringBounder);
final double titleAndHeaderNoteHeight = diffHeightTitle(stringBounder) + headerNoteHeight(stringBounder);
if (orig.hasPointOut()) {
return new FtileGeometry(width, height, orig.getLeft() + suppWidth / 2, orig.getInY()
+ titleAndHeaderNoteHeight, orig.getOutY() + titleAndHeaderNoteHeight);
return new FtileGeometry(width, height, orig.getLeft() + suppWidth / 2,
orig.getInY() + titleAndHeaderNoteHeight, orig.getOutY() + titleAndHeaderNoteHeight);
}
return new FtileGeometry(width, height, orig.getLeft() + suppWidth / 2, orig.getInY()
+ titleAndHeaderNoteHeight);
return new FtileGeometry(width, height, orig.getLeft() + suppWidth / 2,
orig.getInY() + titleAndHeaderNoteHeight);
}
private double headerNoteHeight(StringBounder stringBounder) {
@ -222,12 +222,14 @@ public class FtileGroup extends AbstractFtile {
final StringBounder stringBounder = ug.getStringBounder();
final Dimension2D dimTotal = calculateDimension(stringBounder);
// final double roundCorner = type.getSkinParameter().getRoundCorner(skinParam(), null);
// final double roundCorner =
// type.getSkinParameter().getRoundCorner(skinParam(), null);
final SymbolContext symbolContext = new SymbolContext(backColor, borderColor).withShadow(shadowing)
.withStroke(stroke).withCorner(roundCorner, 0);
type.asBig(name, inner.skinParam().getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null, false),
TextBlockUtils.empty(0, 0), dimTotal.getWidth(), dimTotal.getHeight(), symbolContext,
final HorizontalAlignment align = inner.skinParam().getHorizontalAlignment(AlignmentParam.packageTitleAlignment,
null, false);
type.asBig(name, align, TextBlockUtils.empty(0, 0), dimTotal.getWidth(), dimTotal.getHeight(), symbolContext,
skinParam().getStereotypeAlignment()).drawU(ug);
final Dimension2D dimHeaderNote = headerNote.calculateDimension(stringBounder);

View File

@ -154,12 +154,12 @@ class FtileRepeat extends AbstractFtile {
final List<Connection> conns = new ArrayList<Connection>();
final Display in1 = repeat.getInLinkRendering().getDisplay();
final TextBlock tbin1 = in1 == null ? null : in1.create(fcArrow, HorizontalAlignment.LEFT, spriteContainer,
final TextBlock tbin1 = in1 == null ? null : in1.create7(fcArrow, HorizontalAlignment.LEFT, spriteContainer,
CreoleMode.SIMPLE_LINE);
conns.add(result.new ConnectionIn(repeat.getInLinkRendering().getRainbow(arrowColor), tbin1));
final Display backLink1 = backRepeatLinkRendering.getDisplay();
final TextBlock tbbackLink1 = backLink1 == null ? null : backLink1.create(fcArrow, HorizontalAlignment.LEFT,
final TextBlock tbbackLink1 = backLink1 == null ? null : backLink1.create7(fcArrow, HorizontalAlignment.LEFT,
spriteContainer, CreoleMode.SIMPLE_LINE);
if (repeat.getSwimlaneIn() == swimlaneOut) {
if (backward == null) {
@ -176,7 +176,7 @@ class FtileRepeat extends AbstractFtile {
}
final Display out1 = repeat.getOutLinkRendering().getDisplay();
final TextBlock tbout1 = out1 == null ? null : out1.create(fcArrow, HorizontalAlignment.LEFT, spriteContainer,
final TextBlock tbout1 = out1 == null ? null : out1.create7(fcArrow, HorizontalAlignment.LEFT, spriteContainer,
CreoleMode.SIMPLE_LINE);
final Rainbow tmpColor = endRepeatLinkColor.withDefault(arrowColor);

View File

@ -52,7 +52,6 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileKilled;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.Snake;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
import net.sourceforge.plantuml.activitydiagram3.ftile.vertical.FtileThinSplit;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.Rainbow;

View File

@ -267,7 +267,7 @@ public class ConditionalBuilder {
}
private TextBlock getLabelPositive(Branch branch) {
return branch.getLabelPositive().create(fontArrow, HorizontalAlignment.LEFT, ftileFactory.skinParam(),
return branch.getLabelPositive().create7(fontArrow, HorizontalAlignment.LEFT, ftileFactory.skinParam(),
CreoleMode.SIMPLE_LINE);
}
@ -279,10 +279,10 @@ public class ConditionalBuilder {
// else use default ConditionEndStyle.DIAMOND
if (hasTwoBranches()) {
final Display out1 = branch1.getFtile().getOutLinkRendering().getDisplay();
final TextBlock tbout1 = out1 == null ? null : out1.create(fontArrow, HorizontalAlignment.LEFT,
final TextBlock tbout1 = out1 == null ? null : out1.create7(fontArrow, HorizontalAlignment.LEFT,
ftileFactory.skinParam(), CreoleMode.SIMPLE_LINE);
final Display out2 = branch2.getFtile().getOutLinkRendering().getDisplay();
final TextBlock tbout2 = out2 == null ? null : out2.create(fontArrow, HorizontalAlignment.LEFT,
final TextBlock tbout2 = out2 == null ? null : out2.create7(fontArrow, HorizontalAlignment.LEFT,
ftileFactory.skinParam(), CreoleMode.SIMPLE_LINE);
FtileDiamond tmp = new FtileDiamond(tile1.skinParam(), backColor, borderColor, swimlane);
tmp = useNorth ? tmp.withNorth(tbout1) : tmp.withWest(tbout1);

View File

@ -194,7 +194,7 @@ public class FtileSwitchWithDiamonds extends FtileSwitchNude {
protected TextBlock getLabelPositive(Branch branch) {
final FontConfiguration fcArrow = new FontConfiguration(skinParam(), FontParam.ARROW, null);
return branch.getLabelPositive().create(fcArrow, HorizontalAlignment.LEFT, skinParam(), CreoleMode.SIMPLE_LINE);
return branch.getLabelPositive().create7(fcArrow, HorizontalAlignment.LEFT, skinParam(), CreoleMode.SIMPLE_LINE);
}
}

View File

@ -39,7 +39,6 @@ import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.activitydiagram3.Branch;
import net.sourceforge.plantuml.activitydiagram3.ftile.AbstractConnection;
import net.sourceforge.plantuml.activitydiagram3.ftile.Arrows;
@ -49,12 +48,8 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.Snake;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
import net.sourceforge.plantuml.creole.CreoleMode;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.Rainbow;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.ugraphic.UGraphic;
public class FtileSwitchWithOneLink extends FtileSwitchWithDiamonds {

View File

@ -91,7 +91,7 @@ public class FtileBlackBlock extends AbstractFtile {
}
public void drawU(UGraphic ug) {
final URectangle rect = new URectangle(width, height).rounded(5).ignoreForCompression();
final URectangle rect = new URectangle(width, height).rounded(5).ignoreForCompressionOnX();
if (skinParam().shadowing(null)) {
rect.setDeltaShadow(3);
}

Some files were not shown because too many files have changed in this diff Show More