Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/jfree/StableXYDifferenceRenderer.java @ 9182:77eb4553245b
Fixed: waterlevels could not show a band any more
Correctly implemented 'showarea' on area themes now
author | gernotbelger |
---|---|
date | Tue, 26 Jun 2018 20:19:16 +0200 |
parents | d9c89651bd67 |
children | eec4df8165a1 |
comparison
equal
deleted
inserted
replaced
9181:5dacb6ea75a1 | 9182:77eb4553245b |
---|---|
85 */ | 85 */ |
86 package org.dive4elements.river.jfree; | 86 package org.dive4elements.river.jfree; |
87 | 87 |
88 import java.awt.BasicStroke; | 88 import java.awt.BasicStroke; |
89 import java.awt.Color; | 89 import java.awt.Color; |
90 import java.awt.Font; | |
90 import java.awt.Graphics2D; | 91 import java.awt.Graphics2D; |
91 import java.awt.Font; | |
92 import java.awt.Paint; | 92 import java.awt.Paint; |
93 import java.awt.geom.Point2D; | |
94 import java.awt.Shape; | 93 import java.awt.Shape; |
95 import java.awt.Stroke; | 94 import java.awt.Stroke; |
96 import java.awt.geom.GeneralPath; | 95 import java.awt.geom.GeneralPath; |
97 import java.awt.geom.Line2D; | 96 import java.awt.geom.Line2D; |
97 import java.awt.geom.Point2D; | |
98 import java.awt.geom.Rectangle2D; | 98 import java.awt.geom.Rectangle2D; |
99 import java.io.IOException; | 99 import java.io.IOException; |
100 import java.io.ObjectInputStream; | 100 import java.io.ObjectInputStream; |
101 import java.io.ObjectOutputStream; | 101 import java.io.ObjectOutputStream; |
102 import java.text.NumberFormat; | |
102 import java.util.ArrayList; | 103 import java.util.ArrayList; |
103 import java.util.Collections; | 104 import java.util.Collections; |
104 import java.util.LinkedList; | 105 import java.util.LinkedList; |
105 import java.util.List; | 106 import java.util.List; |
106 | 107 |
108 import org.apache.log4j.Logger; | |
109 import org.dive4elements.river.artifacts.math.Linear; | |
107 import org.jfree.chart.LegendItem; | 110 import org.jfree.chart.LegendItem; |
108 import org.jfree.chart.axis.ValueAxis; | 111 import org.jfree.chart.axis.ValueAxis; |
109 import org.jfree.chart.entity.EntityCollection; | 112 import org.jfree.chart.entity.EntityCollection; |
110 import org.jfree.chart.entity.XYItemEntity; | 113 import org.jfree.chart.entity.XYItemEntity; |
111 import org.jfree.chart.event.RendererChangeEvent; | 114 import org.jfree.chart.event.RendererChangeEvent; |
112 import org.jfree.chart.labels.XYToolTipGenerator; | 115 import org.jfree.chart.labels.XYToolTipGenerator; |
113 import org.jfree.chart.plot.CrosshairState; | 116 import org.jfree.chart.plot.CrosshairState; |
114 import org.jfree.chart.plot.PlotOrientation; | 117 import org.jfree.chart.plot.PlotOrientation; |
115 import org.jfree.chart.plot.PlotRenderingInfo; | 118 import org.jfree.chart.plot.PlotRenderingInfo; |
116 import org.jfree.chart.plot.XYPlot; | 119 import org.jfree.chart.plot.XYPlot; |
120 import org.jfree.chart.renderer.xy.AbstractXYItemRenderer; | |
121 import org.jfree.chart.renderer.xy.XYItemRendererState; | |
117 import org.jfree.chart.urls.XYURLGenerator; | 122 import org.jfree.chart.urls.XYURLGenerator; |
123 import org.jfree.data.xy.DefaultXYDataset; | |
118 import org.jfree.data.xy.XYDataset; | 124 import org.jfree.data.xy.XYDataset; |
119 import org.jfree.data.xy.DefaultXYDataset; | |
120 import org.jfree.io.SerialUtilities; | 125 import org.jfree.io.SerialUtilities; |
121 import org.jfree.ui.RectangleEdge; | 126 import org.jfree.ui.RectangleEdge; |
122 import org.jfree.util.PaintUtilities; | 127 import org.jfree.util.PaintUtilities; |
123 import org.jfree.util.PublicCloneable; | 128 import org.jfree.util.PublicCloneable; |
124 import org.jfree.util.ShapeUtilities; | 129 import org.jfree.util.ShapeUtilities; |
125 | 130 |
126 import org.jfree.chart.renderer.xy.AbstractXYItemRenderer; | |
127 import org.jfree.chart.renderer.xy.XYItemRenderer; | |
128 import org.jfree.chart.renderer.xy.XYItemRendererState; | |
129 | |
130 import gnu.trove.TDoubleArrayList; | 131 import gnu.trove.TDoubleArrayList; |
131 | |
132 import org.dive4elements.river.artifacts.math.Linear; | |
133 | |
134 import java.text.NumberFormat; | |
135 | |
136 import org.apache.log4j.Logger; | |
137 | 132 |
138 /** | 133 /** |
139 * A renderer for an {@link XYPlot} that highlights the differences between two | 134 * A renderer for an {@link XYPlot} that highlights the differences between two |
140 * series. The example shown here is generated by the | 135 * series. The example shown here is generated by the |
141 * <code>DifferenceChartDemo1.java</code> program included in the JFreeChart | 136 * <code>DifferenceChartDemo1.java</code> program included in the JFreeChart |
142 * demo collection: | 137 * demo collection: |
143 * <br><br> | 138 * <br> |
139 * <br> | |
144 * <img src="../../../../../images/StableXYDifferenceRendererSample.png" | 140 * <img src="../../../../../images/StableXYDifferenceRendererSample.png" |
145 * alt="StableXYDifferenceRendererSample.png" /> | 141 * alt="StableXYDifferenceRendererSample.png" /> |
146 */ | 142 */ |
147 public class StableXYDifferenceRenderer extends AbstractXYItemRenderer | 143 public class StableXYDifferenceRenderer extends AbstractXYItemRenderer implements PublicCloneable { |
148 implements XYItemRenderer, PublicCloneable { | 144 |
149 | 145 private static Logger log = Logger.getLogger(StableXYDifferenceRenderer.class); |
150 private static Logger log = Logger.getLogger( | |
151 StableXYDifferenceRenderer.class); | |
152 | 146 |
153 public static final int CALCULATE_POSITIVE_AREA = 1; | 147 public static final int CALCULATE_POSITIVE_AREA = 1; |
154 public static final int CALCULATE_NEGATIVE_AREA = 2; | 148 public static final int CALCULATE_NEGATIVE_AREA = 2; |
155 public static final int CALCULATE_ALL_AREA = | 149 public static final int CALCULATE_ALL_AREA = CALCULATE_POSITIVE_AREA | CALCULATE_NEGATIVE_AREA; |
156 CALCULATE_POSITIVE_AREA | CALCULATE_NEGATIVE_AREA; | |
157 | 150 |
158 /** For serialization. */ | 151 /** For serialization. */ |
159 private static final long serialVersionUID = -8447915602375584857L; | 152 private static final long serialVersionUID = -8447915602375584857L; |
160 | 153 |
154 private boolean drawArea = true; | |
155 | |
161 /** The paint used to highlight positive differences (y(0) > y(1)). */ | 156 /** The paint used to highlight positive differences (y(0) > y(1)). */ |
162 private transient Paint positivePaint; | 157 private transient Paint positivePaint; |
163 | 158 |
164 /** The paint used to highlight negative differences (y(0) < y(1)). */ | 159 /** The paint used to highlight negative differences (y(0) < y(1)). */ |
165 private transient Paint negativePaint; | 160 private transient Paint negativePaint; |
166 | 161 |
167 /** Display shapes at each point? */ | 162 /** Display shapes at each point? */ |
168 private boolean shapesVisible; | 163 private boolean shapesVisible; |
169 | 164 |
170 /** Display shapes at each point? */ | 165 /** Display shapes at each point? */ |
171 protected boolean drawOutline; | 166 private boolean drawOutline; |
172 | 167 |
173 /** Which stroke to draw outline with? */ | 168 /** Which stroke to draw outline with? */ |
174 protected Stroke outlineStroke; | 169 private Stroke outlineStroke; |
175 | 170 |
176 /** Which paint to draw outline with? */ | 171 /** Which paint to draw outline with? */ |
177 protected Paint outlinePaint; | 172 private Paint outlinePaint; |
178 | 173 |
179 /** The shape to display in the legend item. */ | 174 /** The shape to display in the legend item. */ |
180 private transient Shape legendShape; | 175 private transient Shape legendShape; |
181 | 176 |
182 protected boolean drawOriginalSeries; | 177 private final boolean drawOriginalSeries; |
183 | 178 |
184 /** The color of the label showing the calculated area. */ | 179 /** The color of the label showing the calculated area. */ |
185 protected Color labelColor; | 180 private Color labelColor; |
186 | 181 |
187 /** The background color of the label showing the calculated area. */ | 182 /** The background color of the label showing the calculated area. */ |
188 protected Color labelBGColor; | 183 private Color labelBGColor; |
189 | 184 |
190 /** Font to draw label of calculated area with. */ | 185 /** Font to draw label of calculated area with. */ |
191 protected Font labelFont; | 186 private Font labelFont; |
192 | 187 |
193 /** Template to create i18ned label for area. */ | 188 /** Template to create i18ned label for area. */ |
194 protected String areaLabelTamplate; | 189 private String areaLabelTamplate; |
195 | 190 |
196 /** NumberFormat to use for area. */ | 191 /** NumberFormat to use for area. */ |
197 protected NumberFormat areaLabelNumberFormat; | 192 private NumberFormat areaLabelNumberFormat; |
198 | 193 |
199 protected int areaCalculationMode; | 194 private int areaCalculationMode; |
200 | 195 |
201 protected double positiveArea; | 196 private double positiveArea; |
202 protected double negativeArea; | 197 |
198 private double negativeArea; | |
203 | 199 |
204 /** Whether or not to draw a label in the area. */ | 200 /** Whether or not to draw a label in the area. */ |
205 protected boolean labelArea = true; | 201 private boolean labelArea = true; |
206 | |
207 | 202 |
208 /** Arithmetic centroid of drawn polygons. */ | 203 /** Arithmetic centroid of drawn polygons. */ |
209 protected Point2D.Double centroid; | 204 private Point2D.Double centroid; |
210 | |
211 | 205 |
212 /** Number of points that contributed to the centroid. */ | 206 /** Number of points that contributed to the centroid. */ |
213 protected int centroidNPoints = 0; | 207 private int centroidNPoints = 0; |
214 | |
215 | 208 |
216 /** | 209 /** |
217 * This flag controls whether or not the x-coordinates (in Java2D space) | 210 * This flag controls whether or not the x-coordinates (in Java2D space) |
218 * are rounded to integers. When set to true, this can avoid the vertical | 211 * are rounded to integers. When set to true, this can avoid the vertical |
219 * striping that anti-aliasing can generate. However, the rounding may not | 212 * striping that anti-aliasing can generate. However, the rounding may not |
220 * be appropriate for output in high resolution formats (for example, | 213 * be appropriate for output in high resolution formats (for example, |
221 * vector graphics formats such as SVG and PDF). | 214 * vector graphics formats such as SVG and PDF). |
222 * | 215 * |
223 * @since 1.0.4 | 216 * @since 1.0.4 |
224 */ | 217 */ |
225 private boolean roundXCoordinates; | 218 private final boolean roundXCoordinates; |
226 | 219 |
227 /** | 220 /** |
228 * Creates a new renderer with default attributes. | 221 * Creates a new renderer with default attributes. |
229 */ | 222 */ |
230 public StableXYDifferenceRenderer() { | 223 public StableXYDifferenceRenderer() { |
231 this(Color.green, Color.red, false /*, null */); | 224 this(Color.green, Color.red, false, CALCULATE_ALL_AREA); |
232 } | |
233 | |
234 public StableXYDifferenceRenderer(Paint positivePaint, Paint negativePaint, | |
235 boolean shapes) { | |
236 this(positivePaint, negativePaint, shapes, CALCULATE_ALL_AREA); | |
237 } | 225 } |
238 | 226 |
239 /** | 227 /** |
240 * Creates a new renderer. | 228 * Creates a new renderer. |
241 * | 229 * |
242 * @param positivePaint the highlight color for positive differences | 230 * @param positivePaint |
243 * (<code>null</code> not permitted). | 231 * the highlight color for positive differences |
244 * @param negativePaint the highlight color for negative differences | 232 * (<code>null</code> not permitted). |
245 * (<code>null</code> not permitted). | 233 * @param negativePaint |
246 * @param shapes draw shapes? | 234 * the highlight color for negative differences |
247 */ | 235 * (<code>null</code> not permitted). |
248 public StableXYDifferenceRenderer(Paint positivePaint, Paint negativePaint, | 236 * @param shapes |
249 boolean shapes, int areaCalculationMode) { | 237 * draw shapes? |
238 */ | |
239 private StableXYDifferenceRenderer(final Paint positivePaint, final Paint negativePaint, final boolean shapes, final int areaCalculationMode) { | |
250 if (positivePaint == null) { | 240 if (positivePaint == null) { |
251 throw new IllegalArgumentException( | 241 throw new IllegalArgumentException("Null 'positivePaint' argument."); |
252 "Null 'positivePaint' argument."); | |
253 } | 242 } |
254 if (negativePaint == null) { | 243 if (negativePaint == null) { |
255 throw new IllegalArgumentException( | 244 throw new IllegalArgumentException("Null 'negativePaint' argument."); |
256 "Null 'negativePaint' argument."); | |
257 } | 245 } |
258 this.positivePaint = positivePaint; | 246 this.positivePaint = positivePaint; |
259 this.negativePaint = negativePaint; | 247 this.negativePaint = negativePaint; |
260 this.shapesVisible = shapes; | 248 this.shapesVisible = shapes; |
261 this.legendShape = new Rectangle2D.Double(-3.0, -3.0, 10.0, 10.0); | 249 this.legendShape = new Rectangle2D.Double(-3.0, -3.0, 10.0, 10.0); |
262 this.roundXCoordinates = false; | 250 this.roundXCoordinates = false; |
263 this.drawOutline = true; | 251 this.drawOutline = true; |
264 this.outlineStroke = new BasicStroke(1); | 252 this.outlineStroke = new BasicStroke(1); |
265 this.outlinePaint = Color.black; | 253 this.outlinePaint = Color.black; |
266 this.drawOriginalSeries = false; | 254 this.drawOriginalSeries = false; |
267 this.areaCalculationMode = areaCalculationMode; | 255 this.areaCalculationMode = areaCalculationMode; |
268 this.labelBGColor = null; | 256 this.labelBGColor = null; |
269 this.centroid = new Point2D.Double(0,0); | 257 this.centroid = new Point2D.Double(0, 0); |
270 } | 258 } |
271 | 259 |
272 public int getAreaCalculationMode() { | 260 public void setAreaCalculationMode(final int areaCalculationMode) { |
273 return areaCalculationMode; | |
274 } | |
275 | |
276 public void setAreaCalculationMode(int areaCalculationMode) { | |
277 this.areaCalculationMode = areaCalculationMode; | 261 this.areaCalculationMode = areaCalculationMode; |
278 } | 262 } |
279 | 263 |
280 | |
281 /** Set template to use to create area label (e.g. 'Area=%dm2'). */ | 264 /** Set template to use to create area label (e.g. 'Area=%dm2'). */ |
282 public void setAreaLabelTemplate(String areaTemplate) { | 265 public void setAreaLabelTemplate(final String areaTemplate) { |
283 this.areaLabelTamplate = areaTemplate; | 266 this.areaLabelTamplate = areaTemplate; |
284 } | 267 } |
285 | 268 |
286 | 269 public void setAreaLabelNumberFormat(final NumberFormat nf) { |
287 public void setAreaLabelNumberFormat(NumberFormat nf) { | |
288 this.areaLabelNumberFormat = nf; | 270 this.areaLabelNumberFormat = nf; |
289 } | 271 } |
290 | 272 |
291 | 273 public void setLabelArea(final boolean label) { |
292 public boolean isLabelArea() { | |
293 return this.labelArea; | |
294 } | |
295 | |
296 public void setLabelArea(boolean label) { | |
297 this.labelArea = label; | 274 this.labelArea = label; |
298 } | 275 } |
299 | 276 |
300 | |
301 /** Set font to paint label with. */ | 277 /** Set font to paint label with. */ |
302 public void setLabelFont(Font font) { | 278 public void setLabelFont(final Font font) { |
303 this.labelFont = font; | 279 this.labelFont = font; |
304 } | 280 } |
305 | 281 |
306 | |
307 /** Get font with which label is painted. */ | |
308 public Font getLabelFont() { | |
309 return this.labelFont; | |
310 } | |
311 | |
312 | |
313 /** Set color with which to paint label. */ | 282 /** Set color with which to paint label. */ |
314 public void setLabelColor(Color color) { | 283 public void setLabelColor(final Color color) { |
315 this.labelColor = color; | 284 this.labelColor = color; |
316 } | 285 } |
317 | 286 |
318 | |
319 /** Get color with which label is painted. */ | |
320 public Color getLabelColor() { | |
321 return this.labelColor; | |
322 } | |
323 | |
324 | |
325 /** Set color with which to paint label bg. */ | 287 /** Set color with which to paint label bg. */ |
326 public void setLabelBGColor(Color color) { | 288 public void setLabelBGColor(final Color color) { |
327 this.labelBGColor = color; | 289 this.labelBGColor = color; |
328 } | 290 } |
329 | 291 |
330 | |
331 /** Get color with which label is painted. */ | |
332 public Color getLabelBGColor() { | |
333 return this.labelBGColor; | |
334 } | |
335 | |
336 | |
337 public double getCalculatedArea() { | |
338 return positiveArea + negativeArea; | |
339 } | |
340 | |
341 /** | 292 /** |
342 * Sets color that is used if drawOutline is true. | 293 * Sets color that is used if drawOutline is true. |
343 */ | 294 */ |
344 public void setOutlinePaint(Paint outlinePaint) { | 295 @Override |
296 public void setOutlinePaint(final Paint outlinePaint) { | |
345 this.outlinePaint = outlinePaint; | 297 this.outlinePaint = outlinePaint; |
346 } | 298 } |
347 | 299 |
348 | |
349 /** | |
350 * Gets color which is used if drawOutline is true. | |
351 */ | |
352 public Paint getOutlinePaint() { | |
353 return this.outlinePaint; | |
354 } | |
355 | |
356 | |
357 /** | 300 /** |
358 * Sets Stroke that is used if drawOutline is true. | 301 * Sets Stroke that is used if drawOutline is true. |
359 */ | 302 */ |
360 public void setOutlineStroke(Stroke stroke) { | 303 @Override |
304 public void setOutlineStroke(final Stroke stroke) { | |
361 this.outlineStroke = stroke; | 305 this.outlineStroke = stroke; |
362 } | 306 } |
363 | |
364 | |
365 /** | |
366 * Returns Stroke that is used if drawOutline is true. | |
367 */ | |
368 public Stroke getOutlineStroke() { | |
369 return this.outlineStroke; | |
370 } | |
371 | |
372 | 307 |
373 /** | 308 /** |
374 * Whether or not to draw the 'Shape' of the area (in contrast to | 309 * Whether or not to draw the 'Shape' of the area (in contrast to |
375 * shapes at data items). | 310 * shapes at data items). |
376 */ | 311 */ |
377 public void setDrawOutline(boolean doDrawOutline) { | 312 public void setDrawOutline(final boolean doDrawOutline) { |
378 this.drawOutline = doDrawOutline; | 313 this.drawOutline = doDrawOutline; |
379 } | 314 } |
380 | 315 |
381 | 316 public void setDrawArea(final boolean doDrawArea) { |
382 /** | 317 this.drawArea = doDrawArea; |
383 * Returns whether or not to draw the shape of the outline. | 318 } |
384 */ | |
385 public boolean getDrawOutline() { | |
386 return this.drawOutline; | |
387 } | |
388 | |
389 | 319 |
390 /** | 320 /** |
391 * Returns the paint used to highlight positive differences. | 321 * Returns the paint used to highlight positive differences. |
392 * | 322 * |
393 * @return The paint (never <code>null</code>). | 323 * @return The paint (never <code>null</code>). |
394 * | 324 * |
395 * @see #setPositivePaint(Paint) | 325 * @see #setPositivePaint(Paint) |
396 */ | 326 */ |
397 public Paint getPositivePaint() { | 327 private Paint getPositivePaint() { |
398 return this.positivePaint; | 328 return this.positivePaint; |
399 } | 329 } |
400 | 330 |
401 /** | 331 /** |
402 * Sets the paint used to highlight positive differences and sends a | 332 * Sets the paint used to highlight positive differences and sends a |
403 * {@link RendererChangeEvent} to all registered listeners. | 333 * {@link RendererChangeEvent} to all registered listeners. |
404 * | 334 * |
405 * @param paint the paint (<code>null</code> not permitted). | 335 * @param paint |
336 * the paint (<code>null</code> not permitted). | |
406 * | 337 * |
407 * @see #getPositivePaint() | 338 * @see #getPositivePaint() |
408 */ | 339 */ |
409 public void setPositivePaint(Paint paint) { | 340 public void setPositivePaint(final Paint paint) { |
410 this.positivePaint = paint; | 341 this.positivePaint = paint; |
411 fireChangeEvent(); | 342 fireChangeEvent(); |
412 } | 343 } |
413 | 344 |
414 /** | 345 /** |
416 * | 347 * |
417 * @return The paint (never <code>null</code>). | 348 * @return The paint (never <code>null</code>). |
418 * | 349 * |
419 * @see #setNegativePaint(Paint) | 350 * @see #setNegativePaint(Paint) |
420 */ | 351 */ |
421 public Paint getNegativePaint() { | 352 private Paint getNegativePaint() { |
422 return this.negativePaint; | 353 return this.negativePaint; |
423 } | 354 } |
424 | 355 |
425 /** | 356 /** |
426 * Sets the paint used to highlight negative differences. | 357 * Sets the paint used to highlight negative differences. |
427 * | 358 * |
428 * @param paint the paint (<code>null</code> not permitted). | 359 * @param paint |
360 * the paint (<code>null</code> not permitted). | |
429 * | 361 * |
430 * @see #getNegativePaint() | 362 * @see #getNegativePaint() |
431 */ | 363 */ |
432 public void setNegativePaint(Paint paint) { | 364 public void setNegativePaint(final Paint paint) { |
433 this.negativePaint = paint; | 365 this.negativePaint = paint; |
434 notifyListeners(new RendererChangeEvent(this)); | 366 notifyListeners(new RendererChangeEvent(this)); |
435 } | 367 } |
436 | 368 |
437 /** | 369 /** |
440 * | 372 * |
441 * @return A boolean. | 373 * @return A boolean. |
442 * | 374 * |
443 * @see #setShapesVisible(boolean) | 375 * @see #setShapesVisible(boolean) |
444 */ | 376 */ |
445 public boolean getShapesVisible() { | 377 private boolean getShapesVisible() { |
446 return this.shapesVisible; | 378 return this.shapesVisible; |
447 } | 379 } |
448 | 380 |
449 /** | 381 /** |
450 * Sets a flag that controls whether or not shapes are drawn for each | 382 * Sets a flag that controls whether or not shapes are drawn for each |
451 * data value, and sends a {@link RendererChangeEvent} to all registered | 383 * data value, and sends a {@link RendererChangeEvent} to all registered |
452 * listeners. | 384 * listeners. |
453 * | 385 * |
454 * @param flag the flag. | 386 * @param flag |
387 * the flag. | |
455 * | 388 * |
456 * @see #getShapesVisible() | 389 * @see #getShapesVisible() |
457 */ | 390 */ |
458 public void setShapesVisible(boolean flag) { | 391 public void setShapesVisible(final boolean flag) { |
459 this.shapesVisible = flag; | 392 this.shapesVisible = flag; |
460 fireChangeEvent(); | 393 fireChangeEvent(); |
461 } | 394 } |
462 | 395 |
463 /** | 396 /** |
465 * | 398 * |
466 * @return The legend line (never <code>null</code>). | 399 * @return The legend line (never <code>null</code>). |
467 * | 400 * |
468 * @see #setLegendLine(Shape) | 401 * @see #setLegendLine(Shape) |
469 */ | 402 */ |
470 public Shape getLegendLine() { | 403 private Shape getLegendLine() { |
471 return this.legendShape; | 404 return this.legendShape; |
472 } | 405 } |
473 | 406 |
474 /** | 407 /** |
475 * Sets the shape used as a line in each legend item and sends a | 408 * Initializes the renderer and returns a state object that should be |
476 * {@link RendererChangeEvent} to all registered listeners. | 409 * passed to subsequent calls to the drawItem() method. This method will |
477 * | |
478 * @param line the line (<code>null</code> not permitted). | |
479 * | |
480 * @see #getLegendLine() | |
481 */ | |
482 public void setLegendLine(Shape line) { | |
483 if (line == null) { | |
484 throw new IllegalArgumentException("Null 'line' argument."); | |
485 } | |
486 this.legendShape = line; | |
487 fireChangeEvent(); | |
488 } | |
489 | |
490 /** | |
491 * Returns the flag that controls whether or not the x-coordinates (in | |
492 * Java2D space) are rounded to integer values. | |
493 * | |
494 * @return The flag. | |
495 * | |
496 * @since 1.0.4 | |
497 * | |
498 * @see #setRoundXCoordinates(boolean) | |
499 */ | |
500 public boolean getRoundXCoordinates() { | |
501 return this.roundXCoordinates; | |
502 } | |
503 | |
504 /** | |
505 * Sets the flag that controls whether or not the x-coordinates (in | |
506 * Java2D space) are rounded to integer values, and sends a | |
507 * {@link RendererChangeEvent} to all registered listeners. | |
508 * | |
509 * @param round the new flag value. | |
510 * | |
511 * @since 1.0.4 | |
512 * | |
513 * @see #getRoundXCoordinates() | |
514 */ | |
515 public void setRoundXCoordinates(boolean round) { | |
516 this.roundXCoordinates = round; | |
517 fireChangeEvent(); | |
518 } | |
519 | |
520 /** | |
521 * Initialises the renderer and returns a state object that should be | |
522 * passed to subsequent calls to the drawItem() method. This method will | |
523 * be called before the first item is rendered, giving the renderer an | 410 * be called before the first item is rendered, giving the renderer an |
524 * opportunity to initialise any state information it wants to maintain. | 411 * opportunity to initialize any state information it wants to maintain. |
525 * The renderer can do nothing if it chooses. | 412 * The renderer can do nothing if it chooses. |
526 * | 413 * |
527 * @param g2 the graphics device. | 414 * @param g2 |
528 * @param dataArea the (visible) area inside the axes. | 415 * the graphics device. |
529 * @param plot the plot. | 416 * @param dataArea |
530 * @param data the data. | 417 * the (visible) area inside the axes. |
531 * @param info an optional info collection object to return data back to | 418 * @param plot |
532 * the caller. | 419 * the plot. |
420 * @param data | |
421 * the data. | |
422 * @param info | |
423 * an optional info collection object to return data back to | |
424 * the caller. | |
533 * | 425 * |
534 * @return A state object. | 426 * @return A state object. |
535 */ | 427 */ |
536 public XYItemRendererState initialise(Graphics2D g2, | 428 @Override |
537 Rectangle2D dataArea, | 429 public XYItemRendererState initialise(final Graphics2D g2, final Rectangle2D dataArea, final XYPlot plot, final XYDataset data, |
538 XYPlot plot, | 430 final PlotRenderingInfo info) { |
539 XYDataset data, | 431 |
540 PlotRenderingInfo info) { | 432 final XYItemRendererState state = super.initialise(g2, dataArea, plot, data, info); |
541 | |
542 XYItemRendererState state = super.initialise(g2, dataArea, plot, data, | |
543 info); | |
544 state.setProcessVisibleItemsOnly(false); | 433 state.setProcessVisibleItemsOnly(false); |
545 return state; | 434 return state; |
546 } | 435 } |
547 | 436 |
548 /** | 437 /** |
549 * Returns <code>2</code>, the number of passes required by the renderer. | 438 * Returns <code>2</code>, the number of passes required by the renderer. |
550 * The {@link XYPlot} will run through the dataset this number of times. | 439 * The {@link XYPlot} will run through the dataset this number of times. |
551 * | 440 * |
552 * @return The number of passes required by the renderer. | 441 * @return The number of passes required by the renderer. |
553 */ | 442 */ |
443 @Override | |
554 public int getPassCount() { | 444 public int getPassCount() { |
555 return 2; | 445 return 2; |
556 } | 446 } |
557 | 447 |
558 | |
559 /** | 448 /** |
560 * Adds x/y data to series. | 449 * Adds x/y data to series. |
561 */ | 450 */ |
562 private static final void addSeries( | 451 private static final void addSeries(final DefaultXYDataset ds, final Comparable key, final TDoubleArrayList xs, final TDoubleArrayList ys) { |
563 DefaultXYDataset ds, | 452 ds.addSeries(key, new double[][] { xs.toNativeArray(), ys.toNativeArray() }); |
564 Comparable key, | 453 } |
565 TDoubleArrayList xs, | 454 |
566 TDoubleArrayList ys | 455 private static List<XYDataset> splitByNaNsOneSeries(final XYDataset dataset) { |
567 ) { | 456 final List<XYDataset> datasets = new ArrayList<>(); |
568 ds.addSeries( | 457 |
569 key, | 458 final int N = dataset.getItemCount(0); |
570 new double [][] { | 459 final TDoubleArrayList xs = new TDoubleArrayList(N); |
571 xs.toNativeArray(), | 460 final TDoubleArrayList ys = new TDoubleArrayList(N); |
572 ys.toNativeArray() | |
573 }); | |
574 } | |
575 | |
576 protected static List<XYDataset> splitByNaNsOneSeries( | |
577 XYDataset dataset | |
578 ) { | |
579 List<XYDataset> datasets = new ArrayList<XYDataset>(); | |
580 | |
581 int N = dataset.getItemCount(0); | |
582 TDoubleArrayList xs = new TDoubleArrayList(N); | |
583 TDoubleArrayList ys = new TDoubleArrayList(N); | |
584 for (int i = 0; i < N; ++i) { | 461 for (int i = 0; i < N; ++i) { |
585 double x = dataset.getXValue(0, i); | 462 final double x = dataset.getXValue(0, i); |
586 double y = dataset.getYValue(0, i); | 463 final double y = dataset.getYValue(0, i); |
587 if (Double.isNaN(x) || Double.isNaN(y)) { | 464 if (Double.isNaN(x) || Double.isNaN(y)) { |
588 if (!xs.isEmpty()) { | 465 if (!xs.isEmpty()) { |
589 DefaultXYDataset ds = new DefaultXYDataset(); | 466 final DefaultXYDataset ds = new DefaultXYDataset(); |
590 addSeries(ds, dataset.getSeriesKey(0), xs, ys); | 467 addSeries(ds, dataset.getSeriesKey(0), xs, ys); |
591 datasets.add(ds); | 468 datasets.add(ds); |
592 xs.resetQuick(); | 469 xs.resetQuick(); |
593 ys.resetQuick(); | 470 ys.resetQuick(); |
594 } | 471 } |
595 } | 472 } else { |
596 else { | |
597 xs.add(x); | 473 xs.add(x); |
598 ys.add(y); | 474 ys.add(y); |
599 } | 475 } |
600 } | 476 } |
601 if (!xs.isEmpty()) { | 477 if (!xs.isEmpty()) { |
602 DefaultXYDataset ds = new DefaultXYDataset(); | 478 final DefaultXYDataset ds = new DefaultXYDataset(); |
603 addSeries(ds, dataset.getSeriesKey(0), xs, ys); | 479 addSeries(ds, dataset.getSeriesKey(0), xs, ys); |
604 datasets.add(ds); | 480 datasets.add(ds); |
605 } | 481 } |
606 | 482 |
607 return datasets; | 483 return datasets; |
608 } | 484 } |
609 | 485 |
610 private static final boolean add(TDoubleArrayList xs, double x) { | 486 private static final boolean add(final TDoubleArrayList xs, final double x) { |
611 int N = xs.size(); | 487 final int N = xs.size(); |
612 if (N == 0 || xs.getQuick(N-1) < x) { | 488 if (N == 0 || xs.getQuick(N - 1) < x) { |
613 xs.add(x); | 489 xs.add(x); |
614 return true; | 490 return true; |
615 } | 491 } |
616 return false; | 492 return false; |
617 } | 493 } |
618 | 494 |
619 protected static boolean hasNaN(XYDataset dataset) { | 495 private static boolean hasNaN(final XYDataset dataset) { |
620 int N = dataset.getItemCount(0); | 496 final int N = dataset.getItemCount(0); |
621 int M = dataset.getItemCount(1); | 497 final int M = dataset.getItemCount(1); |
622 | 498 |
623 for (int i = 0; i < N; ++i) { | 499 for (int i = 0; i < N; ++i) { |
624 double x = dataset.getXValue(0, i); | 500 final double x = dataset.getXValue(0, i); |
625 double y = dataset.getYValue(0, i); | 501 final double y = dataset.getYValue(0, i); |
626 if (Double.isNaN(x) || Double.isNaN(y)) { | 502 if (Double.isNaN(x) || Double.isNaN(y)) { |
627 return true; | 503 return true; |
628 } | 504 } |
629 } | 505 } |
630 | 506 |
631 for (int j = 0; j < M; ++j) { | 507 for (int j = 0; j < M; ++j) { |
632 double x = dataset.getXValue(1, j); | 508 final double x = dataset.getXValue(1, j); |
633 double y = dataset.getYValue(1, j); | 509 final double y = dataset.getYValue(1, j); |
634 if (Double.isNaN(x) || Double.isNaN(y)) { | 510 if (Double.isNaN(x) || Double.isNaN(y)) { |
635 return true; | 511 return true; |
636 } | 512 } |
637 } | 513 } |
638 return false; | 514 return false; |
639 } | 515 } |
640 | 516 |
641 | 517 private static List<XYDataset> splitByNaNsTwoSeries(final XYDataset dataset) { |
642 protected static List<XYDataset> splitByNaNsTwoSeries( | 518 final boolean debug = log.isDebugEnabled(); |
643 XYDataset dataset | 519 |
644 ) { | 520 final List<XYDataset> datasets = new ArrayList<>(); |
645 boolean debug = log.isDebugEnabled(); | |
646 | |
647 List<XYDataset> datasets = new ArrayList<XYDataset>(); | |
648 | 521 |
649 if (!hasNaN(dataset)) { | 522 if (!hasNaN(dataset)) { |
650 datasets.add(dataset); | 523 datasets.add(dataset); |
651 return datasets; | 524 return datasets; |
652 } | 525 } |
653 | 526 |
654 int N = dataset.getItemCount(0); | 527 final int N = dataset.getItemCount(0); |
655 int M = dataset.getItemCount(1); | 528 final int M = dataset.getItemCount(1); |
656 | 529 |
657 int i = 0, j = 0; | 530 int i = 0, j = 0; |
658 // ignore leading NaNs | 531 // ignore leading NaNs |
659 for (; i < N; ++i) { | 532 for (; i < N; ++i) { |
660 double x = dataset.getXValue(0, i); | 533 final double x = dataset.getXValue(0, i); |
661 double y = dataset.getYValue(0, i); | 534 final double y = dataset.getYValue(0, i); |
662 if (!Double.isNaN(x) && !Double.isNaN(y)) { | 535 if (!Double.isNaN(x) && !Double.isNaN(y)) { |
663 break; | 536 break; |
664 } | 537 } |
665 } | 538 } |
666 | 539 |
667 for (; j < M; ++j) { | 540 for (; j < M; ++j) { |
668 double x = dataset.getXValue(1, j); | 541 final double x = dataset.getXValue(1, j); |
669 double y = dataset.getYValue(1, j); | 542 final double y = dataset.getYValue(1, j); |
670 if (!Double.isNaN(x) && !Double.isNaN(y)) { | 543 if (!Double.isNaN(x) && !Double.isNaN(y)) { |
671 break; | 544 break; |
672 } | 545 } |
673 } | 546 } |
674 | 547 |
675 TDoubleArrayList six = new TDoubleArrayList(); | 548 final TDoubleArrayList six = new TDoubleArrayList(); |
676 TDoubleArrayList siy = new TDoubleArrayList(); | 549 final TDoubleArrayList siy = new TDoubleArrayList(); |
677 TDoubleArrayList sjx = new TDoubleArrayList(); | 550 final TDoubleArrayList sjx = new TDoubleArrayList(); |
678 TDoubleArrayList sjy = new TDoubleArrayList(); | 551 final TDoubleArrayList sjy = new TDoubleArrayList(); |
679 | 552 |
680 while (i < N && j < M) { | 553 while (i < N && j < M) { |
681 int ni = i+1; | 554 int ni = i + 1; |
682 for (; ni < N && !Double.isNaN(dataset.getXValue(0, ni)); ++ni); | 555 for (; ni < N && !Double.isNaN(dataset.getXValue(0, ni)); ++ni) |
683 for (; ni < N && Double.isNaN(dataset.getXValue(0, ni)); ++ni); | 556 ; |
684 | 557 for (; ni < N && Double.isNaN(dataset.getXValue(0, ni)); ++ni) |
685 int nj = j+1; | 558 ; |
686 for (; nj < M && !Double.isNaN(dataset.getXValue(1, nj)); ++nj); | 559 |
687 for (; nj < M && Double.isNaN(dataset.getXValue(1, nj)); ++nj); | 560 int nj = j + 1; |
561 for (; nj < M && !Double.isNaN(dataset.getXValue(1, nj)); ++nj) | |
562 ; | |
563 for (; nj < M && Double.isNaN(dataset.getXValue(1, nj)); ++nj) | |
564 ; | |
688 | 565 |
689 if (ni == N && nj == M) { // no more splits | 566 if (ni == N && nj == M) { // no more splits |
690 log.debug("no more splits ...."); | 567 log.debug("no more splits ...."); |
691 for (; i < ni; ++i) { | 568 for (; i < ni; ++i) { |
692 double x = dataset.getXValue(0, i); | 569 final double x = dataset.getXValue(0, i); |
693 double y = dataset.getYValue(0, i); | 570 final double y = dataset.getYValue(0, i); |
694 if (!Double.isNaN(x) | 571 if (!Double.isNaN(x) && !Double.isNaN(y) && add(six, x)) { |
695 && !Double.isNaN(y) | |
696 && add(six, x)) { | |
697 siy.add(y); | 572 siy.add(y); |
698 } | 573 } |
699 } | 574 } |
700 for (; j < nj; ++j) { | 575 for (; j < nj; ++j) { |
701 double x = dataset.getXValue(1, j); | 576 final double x = dataset.getXValue(1, j); |
702 double y = dataset.getYValue(1, j); | 577 final double y = dataset.getYValue(1, j); |
703 if (!Double.isNaN(x) | 578 if (!Double.isNaN(x) && !Double.isNaN(y) && add(sjx, x)) { |
704 && !Double.isNaN(y) | |
705 && add(sjx, x)) { | |
706 sjy.add(y); | 579 sjy.add(y); |
707 } | 580 } |
708 } | 581 } |
709 if (!six.isEmpty() && !sjx.isEmpty()) { | 582 if (!six.isEmpty() && !sjx.isEmpty()) { |
710 DefaultXYDataset ds = new DefaultXYDataset(); | 583 final DefaultXYDataset ds = new DefaultXYDataset(); |
711 addSeries(ds, dataset.getSeriesKey(0), six, siy); | 584 addSeries(ds, dataset.getSeriesKey(0), six, siy); |
712 addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); | 585 addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); |
713 datasets.add(ds); | 586 datasets.add(ds); |
714 } | 587 } |
715 break; | 588 break; |
718 if (debug) { | 591 if (debug) { |
719 log.debug("ni: " + ni + " " + N); | 592 log.debug("ni: " + ni + " " + N); |
720 log.debug("nj: " + nj + " " + M); | 593 log.debug("nj: " + nj + " " + M); |
721 } | 594 } |
722 | 595 |
723 double xni = ni < N | 596 final double xni = ni < N ? dataset.getXValue(0, ni) : Double.MAX_VALUE; |
724 ? dataset.getXValue(0, ni) | 597 |
725 : Double.MAX_VALUE; | 598 final double xnj = nj < M ? dataset.getXValue(1, nj) : Double.MAX_VALUE; |
726 | 599 |
727 double xnj = nj < M | 600 final double xns = Math.min(xni, xnj); |
728 ? dataset.getXValue(1, nj) | |
729 : Double.MAX_VALUE; | |
730 | |
731 double xns = Math.min(xni, xnj); | |
732 | 601 |
733 double pushxi = Double.NaN; | 602 double pushxi = Double.NaN; |
734 double pushyi = Double.NaN; | 603 double pushyi = Double.NaN; |
735 double pushxj = Double.NaN; | 604 double pushxj = Double.NaN; |
736 double pushyj = Double.NaN; | 605 double pushyj = Double.NaN; |
737 | 606 |
738 for (; i < ni; ++i) { | 607 for (; i < ni; ++i) { |
739 double x = dataset.getXValue(0, i); | 608 final double x = dataset.getXValue(0, i); |
740 double y = dataset.getYValue(0, i); | 609 final double y = dataset.getYValue(0, i); |
741 if (Double.isNaN(x) || Double.isNaN(y)) { | 610 if (Double.isNaN(x) || Double.isNaN(y)) { |
742 continue; | 611 continue; |
743 } | 612 } |
744 if (x < xns) { | 613 if (x < xns) { |
745 if (add(six, x)) { | 614 if (add(six, x)) { |
749 } | 618 } |
750 if (x == xns) { // exact match | 619 if (x == xns) { // exact match |
751 if (add(six, x)) { | 620 if (add(six, x)) { |
752 siy.add(y); | 621 siy.add(y); |
753 } | 622 } |
754 pushxi = x; pushyi = y; | 623 pushxi = x; |
755 } | 624 pushyi = y; |
756 else { // x > xns: intersection | 625 } else { // x > xns: intersection |
757 if (debug) { | 626 if (debug) { |
758 log.debug("xns: " + xns); | 627 log.debug("xns: " + xns); |
759 log.debug("x/y: " + x + " / " + y); | 628 log.debug("x/y: " + x + " / " + y); |
760 } | 629 } |
761 int SIX = six.size(); | 630 final int SIX = six.size(); |
762 if (SIX > 0) { // should always be true | 631 if (SIX > 0) { // should always be true |
763 double yns = Linear.linear( | 632 final double yns = Linear.linear(xns, six.getQuick(SIX - 1), x, siy.getQuick(SIX - 1), y); |
764 xns, | |
765 six.getQuick(SIX-1), x, | |
766 siy.getQuick(SIX-1), y); | |
767 if (debug) { | 633 if (debug) { |
768 log.debug("intersection at: " + yns); | 634 log.debug("intersection at: " + yns); |
769 } | 635 } |
770 if (add(six, xns)) { | 636 if (add(six, xns)) { |
771 siy.add(yns); | 637 siy.add(yns); |
776 } | 642 } |
777 break; // Split point reached. | 643 break; // Split point reached. |
778 } | 644 } |
779 | 645 |
780 for (; j < nj; ++j) { | 646 for (; j < nj; ++j) { |
781 double x = dataset.getXValue(1, j); | 647 final double x = dataset.getXValue(1, j); |
782 double y = dataset.getYValue(1, j); | 648 final double y = dataset.getYValue(1, j); |
783 if (Double.isNaN(x) || Double.isNaN(y)) { | 649 if (Double.isNaN(x) || Double.isNaN(y)) { |
784 continue; | 650 continue; |
785 } | 651 } |
786 if (x < xns) { | 652 if (x < xns) { |
787 if (add(sjx, x)) { | 653 if (add(sjx, x)) { |
791 } | 657 } |
792 if (x == xns) { // exact match | 658 if (x == xns) { // exact match |
793 if (add(sjx, x)) { | 659 if (add(sjx, x)) { |
794 sjy.add(y); | 660 sjy.add(y); |
795 } | 661 } |
796 pushxj = x; pushyj = y; | 662 pushxj = x; |
797 } | 663 pushyj = y; |
798 else { // x > xns: intersection | 664 } else { // x > xns: intersection |
799 int SJX = sjx.size(); | 665 final int SJX = sjx.size(); |
800 if (SJX > 0) { // should always be true | 666 if (SJX > 0) { // should always be true |
801 double yns = Linear.linear( | 667 final double yns = Linear.linear(xns, sjx.getQuick(SJX - 1), x, sjy.getQuick(SJX - 1), y); |
802 xns, | |
803 sjx.getQuick(SJX-1), x, | |
804 sjy.getQuick(SJX-1), y); | |
805 if (debug) { | 668 if (debug) { |
806 log.debug("intersection at: " + yns); | 669 log.debug("intersection at: " + yns); |
807 } | 670 } |
808 if (add(sjx, xns)) { | 671 if (add(sjx, xns)) { |
809 sjy.add(yns); | 672 sjy.add(yns); |
810 } | 673 } |
811 pushxj = xns; pushyj = yns; | 674 pushxj = xns; |
675 pushyj = yns; | |
812 } | 676 } |
813 } | 677 } |
814 break; // Split point reached. | 678 break; // Split point reached. |
815 } | 679 } |
816 | 680 |
817 if (!six.isEmpty() && !sjx.isEmpty()) { | 681 if (!six.isEmpty() && !sjx.isEmpty()) { |
818 DefaultXYDataset ds = new DefaultXYDataset(); | 682 final DefaultXYDataset ds = new DefaultXYDataset(); |
819 addSeries(ds, dataset.getSeriesKey(0), six, siy); | 683 addSeries(ds, dataset.getSeriesKey(0), six, siy); |
820 addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); | 684 addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); |
821 datasets.add(ds); | 685 datasets.add(ds); |
822 } | 686 } |
823 | 687 |
824 six.resetQuick(); siy.resetQuick(); | 688 six.resetQuick(); |
825 sjx.resetQuick(); sjy.resetQuick(); | 689 siy.resetQuick(); |
690 sjx.resetQuick(); | |
691 sjy.resetQuick(); | |
826 | 692 |
827 // Push split points. | 693 // Push split points. |
828 if (!Double.isNaN(pushxi)) { | 694 if (!Double.isNaN(pushxi)) { |
829 six.add(pushxi); | 695 six.add(pushxi); |
830 siy.add(pushyi); | 696 siy.add(pushyi); |
836 } | 702 } |
837 } | 703 } |
838 | 704 |
839 // Copy the rest. | 705 // Copy the rest. |
840 for (; i < N; ++i) { | 706 for (; i < N; ++i) { |
841 double x = dataset.getXValue(0, i); | 707 final double x = dataset.getXValue(0, i); |
842 double y = dataset.getXValue(0, i); | 708 final double y = dataset.getXValue(0, i); |
843 if (!Double.isNaN(x) | 709 if (!Double.isNaN(x) && !Double.isNaN(y) && add(six, x)) { |
844 && !Double.isNaN(y) | |
845 && add(six, x)) { | |
846 siy.add(y); | 710 siy.add(y); |
847 } | 711 } |
848 } | 712 } |
849 | 713 |
850 for (; j < M; ++j) { | 714 for (; j < M; ++j) { |
851 double x = dataset.getXValue(1, j); | 715 final double x = dataset.getXValue(1, j); |
852 double y = dataset.getXValue(1, j); | 716 final double y = dataset.getXValue(1, j); |
853 if (!Double.isNaN(x) | 717 if (!Double.isNaN(x) && !Double.isNaN(y) && add(sjx, x)) { |
854 && !Double.isNaN(y) | |
855 && add(sjx, x)) { | |
856 sjy.add(y); | 718 sjy.add(y); |
857 } | 719 } |
858 } | 720 } |
859 | 721 |
860 // Build final dataset. | 722 // Build final dataset. |
861 if (!six.isEmpty() && !sjx.isEmpty()) { | 723 if (!six.isEmpty() && !sjx.isEmpty()) { |
862 DefaultXYDataset ds = new DefaultXYDataset(); | 724 final DefaultXYDataset ds = new DefaultXYDataset(); |
863 addSeries(ds, dataset.getSeriesKey(0), six, siy); | 725 addSeries(ds, dataset.getSeriesKey(0), six, siy); |
864 addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); | 726 addSeries(ds, dataset.getSeriesKey(1), sjx, sjy); |
865 datasets.add(ds); | 727 datasets.add(ds); |
866 } | 728 } |
867 | 729 |
868 if (debug) { | 730 if (debug) { |
869 log.debug("datasets after split: " + datasets.size()); | 731 log.debug("datasets after split: " + datasets.size()); |
870 } | 732 } |
871 | 733 |
872 /* | 734 /* |
873 log.debug("Begin dump datasets: "); | 735 * log.debug("Begin dump datasets: "); |
874 log.debug("Original"); | 736 * log.debug("Original"); |
875 i=0; | 737 * i=0; |
876 dumpDataset(dataset, "Original" ); | 738 * dumpDataset(dataset, "Original" ); |
877 for (XYDataset set: datasets) { | 739 * for (XYDataset set: datasets) { |
878 dumpDataset(dataset, "New: " + i++); | 740 * dumpDataset(dataset, "New: " + i++); |
879 } | 741 * } |
880 log.debug("End dump datasets: "); | 742 * log.debug("End dump datasets: "); |
881 */ | 743 */ |
882 | 744 |
883 return datasets; | 745 return datasets; |
884 } | 746 } |
885 | 747 |
886 /* | 748 /* |
887 public static void dumpDataset(XYDataset dataset, String msg) { | 749 * public static void dumpDataset(XYDataset dataset, String msg) { |
888 log.debug("Begin dump Dataset: " + msg); | 750 * log.debug("Begin dump Dataset: " + msg); |
889 | 751 * int N = dataset.getItemCount(0); |
890 int N = dataset.getItemCount(0); | 752 * int M = dataset.getItemCount(1); |
891 int M = dataset.getItemCount(1); | 753 * int i = 0, j = 0; |
892 | 754 * for (; i < N; ++i) { |
893 int i = 0, j = 0; | 755 * double x = dataset.getXValue(0, i); |
894 for (; i < N; ++i) { | 756 * double y = dataset.getYValue(0, i); |
895 double x = dataset.getXValue(0, i); | 757 * log.debug("0 " + i + " X: "+ x + "Y: "+ y); |
896 double y = dataset.getYValue(0, i); | 758 * } |
897 log.debug("0 " + i + " X: "+ x + "Y: "+ y); | 759 * for (; j < M; ++j) { |
898 } | 760 * double x = dataset.getXValue(1, j); |
899 | 761 * double y = dataset.getYValue(1, j); |
900 for (; j < M; ++j) { | 762 * log.debug("1 " + i + " X: "+ x + "Y: "+ y); |
901 double x = dataset.getXValue(1, j); | 763 * } |
902 double y = dataset.getYValue(1, j); | 764 * log.debug("End dump Dataset: " + msg); |
903 log.debug("1 " + i + " X: "+ x + "Y: "+ y); | 765 * } |
904 } | 766 */ |
905 log.debug("End dump Dataset: " + msg); | 767 |
906 } | 768 private static List<XYDataset> splitByNaNs(final XYDataset dataset) { |
907 */ | |
908 | |
909 | |
910 public static List<XYDataset> splitByNaNs(XYDataset dataset) { | |
911 | 769 |
912 switch (dataset.getSeriesCount()) { | 770 switch (dataset.getSeriesCount()) { |
913 case 0: | 771 case 0: |
914 return Collections.<XYDataset>emptyList(); | 772 return Collections.<XYDataset>emptyList(); |
915 case 1: | 773 case 1: |
916 return splitByNaNsOneSeries(dataset); | 774 return splitByNaNsOneSeries(dataset); |
917 default: // two or more | 775 default: // two or more |
918 return splitByNaNsTwoSeries(dataset); | 776 return splitByNaNsTwoSeries(dataset); |
919 } | 777 } |
920 } | 778 } |
921 | |
922 | 779 |
923 /** | 780 /** |
924 * Draws the visual representation of a single data item. | 781 * Draws the visual representation of a single data item. |
925 * | 782 * |
926 * @param g2 the graphics device. | 783 * @param g2 |
927 * @param state the renderer state. | 784 * the graphics device. |
928 * @param dataArea the area within which the data is being drawn. | 785 * @param state |
929 * @param info collects information about the drawing. | 786 * the renderer state. |
930 * @param plot the plot (can be used to obtain standard color | 787 * @param dataArea |
931 * information etc). | 788 * the area within which the data is being drawn. |
932 * @param domainAxis the domain (horizontal) axis. | 789 * @param info |
933 * @param rangeAxis the range (vertical) axis. | 790 * collects information about the drawing. |
934 * @param dataset the dataset. | 791 * @param plot |
935 * @param series the series index (zero-based). | 792 * the plot (can be used to obtain standard color |
936 * @param item the item index (zero-based). | 793 * information etc). |
937 * @param crosshairState crosshair information for the plot | 794 * @param domainAxis |
938 * (<code>null</code> permitted). | 795 * the domain (horizontal) axis. |
939 * @param pass the pass index. | 796 * @param rangeAxis |
940 */ | 797 * the range (vertical) axis. |
941 public void drawItem(Graphics2D g2, | 798 * @param dataset |
942 XYItemRendererState state, | 799 * the dataset. |
943 Rectangle2D dataArea, | 800 * @param series |
944 PlotRenderingInfo info, | 801 * the series index (zero-based). |
945 XYPlot plot, | 802 * @param item |
946 ValueAxis domainAxis, | 803 * the item index (zero-based). |
947 ValueAxis rangeAxis, | 804 * @param crosshairState |
948 XYDataset dataset, | 805 * crosshair information for the plot |
949 int series, | 806 * (<code>null</code> permitted). |
950 int item, | 807 * @param pass |
951 CrosshairState crosshairState, | 808 * the pass index. |
952 int pass) { | 809 */ |
810 @Override | |
811 public void drawItem(final Graphics2D g2, final XYItemRendererState state, final Rectangle2D dataArea, final PlotRenderingInfo info, final XYPlot plot, | |
812 final ValueAxis domainAxis, final ValueAxis rangeAxis, final XYDataset dataset, final int series, final int item, | |
813 final CrosshairState crosshairState, final int pass) { | |
953 switch (pass) { | 814 switch (pass) { |
954 case 0: | 815 case 0: |
955 for (XYDataset ds: splitByNaNs(dataset)) { | 816 for (final XYDataset ds : splitByNaNs(dataset)) { |
956 drawItemPass0(g2, dataArea, info, | 817 drawItemPass0(g2, dataArea, info, plot, domainAxis, rangeAxis, ds, series, item, crosshairState); |
957 plot, domainAxis, rangeAxis, | 818 } |
958 ds, series, item, crosshairState); | 819 break; |
959 } | 820 case 1: |
960 break; | 821 drawItemPass1(g2, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState); |
961 case 1: | |
962 drawItemPass1(g2, dataArea, info, | |
963 plot, domainAxis, rangeAxis, | |
964 dataset, series, item, crosshairState); | |
965 } | 822 } |
966 | 823 |
967 // Find geometric middle, calculate area and paint | 824 // Find geometric middle, calculate area and paint |
968 // a string with it here. | 825 // a string with it here. |
969 if (pass == 1 | 826 if (pass == 1 && this.labelArea && this.areaLabelNumberFormat != null && this.areaLabelTamplate != null) { |
970 && this.labelArea | 827 double center_x = this.centroid.getX(); |
971 && areaLabelNumberFormat != null | 828 double center_y = this.centroid.getY(); |
972 && areaLabelTamplate != null | 829 center_x = domainAxis.valueToJava2D(center_x, dataArea, plot.getDomainAxisEdge()); |
973 ) { | 830 center_y = rangeAxis.valueToJava2D(center_y, dataArea, plot.getRangeAxisEdge()); |
974 double center_x = centroid.getX(); | |
975 double center_y = centroid.getY(); | |
976 center_x = domainAxis.valueToJava2D(center_x, dataArea, | |
977 plot.getDomainAxisEdge()); | |
978 center_y = rangeAxis.valueToJava2D(center_y, dataArea, | |
979 plot.getRangeAxisEdge()); | |
980 | 831 |
981 // Respect text-extend if text should appear really centered. | 832 // Respect text-extend if text should appear really centered. |
982 | 833 |
983 float area = 0f; | 834 float area = 0f; |
984 if (areaCalculationMode == CALCULATE_POSITIVE_AREA | 835 if (this.areaCalculationMode == CALCULATE_POSITIVE_AREA || this.areaCalculationMode == CALCULATE_ALL_AREA) { |
985 || areaCalculationMode == CALCULATE_ALL_AREA) { | 836 area += Math.abs(this.positiveArea); |
986 area += Math.abs(positiveArea); | 837 } |
987 } | 838 if (this.areaCalculationMode == CALCULATE_NEGATIVE_AREA || this.areaCalculationMode == CALCULATE_ALL_AREA) { |
988 if (areaCalculationMode == CALCULATE_NEGATIVE_AREA | 839 area += Math.abs(this.negativeArea); |
989 || areaCalculationMode == CALCULATE_ALL_AREA) { | |
990 area += Math.abs(negativeArea); | |
991 } | 840 } |
992 if (area != 0f) { | 841 if (area != 0f) { |
993 Color oldColor = g2.getColor(); | 842 final Color oldColor = g2.getColor(); |
994 Font oldFont = g2.getFont(); | 843 final Font oldFont = g2.getFont(); |
995 g2.setFont(labelFont); | 844 g2.setFont(this.labelFont); |
996 String labelText = String.format(this.areaLabelTamplate, | 845 final String labelText = String.format(this.areaLabelTamplate, this.areaLabelNumberFormat.format(area)); |
997 areaLabelNumberFormat.format(area)); | 846 if (this.labelBGColor != null) { |
998 if (labelBGColor != null) { | 847 EnhancedLineAndShapeRenderer.drawTextBox(g2, labelText, (float) center_x, (float) center_y, this.labelBGColor); |
999 EnhancedLineAndShapeRenderer.drawTextBox(g2, labelText, | |
1000 (float)center_x, (float)center_y, labelBGColor); | |
1001 } | 848 } |
1002 g2.setColor(labelColor); | 849 g2.setColor(this.labelColor); |
1003 g2.drawString(labelText, (float)center_x, (float)center_y); | 850 g2.drawString(labelText, (float) center_x, (float) center_y); |
1004 g2.setFont(oldFont); | 851 g2.setFont(oldFont); |
1005 g2.setColor(oldColor); | 852 g2.setColor(oldColor); |
1006 } | 853 } |
1007 } | 854 } |
1008 } | 855 } |
1009 | 856 |
1010 /** | 857 /** |
1011 * Draws the visual representation of a single data item, first pass. | 858 * Draws the visual representation of a single data item, first pass. |
1012 * | 859 * |
1013 * @param x_graphics the graphics device. | 860 * @param x_graphics |
1014 * @param x_dataArea the area within which the data is being drawn. | 861 * the graphics device. |
1015 * @param x_info collects information about the drawing. | 862 * @param x_dataArea |
1016 * @param x_plot the plot (can be used to obtain standard color | 863 * the area within which the data is being drawn. |
1017 * information etc). | 864 * @param x_info |
1018 * @param x_domainAxis the domain (horizontal) axis. | 865 * collects information about the drawing. |
1019 * @param x_rangeAxis the range (vertical) axis. | 866 * @param x_plot |
1020 * @param x_dataset the dataset. | 867 * the plot (can be used to obtain standard color |
1021 * @param x_series the series index (zero-based). | 868 * information etc). |
1022 * @param x_item the item index (zero-based). | 869 * @param x_domainAxis |
1023 * @param x_crosshairState crosshair information for the plot | 870 * the domain (horizontal) axis. |
1024 * (<code>null</code> permitted). | 871 * @param x_rangeAxis |
1025 */ | 872 * the range (vertical) axis. |
1026 protected void drawItemPass0(Graphics2D x_graphics, | 873 * @param x_dataset |
1027 Rectangle2D x_dataArea, | 874 * the dataset. |
1028 PlotRenderingInfo x_info, | 875 * @param x_series |
1029 XYPlot x_plot, | 876 * the series index (zero-based). |
1030 ValueAxis x_domainAxis, | 877 * @param x_item |
1031 ValueAxis x_rangeAxis, | 878 * the item index (zero-based). |
1032 XYDataset x_dataset, | 879 * @param x_crosshairState |
1033 int x_series, | 880 * crosshair information for the plot |
1034 int x_item, | 881 * (<code>null</code> permitted). |
1035 CrosshairState x_crosshairState) { | 882 */ |
883 private void drawItemPass0(final Graphics2D x_graphics, final Rectangle2D x_dataArea, final PlotRenderingInfo x_info, final XYPlot x_plot, | |
884 final ValueAxis x_domainAxis, final ValueAxis x_rangeAxis, final XYDataset x_dataset, final int x_series, final int x_item, | |
885 final CrosshairState x_crosshairState) { | |
1036 | 886 |
1037 if (!((0 == x_series) && (0 == x_item))) { | 887 if (!((0 == x_series) && (0 == x_item))) { |
1038 return; | 888 return; |
1039 } | 889 } |
1040 | 890 |
1041 boolean b_impliedZeroSubtrahend = (1 == x_dataset.getSeriesCount()); | 891 final boolean b_impliedZeroSubtrahend = (1 == x_dataset.getSeriesCount()); |
1042 | 892 |
1043 // check if either series is a degenerate case (i.e. less than 2 points) | 893 // check if either series is a degenerate case (i.e. less than 2 points) |
1044 if (isEitherSeriesDegenerate(x_dataset, b_impliedZeroSubtrahend)) { | 894 if (isEitherSeriesDegenerate(x_dataset, b_impliedZeroSubtrahend)) { |
1045 return; | 895 return; |
1046 } | 896 } |
1049 if (!b_impliedZeroSubtrahend && areSeriesDisjoint(x_dataset)) { | 899 if (!b_impliedZeroSubtrahend && areSeriesDisjoint(x_dataset)) { |
1050 return; | 900 return; |
1051 } | 901 } |
1052 | 902 |
1053 // polygon definitions | 903 // polygon definitions |
1054 LinkedList l_minuendXs = new LinkedList(); | 904 final List<Double> l_minuendXs = new LinkedList<>(); |
1055 LinkedList l_minuendYs = new LinkedList(); | 905 final List<Double> l_minuendYs = new LinkedList<>(); |
1056 LinkedList l_subtrahendXs = new LinkedList(); | 906 final List<Double> l_subtrahendXs = new LinkedList<>(); |
1057 LinkedList l_subtrahendYs = new LinkedList(); | 907 final List<Double> l_subtrahendYs = new LinkedList<>(); |
1058 LinkedList l_polygonXs = new LinkedList(); | 908 final List<Double> l_polygonXs = new LinkedList<>(); |
1059 LinkedList l_polygonYs = new LinkedList(); | 909 final List<Double> l_polygonYs = new LinkedList<>(); |
1060 | 910 |
1061 // state | 911 // state |
1062 int l_minuendItem = 0; | 912 int l_minuendItem = 0; |
1063 int l_minuendItemCount = x_dataset.getItemCount(0); | 913 final int l_minuendItemCount = x_dataset.getItemCount(0); |
1064 Double l_minuendCurX = null; | 914 Double l_minuendCurX = null; |
1065 Double l_minuendNextX = null; | 915 Double l_minuendNextX = null; |
1066 Double l_minuendCurY = null; | 916 Double l_minuendCurY = null; |
1067 Double l_minuendNextY = null; | 917 Double l_minuendNextY = null; |
1068 double l_minuendMaxY = Double.NEGATIVE_INFINITY; | 918 double l_minuendMaxY = Double.NEGATIVE_INFINITY; |
1069 double l_minuendMinY = Double.POSITIVE_INFINITY; | 919 double l_minuendMinY = Double.POSITIVE_INFINITY; |
1070 | 920 |
1071 int l_subtrahendItem = 0; | 921 int l_subtrahendItem = 0; |
1072 int l_subtrahendItemCount = 0; // actual value set below | 922 int l_subtrahendItemCount = 0; // actual value set below |
1073 Double l_subtrahendCurX = null; | 923 Double l_subtrahendCurX = null; |
1074 Double l_subtrahendNextX = null; | 924 Double l_subtrahendNextX = null; |
1075 Double l_subtrahendCurY = null; | 925 Double l_subtrahendCurY = null; |
1076 Double l_subtrahendNextY = null; | 926 Double l_subtrahendNextY = null; |
1077 double l_subtrahendMaxY = Double.NEGATIVE_INFINITY; | 927 double l_subtrahendMaxY = Double.NEGATIVE_INFINITY; |
1078 double l_subtrahendMinY = Double.POSITIVE_INFINITY; | 928 double l_subtrahendMinY = Double.POSITIVE_INFINITY; |
1079 | 929 |
1080 // if a subtrahend is not specified, assume it is zero | 930 // if a subtrahend is not specified, assume it is zero |
1081 if (b_impliedZeroSubtrahend) { | 931 if (b_impliedZeroSubtrahend) { |
1082 l_subtrahendItem = 0; | 932 l_subtrahendItem = 0; |
1083 l_subtrahendItemCount = 2; | 933 l_subtrahendItemCount = 2; |
1084 l_subtrahendCurX = new Double(x_dataset.getXValue(0, 0)); | 934 l_subtrahendCurX = new Double(x_dataset.getXValue(0, 0)); |
1085 l_subtrahendNextX = new Double(x_dataset.getXValue(0, | 935 l_subtrahendNextX = new Double(x_dataset.getXValue(0, (l_minuendItemCount - 1))); |
1086 (l_minuendItemCount - 1))); | 936 l_subtrahendCurY = new Double(0.0); |
1087 l_subtrahendCurY = new Double(0.0); | 937 l_subtrahendNextY = new Double(0.0); |
1088 l_subtrahendNextY = new Double(0.0); | 938 l_subtrahendMaxY = 0.0; |
1089 l_subtrahendMaxY = 0.0; | 939 l_subtrahendMinY = 0.0; |
1090 l_subtrahendMinY = 0.0; | |
1091 | 940 |
1092 l_subtrahendXs.add(l_subtrahendCurX); | 941 l_subtrahendXs.add(l_subtrahendCurX); |
1093 l_subtrahendYs.add(l_subtrahendCurY); | 942 l_subtrahendYs.add(l_subtrahendCurY); |
1094 } | 943 } else { |
1095 else { | |
1096 l_subtrahendItemCount = x_dataset.getItemCount(1); | 944 l_subtrahendItemCount = x_dataset.getItemCount(1); |
1097 } | 945 } |
1098 | 946 |
1099 boolean b_minuendDone = false; | 947 boolean b_minuendDone = false; |
1100 boolean b_minuendAdvanced = true; | 948 boolean b_minuendAdvanced = true; |
1101 boolean b_minuendAtIntersect = false; | 949 boolean b_minuendAtIntersect = false; |
1102 boolean b_minuendFastForward = false; | 950 boolean b_minuendFastForward = false; |
1103 boolean b_subtrahendDone = false; | 951 boolean b_subtrahendDone = false; |
1104 boolean b_subtrahendAdvanced = true; | 952 boolean b_subtrahendAdvanced = true; |
1105 boolean b_subtrahendAtIntersect = false; | 953 boolean b_subtrahendAtIntersect = false; |
1106 boolean b_subtrahendFastForward = false; | 954 boolean b_subtrahendFastForward = false; |
1107 boolean b_colinear = false; | 955 boolean b_colinear = false; |
1108 | 956 |
1109 boolean b_positive; | 957 boolean b_positive; |
1110 | 958 |
1111 // coordinate pairs | 959 // coordinate pairs |
1112 double l_x1 = 0.0, l_y1 = 0.0; // current minuend point | 960 double l_x1 = 0.0, l_y1 = 0.0; // current minuend point |
1121 l_x1 = x_dataset.getXValue(0, l_minuendItem); | 969 l_x1 = x_dataset.getXValue(0, l_minuendItem); |
1122 l_y1 = x_dataset.getYValue(0, l_minuendItem); | 970 l_y1 = x_dataset.getYValue(0, l_minuendItem); |
1123 l_x2 = x_dataset.getXValue(0, l_minuendItem + 1); | 971 l_x2 = x_dataset.getXValue(0, l_minuendItem + 1); |
1124 l_y2 = x_dataset.getYValue(0, l_minuendItem + 1); | 972 l_y2 = x_dataset.getYValue(0, l_minuendItem + 1); |
1125 | 973 |
1126 l_minuendCurX = new Double(l_x1); | 974 l_minuendCurX = new Double(l_x1); |
1127 l_minuendCurY = new Double(l_y1); | 975 l_minuendCurY = new Double(l_y1); |
1128 l_minuendNextX = new Double(l_x2); | 976 l_minuendNextX = new Double(l_x2); |
1129 l_minuendNextY = new Double(l_y2); | 977 l_minuendNextY = new Double(l_y2); |
1130 | 978 |
1131 if (b_impliedZeroSubtrahend) { | 979 if (b_impliedZeroSubtrahend) { |
1132 l_x3 = l_subtrahendCurX.doubleValue(); | 980 l_x3 = l_subtrahendCurX.doubleValue(); |
1133 l_y3 = l_subtrahendCurY.doubleValue(); | 981 l_y3 = l_subtrahendCurY.doubleValue(); |
1134 l_x4 = l_subtrahendNextX.doubleValue(); | 982 l_x4 = l_subtrahendNextX.doubleValue(); |
1135 l_y4 = l_subtrahendNextY.doubleValue(); | 983 l_y4 = l_subtrahendNextY.doubleValue(); |
1136 } | 984 } else { |
1137 else { | |
1138 l_x3 = x_dataset.getXValue(1, l_subtrahendItem); | 985 l_x3 = x_dataset.getXValue(1, l_subtrahendItem); |
1139 l_y3 = x_dataset.getYValue(1, l_subtrahendItem); | 986 l_y3 = x_dataset.getYValue(1, l_subtrahendItem); |
1140 l_x4 = x_dataset.getXValue(1, l_subtrahendItem + 1); | 987 l_x4 = x_dataset.getXValue(1, l_subtrahendItem + 1); |
1141 l_y4 = x_dataset.getYValue(1, l_subtrahendItem + 1); | 988 l_y4 = x_dataset.getYValue(1, l_subtrahendItem + 1); |
1142 | 989 |
1143 l_subtrahendCurX = new Double(l_x3); | 990 l_subtrahendCurX = new Double(l_x3); |
1144 l_subtrahendCurY = new Double(l_y3); | 991 l_subtrahendCurY = new Double(l_y3); |
1145 l_subtrahendNextX = new Double(l_x4); | 992 l_subtrahendNextX = new Double(l_x4); |
1146 l_subtrahendNextY = new Double(l_y4); | 993 l_subtrahendNextY = new Double(l_y4); |
1147 } | 994 } |
1148 | 995 |
1149 if (l_x2 <= l_x3) { | 996 if (l_x2 <= l_x3) { |
1161 } | 1008 } |
1162 | 1009 |
1163 // check if initial polygon needs to be clipped | 1010 // check if initial polygon needs to be clipped |
1164 if ((l_x3 < l_x1) && (l_x1 < l_x4)) { | 1011 if ((l_x3 < l_x1) && (l_x1 < l_x4)) { |
1165 // project onto subtrahend | 1012 // project onto subtrahend |
1166 double l_slope = (l_y4 - l_y3) / (l_x4 - l_x3); | 1013 final double l_slope = (l_y4 - l_y3) / (l_x4 - l_x3); |
1167 l_subtrahendCurX = l_minuendCurX; | 1014 l_subtrahendCurX = l_minuendCurX; |
1168 l_subtrahendCurY = new Double((l_slope * l_x1) | 1015 l_subtrahendCurY = new Double((l_slope * l_x1) + (l_y3 - (l_slope * l_x3))); |
1169 + (l_y3 - (l_slope * l_x3))); | |
1170 | 1016 |
1171 l_subtrahendXs.add(l_subtrahendCurX); | 1017 l_subtrahendXs.add(l_subtrahendCurX); |
1172 l_subtrahendYs.add(l_subtrahendCurY); | 1018 l_subtrahendYs.add(l_subtrahendCurY); |
1173 } | 1019 } |
1174 | 1020 |
1175 if ((l_x1 < l_x3) && (l_x3 < l_x2)) { | 1021 if ((l_x1 < l_x3) && (l_x3 < l_x2)) { |
1176 // project onto minuend | 1022 // project onto minuend |
1177 double l_slope = (l_y2 - l_y1) / (l_x2 - l_x1); | 1023 final double l_slope = (l_y2 - l_y1) / (l_x2 - l_x1); |
1178 l_minuendCurX = l_subtrahendCurX; | 1024 l_minuendCurX = l_subtrahendCurX; |
1179 l_minuendCurY = new Double((l_slope * l_x3) | 1025 l_minuendCurY = new Double((l_slope * l_x3) + (l_y1 - (l_slope * l_x1))); |
1180 + (l_y1 - (l_slope * l_x1))); | |
1181 | 1026 |
1182 l_minuendXs.add(l_minuendCurX); | 1027 l_minuendXs.add(l_minuendCurX); |
1183 l_minuendYs.add(l_minuendCurY); | 1028 l_minuendYs.add(l_minuendCurY); |
1184 } | 1029 } |
1185 | 1030 |
1186 l_minuendMaxY = l_minuendCurY.doubleValue(); | 1031 l_minuendMaxY = l_minuendCurY.doubleValue(); |
1187 l_minuendMinY = l_minuendCurY.doubleValue(); | 1032 l_minuendMinY = l_minuendCurY.doubleValue(); |
1188 l_subtrahendMaxY = l_subtrahendCurY.doubleValue(); | 1033 l_subtrahendMaxY = l_subtrahendCurY.doubleValue(); |
1189 l_subtrahendMinY = l_subtrahendCurY.doubleValue(); | 1034 l_subtrahendMinY = l_subtrahendCurY.doubleValue(); |
1190 | 1035 |
1191 b_fastForwardDone = true; | 1036 b_fastForwardDone = true; |
1192 } | 1037 } |
1212 l_minuendNextX = new Double(l_x2); | 1057 l_minuendNextX = new Double(l_x2); |
1213 l_minuendNextY = new Double(l_y2); | 1058 l_minuendNextY = new Double(l_y2); |
1214 } | 1059 } |
1215 | 1060 |
1216 // never updated the subtrahend if it is implied to be zero | 1061 // never updated the subtrahend if it is implied to be zero |
1217 if (!b_impliedZeroSubtrahend && !b_subtrahendDone | 1062 if (!b_impliedZeroSubtrahend && !b_subtrahendDone && !b_subtrahendFastForward && b_subtrahendAdvanced) { |
1218 && !b_subtrahendFastForward && b_subtrahendAdvanced) { | |
1219 l_x3 = x_dataset.getXValue(1, l_subtrahendItem); | 1063 l_x3 = x_dataset.getXValue(1, l_subtrahendItem); |
1220 l_y3 = x_dataset.getYValue(1, l_subtrahendItem); | 1064 l_y3 = x_dataset.getYValue(1, l_subtrahendItem); |
1221 l_subtrahendCurX = new Double(l_x3); | 1065 l_subtrahendCurX = new Double(l_x3); |
1222 l_subtrahendCurY = new Double(l_y3); | 1066 l_subtrahendCurY = new Double(l_y3); |
1223 | 1067 |
1234 l_subtrahendNextX = new Double(l_x4); | 1078 l_subtrahendNextX = new Double(l_x4); |
1235 l_subtrahendNextY = new Double(l_y4); | 1079 l_subtrahendNextY = new Double(l_y4); |
1236 } | 1080 } |
1237 | 1081 |
1238 // deassert b_*FastForward (only matters for 1st time through loop) | 1082 // deassert b_*FastForward (only matters for 1st time through loop) |
1239 b_minuendFastForward = false; | 1083 b_minuendFastForward = false; |
1240 b_subtrahendFastForward = false; | 1084 b_subtrahendFastForward = false; |
1241 | 1085 |
1242 Double l_intersectX = null; | 1086 Double l_intersectX = null; |
1243 Double l_intersectY = null; | 1087 Double l_intersectY = null; |
1244 boolean b_intersect = false; | 1088 boolean b_intersect = false; |
1245 | 1089 |
1246 b_minuendAtIntersect = false; | 1090 b_minuendAtIntersect = false; |
1247 b_subtrahendAtIntersect = false; | 1091 b_subtrahendAtIntersect = false; |
1248 | 1092 |
1249 // check for intersect | 1093 // check for intersect |
1250 if ((l_x2 == l_x4) && (l_y2 == l_y4)) { | 1094 if ((l_x2 == l_x4) && (l_y2 == l_y4)) { |
1251 // check if line segments are colinear | 1095 // check if line segments are colinear |
1252 if ((l_x1 == l_x3) && (l_y1 == l_y3)) { | 1096 if ((l_x1 == l_x3) && (l_y1 == l_y3)) { |
1253 b_colinear = true; | 1097 b_colinear = true; |
1254 } | 1098 } else { |
1255 else { | |
1256 // the intersect is at the next point for both the minuend | 1099 // the intersect is at the next point for both the minuend |
1257 // and subtrahend | 1100 // and subtrahend |
1258 l_intersectX = new Double(l_x2); | 1101 l_intersectX = new Double(l_x2); |
1259 l_intersectY = new Double(l_y2); | 1102 l_intersectY = new Double(l_y2); |
1260 | 1103 |
1261 b_intersect = true; | 1104 b_intersect = true; |
1262 b_minuendAtIntersect = true; | 1105 b_minuendAtIntersect = true; |
1263 b_subtrahendAtIntersect = true; | 1106 b_subtrahendAtIntersect = true; |
1264 } | 1107 } |
1265 } | 1108 } else { |
1266 else { | |
1267 // compute common denominator | 1109 // compute common denominator |
1268 double l_denominator = ((l_y4 - l_y3) * (l_x2 - l_x1)) | 1110 final double l_denominator = ((l_y4 - l_y3) * (l_x2 - l_x1)) - ((l_x4 - l_x3) * (l_y2 - l_y1)); |
1269 - ((l_x4 - l_x3) * (l_y2 - l_y1)); | |
1270 | 1111 |
1271 // compute common deltas | 1112 // compute common deltas |
1272 double l_deltaY = l_y1 - l_y3; | 1113 final double l_deltaY = l_y1 - l_y3; |
1273 double l_deltaX = l_x1 - l_x3; | 1114 final double l_deltaX = l_x1 - l_x3; |
1274 | 1115 |
1275 // compute numerators | 1116 // compute numerators |
1276 double l_numeratorA = ((l_x4 - l_x3) * l_deltaY) | 1117 final double l_numeratorA = ((l_x4 - l_x3) * l_deltaY) - ((l_y4 - l_y3) * l_deltaX); |
1277 - ((l_y4 - l_y3) * l_deltaX); | 1118 final double l_numeratorB = ((l_x2 - l_x1) * l_deltaY) - ((l_y2 - l_y1) * l_deltaX); |
1278 double l_numeratorB = ((l_x2 - l_x1) * l_deltaY) | |
1279 - ((l_y2 - l_y1) * l_deltaX); | |
1280 | 1119 |
1281 // check if line segments are colinear | 1120 // check if line segments are colinear |
1282 if ((0 == l_numeratorA) && (0 == l_numeratorB) | 1121 if ((0 == l_numeratorA) && (0 == l_numeratorB) && (0 == l_denominator)) { |
1283 && (0 == l_denominator)) { | |
1284 b_colinear = true; | 1122 b_colinear = true; |
1285 } | 1123 } else { |
1286 else { | |
1287 // check if previously colinear | 1124 // check if previously colinear |
1288 if (b_colinear) { | 1125 if (b_colinear) { |
1289 // clear colinear points and flag | 1126 // clear colinear points and flag |
1290 l_minuendXs.clear(); | 1127 l_minuendXs.clear(); |
1291 l_minuendYs.clear(); | 1128 l_minuendYs.clear(); |
1295 l_polygonYs.clear(); | 1132 l_polygonYs.clear(); |
1296 | 1133 |
1297 b_colinear = false; | 1134 b_colinear = false; |
1298 | 1135 |
1299 // set new starting point for the polygon | 1136 // set new starting point for the polygon |
1300 boolean b_useMinuend = ((l_x3 <= l_x1) | 1137 final boolean b_useMinuend = ((l_x3 <= l_x1) && (l_x1 <= l_x4)); |
1301 && (l_x1 <= l_x4)); | 1138 l_polygonXs.add(b_useMinuend ? l_minuendCurX : l_subtrahendCurX); |
1302 l_polygonXs.add(b_useMinuend ? l_minuendCurX | 1139 l_polygonYs.add(b_useMinuend ? l_minuendCurY : l_subtrahendCurY); |
1303 : l_subtrahendCurX); | |
1304 l_polygonYs.add(b_useMinuend ? l_minuendCurY | |
1305 : l_subtrahendCurY); | |
1306 } | 1140 } |
1307 | 1141 |
1308 // compute slope components | 1142 // compute slope components |
1309 double l_slopeA = l_numeratorA / l_denominator; | 1143 final double l_slopeA = l_numeratorA / l_denominator; |
1310 double l_slopeB = l_numeratorB / l_denominator; | 1144 final double l_slopeB = l_numeratorB / l_denominator; |
1311 | 1145 |
1312 // check if the line segments intersect | 1146 // check if the line segments intersect |
1313 if ((0 < l_slopeA) && (l_slopeA <= 1) && (0 < l_slopeB) | 1147 if ((0 < l_slopeA) && (l_slopeA <= 1) && (0 < l_slopeB) && (l_slopeB <= 1)) { |
1314 && (l_slopeB <= 1)) { | |
1315 // compute the point of intersection | 1148 // compute the point of intersection |
1316 double l_xi = l_x1 + (l_slopeA * (l_x2 - l_x1)); | 1149 final double l_xi = l_x1 + (l_slopeA * (l_x2 - l_x1)); |
1317 double l_yi = l_y1 + (l_slopeA * (l_y2 - l_y1)); | 1150 final double l_yi = l_y1 + (l_slopeA * (l_y2 - l_y1)); |
1318 | 1151 |
1319 l_intersectX = new Double(l_xi); | 1152 l_intersectX = new Double(l_xi); |
1320 l_intersectY = new Double(l_yi); | 1153 l_intersectY = new Double(l_yi); |
1321 b_intersect = true; | 1154 b_intersect = true; |
1322 b_minuendAtIntersect = ((l_xi == l_x2) | 1155 b_minuendAtIntersect = ((l_xi == l_x2) && (l_yi == l_y2)); |
1323 && (l_yi == l_y2)); | 1156 b_subtrahendAtIntersect = ((l_xi == l_x4) && (l_yi == l_y4)); |
1324 b_subtrahendAtIntersect = ((l_xi == l_x4) | |
1325 && (l_yi == l_y4)); | |
1326 | 1157 |
1327 // advance minuend and subtrahend to intesect | 1158 // advance minuend and subtrahend to intesect |
1328 l_minuendCurX = l_intersectX; | 1159 l_minuendCurX = l_intersectX; |
1329 l_minuendCurY = l_intersectY; | 1160 l_minuendCurY = l_intersectY; |
1330 l_subtrahendCurX = l_intersectX; | 1161 l_subtrahendCurX = l_intersectX; |
1331 l_subtrahendCurY = l_intersectY; | 1162 l_subtrahendCurY = l_intersectY; |
1332 } | 1163 } |
1333 } | 1164 } |
1334 } | 1165 } |
1348 Collections.reverse(l_subtrahendYs); | 1179 Collections.reverse(l_subtrahendYs); |
1349 l_polygonXs.addAll(l_subtrahendXs); | 1180 l_polygonXs.addAll(l_subtrahendXs); |
1350 l_polygonYs.addAll(l_subtrahendYs); | 1181 l_polygonYs.addAll(l_subtrahendYs); |
1351 | 1182 |
1352 // create an actual polygon | 1183 // create an actual polygon |
1353 b_positive = (l_subtrahendMaxY <= l_minuendMaxY) | 1184 b_positive = (l_subtrahendMaxY <= l_minuendMaxY) && (l_subtrahendMinY <= l_minuendMinY); |
1354 && (l_subtrahendMinY <= l_minuendMinY); | 1185 createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis, x_rangeAxis, b_positive, l_polygonXs, l_polygonYs); |
1355 createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis, | |
1356 x_rangeAxis, b_positive, l_polygonXs, l_polygonYs); | |
1357 | 1186 |
1358 // clear the point vectors | 1187 // clear the point vectors |
1359 l_minuendXs.clear(); | 1188 l_minuendXs.clear(); |
1360 l_minuendYs.clear(); | 1189 l_minuendYs.clear(); |
1361 l_subtrahendXs.clear(); | 1190 l_subtrahendXs.clear(); |
1362 l_subtrahendYs.clear(); | 1191 l_subtrahendYs.clear(); |
1363 l_polygonXs.clear(); | 1192 l_polygonXs.clear(); |
1364 l_polygonYs.clear(); | 1193 l_polygonYs.clear(); |
1365 | 1194 |
1366 // set the maxY and minY values to intersect y-value | 1195 // set the maxY and minY values to intersect y-value |
1367 double l_y = l_intersectY.doubleValue(); | 1196 final double l_y = l_intersectY.doubleValue(); |
1368 l_minuendMaxY = l_y; | 1197 l_minuendMaxY = l_y; |
1369 l_subtrahendMaxY = l_y; | 1198 l_subtrahendMaxY = l_y; |
1370 l_minuendMinY = l_y; | 1199 l_minuendMinY = l_y; |
1371 l_subtrahendMinY = l_y; | 1200 l_subtrahendMinY = l_y; |
1372 | 1201 |
1373 // add interection point to new polygon | 1202 // add interection point to new polygon |
1374 l_polygonXs.add(l_intersectX); | 1203 l_polygonXs.add(l_intersectX); |
1375 l_polygonYs.add(l_intersectY); | 1204 l_polygonYs.add(l_intersectY); |
1377 | 1206 |
1378 // advance the minuend if needed | 1207 // advance the minuend if needed |
1379 if (l_x2 <= l_x4) { | 1208 if (l_x2 <= l_x4) { |
1380 l_minuendItem++; | 1209 l_minuendItem++; |
1381 b_minuendAdvanced = true; | 1210 b_minuendAdvanced = true; |
1382 } | 1211 } else { |
1383 else { | |
1384 b_minuendAdvanced = false; | 1212 b_minuendAdvanced = false; |
1385 } | 1213 } |
1386 | 1214 |
1387 // advance the subtrahend if needed | 1215 // advance the subtrahend if needed |
1388 if (l_x4 <= l_x2) { | 1216 if (l_x4 <= l_x2) { |
1389 l_subtrahendItem++; | 1217 l_subtrahendItem++; |
1390 b_subtrahendAdvanced = true; | 1218 b_subtrahendAdvanced = true; |
1391 } | 1219 } else { |
1392 else { | |
1393 b_subtrahendAdvanced = false; | 1220 b_subtrahendAdvanced = false; |
1394 } | 1221 } |
1395 | 1222 |
1396 b_minuendDone = (l_minuendItem == (l_minuendItemCount - 1)); | 1223 b_minuendDone = (l_minuendItem == (l_minuendItemCount - 1)); |
1397 b_subtrahendDone = (l_subtrahendItem == (l_subtrahendItemCount | 1224 b_subtrahendDone = (l_subtrahendItem == (l_subtrahendItemCount - 1)); |
1398 - 1)); | |
1399 } | 1225 } |
1400 | 1226 |
1401 // check if the final polygon needs to be clipped | 1227 // check if the final polygon needs to be clipped |
1402 if (b_minuendDone && (l_x3 < l_x2) && (l_x2 < l_x4)) { | 1228 if (b_minuendDone && (l_x3 < l_x2) && (l_x2 < l_x4)) { |
1403 // project onto subtrahend | 1229 // project onto subtrahend |
1404 double l_slope = (l_y4 - l_y3) / (l_x4 - l_x3); | 1230 final double l_slope = (l_y4 - l_y3) / (l_x4 - l_x3); |
1405 l_subtrahendNextX = l_minuendNextX; | 1231 l_subtrahendNextX = l_minuendNextX; |
1406 l_subtrahendNextY = new Double((l_slope * l_x2) | 1232 l_subtrahendNextY = new Double((l_slope * l_x2) + (l_y3 - (l_slope * l_x3))); |
1407 + (l_y3 - (l_slope * l_x3))); | |
1408 } | 1233 } |
1409 | 1234 |
1410 if (b_subtrahendDone && (l_x1 < l_x4) && (l_x4 < l_x2)) { | 1235 if (b_subtrahendDone && (l_x1 < l_x4) && (l_x4 < l_x2)) { |
1411 // project onto minuend | 1236 // project onto minuend |
1412 double l_slope = (l_y2 - l_y1) / (l_x2 - l_x1); | 1237 final double l_slope = (l_y2 - l_y1) / (l_x2 - l_x1); |
1413 l_minuendNextX = l_subtrahendNextX; | 1238 l_minuendNextX = l_subtrahendNextX; |
1414 l_minuendNextY = new Double((l_slope * l_x4) | 1239 l_minuendNextY = new Double((l_slope * l_x4) + (l_y1 - (l_slope * l_x1))); |
1415 + (l_y1 - (l_slope * l_x1))); | |
1416 } | 1240 } |
1417 | 1241 |
1418 // consider last point of minuend and subtrahend for determining | 1242 // consider last point of minuend and subtrahend for determining |
1419 // positivity | 1243 // positivity |
1420 l_minuendMaxY = Math.max(l_minuendMaxY, | 1244 l_minuendMaxY = Math.max(l_minuendMaxY, l_minuendNextY.doubleValue()); |
1421 l_minuendNextY.doubleValue()); | 1245 l_subtrahendMaxY = Math.max(l_subtrahendMaxY, l_subtrahendNextY.doubleValue()); |
1422 l_subtrahendMaxY = Math.max(l_subtrahendMaxY, | 1246 l_minuendMinY = Math.min(l_minuendMinY, l_minuendNextY.doubleValue()); |
1423 l_subtrahendNextY.doubleValue()); | 1247 l_subtrahendMinY = Math.min(l_subtrahendMinY, l_subtrahendNextY.doubleValue()); |
1424 l_minuendMinY = Math.min(l_minuendMinY, | |
1425 l_minuendNextY.doubleValue()); | |
1426 l_subtrahendMinY = Math.min(l_subtrahendMinY, | |
1427 l_subtrahendNextY.doubleValue()); | |
1428 | 1248 |
1429 // add the last point of the minuned and subtrahend | 1249 // add the last point of the minuned and subtrahend |
1430 l_minuendXs.add(l_minuendNextX); | 1250 l_minuendXs.add(l_minuendNextX); |
1431 l_minuendYs.add(l_minuendNextY); | 1251 l_minuendYs.add(l_minuendNextY); |
1432 l_subtrahendXs.add(l_subtrahendNextX); | 1252 l_subtrahendXs.add(l_subtrahendNextX); |
1442 Collections.reverse(l_subtrahendYs); | 1262 Collections.reverse(l_subtrahendYs); |
1443 l_polygonXs.addAll(l_subtrahendXs); | 1263 l_polygonXs.addAll(l_subtrahendXs); |
1444 l_polygonYs.addAll(l_subtrahendYs); | 1264 l_polygonYs.addAll(l_subtrahendYs); |
1445 | 1265 |
1446 // create an actual polygon | 1266 // create an actual polygon |
1447 b_positive = (l_subtrahendMaxY <= l_minuendMaxY) | 1267 b_positive = (l_subtrahendMaxY <= l_minuendMaxY) && (l_subtrahendMinY <= l_minuendMinY); |
1448 && (l_subtrahendMinY <= l_minuendMinY); | 1268 createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis, x_rangeAxis, b_positive, l_polygonXs, l_polygonYs); |
1449 createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis, | 1269 } |
1450 x_rangeAxis, b_positive, l_polygonXs, l_polygonYs); | 1270 |
1451 } | 1271 /** |
1452 | 1272 * Draws the visual representation of a single data item, second pass. In |
1453 /** | |
1454 * Draws the visual representation of a single data item, second pass. In | |
1455 * the second pass, the renderer draws the lines and shapes for the | 1273 * the second pass, the renderer draws the lines and shapes for the |
1456 * individual points in the two series. | 1274 * individual points in the two series. |
1457 * | 1275 * |
1458 * @param x_graphics the graphics device. | 1276 * @param x_graphics |
1459 * @param x_dataArea the area within which the data is being drawn. | 1277 * the graphics device. |
1460 * @param x_info collects information about the drawing. | 1278 * @param x_dataArea |
1461 * @param x_plot the plot (can be used to obtain standard color | 1279 * the area within which the data is being drawn. |
1462 * information etc). | 1280 * @param x_info |
1463 * @param x_domainAxis the domain (horizontal) axis. | 1281 * collects information about the drawing. |
1464 * @param x_rangeAxis the range (vertical) axis. | 1282 * @param x_plot |
1465 * @param x_dataset the dataset. | 1283 * the plot (can be used to obtain standard color |
1466 * @param x_series the series index (zero-based). | 1284 * information etc). |
1467 * @param x_item the item index (zero-based). | 1285 * @param x_domainAxis |
1468 * @param x_crosshairState crosshair information for the plot | 1286 * the domain (horizontal) axis. |
1469 * (<code>null</code> permitted). | 1287 * @param x_rangeAxis |
1470 */ | 1288 * the range (vertical) axis. |
1471 protected void drawItemPass1(Graphics2D x_graphics, | 1289 * @param x_dataset |
1472 Rectangle2D x_dataArea, | 1290 * the dataset. |
1473 PlotRenderingInfo x_info, | 1291 * @param x_series |
1474 XYPlot x_plot, | 1292 * the series index (zero-based). |
1475 ValueAxis x_domainAxis, | 1293 * @param x_item |
1476 ValueAxis x_rangeAxis, | 1294 * the item index (zero-based). |
1477 XYDataset x_dataset, | 1295 * @param x_crosshairState |
1478 int x_series, | 1296 * crosshair information for the plot |
1479 int x_item, | 1297 * (<code>null</code> permitted). |
1480 CrosshairState x_crosshairState) { | 1298 */ |
1299 private void drawItemPass1(final Graphics2D x_graphics, final Rectangle2D x_dataArea, final PlotRenderingInfo x_info, final XYPlot x_plot, | |
1300 final ValueAxis x_domainAxis, final ValueAxis x_rangeAxis, final XYDataset x_dataset, final int x_series, final int x_item, | |
1301 final CrosshairState x_crosshairState) { | |
1481 | 1302 |
1482 Shape l_entityArea = null; | 1303 Shape l_entityArea = null; |
1483 EntityCollection l_entities = null; | 1304 EntityCollection l_entities = null; |
1484 if (null != x_info) { | 1305 if (null != x_info) { |
1485 l_entities = x_info.getOwner().getEntityCollection(); | 1306 l_entities = x_info.getOwner().getEntityCollection(); |
1486 } | 1307 } |
1487 | 1308 |
1488 Paint l_seriesPaint = getItemPaint(x_series, x_item); | 1309 final Paint l_seriesPaint = getItemPaint(x_series, x_item); |
1489 Stroke l_seriesStroke = getItemStroke(x_series, x_item); | 1310 final Stroke l_seriesStroke = getItemStroke(x_series, x_item); |
1490 x_graphics.setPaint(l_seriesPaint); | 1311 x_graphics.setPaint(l_seriesPaint); |
1491 x_graphics.setStroke(l_seriesStroke); | 1312 x_graphics.setStroke(l_seriesStroke); |
1492 | 1313 |
1493 PlotOrientation l_orientation = x_plot.getOrientation(); | 1314 final PlotOrientation l_orientation = x_plot.getOrientation(); |
1494 RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge(); | 1315 final RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge(); |
1495 RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge(); | 1316 final RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge(); |
1496 | 1317 |
1497 double l_x0 = x_dataset.getXValue(x_series, x_item); | 1318 final double l_x0 = x_dataset.getXValue(x_series, x_item); |
1498 double l_y0 = x_dataset.getYValue(x_series, x_item); | 1319 final double l_y0 = x_dataset.getYValue(x_series, x_item); |
1499 double l_x1 = x_domainAxis.valueToJava2D(l_x0, x_dataArea, | 1320 final double l_x1 = x_domainAxis.valueToJava2D(l_x0, x_dataArea, l_domainAxisLocation); |
1500 l_domainAxisLocation); | 1321 final double l_y1 = x_rangeAxis.valueToJava2D(l_y0, x_dataArea, l_rangeAxisLocation); |
1501 double l_y1 = x_rangeAxis.valueToJava2D(l_y0, x_dataArea, | |
1502 l_rangeAxisLocation); | |
1503 | 1322 |
1504 // These are the shapes of the series items. | 1323 // These are the shapes of the series items. |
1505 if (getShapesVisible()) { | 1324 if (getShapesVisible()) { |
1506 Shape l_shape = getItemShape(x_series, x_item); | 1325 Shape l_shape = getItemShape(x_series, x_item); |
1507 if (l_orientation == PlotOrientation.HORIZONTAL) { | 1326 if (l_orientation == PlotOrientation.HORIZONTAL) { |
1508 l_shape = ShapeUtilities.createTranslatedShape(l_shape, | 1327 l_shape = ShapeUtilities.createTranslatedShape(l_shape, l_y1, l_x1); |
1509 l_y1, l_x1); | 1328 } else { |
1510 } | 1329 l_shape = ShapeUtilities.createTranslatedShape(l_shape, l_x1, l_y1); |
1511 else { | |
1512 l_shape = ShapeUtilities.createTranslatedShape(l_shape, | |
1513 l_x1, l_y1); | |
1514 } | 1330 } |
1515 if (l_shape.intersects(x_dataArea)) { | 1331 if (l_shape.intersects(x_dataArea)) { |
1516 x_graphics.setPaint(getItemPaint(x_series, x_item)); | 1332 x_graphics.setPaint(getItemPaint(x_series, x_item)); |
1517 x_graphics.fill(l_shape); | 1333 x_graphics.fill(l_shape); |
1518 /* TODO We could draw the shapes of single items here. | 1334 /* |
1519 if (drawOutline) { | 1335 * TODO We could draw the shapes of single items here. |
1520 x_graphics.setPaint(this.outlinePaint); | 1336 * if (drawOutline) { |
1521 x_graphics.setStroke(this.outlineStroke); | 1337 * x_graphics.setPaint(this.outlinePaint); |
1522 x_graphics.draw(l_shape); | 1338 * x_graphics.setStroke(this.outlineStroke); |
1523 } | 1339 * x_graphics.draw(l_shape); |
1524 */ | 1340 * } |
1341 */ | |
1525 } | 1342 } |
1526 l_entityArea = l_shape; | 1343 l_entityArea = l_shape; |
1527 } // if (getShapesVisible()) | 1344 } // if (getShapesVisible()) |
1528 | 1345 |
1529 // add an entity for the item... | 1346 // add an entity for the item... |
1530 if (null != l_entities) { | 1347 if (null != l_entities) { |
1531 if (null == l_entityArea) { | 1348 if (null == l_entityArea) { |
1532 l_entityArea = new Rectangle2D.Double((l_x1 - 2), (l_y1 - 2), | 1349 l_entityArea = new Rectangle2D.Double((l_x1 - 2), (l_y1 - 2), 4, 4); |
1533 4, 4); | |
1534 } | 1350 } |
1535 String l_tip = null; | 1351 String l_tip = null; |
1536 XYToolTipGenerator l_tipGenerator = getToolTipGenerator(x_series, | 1352 final XYToolTipGenerator l_tipGenerator = getToolTipGenerator(x_series, x_item); |
1537 x_item); | |
1538 if (null != l_tipGenerator) { | 1353 if (null != l_tipGenerator) { |
1539 l_tip = l_tipGenerator.generateToolTip(x_dataset, x_series, | 1354 l_tip = l_tipGenerator.generateToolTip(x_dataset, x_series, x_item); |
1540 x_item); | |
1541 } | 1355 } |
1542 String l_url = null; | 1356 String l_url = null; |
1543 XYURLGenerator l_urlGenerator = getURLGenerator(); | 1357 final XYURLGenerator l_urlGenerator = getURLGenerator(); |
1544 if (null != l_urlGenerator) { | 1358 if (null != l_urlGenerator) { |
1545 l_url = l_urlGenerator.generateURL(x_dataset, x_series, | 1359 l_url = l_urlGenerator.generateURL(x_dataset, x_series, x_item); |
1546 x_item); | 1360 } |
1547 } | 1361 final XYItemEntity l_entity = new XYItemEntity(l_entityArea, x_dataset, x_series, x_item, l_tip, l_url); |
1548 XYItemEntity l_entity = new XYItemEntity(l_entityArea, x_dataset, | |
1549 x_series, x_item, l_tip, l_url); | |
1550 l_entities.add(l_entity); | 1362 l_entities.add(l_entity); |
1551 } | 1363 } |
1552 | 1364 |
1553 // draw the item label if there is one... | 1365 // draw the item label if there is one... |
1554 if (isItemLabelVisible(x_series, x_item)) { | 1366 if (isItemLabelVisible(x_series, x_item)) { |
1555 drawItemLabel(x_graphics, l_orientation, x_dataset, x_series, | 1367 drawItemLabel(x_graphics, l_orientation, x_dataset, x_series, x_item, l_x1, l_y1, (l_y1 < 0.0)); |
1556 x_item, l_x1, l_y1, (l_y1 < 0.0)); | 1368 } |
1557 } | 1369 |
1558 | 1370 final int l_domainAxisIndex = x_plot.getDomainAxisIndex(x_domainAxis); |
1559 int l_domainAxisIndex = x_plot.getDomainAxisIndex(x_domainAxis); | 1371 final int l_rangeAxisIndex = x_plot.getRangeAxisIndex(x_rangeAxis); |
1560 int l_rangeAxisIndex = x_plot.getRangeAxisIndex(x_rangeAxis); | 1372 updateCrosshairValues(x_crosshairState, l_x0, l_y0, l_domainAxisIndex, l_rangeAxisIndex, l_x1, l_y1, l_orientation); |
1561 updateCrosshairValues(x_crosshairState, l_x0, l_y0, l_domainAxisIndex, | |
1562 l_rangeAxisIndex, l_x1, l_y1, l_orientation); | |
1563 | 1373 |
1564 if (0 == x_item) { | 1374 if (0 == x_item) { |
1565 return; | 1375 return; |
1566 } | 1376 } |
1567 | 1377 |
1568 double l_x2 = x_domainAxis.valueToJava2D(x_dataset.getXValue(x_series, | 1378 final double l_x2 = x_domainAxis.valueToJava2D(x_dataset.getXValue(x_series, (x_item - 1)), x_dataArea, l_domainAxisLocation); |
1569 (x_item - 1)), x_dataArea, l_domainAxisLocation); | 1379 final double l_y2 = x_rangeAxis.valueToJava2D(x_dataset.getYValue(x_series, (x_item - 1)), x_dataArea, l_rangeAxisLocation); |
1570 double l_y2 = x_rangeAxis.valueToJava2D(x_dataset.getYValue(x_series, | |
1571 (x_item - 1)), x_dataArea, l_rangeAxisLocation); | |
1572 | 1380 |
1573 Line2D l_line = null; | 1381 Line2D l_line = null; |
1574 if (PlotOrientation.HORIZONTAL == l_orientation) { | 1382 if (PlotOrientation.HORIZONTAL == l_orientation) { |
1575 l_line = new Line2D.Double(l_y1, l_x1, l_y2, l_x2); | 1383 l_line = new Line2D.Double(l_y1, l_x1, l_y2, l_x2); |
1576 } | 1384 } else if (PlotOrientation.VERTICAL == l_orientation) { |
1577 else if (PlotOrientation.VERTICAL == l_orientation) { | |
1578 l_line = new Line2D.Double(l_x1, l_y1, l_x2, l_y2); | 1385 l_line = new Line2D.Double(l_x1, l_y1, l_x2, l_y2); |
1579 } | 1386 } |
1580 | 1387 |
1581 if ((null != l_line) && l_line.intersects(x_dataArea)) { | 1388 if ((null != l_line) && l_line.intersects(x_dataArea)) { |
1582 x_graphics.setPaint(getItemPaint(x_series, x_item)); | 1389 x_graphics.setPaint(getItemPaint(x_series, x_item)); |
1583 x_graphics.setStroke(getItemStroke(x_series, x_item)); | 1390 x_graphics.setStroke(getItemStroke(x_series, x_item)); |
1584 if (drawOriginalSeries) { | 1391 if (this.drawOriginalSeries) { |
1585 x_graphics.setPaint(this.outlinePaint); | 1392 x_graphics.setPaint(this.outlinePaint); |
1586 x_graphics.setStroke(this.outlineStroke); | 1393 x_graphics.setStroke(this.outlineStroke); |
1587 x_graphics.draw(l_line); | 1394 x_graphics.draw(l_line); |
1588 } | 1395 } |
1589 } | 1396 } |
1590 } | 1397 } |
1591 | 1398 |
1592 /** | 1399 /** |
1593 * Determines if a dataset is degenerate. A degenerate dataset is a | 1400 * Determines if a dataset is degenerate. A degenerate dataset is a |
1594 * dataset where either series has less than two (2) points. | 1401 * dataset where either series has less than two (2) points. |
1595 * | 1402 * |
1596 * @param x_dataset the dataset. | 1403 * @param x_dataset |
1597 * @param x_impliedZeroSubtrahend if false, do not check the subtrahend | 1404 * the dataset. |
1405 * @param x_impliedZeroSubtrahend | |
1406 * if false, do not check the subtrahend | |
1598 * | 1407 * |
1599 * @return true if the dataset is degenerate. | 1408 * @return true if the dataset is degenerate. |
1600 */ | 1409 */ |
1601 private boolean isEitherSeriesDegenerate(XYDataset x_dataset, | 1410 private boolean isEitherSeriesDegenerate(final XYDataset x_dataset, final boolean x_impliedZeroSubtrahend) { |
1602 boolean x_impliedZeroSubtrahend) { | |
1603 | 1411 |
1604 if (x_impliedZeroSubtrahend) { | 1412 if (x_impliedZeroSubtrahend) { |
1605 return (x_dataset.getItemCount(0) < 2); | 1413 return (x_dataset.getItemCount(0) < 2); |
1606 } | 1414 } |
1607 | 1415 |
1608 return ((x_dataset.getItemCount(0) < 2) | 1416 return ((x_dataset.getItemCount(0) < 2) || (x_dataset.getItemCount(1) < 2)); |
1609 || (x_dataset.getItemCount(1) < 2)); | |
1610 } | 1417 } |
1611 | 1418 |
1612 /** | 1419 /** |
1613 * Determines if the two (2) series are disjoint. | 1420 * Determines if the two (2) series are disjoint. |
1614 * Disjoint series do not overlap in the domain space. | 1421 * Disjoint series do not overlap in the domain space. |
1615 * | 1422 * |
1616 * @param x_dataset the dataset. | 1423 * @param x_dataset |
1424 * the dataset. | |
1617 * | 1425 * |
1618 * @return true if the dataset is degenerate. | 1426 * @return true if the dataset is degenerate. |
1619 */ | 1427 */ |
1620 private boolean areSeriesDisjoint(XYDataset x_dataset) { | 1428 private boolean areSeriesDisjoint(final XYDataset x_dataset) { |
1621 | 1429 |
1622 int l_minuendItemCount = x_dataset.getItemCount(0); | 1430 final int l_minuendItemCount = x_dataset.getItemCount(0); |
1623 double l_minuendFirst = x_dataset.getXValue(0, 0); | 1431 final double l_minuendFirst = x_dataset.getXValue(0, 0); |
1624 double l_minuendLast = x_dataset.getXValue(0, l_minuendItemCount - 1); | 1432 final double l_minuendLast = x_dataset.getXValue(0, l_minuendItemCount - 1); |
1625 | 1433 |
1626 int l_subtrahendItemCount = x_dataset.getItemCount(1); | 1434 final int l_subtrahendItemCount = x_dataset.getItemCount(1); |
1627 double l_subtrahendFirst = x_dataset.getXValue(1, 0); | 1435 final double l_subtrahendFirst = x_dataset.getXValue(1, 0); |
1628 double l_subtrahendLast = x_dataset.getXValue(1, | 1436 final double l_subtrahendLast = x_dataset.getXValue(1, l_subtrahendItemCount - 1); |
1629 l_subtrahendItemCount - 1); | 1437 |
1630 | 1438 return ((l_minuendLast < l_subtrahendFirst) || (l_subtrahendLast < l_minuendFirst)); |
1631 return ((l_minuendLast < l_subtrahendFirst) | 1439 } |
1632 || (l_subtrahendLast < l_minuendFirst)); | 1440 |
1633 } | 1441 private void updateCentroid(final Object[] xValues, final Object[] yValues) { |
1634 | |
1635 | |
1636 public void updateCentroid(Object [] xValues, Object [] yValues) { | |
1637 double x = 0d, y = 0d; | 1442 double x = 0d, y = 0d; |
1638 | 1443 |
1639 for (int i = 0, N = xValues.length; i < N; ++i) { | 1444 for (int i = 0, N = xValues.length; i < N; ++i) { |
1640 x += ((Double)xValues[i]).doubleValue(); | 1445 x += ((Double) xValues[i]).doubleValue(); |
1641 y += ((Double)yValues[i]).doubleValue(); | 1446 y += ((Double) yValues[i]).doubleValue(); |
1642 } | 1447 } |
1643 | 1448 |
1644 x /= xValues.length; | 1449 x /= xValues.length; |
1645 y /= yValues.length; | 1450 y /= yValues.length; |
1646 | 1451 |
1647 centroidNPoints++; | 1452 this.centroidNPoints++; |
1648 double factorNew = 1d / centroidNPoints; | 1453 final double factorNew = 1d / this.centroidNPoints; |
1649 double factorOld = 1d - factorNew; | 1454 final double factorOld = 1d - factorNew; |
1650 | 1455 |
1651 centroid = new Point2D.Double((factorNew * x + factorOld * centroid.x), | 1456 this.centroid = new Point2D.Double((factorNew * x + factorOld * this.centroid.x), (factorNew * y + factorOld * this.centroid.y)); |
1652 (factorNew * y + factorOld * centroid.y)); | 1457 } |
1653 } | 1458 |
1654 | 1459 private static double calculateArea(final Object[] xValues, final Object[] yValues) { |
1655 | |
1656 public static double calculateArea(Object [] xValues, Object [] yValues) { | |
1657 double area = 0d; | 1460 double area = 0d; |
1658 | 1461 |
1659 for (int i = 0, N = xValues.length; i < N; ++i) { | 1462 for (int i = 0, N = xValues.length; i < N; ++i) { |
1660 int k = (i + 1) % N; | 1463 final int k = (i + 1) % N; |
1661 double xi = ((Double)xValues[i]).doubleValue(); | 1464 final double xi = ((Double) xValues[i]).doubleValue(); |
1662 double yi = ((Double)yValues[i]).doubleValue(); | 1465 final double yi = ((Double) yValues[i]).doubleValue(); |
1663 double xk = ((Double)xValues[k]).doubleValue(); | 1466 final double xk = ((Double) xValues[k]).doubleValue(); |
1664 double yk = ((Double)yValues[k]).doubleValue(); | 1467 final double yk = ((Double) yValues[k]).doubleValue(); |
1665 | 1468 |
1666 area += xi*yk; | 1469 area += xi * yk; |
1667 area -= xk*yi; | 1470 area -= xk * yi; |
1668 // TODO centroid calculation here? | 1471 // TODO centroid calculation here? |
1669 } | 1472 } |
1670 | 1473 |
1671 return 0.5d*area; | 1474 return 0.5d * area; |
1672 } | 1475 } |
1673 | 1476 |
1674 /** | 1477 /** |
1675 * Draws the visual representation of a polygon | 1478 * Draws the visual representation of a polygon |
1676 * | 1479 * |
1677 * @param x_graphics the graphics device. | 1480 * @param x_graphics |
1678 * @param x_dataArea the area within which the data is being drawn. | 1481 * the graphics device. |
1679 * @param x_plot the plot (can be used to obtain standard color | 1482 * @param x_dataArea |
1680 * information etc). | 1483 * the area within which the data is being drawn. |
1681 * @param x_domainAxis the domain (horizontal) axis. | 1484 * @param x_plot |
1682 * @param x_rangeAxis the range (vertical) axis. | 1485 * the plot (can be used to obtain standard color |
1683 * @param x_positive indicates if the polygon is positive (true) or | 1486 * information etc). |
1684 * negative (false). | 1487 * @param x_domainAxis |
1685 * @param x_xValues a linked list of the x values (expects values to be | 1488 * the domain (horizontal) axis. |
1686 * of type Double). | 1489 * @param x_rangeAxis |
1687 * @param x_yValues a linked list of the y values (expects values to be | 1490 * the range (vertical) axis. |
1688 * of type Double). | 1491 * @param x_positive |
1689 */ | 1492 * indicates if the polygon is positive (true) or |
1690 private void createPolygon (Graphics2D x_graphics, | 1493 * negative (false). |
1691 Rectangle2D x_dataArea, | 1494 * @param x_xValues |
1692 XYPlot x_plot, | 1495 * a linked list of the x values (expects values to be |
1693 ValueAxis x_domainAxis, | 1496 * of type Double). |
1694 ValueAxis x_rangeAxis, | 1497 * @param x_yValues |
1695 boolean x_positive, | 1498 * a linked list of the y values (expects values to be |
1696 LinkedList x_xValues, | 1499 * of type Double). |
1697 LinkedList x_yValues) { | 1500 */ |
1698 | 1501 private void createPolygon(final Graphics2D x_graphics, final Rectangle2D x_dataArea, final XYPlot x_plot, final ValueAxis x_domainAxis, |
1699 PlotOrientation l_orientation = x_plot.getOrientation(); | 1502 final ValueAxis x_rangeAxis, final boolean x_positive, final List<Double> x_xValues, final List<Double> x_yValues) { |
1700 RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge(); | 1503 |
1701 RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge(); | 1504 final PlotOrientation l_orientation = x_plot.getOrientation(); |
1702 | 1505 final RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge(); |
1703 Object[] l_xValues = x_xValues.toArray(); | 1506 final RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge(); |
1704 Object[] l_yValues = x_yValues.toArray(); | 1507 |
1705 | 1508 final Object[] l_xValues = x_xValues.toArray(); |
1706 double area = calculateArea(l_xValues, l_yValues); | 1509 final Object[] l_yValues = x_yValues.toArray(); |
1707 if (x_positive) positiveArea += area; | 1510 |
1708 else negativeArea += area; | 1511 final double area = calculateArea(l_xValues, l_yValues); |
1512 if (x_positive) | |
1513 this.positiveArea += area; | |
1514 else | |
1515 this.negativeArea += area; | |
1709 updateCentroid(l_xValues, l_yValues); | 1516 updateCentroid(l_xValues, l_yValues); |
1710 | 1517 |
1711 GeneralPath l_path = new GeneralPath(); | 1518 final GeneralPath l_path = new GeneralPath(); |
1712 | 1519 |
1713 if (PlotOrientation.VERTICAL == l_orientation) { | 1520 if (PlotOrientation.VERTICAL == l_orientation) { |
1714 double l_x = x_domainAxis.valueToJava2D(( | 1521 double l_x = x_domainAxis.valueToJava2D(((Double) l_xValues[0]).doubleValue(), x_dataArea, l_domainAxisLocation); |
1715 (Double) l_xValues[0]).doubleValue(), x_dataArea, | |
1716 l_domainAxisLocation); | |
1717 if (this.roundXCoordinates) { | 1522 if (this.roundXCoordinates) { |
1718 l_x = Math.rint(l_x); | 1523 l_x = Math.rint(l_x); |
1719 } | 1524 } |
1720 | 1525 |
1721 double l_y = x_rangeAxis.valueToJava2D(( | 1526 double l_y = x_rangeAxis.valueToJava2D(((Double) l_yValues[0]).doubleValue(), x_dataArea, l_rangeAxisLocation); |
1722 (Double) l_yValues[0]).doubleValue(), x_dataArea, | |
1723 l_rangeAxisLocation); | |
1724 | 1527 |
1725 l_path.moveTo((float) l_x, (float) l_y); | 1528 l_path.moveTo((float) l_x, (float) l_y); |
1726 for (int i = 1; i < l_xValues.length; i++) { | 1529 for (int i = 1; i < l_xValues.length; i++) { |
1727 l_x = x_domainAxis.valueToJava2D(( | 1530 l_x = x_domainAxis.valueToJava2D(((Double) l_xValues[i]).doubleValue(), x_dataArea, l_domainAxisLocation); |
1728 (Double) l_xValues[i]).doubleValue(), x_dataArea, | |
1729 l_domainAxisLocation); | |
1730 if (this.roundXCoordinates) { | 1531 if (this.roundXCoordinates) { |
1731 l_x = Math.rint(l_x); | 1532 l_x = Math.rint(l_x); |
1732 } | 1533 } |
1733 | 1534 |
1734 l_y = x_rangeAxis.valueToJava2D(( | 1535 l_y = x_rangeAxis.valueToJava2D(((Double) l_yValues[i]).doubleValue(), x_dataArea, l_rangeAxisLocation); |
1735 (Double) l_yValues[i]).doubleValue(), x_dataArea, | |
1736 l_rangeAxisLocation); | |
1737 l_path.lineTo((float) l_x, (float) l_y); | 1536 l_path.lineTo((float) l_x, (float) l_y); |
1738 } | 1537 } |
1739 l_path.closePath(); | 1538 l_path.closePath(); |
1740 } | 1539 } else { |
1741 else { | 1540 double l_x = x_domainAxis.valueToJava2D(((Double) l_xValues[0]).doubleValue(), x_dataArea, l_domainAxisLocation); |
1742 double l_x = x_domainAxis.valueToJava2D(( | |
1743 (Double) l_xValues[0]).doubleValue(), x_dataArea, | |
1744 l_domainAxisLocation); | |
1745 if (this.roundXCoordinates) { | 1541 if (this.roundXCoordinates) { |
1746 l_x = Math.rint(l_x); | 1542 l_x = Math.rint(l_x); |
1747 } | 1543 } |
1748 | 1544 |
1749 double l_y = x_rangeAxis.valueToJava2D(( | 1545 double l_y = x_rangeAxis.valueToJava2D(((Double) l_yValues[0]).doubleValue(), x_dataArea, l_rangeAxisLocation); |
1750 (Double) l_yValues[0]).doubleValue(), x_dataArea, | |
1751 l_rangeAxisLocation); | |
1752 | 1546 |
1753 l_path.moveTo((float) l_y, (float) l_x); | 1547 l_path.moveTo((float) l_y, (float) l_x); |
1754 for (int i = 1; i < l_xValues.length; i++) { | 1548 for (int i = 1; i < l_xValues.length; i++) { |
1755 l_x = x_domainAxis.valueToJava2D(( | 1549 l_x = x_domainAxis.valueToJava2D(((Double) l_xValues[i]).doubleValue(), x_dataArea, l_domainAxisLocation); |
1756 (Double) l_xValues[i]).doubleValue(), x_dataArea, | |
1757 l_domainAxisLocation); | |
1758 if (this.roundXCoordinates) { | 1550 if (this.roundXCoordinates) { |
1759 l_x = Math.rint(l_x); | 1551 l_x = Math.rint(l_x); |
1760 } | 1552 } |
1761 | 1553 |
1762 l_y = x_rangeAxis.valueToJava2D(( | 1554 l_y = x_rangeAxis.valueToJava2D(((Double) l_yValues[i]).doubleValue(), x_dataArea, l_rangeAxisLocation); |
1763 (Double) l_yValues[i]).doubleValue(), x_dataArea, | |
1764 l_rangeAxisLocation); | |
1765 l_path.lineTo((float) l_y, (float) l_x); | 1555 l_path.lineTo((float) l_y, (float) l_x); |
1766 } | 1556 } |
1767 l_path.closePath(); | 1557 l_path.closePath(); |
1768 } | 1558 } |
1769 | 1559 |
1770 if (l_path.intersects(x_dataArea)) { | 1560 if (l_path.intersects(x_dataArea)) { |
1771 | 1561 |
1772 final Paint paint = x_positive ? getPositivePaint(): getNegativePaint(); | 1562 final Paint paint = x_positive ? getPositivePaint() : getNegativePaint(); |
1773 if( paint != null ) { | 1563 if (this.drawArea && paint != null) { |
1774 x_graphics.setPaint(paint); | 1564 x_graphics.setPaint(paint); |
1775 x_graphics.fill(l_path); | 1565 x_graphics.fill(l_path); |
1776 } | 1566 } |
1777 | 1567 |
1778 if (drawOutline) { | 1568 if (this.drawOutline) { |
1779 x_graphics.setStroke(this.outlineStroke); | 1569 x_graphics.setStroke(this.outlineStroke); |
1780 x_graphics.setPaint(this.outlinePaint); | 1570 x_graphics.setPaint(this.outlinePaint); |
1781 x_graphics.draw(l_path); | 1571 x_graphics.draw(l_path); |
1782 } | 1572 } |
1783 } | 1573 } |
1784 } | 1574 } |
1785 | 1575 |
1786 /** | 1576 /** |
1787 * Returns a default legend item for the specified series. Subclasses | 1577 * Returns a default legend item for the specified series. Subclasses |
1788 * should override this method to generate customised items. | 1578 * should override this method to generate customised items. |
1789 * | 1579 * |
1790 * @param datasetIndex the dataset index (zero-based). | 1580 * @param datasetIndex |
1791 * @param series the series index (zero-based). | 1581 * the dataset index (zero-based). |
1582 * @param series | |
1583 * the series index (zero-based). | |
1792 * | 1584 * |
1793 * @return A legend item for the series. | 1585 * @return A legend item for the series. |
1794 */ | 1586 */ |
1795 public LegendItem getLegendItem(int datasetIndex, int series) { | 1587 @Override |
1796 LegendItem result = null; | 1588 public LegendItem getLegendItem(final int datasetIndex, final int series) { |
1797 XYPlot p = getPlot(); | 1589 final XYPlot p = getPlot(); |
1798 if (p != null) { | 1590 if (p == null) |
1799 XYDataset dataset = p.getDataset(datasetIndex); | 1591 return null; |
1800 if (dataset != null) { | 1592 |
1801 if (getItemVisible(series, 0)) { | 1593 final XYDataset dataset = p.getDataset(datasetIndex); |
1802 String label = getLegendItemLabelGenerator().generateLabel( | 1594 if (dataset == null) |
1803 dataset, series); | 1595 return null; |
1804 String description = label; | 1596 |
1805 String toolTipText = null; | 1597 if (!getItemVisible(series, 0)) |
1806 if (getLegendItemToolTipGenerator() != null) { | 1598 return null; |
1807 toolTipText | 1599 |
1808 = getLegendItemToolTipGenerator().generateLabel( | 1600 final String label = getLegendItemLabelGenerator().generateLabel(dataset, series); |
1809 dataset, series); | 1601 final String description = label; |
1810 } | 1602 String toolTipText = null; |
1811 String urlText = null; | 1603 if (getLegendItemToolTipGenerator() != null) { |
1812 if (getLegendItemURLGenerator() != null) { | 1604 toolTipText = getLegendItemToolTipGenerator().generateLabel(dataset, series); |
1813 urlText = getLegendItemURLGenerator().generateLabel( | 1605 } |
1814 dataset, series); | 1606 String urlText = null; |
1815 } | 1607 if (getLegendItemURLGenerator() != null) { |
1816 // Individualized Paints: | 1608 urlText = getLegendItemURLGenerator().generateLabel(dataset, series); |
1817 //Paint paint = lookupSeriesPaint(series); | 1609 } |
1818 | 1610 |
1819 // "Area-Style"- Paint. | 1611 // "Area-Style"- Paint. |
1820 Paint paint = getPositivePaint(); | 1612 final Paint paint = getPositivePaint(); |
1821 Stroke stroke = lookupSeriesStroke(series); | 1613 final Shape line = getLegendLine(); |
1822 Shape line = getLegendLine(); | 1614 |
1823 // Not-filled Shape: | 1615 // Filled Shape ("Area-Style"). |
1824 //result = new LegendItem(label, description, | 1616 final BasicStroke NULL_STROKE = new BasicStroke(0.0f); |
1825 // toolTipText, urlText, line, stroke, paint); | 1617 final Shape NULL_SHAPE = new Line2D.Float(); |
1826 | 1618 |
1827 if (drawOutline) { | 1619 final Paint outlPaint = this.drawOutline ? this.outlinePaint : Color.black; |
1828 // TODO Include outline style in legenditem | 1620 final Stroke outlStroke = this.drawOutline ? this.outlineStroke : NULL_STROKE; |
1829 // (there is a constructor for that) | 1621 |
1830 } | 1622 final LegendItem result = new LegendItem(label, description, toolTipText, urlText, true, line, this.drawArea, paint, this.drawOutline, outlPaint, |
1831 | 1623 outlStroke, false, NULL_SHAPE, NULL_STROKE, Color.black); |
1832 // Filled Shape ("Area-Style"). | 1624 |
1833 result = new LegendItem(label, description, | 1625 result.setLabelFont(lookupLegendTextFont(series)); |
1834 toolTipText, urlText, line, paint); | 1626 final Paint labelPaint = lookupLegendTextPaint(series); |
1835 result.setLabelFont(lookupLegendTextFont(series)); | 1627 if (labelPaint != null) |
1836 Paint labelPaint = lookupLegendTextPaint(series); | 1628 result.setLabelPaint(labelPaint); |
1837 if (labelPaint != null) { | 1629 result.setDataset(dataset); |
1838 result.setLabelPaint(labelPaint); | 1630 result.setDatasetIndex(datasetIndex); |
1839 } | 1631 result.setSeriesKey(dataset.getSeriesKey(series)); |
1840 result.setDataset(dataset); | 1632 result.setSeriesIndex(series); |
1841 result.setDatasetIndex(datasetIndex); | |
1842 result.setSeriesKey(dataset.getSeriesKey(series)); | |
1843 result.setSeriesIndex(series); | |
1844 } | |
1845 } | |
1846 | |
1847 } | |
1848 | 1633 |
1849 return result; | 1634 return result; |
1850 } | 1635 } |
1851 | 1636 |
1852 /** | 1637 /** |
1853 * Tests this renderer for equality with an arbitrary object. | 1638 * Tests this renderer for equality with an arbitrary object. |
1854 * | 1639 * |
1855 * @param obj the object (<code>null</code> permitted). | 1640 * @param obj |
1641 * the object (<code>null</code> permitted). | |
1856 * | 1642 * |
1857 * @return A boolean. | 1643 * @return A boolean. |
1858 */ | 1644 */ |
1859 public boolean equals(Object obj) { | 1645 @Override |
1646 public boolean equals(final Object obj) { | |
1860 if (obj == this) { | 1647 if (obj == this) { |
1861 return true; | 1648 return true; |
1862 } | 1649 } |
1863 if (!(obj instanceof StableXYDifferenceRenderer)) { | 1650 if (!(obj instanceof StableXYDifferenceRenderer)) { |
1864 return false; | 1651 return false; |
1865 } | 1652 } |
1866 if (!super.equals(obj)) { | 1653 if (!super.equals(obj)) { |
1867 return false; | 1654 return false; |
1868 } | 1655 } |
1869 StableXYDifferenceRenderer that = (StableXYDifferenceRenderer) obj; | 1656 final StableXYDifferenceRenderer that = (StableXYDifferenceRenderer) obj; |
1870 if (!PaintUtilities.equal(this.positivePaint, that.positivePaint)) { | 1657 if (!PaintUtilities.equal(this.positivePaint, that.positivePaint)) { |
1871 return false; | 1658 return false; |
1872 } | 1659 } |
1873 if (!PaintUtilities.equal(this.negativePaint, that.negativePaint)) { | 1660 if (!PaintUtilities.equal(this.negativePaint, that.negativePaint)) { |
1874 return false; | 1661 return false; |
1888 /** | 1675 /** |
1889 * Returns a clone of the renderer. | 1676 * Returns a clone of the renderer. |
1890 * | 1677 * |
1891 * @return A clone. | 1678 * @return A clone. |
1892 * | 1679 * |
1893 * @throws CloneNotSupportedException if the renderer cannot be cloned. | 1680 * @throws CloneNotSupportedException |
1894 */ | 1681 * if the renderer cannot be cloned. |
1682 */ | |
1683 @Override | |
1895 public Object clone() throws CloneNotSupportedException { | 1684 public Object clone() throws CloneNotSupportedException { |
1896 StableXYDifferenceRenderer clone = | 1685 final StableXYDifferenceRenderer clone = (StableXYDifferenceRenderer) super.clone(); |
1897 (StableXYDifferenceRenderer) super.clone(); | |
1898 clone.legendShape = ShapeUtilities.clone(this.legendShape); | 1686 clone.legendShape = ShapeUtilities.clone(this.legendShape); |
1899 return clone; | 1687 return clone; |
1900 } | 1688 } |
1901 | 1689 |
1902 /** | 1690 /** |
1903 * Provides serialization support. | 1691 * Provides serialization support. |
1904 * | 1692 * |
1905 * @param stream the output stream. | 1693 * @param stream |
1906 * | 1694 * the output stream. |
1907 * @throws IOException if there is an I/O error. | 1695 * |
1908 */ | 1696 * @throws IOException |
1909 private void writeObject(ObjectOutputStream stream) throws IOException { | 1697 * if there is an I/O error. |
1698 */ | |
1699 private void writeObject(final ObjectOutputStream stream) throws IOException { | |
1910 stream.defaultWriteObject(); | 1700 stream.defaultWriteObject(); |
1911 SerialUtilities.writePaint(this.positivePaint, stream); | 1701 SerialUtilities.writePaint(this.positivePaint, stream); |
1912 SerialUtilities.writePaint(this.negativePaint, stream); | 1702 SerialUtilities.writePaint(this.negativePaint, stream); |
1913 SerialUtilities.writeShape(this.legendShape, stream); | 1703 SerialUtilities.writeShape(this.legendShape, stream); |
1914 } | 1704 } |
1915 | 1705 |
1916 /** | 1706 /** |
1917 * Provides serialization support. | 1707 * Provides serialization support. |
1918 * | 1708 * |
1919 * @param stream the input stream. | 1709 * @param stream |
1920 * | 1710 * the input stream. |
1921 * @throws IOException if there is an I/O error. | 1711 * |
1922 * @throws ClassNotFoundException if there is a classpath problem. | 1712 * @throws IOException |
1923 */ | 1713 * if there is an I/O error. |
1924 private void readObject(ObjectInputStream stream) | 1714 * @throws ClassNotFoundException |
1925 throws IOException, ClassNotFoundException { | 1715 * if there is a classpath problem. |
1716 */ | |
1717 private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException { | |
1926 stream.defaultReadObject(); | 1718 stream.defaultReadObject(); |
1927 this.positivePaint = SerialUtilities.readPaint(stream); | 1719 this.positivePaint = SerialUtilities.readPaint(stream); |
1928 this.negativePaint = SerialUtilities.readPaint(stream); | 1720 this.negativePaint = SerialUtilities.readPaint(stream); |
1929 this.legendShape = SerialUtilities.readShape(stream); | 1721 this.legendShape = SerialUtilities.readShape(stream); |
1930 } | 1722 } |
1931 } | 1723 } |
1932 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |