All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jcckit.plot.Plot Maven / Gradle / Ivy

There is a newer version: 1.2024.8
Show newest version
// THIS FILE HAS BEEN GENERATED BY A PREPROCESSOR.
/* +=======================================================================
 * |
 * |      PlantUML : a free UML diagram generator
 * |
 * +=======================================================================
 *
 * (C) Copyright 2009-2024, Arnaud Roques
 *
 * Project Info:  https://plantuml.com
 *
 * If you like this project or if you find it useful, you can support us at:
 *
 * https://plantuml.com/patreon (only 1$ per month!)
 * https://plantuml.com/liberapay (only 1€ per month!)
 * https://plantuml.com/paypal
 *
 *
 * PlantUML is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License V2.
 *
 * THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
 * LICENSE ("AGREEMENT"). [GNU General Public License V2]
 *
 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES
 * RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
 *
 * You may obtain a copy of the License at
 *
 * https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * PlantUML can occasionally display sponsored or advertising messages. Those
 * messages are usually generated on welcome or error images and never on
 * functional diagrams.
 * See https://plantuml.com/professional if you want to remove them
 *
 * Images (whatever their format : PNG, SVG, EPS...) generated by running PlantUML
 * are owned by the author of their corresponding sources code (that is, their
 * textual description in PlantUML language). Those images are not covered by
 * this GPL v2 license.
 *
 * The generated images can then be used without any reference to the GPL v2 license.
 * It is not even necessary to stipulate that they have been generated with PlantUML,
 * although this will be appreciated by the PlantUML team.
 *
 * There is an exception : if the textual description in PlantUML language is also covered
 * by any license, then the generated images are logically covered
 * by the very same license.
 *
 * This is the IGY distribution (Install GraphViz by Yourself).
 * You have to install GraphViz and to setup the GRAPHVIZ_DOT environment variable
 * (see https://plantuml.com/graphviz-dot )
 *
 * Icons provided by OpenIconic :  https://useiconic.com/open
 * Archimate sprites provided by Archi :  http://www.archimatetool.com
 * Stdlib AWS provided by https://github.com/milo-minderbinder/AWS-PlantUML
 * Stdlib Icons provided https://github.com/tupadr3/plantuml-icon-font-sprites
 * ASCIIMathML (c) Peter Jipsen http://www.chapman.edu/~jipsen
 * ASCIIMathML (c) David Lippman http://www.pierce.ctc.edu/dlippman
 * CafeUndZopfli ported by Eugene Klyuchnikov https://github.com/eustas/CafeUndZopfli
 * Brotli (c) by the Brotli Authors https://github.com/google/brotli
 * Themes (c) by Brett Schwarz https://github.com/bschwarz/puml-themes
 * Twemoji (c) by Twitter at https://twemoji.twitter.com/
 *
 */
package jcckit.plot;

import java.util.Vector;

import jcckit.data.DataCurve;
import jcckit.data.DataEvent;
import jcckit.data.DataListener;
import jcckit.data.DataPlot;
import jcckit.data.DataPoint;
import jcckit.graphic.ClippingShape;
import jcckit.graphic.GraphPoint;
import jcckit.graphic.GraphicalComposite;
import jcckit.graphic.GraphicalElement;
import jcckit.transformation.Transformation;
import jcckit.util.ConfigParameters;
import jcckit.util.Factory;

