Implement clamping in while panning. Don't allow panning past the min
or max.
This commit is contained in:
parent
d9c0f68e64
commit
06e702839f
@ -49,41 +49,41 @@ import org.jfree.ui.RectangleAnchor;
|
||||
import org.jfree.ui.TextAnchor;
|
||||
|
||||
public class SimulationPlot {
|
||||
|
||||
|
||||
private static final float PLOT_STROKE_WIDTH = 1.5f;
|
||||
|
||||
|
||||
private final JFreeChart chart;
|
||||
|
||||
|
||||
private final PlotConfiguration config;
|
||||
private final Simulation simulation;
|
||||
private final PlotConfiguration filled;
|
||||
|
||||
private final List<EventDisplayInfo> eventList;
|
||||
private final List<ModifiedXYItemRenderer> renderers = new ArrayList<ModifiedXYItemRenderer>();
|
||||
|
||||
private final List<ModifiedXYItemRenderer> renderers = new ArrayList<ModifiedXYItemRenderer>();
|
||||
|
||||
int branchCount;
|
||||
|
||||
void setShowPoints( boolean showPoints ) {
|
||||
|
||||
void setShowPoints(boolean showPoints) {
|
||||
for (ModifiedXYItemRenderer r : renderers) {
|
||||
r.setBaseShapesVisible(showPoints);
|
||||
}
|
||||
}
|
||||
|
||||
void setShowBranch( int branch ) {
|
||||
|
||||
void setShowBranch(int branch) {
|
||||
XYPlot plot = (XYPlot) chart.getPlot();
|
||||
int datasetcount = plot.getDatasetCount();
|
||||
for( int i =0; i< datasetcount; i++ ) {
|
||||
int seriescount = ((XYSeriesCollection)plot.getDataset(i)).getSeriesCount();
|
||||
XYItemRenderer r = ((XYPlot)chart.getPlot()).getRenderer(i);
|
||||
for( int j=0; j<seriescount; j++) {
|
||||
boolean show = (branch<0) || (j % branchCount == branch);
|
||||
for (int i = 0; i < datasetcount; i++) {
|
||||
int seriescount = ((XYSeriesCollection) plot.getDataset(i)).getSeriesCount();
|
||||
XYItemRenderer r = ((XYPlot) chart.getPlot()).getRenderer(i);
|
||||
for (int j = 0; j < seriescount; j++) {
|
||||
boolean show = (branch < 0) || (j % branchCount == branch);
|
||||
r.setSeriesVisible(j, show);
|
||||
}
|
||||
}
|
||||
drawDomainMarkers(branch);
|
||||
}
|
||||
|
||||
SimulationPlot( Simulation simulation, PlotConfiguration config, boolean initialShowPoints ) {
|
||||
|
||||
SimulationPlot(Simulation simulation, PlotConfiguration config, boolean initialShowPoints) {
|
||||
this.simulation = simulation;
|
||||
this.config = config;
|
||||
|
||||
@ -98,31 +98,31 @@ public class SimulationPlot {
|
||||
true,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
chart.addSubtitle(new TextTitle(config.getName()));
|
||||
|
||||
|
||||
this.branchCount = simulation.getSimulatedData().getBranchCount();
|
||||
|
||||
|
||||
// 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);
|
||||
List<Axis> axes = filled.getAllAxes();
|
||||
|
||||
|
||||
// Create the data series for both axes
|
||||
XYSeriesCollection[] data = new XYSeriesCollection[2];
|
||||
data[0] = new XYSeriesCollection();
|
||||
data[1] = new XYSeriesCollection();
|
||||
|
||||
|
||||
// Get the domain axis type
|
||||
final FlightDataType domainType = filled.getDomainAxisType();
|
||||
final Unit domainUnit = filled.getDomainAxisUnit();
|
||||
if (domainType == null) {
|
||||
throw new IllegalArgumentException("Domain axis type not specified.");
|
||||
}
|
||||
|
||||
|
||||
// Get plot length (ignore trailing NaN's)
|
||||
int typeCount = filled.getTypeCount();
|
||||
|
||||
|
||||
// Create the XYSeries objects from the flight data and store into the collections
|
||||
String[] axisLabel = new String[2];
|
||||
for (int i = 0; i < typeCount; i++) {
|
||||
@ -131,34 +131,34 @@ public class SimulationPlot {
|
||||
Unit unit = filled.getUnit(i);
|
||||
int axis = filled.getAxis(i);
|
||||
String name = getLabel(type, unit);
|
||||
|
||||
|
||||
List<String> seriesNames = Util.generateSeriesLabels(simulation);
|
||||
for( int branchIndex=0; branchIndex<branchCount; branchIndex++ ) {
|
||||
for (int branchIndex = 0; branchIndex < branchCount; branchIndex++) {
|
||||
FlightDataBranch thisBranch = simulation.getSimulatedData().getBranch(branchIndex);
|
||||
// Store data in provided units
|
||||
List<Double> plotx = thisBranch.get(domainType);
|
||||
List<Double> ploty = thisBranch.get(type);
|
||||
XYSeries series = new XYSeries(seriesNames.get(branchIndex) + ": " + name, false, true);
|
||||
series.setDescription(thisBranch.getBranchName()+": " + name);
|
||||
series.setDescription(thisBranch.getBranchName() + ": " + name);
|
||||
int pointCount = plotx.size();
|
||||
for (int j = 0; j < pointCount; j++) {
|
||||
series.add(domainUnit.toUnit(plotx.get(j)), unit.toUnit(ploty.get(j)));
|
||||
}
|
||||
data[axis].addSeries(series);
|
||||
}
|
||||
|
||||
|
||||
// Update axis label
|
||||
if (axisLabel[axis] == null)
|
||||
axisLabel[axis] = type.getName();
|
||||
else
|
||||
axisLabel[axis] += "; " + type.getName();
|
||||
}
|
||||
|
||||
|
||||
// Add the data and formatting to the plot
|
||||
XYPlot plot = chart.getXYPlot();
|
||||
plot.setDomainPannable(true);
|
||||
plot.setRangePannable(true);
|
||||
|
||||
|
||||
int axisno = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// Check whether axis has any data
|
||||
@ -170,7 +170,12 @@ public class SimulationPlot {
|
||||
axis.setLabel(axisLabel[i]);
|
||||
// axis.setRange(axes.get(i).getMinValue(), axes.get(i).getMaxValue());
|
||||
plot.setRangeAxis(axisno, axis);
|
||||
|
||||
|
||||
double domainMin = data[i].getDomainLowerBound(true);
|
||||
double domainMax = data[i].getDomainUpperBound(true);
|
||||
|
||||
plot.setDomainAxis(new PresetNumberAxis(domainMin, domainMax));
|
||||
|
||||
// Add data and map to the axis
|
||||
plot.setDataset(axisno, data[i]);
|
||||
ModifiedXYItemRenderer r = new ModifiedXYItemRenderer(branchCount);
|
||||
@ -185,25 +190,25 @@ public class SimulationPlot {
|
||||
axisno++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
plot.getDomainAxis().setLabel(getLabel(domainType, domainUnit));
|
||||
plot.addDomainMarker(new ValueMarker(0));
|
||||
plot.addRangeMarker(new ValueMarker(0));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Create list of events to show (combine event too close to each other)
|
||||
this.eventList = buildEventInfo();
|
||||
|
||||
|
||||
// Create the event markers
|
||||
drawDomainMarkers(-1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
JFreeChart getJFreeChart() {
|
||||
return chart;
|
||||
}
|
||||
|
||||
|
||||
private String getLabel(FlightDataType type, Unit unit) {
|
||||
String name = type.getName();
|
||||
if (unit != null && !UnitGroup.UNITS_NONE.contains(unit) &&
|
||||
@ -211,16 +216,16 @@ public class SimulationPlot {
|
||||
name += " (" + unit.getUnit() + ")";
|
||||
return name;
|
||||
}
|
||||
|
||||
private void drawDomainMarkers( int stage ) {
|
||||
|
||||
private void drawDomainMarkers(int stage) {
|
||||
XYPlot plot = chart.getXYPlot();
|
||||
FlightDataBranch mainBranch = simulation.getSimulatedData().getBranch( 0 );
|
||||
FlightDataBranch mainBranch = simulation.getSimulatedData().getBranch(0);
|
||||
|
||||
// Clear existing domain markers
|
||||
plot.clearDomainMarkers();
|
||||
|
||||
// Construct domain marker lists collapsing based on time.
|
||||
|
||||
|
||||
List<Double> eventTimes = new ArrayList<Double>();
|
||||
List<String> eventLabels = new ArrayList<String>();
|
||||
List<Color> eventColors = new ArrayList<Color>();
|
||||
@ -231,25 +236,25 @@ public class SimulationPlot {
|
||||
String text = null;
|
||||
Color color = null;
|
||||
Image image = null;
|
||||
for( EventDisplayInfo info : eventList ) {
|
||||
if ( stage >=0 && stage != info.stage ) {
|
||||
for (EventDisplayInfo info : eventList) {
|
||||
if (stage >= 0 && stage != info.stage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double t = info.time;
|
||||
FlightEvent.Type type = info.event.getType();
|
||||
|
||||
|
||||
if (Math.abs(t - prevTime) <= 0.05) {
|
||||
|
||||
|
||||
if (!typeSet.contains(type)) {
|
||||
text = text + ", " + type.toString();
|
||||
color = EventGraphics.getEventColor(type);
|
||||
image = EventGraphics.getEventImage(type);
|
||||
typeSet.add(type);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if (text != null) {
|
||||
eventTimes.add(prevTime);
|
||||
eventLabels.add(text);
|
||||
@ -263,7 +268,7 @@ public class SimulationPlot {
|
||||
typeSet.clear();
|
||||
typeSet.add(type);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (text != null) {
|
||||
eventTimes.add(prevTime);
|
||||
@ -275,13 +280,13 @@ public class SimulationPlot {
|
||||
|
||||
// Plot the markers
|
||||
if (config.getDomainAxisType() == FlightDataType.TYPE_TIME) {
|
||||
|
||||
|
||||
// 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);
|
||||
String event = eventLabels.get(i);
|
||||
Color color = eventColors.get(i);
|
||||
|
||||
|
||||
ValueMarker m = new ValueMarker(t);
|
||||
m.setLabel(event);
|
||||
m.setPaint(color);
|
||||
@ -289,41 +294,41 @@ public class SimulationPlot {
|
||||
m.setAlpha(0.7f);
|
||||
plot.addDomainMarker(m);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
// Other domains are plotted as image annotations
|
||||
List<Double> time = mainBranch.get(FlightDataType.TYPE_TIME);
|
||||
List<Double> domain = mainBranch.get(config.getDomainAxisType());
|
||||
|
||||
LinearInterpolator domainInterpolator = new LinearInterpolator( time, domain );
|
||||
|
||||
for ( int i=0; i<eventTimes.size(); i++ ) {
|
||||
|
||||
LinearInterpolator domainInterpolator = new LinearInterpolator(time, domain);
|
||||
|
||||
for (int i = 0; i < eventTimes.size(); i++) {
|
||||
double t = eventTimes.get(i);
|
||||
String event = eventLabels.get(i);
|
||||
Image image = eventImages.get(i);
|
||||
|
||||
|
||||
if (image == null)
|
||||
continue;
|
||||
|
||||
|
||||
double xcoord = domainInterpolator.getValue(t);
|
||||
for (int index = 0; index < config.getTypeCount(); index++) {
|
||||
FlightDataType type = config.getType(index);
|
||||
List<Double> range = mainBranch.get(type);
|
||||
|
||||
|
||||
LinearInterpolator rangeInterpolator = new LinearInterpolator(time, range);
|
||||
// Image annotations are not supported on the right-side axis
|
||||
// TODO: LOW: Can this be achieved by JFreeChart?
|
||||
if (filled.getAxis(index) != SimulationPlotPanel.LEFT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
double ycoord = rangeInterpolator.getValue(t);
|
||||
|
||||
|
||||
// Convert units
|
||||
xcoord = config.getDomainAxisUnit().toUnit(xcoord);
|
||||
ycoord = config.getUnit(index).toUnit(ycoord);
|
||||
|
||||
|
||||
XYImageAnnotation annotation =
|
||||
new XYImageAnnotation(xcoord, ycoord, image, RectangleAnchor.CENTER);
|
||||
annotation.setToolTipText(event);
|
||||
@ -335,12 +340,12 @@ public class SimulationPlot {
|
||||
|
||||
private List<EventDisplayInfo> buildEventInfo() {
|
||||
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();
|
||||
for( FlightEvent event : events ) {
|
||||
for (FlightEvent event : events) {
|
||||
FlightEvent.Type type = event.getType();
|
||||
if ( type != FlightEvent.Type.ALTITUDE && config.isEventActive(type)) {
|
||||
if (type != FlightEvent.Type.ALTITUDE && config.isEventActive(type)) {
|
||||
EventDisplayInfo info = new EventDisplayInfo();
|
||||
info.stage = branch;
|
||||
info.time = event.getTime();
|
||||
@ -351,11 +356,13 @@ public class SimulationPlot {
|
||||
}
|
||||
|
||||
Collections.sort(eventList, new Comparator<EventDisplayInfo>() {
|
||||
|
||||
|
||||
@Override
|
||||
public int compare(EventDisplayInfo o1, EventDisplayInfo o2) {
|
||||
if ( o1.time< o2.time) return -1;
|
||||
if ( o1.time == o2.time)return 0;
|
||||
if (o1.time < o2.time)
|
||||
return -1;
|
||||
if (o1.time == o2.time)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -363,61 +370,8 @@ public class SimulationPlot {
|
||||
|
||||
return eventList;
|
||||
|
||||
/*
|
||||
double prevTime = -100;
|
||||
String text = null;
|
||||
Color color = null;
|
||||
Image image = null;
|
||||
for ( int branch=0; branch<branchCount; branch++ ) {
|
||||
List<FlightEvent> events = simulation.getSimulatedData().getBranch(branch).getEvents();
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
FlightEvent event = events.get(i);
|
||||
double t = event.getTime();
|
||||
FlightEvent.Type type = event.getType();
|
||||
|
||||
if (type != FlightEvent.Type.ALTITUDE && config.isEventActive(type)) {
|
||||
if (Math.abs(t - prevTime) <= 0.05) {
|
||||
|
||||
if (!typeSet.contains(type)) {
|
||||
text = text + ", " + type.toString();
|
||||
color = EventGraphics.getEventColor(type);
|
||||
image = EventGraphics.getEventImage(type);
|
||||
typeSet.add(type);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (text != null) {
|
||||
EventDisplayInfo info = new EventDisplayInfo();
|
||||
info.time = prevTime;
|
||||
info.event = text;
|
||||
info.color = color;
|
||||
info.image = image;
|
||||
eventList.add(info);
|
||||
}
|
||||
prevTime = t;
|
||||
text = type.toString();
|
||||
color = EventGraphics.getEventColor(type);
|
||||
image = EventGraphics.getEventImage(type);
|
||||
typeSet.clear();
|
||||
typeSet.add(type);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (text != null) {
|
||||
EventDisplayInfo info = new EventDisplayInfo();
|
||||
info.time = prevTime;
|
||||
info.event = text;
|
||||
info.color = color;
|
||||
info.image = image;
|
||||
eventList.add(info);
|
||||
}
|
||||
return eventList;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A modification to the standard renderer that renders the domain marker
|
||||
* labels vertically instead of horizontally.
|
||||
@ -435,68 +389,68 @@ public class SimulationPlot {
|
||||
* series c stage 1
|
||||
*/
|
||||
private static class ModifiedXYItemRenderer extends XYLineAndShapeRenderer {
|
||||
|
||||
|
||||
private final int branchCount;
|
||||
|
||||
private ModifiedXYItemRenderer( int branchCount ) {
|
||||
|
||||
private ModifiedXYItemRenderer(int branchCount) {
|
||||
this.branchCount = branchCount;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Paint lookupSeriesPaint(int series) {
|
||||
return super.lookupSeriesPaint(series/branchCount);
|
||||
return super.lookupSeriesPaint(series / branchCount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Paint lookupSeriesFillPaint(int series) {
|
||||
return super.lookupSeriesFillPaint(series/branchCount);
|
||||
return super.lookupSeriesFillPaint(series / branchCount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Paint lookupSeriesOutlinePaint(int series) {
|
||||
return super.lookupSeriesOutlinePaint(series/branchCount);
|
||||
return super.lookupSeriesOutlinePaint(series / branchCount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Stroke lookupSeriesStroke(int series) {
|
||||
return super.lookupSeriesStroke(series/branchCount);
|
||||
return super.lookupSeriesStroke(series / branchCount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Stroke lookupSeriesOutlineStroke(int series) {
|
||||
return super.lookupSeriesOutlineStroke(series/branchCount);
|
||||
return super.lookupSeriesOutlineStroke(series / branchCount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
public Font lookupLegendTextFont(int series) {
|
||||
return super.lookupLegendTextFont(series/branchCount);
|
||||
return super.lookupLegendTextFont(series / branchCount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Paint lookupLegendTextPaint(int series) {
|
||||
return super.lookupLegendTextPaint(series/branchCount);
|
||||
return super.lookupLegendTextPaint(series / branchCount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void drawDomainMarker(Graphics2D g2, XYPlot plot, ValueAxis domainAxis,
|
||||
Marker marker, Rectangle2D dataArea) {
|
||||
|
||||
|
||||
if (!(marker instanceof ValueMarker)) {
|
||||
// Use parent for all others
|
||||
super.drawDomainMarker(g2, plot, domainAxis, marker, dataArea);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Draw the normal marker, but with rotated text.
|
||||
* Copied from the overridden method.
|
||||
@ -507,9 +461,9 @@ public class SimulationPlot {
|
||||
if (!range.contains(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
double v = domainAxis.valueToJava2D(value, dataArea, plot.getDomainAxisEdge());
|
||||
|
||||
|
||||
PlotOrientation orientation = plot.getOrientation();
|
||||
Line2D line = null;
|
||||
if (orientation == PlotOrientation.HORIZONTAL) {
|
||||
@ -517,14 +471,14 @@ public class SimulationPlot {
|
||||
} else {
|
||||
line = new Line2D.Double(v, dataArea.getMinY(), v, dataArea.getMaxY());
|
||||
}
|
||||
|
||||
|
||||
final Composite originalComposite = g2.getComposite();
|
||||
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, marker
|
||||
.getAlpha()));
|
||||
g2.setPaint(marker.getPaint());
|
||||
g2.setStroke(marker.getStroke());
|
||||
g2.draw(line);
|
||||
|
||||
|
||||
String label = marker.getLabel();
|
||||
RectangleAnchor anchor = marker.getLabelAnchor();
|
||||
if (label != null) {
|
||||
@ -533,8 +487,8 @@ public class SimulationPlot {
|
||||
g2.setPaint(marker.getLabelPaint());
|
||||
Point2D coordinates = calculateDomainMarkerTextAnchorPoint(g2,
|
||||
orientation, dataArea, line.getBounds2D(), marker
|
||||
.getLabelOffset(), LengthAdjustmentType.EXPAND, anchor);
|
||||
|
||||
.getLabelOffset(), LengthAdjustmentType.EXPAND, anchor);
|
||||
|
||||
// Changed:
|
||||
TextAnchor textAnchor = TextAnchor.TOP_RIGHT;
|
||||
TextUtilities.drawRotatedString(label, g2, (float) coordinates.getX() + 2,
|
||||
@ -543,29 +497,42 @@ public class SimulationPlot {
|
||||
}
|
||||
g2.setComposite(originalComposite);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class PresetNumberAxis extends NumberAxis {
|
||||
private final double min;
|
||||
private final double max;
|
||||
|
||||
|
||||
public PresetNumberAxis(double min, double max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
autoAdjustRange();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void autoAdjustRange() {
|
||||
this.setRange(min, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRange(Range range) {
|
||||
double lowerValue = range.getLowerBound();
|
||||
double upperValue = range.getUpperBound();
|
||||
if (lowerValue < min || upperValue > max) {
|
||||
// Don't blow past the min & max of the range this is important to keep
|
||||
// panning constrained within the current bounds.
|
||||
return;
|
||||
}
|
||||
super.setRange(new Range(lowerValue, upperValue));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class EventDisplayInfo {
|
||||
int stage;
|
||||
double time;
|
||||
FlightEvent event;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user