Improved appearance plot

This commit is contained in:
Sibo Van Gool 2021-07-09 03:57:27 +02:00
parent dcacc40d88
commit 2f2a3a4272

View File

@ -36,7 +36,7 @@ import org.jfree.chart.LegendItemSource;
import org.jfree.chart.annotations.XYImageAnnotation; import org.jfree.chart.annotations.XYImageAnnotation;
import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.LineBorder; import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.DefaultDrawingSupplier; import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.Marker; import org.jfree.chart.plot.Marker;
import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.PlotOrientation;
@ -63,28 +63,28 @@ import org.jfree.ui.TextAnchor;
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class SimulationPlot { public class SimulationPlot {
private static final float PLOT_STROKE_WIDTH = 1.5f; private static final float PLOT_STROKE_WIDTH = 1.5f;
private final JFreeChart chart; private final JFreeChart chart;
private final PlotConfiguration config; private final PlotConfiguration config;
private final Simulation simulation; private final Simulation simulation;
private final PlotConfiguration filled; private final PlotConfiguration filled;
private final List<EventDisplayInfo> eventList; private final List<EventDisplayInfo> eventList;
private final List<ModifiedXYItemRenderer> renderers = new ArrayList<ModifiedXYItemRenderer>(); private final List<ModifiedXYItemRenderer> renderers = new ArrayList<ModifiedXYItemRenderer>();
private final LegendItems legendItems; private final LegendItems legendItems;
int branchCount; int branchCount;
void setShowPoints(boolean showPoints) { void setShowPoints(boolean showPoints) {
for (ModifiedXYItemRenderer r : renderers) { for (ModifiedXYItemRenderer r : renderers) {
r.setBaseShapesVisible(showPoints); r.setBaseShapesVisible(showPoints);
} }
} }
void setShowBranch(int branch) { void setShowBranch(int branch) {
XYPlot plot = (XYPlot) chart.getPlot(); XYPlot plot = (XYPlot) chart.getPlot();
int datasetcount = plot.getDatasetCount(); int datasetcount = plot.getDatasetCount();
@ -98,12 +98,12 @@ public class SimulationPlot {
} }
drawDomainMarkers(branch); drawDomainMarkers(branch);
} }
SimulationPlot(Simulation simulation, PlotConfiguration config, boolean initialShowPoints) { SimulationPlot(Simulation simulation, PlotConfiguration config, boolean initialShowPoints) {
this.simulation = simulation; this.simulation = simulation;
this.config = config; this.config = config;
this.branchCount = simulation.getSimulatedData().getBranchCount(); this.branchCount = simulation.getSimulatedData().getBranchCount();
this.chart = ChartFactory.createXYLineChart( this.chart = ChartFactory.createXYLineChart(
//// Simulated flight //// Simulated flight
/*title*/simulation.getName(), /*title*/simulation.getName(),
@ -114,40 +114,42 @@ public class SimulationPlot {
/*legend*/false, /*legend*/false,
/*tooltips*/true, /*tooltips*/true,
/*urls*/false /*urls*/false
); );
chart.getTitle().setFont(new Font("Dialog", Font.BOLD, 23));
chart.setBackgroundPaint(new Color(240, 240, 240));
this.legendItems = new LegendItems(); this.legendItems = new LegendItems();
LegendTitle legend = new LegendTitle(legendItems); LegendTitle legend = new LegendTitle(legendItems);
legend.setMargin(new RectangleInsets(1.0, 1.0, 1.0, 1.0)); legend.setMargin(new RectangleInsets(1.0, 1.0, 1.0, 1.0));
legend.setFrame(new LineBorder()); legend.setFrame(BlockBorder.NONE);
legend.setBackgroundPaint(Color.white); legend.setBackgroundPaint(new Color(240, 240, 240));
legend.setPosition(RectangleEdge.BOTTOM); legend.setPosition(RectangleEdge.BOTTOM);
chart.addSubtitle(legend); chart.addSubtitle(legend);
chart.addSubtitle(new TextTitle(config.getName())); chart.addSubtitle(new TextTitle(config.getName()));
// Fill the auto-selections based on first branch selected. // Fill the auto-selections based on first branch selected.
FlightDataBranch mainBranch = simulation.getSimulatedData().getBranch(0); FlightDataBranch mainBranch = simulation.getSimulatedData().getBranch(0);
this.filled = config.fillAutoAxes(mainBranch); this.filled = config.fillAutoAxes(mainBranch);
List<Axis> axes = filled.getAllAxes(); List<Axis> axes = filled.getAllAxes();
// Create the data series for both axes // Create the data series for both axes
XYSeriesCollection[] data = new XYSeriesCollection[2]; XYSeriesCollection[] data = new XYSeriesCollection[2];
data[0] = new XYSeriesCollection(); data[0] = new XYSeriesCollection();
data[1] = new XYSeriesCollection(); data[1] = new XYSeriesCollection();
// Get the domain axis type // Get the domain axis type
final FlightDataType domainType = filled.getDomainAxisType(); final FlightDataType domainType = filled.getDomainAxisType();
final Unit domainUnit = filled.getDomainAxisUnit(); final Unit domainUnit = filled.getDomainAxisUnit();
if (domainType == null) { if (domainType == null) {
throw new IllegalArgumentException("Domain axis type not specified."); throw new IllegalArgumentException("Domain axis type not specified.");
} }
// Get plot length (ignore trailing NaN's) // Get plot length (ignore trailing NaN's)
int typeCount = filled.getTypeCount(); int typeCount = filled.getTypeCount();
int seriesCount = 0; int seriesCount = 0;
// Create the XYSeries objects from the flight data and store into the collections // Create the XYSeries objects from the flight data and store into the collections
String[] axisLabel = new String[2]; String[] axisLabel = new String[2];
for (int i = 0; i < typeCount; i++) { for (int i = 0; i < typeCount; i++) {
@ -156,11 +158,11 @@ public class SimulationPlot {
Unit unit = filled.getUnit(i); Unit unit = filled.getUnit(i);
int axis = filled.getAxis(i); int axis = filled.getAxis(i);
String name = getLabel(type, unit); String name = getLabel(type, unit);
List<String> seriesNames = Util.generateSeriesLabels(simulation); List<String> seriesNames = Util.generateSeriesLabels(simulation);
// Populate data for each branch. // Populate data for each branch.
// The primary branch (branchIndex = 0) is easy since all the data is copied // The primary branch (branchIndex = 0) is easy since all the data is copied
{ {
int branchIndex = 0; int branchIndex = 0;
@ -180,48 +182,57 @@ public class SimulationPlot {
for (int branchIndex = 1; branchIndex < branchCount; branchIndex++) { for (int branchIndex = 1; branchIndex < branchCount; branchIndex++) {
FlightDataBranch primaryBranch = simulation.getSimulatedData().getBranch(0); FlightDataBranch primaryBranch = simulation.getSimulatedData().getBranch(0);
FlightDataBranch thisBranch = simulation.getSimulatedData().getBranch(branchIndex); FlightDataBranch thisBranch = simulation.getSimulatedData().getBranch(branchIndex);
// Get first time index used in secondary branch; // Get first time index used in secondary branch;
double firstSampleTime = thisBranch.get(FlightDataType.TYPE_TIME).get(0); double firstSampleTime = thisBranch.get(FlightDataType.TYPE_TIME).get(0);
XYSeries series = new XYSeries(seriesCount++, false, true); XYSeries series = new XYSeries(seriesCount++, false, true);
series.setDescription(thisBranch.getBranchName() + ": " + name); series.setDescription(thisBranch.getBranchName() + ": " + name);
// Copy the first points from the primaryBranch. // Copy the first points from the primaryBranch.
List<Double> primaryT = primaryBranch.get(FlightDataType.TYPE_TIME); List<Double> primaryT = primaryBranch.get(FlightDataType.TYPE_TIME);
List<Double> primaryx = primaryBranch.get(domainType); List<Double> primaryx = primaryBranch.get(domainType);
List<Double> primaryy = primaryBranch.get(type); List<Double> primaryy = primaryBranch.get(type);
for (int j = 0; j < primaryT.size(); j++) { for (int j = 0; j < primaryT.size(); j++) {
if (primaryT.get(j) >= firstSampleTime) { if (primaryT.get(j) >= firstSampleTime) {
break; break;
} }
series.add(domainUnit.toUnit(primaryx.get(j)), unit.toUnit(primaryy.get(j))); series.add(domainUnit.toUnit(primaryx.get(j)), unit.toUnit(primaryy.get(j)));
} }
// Now copy all the data from the secondary branch // Now copy all the data from the secondary branch
List<Double> plotx = thisBranch.get(domainType); List<Double> plotx = thisBranch.get(domainType);
List<Double> ploty = thisBranch.get(type); List<Double> ploty = thisBranch.get(type);
int pointCount = plotx.size(); int pointCount = plotx.size();
for (int j = 0; j < pointCount; j++) { for (int j = 0; j < pointCount; j++) {
series.add(domainUnit.toUnit(plotx.get(j)), unit.toUnit(ploty.get(j))); series.add(domainUnit.toUnit(plotx.get(j)), unit.toUnit(ploty.get(j)));
} }
data[axis].addSeries(series); data[axis].addSeries(series);
} }
// Update axis label // Update axis label
if (axisLabel[axis] == null) if (axisLabel[axis] == null)
axisLabel[axis] = type.getName(); axisLabel[axis] = type.getName();
else else
axisLabel[axis] += "; " + type.getName(); axisLabel[axis] += "; " + type.getName();
} }
// Add the data and formatting to the plot // Add the data and formatting to the plot
XYPlot plot = chart.getXYPlot(); XYPlot plot = chart.getXYPlot();
plot.setDomainPannable(true); plot.setDomainPannable(true);
plot.setRangePannable(true); plot.setRangePannable(true);
// Plot appearance
plot.setBackgroundPaint(Color.white);
plot.setAxisOffset(new RectangleInsets(0, 0, 0, 0));
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.lightGray);
plot.setDomainGridlinesVisible(true);
plot.setDomainGridlinePaint(Color.lightGray);
int axisno = 0; int axisno = 0;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
// Check whether axis has any data // Check whether axis has any data
@ -233,19 +244,30 @@ public class SimulationPlot {
axis.setLabel(axisLabel[i]); axis.setLabel(axisLabel[i]);
// axis.setRange(axes.get(i).getMinValue(), axes.get(i).getMaxValue()); // axis.setRange(axes.get(i).getMinValue(), axes.get(i).getMaxValue());
plot.setRangeAxis(axisno, axis); plot.setRangeAxis(axisno, axis);
axis.setLabelFont(new Font("Dialog", Font.BOLD, 14));
double domainMin = data[i].getDomainLowerBound(true); double domainMin = data[i].getDomainLowerBound(true);
double domainMax = data[i].getDomainUpperBound(true); double domainMax = data[i].getDomainUpperBound(true);
plot.setDomainAxis(new PresetNumberAxis(domainMin, domainMax)); plot.setDomainAxis(new PresetNumberAxis(domainMin, domainMax));
// Add data and map to the axis // Add data and map to the axis
Color[] colors = {new Color(0,114,189), // Colors for data lines
new Color(217,83,25),
new Color(237,177,32),
new Color(126,49,142),
new Color(119,172,48),
new Color(77,190,238),
new Color(162,20,47)};
plot.setDataset(axisno, data[i]); plot.setDataset(axisno, data[i]);
ModifiedXYItemRenderer r = new ModifiedXYItemRenderer(branchCount); ModifiedXYItemRenderer r = new ModifiedXYItemRenderer(branchCount);
renderers.add(r); renderers.add(r);
plot.setRenderer(axisno, r); plot.setRenderer(axisno, r);
r.setBaseShapesVisible(initialShowPoints); r.setBaseShapesVisible(initialShowPoints);
r.setBaseShapesFilled(true); r.setBaseShapesFilled(true);
r.setSeriesPaint(0, colors[i]);
r.setSeriesPaint(1, colors[i+2]);
r.setSeriesPaint(2, colors[i+4]);
for (int j = 0; j < data[i].getSeriesCount(); j++) { for (int j = 0; j < data[i].getSeriesCount(); j++) {
Stroke lineStroke = new BasicStroke(PLOT_STROKE_WIDTH); Stroke lineStroke = new BasicStroke(PLOT_STROKE_WIDTH);
r.setSeriesStroke(j, lineStroke); r.setSeriesStroke(j, lineStroke);
@ -261,30 +283,30 @@ public class SimulationPlot {
Stroke lineStroke = r.getSeriesStroke(j); Stroke lineStroke = r.getSeriesStroke(j);
this.legendItems.lineStrokes.add(lineStroke); this.legendItems.lineStrokes.add(lineStroke);
} }
plot.mapDatasetToRangeAxis(axisno, axisno); plot.mapDatasetToRangeAxis(axisno, axisno);
axisno++; axisno++;
} }
} }
plot.getDomainAxis().setLabel(getLabel(domainType, domainUnit)); plot.getDomainAxis().setLabel(getLabel(domainType, domainUnit));
plot.addDomainMarker(new ValueMarker(0)); plot.addDomainMarker(new ValueMarker(0));
plot.addRangeMarker(new ValueMarker(0)); plot.addRangeMarker(new ValueMarker(0));
plot.getDomainAxis().setLabelFont(new Font("Dialog", Font.BOLD, 14));
// Create list of events to show (combine event too close to each other) // Create list of events to show (combine event too close to each other)
this.eventList = buildEventInfo(); this.eventList = buildEventInfo();
// Create the event markers // Create the event markers
drawDomainMarkers(-1); drawDomainMarkers(-1);
} }
JFreeChart getJFreeChart() { JFreeChart getJFreeChart() {
return chart; return chart;
} }
private String getLabel(FlightDataType type, Unit unit) { private String getLabel(FlightDataType type, Unit unit) {
String name = type.getName(); String name = type.getName();
if (unit != null && !UnitGroup.UNITS_NONE.contains(unit) && if (unit != null && !UnitGroup.UNITS_NONE.contains(unit) &&
@ -292,16 +314,16 @@ public class SimulationPlot {
name += " (" + unit.getUnit() + ")"; name += " (" + unit.getUnit() + ")";
return name; return name;
} }
private void drawDomainMarkers(int stage) { private void drawDomainMarkers(int stage) {
XYPlot plot = chart.getXYPlot(); XYPlot plot = chart.getXYPlot();
FlightDataBranch mainBranch = simulation.getSimulatedData().getBranch(0); FlightDataBranch mainBranch = simulation.getSimulatedData().getBranch(0);
// Clear existing domain markers // Clear existing domain markers
plot.clearDomainMarkers(); plot.clearDomainMarkers();
// Construct domain marker lists collapsing based on time. // Construct domain marker lists collapsing based on time.
List<Double> eventTimes = new ArrayList<Double>(); List<Double> eventTimes = new ArrayList<Double>();
List<String> eventLabels = new ArrayList<String>(); List<String> eventLabels = new ArrayList<String>();
List<Color> eventColors = new ArrayList<Color>(); List<Color> eventColors = new ArrayList<Color>();
@ -316,21 +338,21 @@ public class SimulationPlot {
if (stage >= 0 && stage != info.stage) { if (stage >= 0 && stage != info.stage) {
continue; continue;
} }
double t = info.time; double t = info.time;
FlightEvent.Type type = info.event.getType(); FlightEvent.Type type = info.event.getType();
if (Math.abs(t - prevTime) <= 0.05) { if (Math.abs(t - prevTime) <= 0.05) {
if (!typeSet.contains(type)) { if (!typeSet.contains(type)) {
text = text + ", " + type.toString(); text = text + ", " + type.toString();
color = EventGraphics.getEventColor(type); color = EventGraphics.getEventColor(type);
image = EventGraphics.getEventImage(type); image = EventGraphics.getEventImage(type);
typeSet.add(type); typeSet.add(type);
} }
} else { } else {
if (text != null) { if (text != null) {
eventTimes.add(prevTime); eventTimes.add(prevTime);
eventLabels.add(text); eventLabels.add(text);
@ -344,7 +366,7 @@ public class SimulationPlot {
typeSet.clear(); typeSet.clear();
typeSet.add(type); typeSet.add(type);
} }
} }
if (text != null) { if (text != null) {
eventTimes.add(prevTime); eventTimes.add(prevTime);
@ -353,58 +375,59 @@ public class SimulationPlot {
eventImages.add(image); eventImages.add(image);
} }
} }
// Plot the markers // Plot the markers
if (config.getDomainAxisType() == FlightDataType.TYPE_TIME) { if (config.getDomainAxisType() == FlightDataType.TYPE_TIME) {
// Domain time is plotted as vertical markers // Domain time is plotted as vertical markers
for (int i = 0; i < eventTimes.size(); i++) { for (int i = 0; i < eventTimes.size(); i++) {
double t = eventTimes.get(i); double t = eventTimes.get(i);
String event = eventLabels.get(i); String event = eventLabels.get(i);
Color color = eventColors.get(i); Color color = eventColors.get(i);
ValueMarker m = new ValueMarker(t); ValueMarker m = new ValueMarker(t);
m.setLabel(event); m.setLabel(event);
m.setPaint(color); m.setPaint(color);
m.setLabelPaint(color); m.setLabelPaint(color);
m.setAlpha(0.7f); m.setAlpha(0.7f);
m.setLabelFont(new Font("Dialog", Font.PLAIN, 13));
plot.addDomainMarker(m); plot.addDomainMarker(m);
} }
} else { } else {
// Other domains are plotted as image annotations // Other domains are plotted as image annotations
List<Double> time = mainBranch.get(FlightDataType.TYPE_TIME); List<Double> time = mainBranch.get(FlightDataType.TYPE_TIME);
List<Double> domain = mainBranch.get(config.getDomainAxisType()); List<Double> domain = mainBranch.get(config.getDomainAxisType());
LinearInterpolator domainInterpolator = new LinearInterpolator(time, domain); LinearInterpolator domainInterpolator = new LinearInterpolator(time, domain);
for (int i = 0; i < eventTimes.size(); i++) { for (int i = 0; i < eventTimes.size(); i++) {
double t = eventTimes.get(i); double t = eventTimes.get(i);
String event = eventLabels.get(i); String event = eventLabels.get(i);
Image image = eventImages.get(i); Image image = eventImages.get(i);
if (image == null) if (image == null)
continue; continue;
double xcoord = domainInterpolator.getValue(t); double xcoord = domainInterpolator.getValue(t);
for (int index = 0; index < config.getTypeCount(); index++) { for (int index = 0; index < config.getTypeCount(); index++) {
FlightDataType type = config.getType(index); FlightDataType type = config.getType(index);
List<Double> range = mainBranch.get(type); List<Double> range = mainBranch.get(type);
LinearInterpolator rangeInterpolator = new LinearInterpolator(time, range); LinearInterpolator rangeInterpolator = new LinearInterpolator(time, range);
// Image annotations are not supported on the right-side axis // Image annotations are not supported on the right-side axis
// TODO: LOW: Can this be achieved by JFreeChart? // TODO: LOW: Can this be achieved by JFreeChart?
if (filled.getAxis(index) != SimulationPlotPanel.LEFT) { if (filled.getAxis(index) != SimulationPlotPanel.LEFT) {
continue; continue;
} }
double ycoord = rangeInterpolator.getValue(t); double ycoord = rangeInterpolator.getValue(t);
// Convert units // Convert units
xcoord = config.getDomainAxisUnit().toUnit(xcoord); xcoord = config.getDomainAxisUnit().toUnit(xcoord);
ycoord = config.getUnit(index).toUnit(ycoord); ycoord = config.getUnit(index).toUnit(ycoord);
XYImageAnnotation annotation = XYImageAnnotation annotation =
new XYImageAnnotation(xcoord, ycoord, image, RectangleAnchor.CENTER); new XYImageAnnotation(xcoord, ycoord, image, RectangleAnchor.CENTER);
annotation.setToolTipText(event); annotation.setToolTipText(event);
@ -413,10 +436,10 @@ public class SimulationPlot {
} }
} }
} }
private List<EventDisplayInfo> buildEventInfo() { private List<EventDisplayInfo> buildEventInfo() {
ArrayList<EventDisplayInfo> eventList = new ArrayList<EventDisplayInfo>(); ArrayList<EventDisplayInfo> eventList = new ArrayList<EventDisplayInfo>();
for (int branch = 0; branch < branchCount; branch++) { for (int branch = 0; branch < branchCount; branch++) {
List<FlightEvent> events = simulation.getSimulatedData().getBranch(branch).getEvents(); List<FlightEvent> events = simulation.getSimulatedData().getBranch(branch).getEvents();
for (FlightEvent event : events) { for (FlightEvent event : events) {
@ -430,9 +453,9 @@ public class SimulationPlot {
} }
} }
} }
Collections.sort(eventList, new Comparator<EventDisplayInfo>() { Collections.sort(eventList, new Comparator<EventDisplayInfo>() {
@Override @Override
public int compare(EventDisplayInfo o1, EventDisplayInfo o2) { public int compare(EventDisplayInfo o1, EventDisplayInfo o2) {
if (o1.time < o2.time) if (o1.time < o2.time)
@ -441,20 +464,20 @@ public class SimulationPlot {
return 0; return 0;
return 1; return 1;
} }
}); });
return eventList; return eventList;
} }
private static class LegendItems implements LegendItemSource { private static class LegendItems implements LegendItemSource {
private final List<String> lineLabels = new ArrayList<String>(); private final List<String> lineLabels = new ArrayList<String>();
private final List<Paint> linePaints = new ArrayList<Paint>(); private final List<Paint> linePaints = new ArrayList<Paint>();
private final List<Stroke> lineStrokes = new ArrayList<Stroke>(); private final List<Stroke> lineStrokes = new ArrayList<Stroke>();
private final List<Shape> pointShapes = new ArrayList<Shape>(); private final List<Shape> pointShapes = new ArrayList<Shape>();
@Override @Override
public LegendItemCollection getLegendItems() { public LegendItemCollection getLegendItems() {
LegendItemCollection c = new LegendItemCollection(); LegendItemCollection c = new LegendItemCollection();
@ -474,30 +497,30 @@ public class SimulationPlot {
boolean lineVisible = true; boolean lineVisible = true;
Stroke lineStroke = lineStrokes.get(i); Stroke lineStroke = lineStrokes.get(i);
Paint linePaint = linePaints.get(i); Paint linePaint = linePaints.get(i);
Shape legendLine = new Line2D.Double(-7.0, 0.0, 7.0, 0.0); Shape legendLine = new Line2D.Double(-7.0, 0.0, 7.0, 0.0);
LegendItem result = new LegendItem(label, description, toolTipText, LegendItem result = new LegendItem(label, description, toolTipText,
urlText, shapeIsVisible, shape, shapeIsFilled, fillPaint, urlText, shapeIsVisible, shape, shapeIsFilled, fillPaint,
shapeOutlineVisible, outlinePaint, outlineStroke, lineVisible, shapeOutlineVisible, outlinePaint, outlineStroke, lineVisible,
legendLine, lineStroke, linePaint); legendLine, lineStroke, linePaint);
c.add(result); c.add(result);
i++; i++;
} }
return c; return c;
} }
} }
/** /**
* A modification to the standard renderer that renders the domain marker * A modification to the standard renderer that renders the domain marker
* labels vertically instead of horizontally. * labels vertically instead of horizontally.
* *
* This class is special in that it assumes the data series are added to it * This class is special in that it assumes the data series are added to it
* in a specific order. In particular they must be "by parameter by stage". * in a specific order. In particular they must be "by parameter by stage".
* Assuming that three series are chosen (a, b, c) and the rocket has 2 stages, the * Assuming that three series are chosen (a, b, c) and the rocket has 2 stages, the
* data series are added in this order: * data series are added in this order:
* *
* series a stage 0 * series a stage 0
* series a stage 1 * series a stage 1
* series b stage 0 * series b stage 0
@ -506,68 +529,68 @@ public class SimulationPlot {
* series c stage 1 * series c stage 1
*/ */
private static class ModifiedXYItemRenderer extends XYLineAndShapeRenderer { private static class ModifiedXYItemRenderer extends XYLineAndShapeRenderer {
private final int branchCount; private final int branchCount;
private ModifiedXYItemRenderer(int branchCount) { private ModifiedXYItemRenderer(int branchCount) {
this.branchCount = branchCount; this.branchCount = branchCount;
} }
@Override @Override
public Paint lookupSeriesPaint(int series) { public Paint lookupSeriesPaint(int series) {
return super.lookupSeriesPaint(series / branchCount); return super.lookupSeriesPaint(series / branchCount);
} }
@Override @Override
public Paint lookupSeriesFillPaint(int series) { public Paint lookupSeriesFillPaint(int series) {
return super.lookupSeriesFillPaint(series / branchCount); return super.lookupSeriesFillPaint(series / branchCount);
} }
@Override @Override
public Paint lookupSeriesOutlinePaint(int series) { public Paint lookupSeriesOutlinePaint(int series) {
return super.lookupSeriesOutlinePaint(series / branchCount); return super.lookupSeriesOutlinePaint(series / branchCount);
} }
@Override @Override
public Stroke lookupSeriesStroke(int series) { public Stroke lookupSeriesStroke(int series) {
return super.lookupSeriesStroke(series / branchCount); return super.lookupSeriesStroke(series / branchCount);
} }
@Override @Override
public Stroke lookupSeriesOutlineStroke(int series) { public Stroke lookupSeriesOutlineStroke(int series) {
return super.lookupSeriesOutlineStroke(series / branchCount); return super.lookupSeriesOutlineStroke(series / branchCount);
} }
@Override @Override
public Shape lookupSeriesShape(int series) { public Shape lookupSeriesShape(int series) {
return DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[series % branchCount % DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE.length]; return DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[series % branchCount % DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE.length];
} }
@Override @Override
public Shape lookupLegendShape(int series) { public Shape lookupLegendShape(int series) {
return DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[series % branchCount % DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE.length]; return DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[series % branchCount % DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE.length];
} }
@Override @Override
public Font lookupLegendTextFont(int series) { public Font lookupLegendTextFont(int series) {
return super.lookupLegendTextFont(series / branchCount); return super.lookupLegendTextFont(series / branchCount);
} }
@Override @Override
public Paint lookupLegendTextPaint(int series) { public Paint lookupLegendTextPaint(int series) {
return super.lookupLegendTextPaint(series / branchCount); return super.lookupLegendTextPaint(series / branchCount);
} }
@Override @Override
public void drawDomainMarker(Graphics2D g2, XYPlot plot, ValueAxis domainAxis, public void drawDomainMarker(Graphics2D g2, XYPlot plot, ValueAxis domainAxis,
Marker marker, Rectangle2D dataArea) { Marker marker, Rectangle2D dataArea) {
if (!(marker instanceof ValueMarker)) { if (!(marker instanceof ValueMarker)) {
// Use parent for all others // Use parent for all others
super.drawDomainMarker(g2, plot, domainAxis, marker, dataArea); super.drawDomainMarker(g2, plot, domainAxis, marker, dataArea);
return; return;
} }
/* /*
* Draw the normal marker, but with rotated text. * Draw the normal marker, but with rotated text.
* Copied from the overridden method. * Copied from the overridden method.
@ -578,9 +601,9 @@ public class SimulationPlot {
if (!range.contains(value)) { if (!range.contains(value)) {
return; return;
} }
double v = domainAxis.valueToJava2D(value, dataArea, plot.getDomainAxisEdge()); double v = domainAxis.valueToJava2D(value, dataArea, plot.getDomainAxisEdge());
PlotOrientation orientation = plot.getOrientation(); PlotOrientation orientation = plot.getOrientation();
Line2D line = null; Line2D line = null;
if (orientation == PlotOrientation.HORIZONTAL) { if (orientation == PlotOrientation.HORIZONTAL) {
@ -588,14 +611,14 @@ public class SimulationPlot {
} else { } else {
line = new Line2D.Double(v, dataArea.getMinY(), v, dataArea.getMaxY()); line = new Line2D.Double(v, dataArea.getMinY(), v, dataArea.getMaxY());
} }
final Composite originalComposite = g2.getComposite(); final Composite originalComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, marker g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, marker
.getAlpha())); .getAlpha()));
g2.setPaint(marker.getPaint()); g2.setPaint(marker.getPaint());
g2.setStroke(marker.getStroke()); g2.setStroke(marker.getStroke());
g2.draw(line); g2.draw(line);
String label = marker.getLabel(); String label = marker.getLabel();
RectangleAnchor anchor = marker.getLabelAnchor(); RectangleAnchor anchor = marker.getLabelAnchor();
if (label != null) { if (label != null) {
@ -605,7 +628,7 @@ public class SimulationPlot {
Point2D coordinates = calculateDomainMarkerTextAnchorPoint(g2, Point2D coordinates = calculateDomainMarkerTextAnchorPoint(g2,
orientation, dataArea, line.getBounds2D(), marker orientation, dataArea, line.getBounds2D(), marker
.getLabelOffset(), LengthAdjustmentType.EXPAND, anchor); .getLabelOffset(), LengthAdjustmentType.EXPAND, anchor);
// Changed: // Changed:
TextAnchor textAnchor = TextAnchor.TOP_RIGHT; TextAnchor textAnchor = TextAnchor.TOP_RIGHT;
TextUtilities.drawRotatedString(label, g2, (float) coordinates.getX() + 2, TextUtilities.drawRotatedString(label, g2, (float) coordinates.getX() + 2,
@ -614,24 +637,24 @@ public class SimulationPlot {
} }
g2.setComposite(originalComposite); g2.setComposite(originalComposite);
} }
} }
private static class PresetNumberAxis extends NumberAxis { private static class PresetNumberAxis extends NumberAxis {
private final double min; private final double min;
private final double max; private final double max;
public PresetNumberAxis(double min, double max) { public PresetNumberAxis(double min, double max) {
this.min = min; this.min = min;
this.max = max; this.max = max;
autoAdjustRange(); autoAdjustRange();
} }
@Override @Override
protected void autoAdjustRange() { protected void autoAdjustRange() {
this.setRange(min, max); this.setRange(min, max);
} }
@Override @Override
public void setRange(Range range) { public void setRange(Range range) {
double lowerValue = range.getLowerBound(); double lowerValue = range.getLowerBound();
@ -643,13 +666,14 @@ public class SimulationPlot {
} }
super.setRange(new Range(lowerValue, upperValue)); super.setRange(new Range(lowerValue, upperValue));
} }
} }
private static class EventDisplayInfo { private static class EventDisplayInfo {
int stage; int stage;
double time; double time;
FlightEvent event; FlightEvent event;
} }
} }