/**
 * A plot is determined by a {@link CoordinateSystem}, {@link Curve Curves},
 * an optional annotation layer and an optional {@link Legend}. When rendered
 * these components are draw in this order.
 * 

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

* A {@link DataPlot} can be connected with a Plot instance. * This is done with the method {@link #connect connect()} which registrates * this Plot instance as * a {@link DataListener} at the connected DataPlot. * After an received {@link DataEvent DataEvents} has been handled * the registrated PlotListeners will receive a * {@link PlotEvent} of the type {@link PlotEventType#DATA_PLOT_CHANGED}. * * @author Franz-Josef Elmer */ public class Plot implements DataListener { /** Configuration parameter key. */ public static final String COORDINATE_SYSTEM_KEY = "coordinateSystem", CURVE_FACTORY_KEY = "curveFactory", LEGEND_VISIBLE_KEY = "legendVisible", LEGEND_KEY = "legend", INITIAL_HINT_FOR_NEXT_CURVE_KEY = "initialHintForNextCurve"; private final Vector _plotListeners = new Vector(); private DataPlot _dataPlot; private final CurveFactory _curveFactory; private final Vector _curves = new Vector(); private final Vector _nextCurveHints = new Vector(); private final Hint _initialHintForNextCurve; private final Legend _legend; private final boolean _legendVisibility; private GraphicalElement _coordinateSystemView; private ClippingShape _clippingShape; private Transformation _transformation; private GraphicalElement _annotation; private GraphicalComposite _legendView = new GraphicalComposite(null); /** * Creates an instance from the specified configuration parameters. *

* * * * * * * * * * * * * * * * * *
Key & Default ValueTypeMandatoryDescription
coordinateSystem = {@link CartesianCoordinateSystem}ConfigParametersnoDefinition of the {@link CoordinateSystem}.
curveFactory = {@link SimpleCurveFactory}ConfigParametersnoDefinition of the {@link CurveFactory}.
initialHintForNextCurve = nullConfigParametersnoDefinition of the initial {@link Hint} which is needed by some * {@link SymbolFactory SymbolFactories} like {@link BarFactory}. *
legend = default values of {@link Legend}ConfigParametersnoConfiguration parameters of a {@link Legend}.
legendVisible = truebooleannoIf true the {@link Legend} will be created.
*/ public Plot(ConfigParameters config) { CoordinateSystem coordinateSystem = (CoordinateSystem) Factory.create( config.getNode(COORDINATE_SYSTEM_KEY), CartesianCoordinateSystem.class.getName()); setCoordinateSystem(coordinateSystem); _curveFactory = (CurveFactory) Factory.create( config.getNode(CURVE_FACTORY_KEY), SimpleCurveFactory.class.getName()); _initialHintForNextCurve = (Hint) Factory.createOrGet( config.getNode(INITIAL_HINT_FOR_NEXT_CURVE_KEY), null); _legend = new Legend(config.getNode(LEGEND_KEY)); _legendVisibility = config.getBoolean(LEGEND_VISIBLE_KEY, true); } /** * Sets the coordinate system. All curves will be regenerated and a * {@link PlotEvent} of type {@link PlotEventType#COODINATE_SYSTEM_CHANGED} * will be fired. * * @param coordinateSystem New coordinate system. */ public void setCoordinateSystem(CoordinateSystem coordinateSystem) { _coordinateSystemView = coordinateSystem.getView(); _clippingShape = coordinateSystem.getClippingShape(); _transformation = coordinateSystem.getTransformation(); if (_dataPlot != null) { generateCurves(_dataPlot); } notifyListeners( new PlotEvent(this, PlotEventType.COODINATE_SYSTEM_CHANGED, null)); } /** * Adds the specified {@link PlotListener}. Does nothing if * already added. */ public void addPlotListener(PlotListener listener) { if (!_plotListeners.contains(listener)) { _plotListeners.addElement(listener); } } /** * Removes the specfied {@link PlotListener}. Does nothing if * already removed. */ public void removePlotListener(PlotListener listener) { _plotListeners.removeElement(listener); } /** * Sends all registrated {@link PlotListener PlotListeners} * the specified event. */ protected void notifyListeners(PlotEvent event) { for (int i = 0, n = _plotListeners.size(); i < n; i++) { ((PlotListener) _plotListeners.elementAt(i)).plotChanged(event); } } /** * Connect the specified {@link DataPlot} with this instance. *

* If this Plot instance is already connected with a * DataPlot the connection will be released and a * {@link PlotEvent} of the type {@link PlotEventType#DATA_PLOT_DISCONNECTED} * will be sent to all registrated {@link PlotListener PlotListeners}. *

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

* Finally all curves will be generated and a PlotEvent * of the type {@link PlotEventType#DATA_PLOT_CONNECTED} will be transmitted. * @param dataPlot Data to be connected with this plot instance. * Can be null in order to disconnect this instance from * any DataPlot. */ public void connect(DataPlot dataPlot) { if (_dataPlot != null) { _dataPlot.removeDataListener(this); notifyListeners(new PlotEvent(this, PlotEventType.DATA_PLOT_DISCONNECTED, _dataPlot)); } _dataPlot = dataPlot; if (_dataPlot != null) { _dataPlot.addDataListener(this); generateCurves(_dataPlot); notifyListeners(new PlotEvent(this, PlotEventType.DATA_PLOT_CONNECTED, _dataPlot)); } } /** * Transforms a point from device-independent coordinates into * data coordinates. * @param point Point in device-independent coordinates. * @return transform point. */ public DataPoint transform(GraphPoint point) { return _transformation.transformToData(point); } /** * Creates a graphical representation of the complete plot. * @return GraphicalComposite containing the views of the * coordinate system, the curves, and optionally the legend (in this order). */ public GraphicalComposite getCompletePlot() { GraphicalComposite result = new GraphicalComposite(null); result.addElement(_coordinateSystemView); GraphicalElement[] curves = getCurves(); for (int i = 0; i < curves.length; i++) { result.addElement(curves[i]); } if (_annotation != null) { result.addElement(_annotation); } if (_legendVisibility) { result.addElement(getLegend()); } return result; } /** Returns the view of the coordinate system. */ public GraphicalElement getCoordinateSystem() { return _coordinateSystemView; } /** Returns the graphical representations of all curves. */ public GraphicalElement[] getCurves() { synchronized (_curves) { GraphicalElement[] curves = new GraphicalElement[_curves.size()]; for (int i = 0; i < curves.length; i++) { curves[i] = ((Curve) _curves.elementAt(i)).getView(); } return curves; } } /** * Returns the annotation layer. * @return null if no annotation layer. */ public GraphicalElement getAnnotation() { return _annotation; } /** * Sets the annotation layer. * @param annotation Any kind of graphics which will be drawn on the * top of the curves but may be covered by the legend. * Can be null. */ public void setAnnotation(GraphicalElement annotation) { _annotation = annotation; } /** Returns true if the legend is visible. */ public boolean isLegendVisible() { return _legendVisibility; } /** Returns the graphical representations of the legend. */ public GraphicalElement getLegend() { return _legendView; } /** * Handles the received {@link DataEvent} and notifies * {@link PlotListener PlotListeners} by an event of the type * {@link PlotEventType#DATA_CURVE_CHANGED} or * {@link PlotEventType#DATA_PLOT_CHANGED}. The following table shows what * this method does: *

* * * * * * *
Source of eventAll hints for the next curve are null?ActionType of sent {@link PlotEvent}
{@link DataCurve}YesRecreate changed curve. * DATA_CURVE_CHANGED
{@link DataCurve}NoRecreate changed curve * and all curves with large curve index. * DATA_PLOT_CHANGED
{@link DataPlot}-Recreate all curves * and {@link Legend} view. * DATA_PLOT_CHANGED
*/ public void dataChanged(DataEvent event) { int index = 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 = curve.getContainer().getIndexOf(curve); type = PlotEventType.DATA_CURVE_CHANGED; fillCurve(index, curve); if (index < numberOfCurves - 1) { Vector curveHints = (Vector) _nextCurveHints.elementAt(index); for (int i = 0, n = curveHints.size(); i < n; i++) { if (curveHints.elementAt(i) != null) { type = PlotEventType.DATA_PLOT_CHANGED; for (int j = index +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); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy