# HG changeset patch # User Felix Wolfsteller # Date 1338908591 0 # Node ID e19ff908603512bb2e8679489d62eee21b62e5a2 # Parent 705d2058b68293e61667516e8397d75740db049c Avoid collisions between line labels. flys-artifacts/trunk@4590 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r 705d2058b682 -r e19ff9086035 flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Tue Jun 05 14:56:57 2012 +0000 +++ b/flys-artifacts/ChangeLog Tue Jun 05 15:03:11 2012 +0000 @@ -1,3 +1,17 @@ +2012-06-05 Felix Wolfsteller + + * src/main/java/de/intevation/flys/jfree/JFreeUtil.java: + Improved collision detection. + + * src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java: + Avoid collisions of line labels, documentation. + + * src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java: + Use JFreeUtil. + + * src/main/java/de/intevation/flys/jfree/CollisionFreeLineLabelEntity.java: + New, ChartEntity class for Line labels. + 2012-06-05 Sascha L. Teichmann * src/main/java/de/intevation/flys/artifacts/model/fixings/FixResults.java: diff -r 705d2058b682 -r e19ff9086035 flys-artifacts/src/main/java/de/intevation/flys/jfree/CollisionFreeLineLabelEntity.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/CollisionFreeLineLabelEntity.java Tue Jun 05 15:03:11 2012 +0000 @@ -0,0 +1,21 @@ +package de.intevation.flys.jfree; + +import java.awt.Shape; + +import org.jfree.chart.entity.XYAnnotationEntity; + +/** + * Chart Entity for Line Labels that should not collide. + */ +public class CollisionFreeLineLabelEntity +extends XYAnnotationEntity { + public CollisionFreeLineLabelEntity( + Shape hotspot, + int rendererIndex, + String toolTip, + String url + ) { + super(hotspot, rendererIndex, toolTip, url); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 705d2058b682 -r e19ff9086035 flys-artifacts/src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java --- a/flys-artifacts/src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java Tue Jun 05 14:56:57 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java Tue Jun 05 15:03:11 2012 +0000 @@ -20,6 +20,8 @@ import org.jfree.ui.RectangleEdge; +import de.intevation.flys.jfree.JFreeUtil; + /** * Custom Annotations class that is drawn only if no collisions with other @@ -87,17 +89,9 @@ // Deviation from superclass: prevent collision. Rectangle2D hotspotBox = hotspot.getBounds2D(); - for (Iterator i = info.getOwner().getEntityCollection().iterator(); - i.hasNext(); ) { - Object next = i.next(); - // Collision with other stuff than XYAnnotations are okay. - if (next instanceof CollisionFreeXYTextAnnotationEntity) { - XYAnnotationEntity drawnShape = (XYAnnotationEntity) next; - if (drawnShape.getArea().intersects(hotspotBox)) { - // Found collision, early stop. - return; - } - } + if (JFreeUtil.collides(hotspot, info.getOwner().getEntityCollection(), + XYAnnotationEntity.class)) { + return; } if (this.getBackgroundPaint() != null) { diff -r 705d2058b682 -r e19ff9086035 flys-artifacts/src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java --- a/flys-artifacts/src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java Tue Jun 05 14:56:57 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java Tue Jun 05 15:03:11 2012 +0000 @@ -21,11 +21,13 @@ import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.ui.RectangleEdge; +import org.jfree.ui.TextAnchor; import org.jfree.util.BooleanList; import org.jfree.util.ShapeUtilities; +import org.jfree.text.TextUtilities; import de.intevation.flys.jfree.HasLabel; - +import de.intevation.flys.jfree.JFreeUtil; /** * Renderer with additional the additional functionality of renderering minima @@ -87,6 +89,10 @@ } + /** + * Whether or not a specific item in a series (maybe the maxima) should + * be rendered with shape. + */ public boolean getItemShapeVisible(XYDataset dataset, int series, int item){ if (super.getItemShapeVisible(series, item)) { return true; @@ -104,11 +110,17 @@ } + /** + * Rectangle used to draw maximums shape. + */ public Shape getMaximumShape(int series, int column) { return new Rectangle2D.Double(-5d, -5d, 10d, 10d); } + /** + * Rectangle used to draw minimums shape. + */ public Shape getMinimumShape(int series, int column) { return new Rectangle2D.Double(-5d, -5d, 10d, 10d); } @@ -272,13 +284,13 @@ } // Draw label of line. - // TODO add colision detection if (isShowLineLabel(series) && isMinimumX (dataset, series, item)) { XYSeries xYSeries = ((XYSeriesCollection) dataset).getSeries(series); String waterlevelLabel = (xYSeries instanceof HasLabel) ? ((HasLabel)xYSeries).getLabel() : xYSeries.getKey().toString(); // TODO Force water of some German rivers to flow direction mountains. + Font oldFont = g2.getFont(); Color oldColor = g2.getColor(); @@ -286,6 +298,21 @@ g2.setColor(this.getLineLabelTextColor(series)); g2.setBackground(Color.black); + // Move to right until no collisions exist anymore + Shape hotspot = TextUtilities.calculateRotatedStringBounds( + waterlevelLabel, g2, (float)xx, (float)yy-3f, TextAnchor.CENTER_LEFT, + 0f, TextAnchor.CENTER_LEFT); + while (JFreeUtil.collides(hotspot, entities, CollisionFreeLineLabelEntity.class)) { + xx += 5f; + hotspot = TextUtilities.calculateRotatedStringBounds( + waterlevelLabel, g2, (float)xx, (float)yy-3f, TextAnchor.CENTER_LEFT, + 0f, TextAnchor.CENTER_LEFT); + } + + // Register to avoid collissions. + entities.add(new CollisionFreeLineLabelEntity(hotspot, + 1, "", "")); + // Fill background. if (isShowLineLabelBG(series)) { drawTextBox(g2, waterlevelLabel, (float)xx, (float)yy-3f, @@ -311,6 +338,9 @@ } + /** + * Sets whether or not the minimum should be rendered with shape. + */ public void setIsMinimumShapeVisisble(int series, boolean isVisible) { this.isMinimumShapeVisible.setBoolean(series, isVisible); } diff -r 705d2058b682 -r e19ff9086035 flys-artifacts/src/main/java/de/intevation/flys/jfree/JFreeUtil.java --- a/flys-artifacts/src/main/java/de/intevation/flys/jfree/JFreeUtil.java Tue Jun 05 14:56:57 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/JFreeUtil.java Tue Jun 05 15:03:11 2012 +0000 @@ -19,10 +19,13 @@ * True if \param hotspot collides with a Entity in \param entities. * @param hotspot Shape to compare against other shapes (bounds only). * @param entities entities against which to compare shape. - * @param true if a collision (non-zero intersection) exists between + * @param exclusiveEntityClass If not null, consider only entities of + * given class. + * @return true if a collision (non-zero intersection) exists between * shapes. */ - public static boolean collides(Shape hotspot, EntityCollection entities) { + public static boolean collides(Shape hotspot, EntityCollection entities, + Class exclusiveEntityClass) { if (entities == null) return false; Rectangle2D hotspotBox = hotspot.getBounds2D(); @@ -30,9 +33,13 @@ for (Iterator i = entities.iterator(); i.hasNext(); ) { Object next = i.next(); ChartEntity entity = (ChartEntity) next; - if (entity.getArea().intersects(hotspotBox)) { - // Found collision, early stop. - return true; + if (exclusiveEntityClass == null + || exclusiveEntityClass.isInstance(entity)) + { + if (entity.getArea().intersects(hotspotBox)) { + // Found collision, early stop. + return true; + } } }