changeset 1036:e6aff80b59ff

Added proof-of-concept collision detection for text annotations. flys-artifacts/trunk@2497 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Wed, 17 Aug 2011 09:16:20 +0000
parents 9f69a5f0af98
children 75cf1b11c97e
files flys-artifacts/ChangeLog flys-artifacts/src/main/java/de/intevation/flys/exports/ChartExportHelper.java flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java
diffstat 3 files changed, 90 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Tue Aug 16 13:24:50 2011 +0000
+++ b/flys-artifacts/ChangeLog	Wed Aug 17 09:16:20 2011 +0000
@@ -1,3 +1,18 @@
+2011-08-16  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Implemented proof-of-concept collision-detection when drawing
+	CustomAnnotations (text only).
+
+	* src/main/java/de/intevation/flys/exports/ChartExportHelper.java:
+	  Pass a fresh ChartRenderingInfo-Object to createBufferedImage, such that
+	  information can be collected while rendering.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  Exploit the fact that XYTextAnnotation already registers drawn shape in the
+	  ChartRenderingInfo if it exists and either an URL or tooltip is set.
+	  Before drawing, calculate own shape and compare against already registered
+	  shapes.
+
 2011-08-16  Felix Wolfsteller <felix.wolfsteller@intevation.de>
 
 	Implemented (yet dummy) custom Annotation class.
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartExportHelper.java	Tue Aug 16 13:24:50 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartExportHelper.java	Wed Aug 17 09:16:20 2011 +0000
@@ -27,6 +27,7 @@
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
+import org.jfree.chart.ChartRenderingInfo;
 
 import javax.imageio.ImageIO;
 
@@ -89,9 +90,11 @@
     {
         log.info("export chart as png");
 
+        ChartRenderingInfo info = new ChartRenderingInfo();
+
         ImageIO.write(
             chart.createBufferedImage(
-                width, height, Transparency.BITMASK, null
+                width, height, Transparency.BITMASK, info
             ),
             format,
             out
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java	Tue Aug 16 13:24:50 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java	Wed Aug 17 09:16:20 2011 +0000
@@ -1,10 +1,14 @@
 package de.intevation.flys.exports;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import org.apache.log4j.Logger;
 
+import java.awt.Shape;
+import java.awt.geom.Rectangle2D;
+
 import org.jfree.chart.annotations.XYLineAnnotation;
 import org.jfree.chart.annotations.XYTextAnnotation;
 import org.jfree.chart.JFreeChart;
@@ -16,6 +20,12 @@
 import org.jfree.data.xy.XYSeries;
 import org.jfree.ui.TextAnchor;
 import org.jfree.chart.plot.PlotRenderingInfo;
+import org.jfree.text.TextUtilities;
+import org.jfree.chart.entity.XYAnnotationEntity;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.ui.RectangleEdge;
+import org.jfree.chart.plot.Plot;
+import org.jfree.chart.ChartRenderingInfo;
 
 import org.w3c.dom.Document;
 
@@ -49,9 +59,20 @@
 
 
     /**
-     * Yet trivial draw without implementing any CustomAnnotation-specific
-     * feature.
+     * Draw the Annotiation if it does not collide with other already drawn
+     * Annotations.
+     *
+     * @param g2            the graphics device.
+     * @param plot          the plot.
+     * @param dataArea      the data area.
+     * @param domainAxis    the domain axis.
+     * @param rangeAxis     the range axis.
+     * @param rendererIndex the render index.
+     * @param info          state information, escpecially collects info about
+     *                      already drawn shapes (and thus annotations), used
+     *                      for collision detection.
      */
+    @Override
     public void draw(
        java.awt.Graphics2D g2,
        XYPlot plot,
@@ -60,6 +81,52 @@
        ValueAxis rangeAxis,
        int rendererIndex,
        PlotRenderingInfo info) {
+
+        if (info == null)
+            return;
+
+        // Calculate bounding box as in super.draw().
+        // TODO overwrite draw such that even if the annotation gets painted
+        // the bounding box has to be calculated only once.
+        ChartRenderingInfo chartInfo = info.getOwner();
+
+        PlotOrientation orientation = plot.getOrientation();
+        RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
+        plot.getDomainAxisLocation(), orientation);
+        RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
+        plot.getRangeAxisLocation(), orientation);
+        float anchorX = (float) domainAxis.valueToJava2D(
+            getX(), dataArea, domainEdge);
+        float anchorY = (float) rangeAxis.valueToJava2D(
+            getY(), dataArea, rangeEdge);
+        if (orientation == PlotOrientation.HORIZONTAL) {
+            float tempAnchor = anchorX;
+            anchorX = anchorY;
+            anchorY = tempAnchor;
+        }         
+
+        Shape hotspot = TextUtilities.calculateRotatedStringBounds(
+           getText(), g2, anchorX, anchorY, getTextAnchor(),
+           getRotationAngle(), getRotationAnchor());
+        Rectangle2D hotspotBox = hotspot.getBounds2D();
+
+        // Check for collisions with other XYAnnotations.
+        for (Iterator i = chartInfo.getEntityCollection().iterator();
+                i.hasNext(); ) {
+            Object next = i.next();
+            // Collision with other stuff than XYAnnotations are okay.
+            if (next instanceof XYAnnotationEntity) {
+                XYAnnotationEntity drawnShape = (XYAnnotationEntity) next;
+                if (drawnShape.getArea().intersects(hotspotBox)) {
+                    // Found collision, early stop.
+                    return;
+                }
+            }
+        }
+
+        // Set URL of current annotation. This will let super.draw() add
+        // the relevant info to the PlotRenderingInfo.
+        setURL("");
         super.draw(g2, plot, dataArea, domainAxis, rangeAxis, rendererIndex, info);
     }
 }
@@ -182,13 +249,10 @@
             posY += 0.1f * (yAxis.getRange().getUpperBound()
                     - yAxis.getRange().getLowerBound());
         }
-        double freeFrom = axis.getRange().getLowerBound();
-        //logger.warn("Axis lower Bound: " + freeFrom);
 
-        // Assuming ordered annotations.
+        // Add all annotations.
         for (Annotation a: annotations) {
             float posX = (float) a.getRange().getA().doubleValue();
-            if (posX < freeFrom) { continue; }
             String text = a.getPosition().getValue();
 
             XYTextAnnotation ta = new CustomAnnotation(text, posX, posY);
@@ -197,9 +261,9 @@
             ta.setRotationAnchor(TextAnchor.CENTER_LEFT);
             ta.setTextAnchor(TextAnchor.CENTER_LEFT);
             plot.getRenderer().addAnnotation(ta);
+            // TODO Merge XYLineAnnotation and CustomAnnotation.
             XYLineAnnotation la = new XYLineAnnotation(posX, 0, posX, posY);
             plot.getRenderer().addAnnotation(la);
-            freeFrom += 2.0;
         }
     }
 

http://dive4elements.wald.intevation.org