Author: kono
Date: 2010-12-23 02:08:57 -0800 (Thu, 23 Dec 2010)
New Revision: 23266

Modified:
   
core3/graph-render/trunk/src/main/java/org/cytoscape/graph/render/immed/GraphGraphics.java
Log:
Merged changed in 2.8.

Modified: 
core3/graph-render/trunk/src/main/java/org/cytoscape/graph/render/immed/GraphGraphics.java
===================================================================
--- 
core3/graph-render/trunk/src/main/java/org/cytoscape/graph/render/immed/GraphGraphics.java
  2010-12-23 08:59:05 UTC (rev 23265)
+++ 
core3/graph-render/trunk/src/main/java/org/cytoscape/graph/render/immed/GraphGraphics.java
  2010-12-23 10:08:57 UTC (rev 23266)
@@ -1,6 +1,13 @@
 /*
- Copyright (c) 2006, 2007, 2010, The Cytoscape Consortium (www.cytoscape.org)
+ Copyright (c) 2006, 2007, The Cytoscape Consortium (www.cytoscape.org)
 
+ The Cytoscape Consortium is:
+ - Institute for Systems Biology
+ - University of California San Diego
+ - Memorial Sloan-Kettering Cancer Center
+ - Institut Pasteur
+ - Agilent Technologies
+
  This library is free software; you can redistribute it and/or modify it
  under the terms of the GNU Lesser General Public License as published
  by the Free Software Foundation; either version 2.1 of the License, or
@@ -24,11 +31,23 @@
  You should have received a copy of the GNU Lesser General Public License
  along with this library; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-*/
+ */
 package org.cytoscape.graph.render.immed;
 
-
-import java.awt.*;
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.TexturePaint;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
 import java.awt.geom.AffineTransform;
@@ -37,10 +56,10 @@
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Line2D;
 import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
 import java.util.HashMap;
 import java.util.Map;
 
-
 import org.cytoscape.graph.render.immed.arrow.Arrow;
 import org.cytoscape.graph.render.immed.arrow.ArrowheadArrow;
 import org.cytoscape.graph.render.immed.arrow.DeltaArrow;
@@ -62,6 +81,7 @@
 import org.cytoscape.graph.render.immed.nodeshape.TriangleNodeShape;
 import org.cytoscape.graph.render.immed.nodeshape.VeeNodeShape;
 
+
 /**
  * The purpose of this class is to make the proper calls on a Graphics2D object
  * to efficiently render nodes, labels, and edges. This is procedural
@@ -100,102 +120,44 @@
  * thread.
  */
 public final class GraphGraphics {
-       /**
-        * 
-        */
-       public static final byte SHAPE_RECTANGLE = 0;
 
        /**
-        * 
+        * Node shape constants
         */
+       public static final byte SHAPE_RECTANGLE = 0;
        public static final byte SHAPE_DIAMOND = 1;
-
-       /**
-        * 
-        */
        public static final byte SHAPE_ELLIPSE = 2;
-
-       /**
-        * 
-        */
        public static final byte SHAPE_HEXAGON = 3;
-
-       /**
-        * 
-        */
        public static final byte SHAPE_OCTAGON = 4;
-
-       /**
-        * 
-        */
        public static final byte SHAPE_PARALLELOGRAM = 5;
-
-       /**
-        * 
-        */
        public static final byte SHAPE_ROUNDED_RECTANGLE = 6;
-
-       /**
-        * 
-        */
        public static final byte SHAPE_TRIANGLE = 7;
-
-       /**
-        * 
-        */
        public static final byte SHAPE_VEE = 8;
+
+       // package scoped for unit testing
        static final byte s_last_shape = SHAPE_VEE;
 
-       private static final Map<Byte, NodeShape> nodeShapes;
+       private static final Map<Byte,NodeShape> nodeShapes;
 
        /**
         * This value is currently 100.
         */
        public static final int CUSTOM_SHAPE_MAX_VERTICES = 100;
 
-       /**
-        * 
-        */
+       //
+       // Arrow shape constants. 
+       //
        public static final byte ARROW_NONE = -1;
-
-       /**
-        * 
-        */
        public static final byte ARROW_DELTA = -2;
-
-       /**
-        * 
-        */
        public static final byte ARROW_DIAMOND = -3;
-
-       /**
-        * 
-        */
        public static final byte ARROW_DISC = -4;
-
-       /**
-        * 
-        */
        public static final byte ARROW_TEE = -5;
-
-       /**
-        * 
-        */
        public static final byte ARROW_HALF_TOP = -6;
-
-       /**
-        * 
-        */
        public static final byte ARROW_HALF_BOTTOM = -7;
-
-       /**
-        * 
-        */
        public static final byte ARROW_ARROWHEAD = -8;
-       private static final byte last_arrow_shape = ARROW_ARROWHEAD;
 
        // The way to access all Arrow objects.
-       private static final Map<Byte, Arrow> arrows;
+       private static final Map<Byte,Arrow> arrows;
 
        /**
         * This value is currently 64.
@@ -221,7 +183,6 @@
                nodeShapes = new HashMap<Byte,NodeShape>();
 
                nodeShapes.put(SHAPE_RECTANGLE, new RectangleNodeShape()); 
-
                nodeShapes.put(SHAPE_ELLIPSE, new EllipseNodeShape()); 
                nodeShapes.put(SHAPE_ROUNDED_RECTANGLE, new 
RoundedRectangleNodeShape()); 
                nodeShapes.put(SHAPE_DIAMOND, new DiamondNodeShape()); 
@@ -231,8 +192,8 @@
                nodeShapes.put(SHAPE_TRIANGLE, new TriangleNodeShape()); 
                nodeShapes.put(SHAPE_VEE, new VeeNodeShape());
 
-               // Defines arrow shapes used in this rendering engine.
                arrows = new HashMap<Byte,Arrow>();
+
                arrows.put(ARROW_NONE, new NoArrow() );
                arrows.put(ARROW_DELTA, new DeltaArrow() );
                arrows.put(ARROW_DISC, new DiscArrow() );
@@ -243,7 +204,7 @@
                arrows.put(ARROW_HALF_BOTTOM, new HalfBottomArrow() );
        }
 
-       private static final float DEF_SHAPE_SIZE = 32.0f;
+       private static final float DEF_SHAPE_SIZE = 32;
 
        /**
         * The image that was passed into the constructor.
@@ -258,49 +219,29 @@
        private final GeneralPath m_path2d = new GeneralPath();
        private final GeneralPath m_path2dPrime = new GeneralPath();
        private final Line2D.Double m_line2d = new Line2D.Double();
-       private final double[] m_polyCoords = // I need this for extra 
precision.
-       new double[2 * CUSTOM_SHAPE_MAX_VERTICES];
-       private final HashMap<Integer, double[]> m_customShapes = new 
HashMap<Integer, double[]>();
        private final double[] m_ptsBuff = new double[4];
-       final EdgeAnchors m_noAnchors = new EdgeAnchors() {
-               public final int numAnchors() {
-                       return 0;
-               }
 
-               public final void getAnchor(final int inx, final float[] arr,
-                               final int off) {
-               }
+       // package scoped for unit testing
+       final EdgeAnchors m_noAnchors = new EdgeAnchors() {
+               public final int numAnchors() { return 0; }
+               public final void getAnchor(final int inx, final float[] arr, 
final int off) { }
        };
 
        private final double[] m_edgePtsBuff = new double[(MAX_EDGE_ANCHORS + 
1) * 6];
-       private int m_polyNumPoints; // Used with m_polyCoords.
        private int m_edgePtsCount; // Number of points stored in m_edgePtsBuff.
        private Graphics2D m_g2d;
        private Graphics2D m_gMinimal; // We use mostly java.awt.Graphics 
methods.
        private boolean m_cleared;
 
-       // The three following member variables shall only be referenced from
-       // the scope of setStroke() definition.
-       private float m_currStrokeWidth;
-       private final float[] m_currDash = new float[] { 0.0f, 0.0f };
-       private int m_currCapType;
-
        // This member variable only to be used from within 
defineCustomNodeShape().
-       private int m_lastCustomShapeType = s_last_shape;
+       private byte m_lastCustomShapeType = s_last_shape;
 
        // This is only used by computeCubicPolyEdgePath().
        private final float[] m_floatBuff = new float[2];
 
-       // The following three member variables shall only be accessed from the
-       // scope of computeEdgeIntersection() definition.
-       private final double[] m_fooPolyCoords = new 
double[CUSTOM_SHAPE_MAX_VERTICES * 4];
-       private final double[] m_foo2PolyCoords = new 
double[CUSTOM_SHAPE_MAX_VERTICES * 4];
-       private final boolean[] m_fooRoundedCorners = new 
boolean[CUSTOM_SHAPE_MAX_VERTICES];
-
        // This member variable shall only be used from within drawTextFull().
        private char[] m_charBuff = new char[20];
-       private final FontRenderContext m_fontRenderContextFull = new 
FontRenderContext(
-                       null, true, true);
+       private final FontRenderContext m_fontRenderContextFull = new 
FontRenderContext(null,true,true);
 
        /**
         * All rendering operations will be performed on the specified image. No
@@ -380,10 +321,7 @@
        public final void clear(final Paint bgPaint, final double xCenter,
                        final double yCenter, final double scaleFactor) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
 
                        if (!(scaleFactor > 0.0d)) {
                                throw new IllegalArgumentException(
@@ -407,17 +345,40 @@
                m_g2d.setPaint(bgPaint);
                m_g2d.fillRect(0, 0, image.getWidth(null), 
image.getHeight(null));
                m_g2d.setComposite(origComposite);
+               
+               // For detailed view, render high quality image as much as 
possible.
+               
+               // Antialiasing is ON
                m_g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
+               
+               // Rendering quality is HIGH.
                m_g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
-                               RenderingHints.VALUE_RENDER_SPEED);
+                               RenderingHints.VALUE_RENDER_QUALITY);
+               
+               // High quality alpha blending is ON.
+               m_g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
+                               
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+               
+               // High quality color rendering is ON.
+               m_g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
+                               RenderingHints.VALUE_COLOR_RENDER_QUALITY);
+               
+               m_g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
+                               RenderingHints.VALUE_DITHER_ENABLE);
+               
+               m_g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                               RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+               
+               // Text antialiasing is ON.
                m_g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                m_g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                                RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                m_g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                                RenderingHints.VALUE_STROKE_PURE);
-               setStroke(0.0f, 0.0f, BasicStroke.CAP_ROUND, true);
+               
+               m_g2d.setStroke(new BasicStroke(0.0f, BasicStroke.CAP_ROUND, 
BasicStroke.JOIN_ROUND, 10.0f));
 
                m_currXform.setToTranslation(0.5d * image.getWidth(null), 0.5d 
* image
                                .getHeight(null));
@@ -428,29 +389,6 @@
                m_cleared = true;
        }
 
-       private final void setStroke(final float width, final float dashLength,
-                       final int capType, final boolean ignoreCache) {
-               if ((!ignoreCache) && (width == m_currStrokeWidth)
-                               && (dashLength == m_currDash[0]) && (capType == 
m_currCapType)) {
-                       return;
-               }
-
-               m_currStrokeWidth = width;
-               m_currDash[0] = dashLength;
-               m_currDash[1] = dashLength;
-               m_currCapType = capType;
-
-               // Unfortunately, BasicStroke is not mutable. So we have to 
construct
-               // lots of new strokes if they constantly change.
-               if (m_currDash[0] == 0.0f) {
-                       m_g2d.setStroke(new BasicStroke(width, capType,
-                                       BasicStroke.JOIN_ROUND, 10.0f));
-               } else {
-                       m_g2d.setStroke(new BasicStroke(width, capType,
-                                       BasicStroke.JOIN_ROUND, 10.0f, 
m_currDash, 0.0f));
-               }
-       }
-
        /**
         * Uses the current transform to map the specified image coordinates to 
node
         * coordinates. The transform used is defined by the last call to 
clear().
@@ -470,15 +408,8 @@
         */
        public final void xformImageToNodeCoords(final double[] coords) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
-
-                       if (!m_cleared) {
-                               throw new IllegalStateException(
-                                               "clear() has not been called 
previously");
-                       }
+                       checkDispatchThread();
+                       checkCleared();
                }
 
                try {
@@ -527,24 +458,11 @@
        public final void drawNodeLow(final float xMin, final float yMin,
                        final float xMax, final float yMax, final Color 
fillColor) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
+                       checkCleared();
+                       checkOrder(xMin,xMax,"x");
+                       checkOrder(yMin,yMax,"y");
 
-                       if (!m_cleared) {
-                               throw new IllegalStateException(
-                                               "clear() has not been called 
previously");
-                       }
-
-                       if (!(xMin < xMax)) {
-                               throw new IllegalArgumentException("xMin not 
less than xMax");
-                       }
-
-                       if (!(yMin < yMax)) {
-                               throw new IllegalArgumentException("yMin not 
less than yMax");
-                       }
-
                        if (fillColor.getAlpha() != 255) {
                                throw new IllegalArgumentException("fillColor 
is not opaque");
                        }
@@ -569,12 +487,11 @@
                final int xOne = (int) m_ptsBuff[2];
                final int yOne = (int) m_ptsBuff[3];
                m_gMinimal.setColor(fillColor);
-               m_gMinimal.fillRect(xNot, yNot, Math.max(1, xOne - xNot), // 
Overflow
-                               // will
-                               Math.max(1, yOne - yNot)); // be problem.
+               m_gMinimal.fillRect(xNot, yNot, Math.max(1, xOne - xNot), // 
Overflow will
+                                               Math.max(1, yOne - yNot)); // 
be problem.
        }
 
-       /*
+       /**
         * Sets m_gMinimal.
         */
        private final void makeMinimalGraphics() {
@@ -766,129 +683,111 @@
         *                little over one hundered custom node shapes can be
         *                defined.
         */
-       public final int defineCustomNodeShape(final float[] coords,
+       public final byte defineCustomNodeShape(final float[] coords,
                        final int offset, final int vertexCount) {
+               if (m_debug) {
+                       checkDispatchThread();
+               }
+
                if (vertexCount > CUSTOM_SHAPE_MAX_VERTICES) {
-                       throw new IllegalArgumentException(
-                                       "too many vertices (greater than "
+                       throw new IllegalArgumentException( "too many vertices 
(greater than "
                                                        + 
CUSTOM_SHAPE_MAX_VERTICES + ")");
                }
 
-               final double[] polyCoords;
+               final double[] polyCoords = new double[vertexCount * 2];
 
-               {
-                       polyCoords = new double[vertexCount * 2];
+               for (int i = 0; i < polyCoords.length; i++)
+                       polyCoords[i] = coords[offset + i];
 
-                       for (int i = 0; i < polyCoords.length; i++)
-                               polyCoords[i] = coords[offset + i];
+               // Normalize the polygon so that it spans [-0.5, 0.5] x [-0.5, 
0.5].
+               double xMin = Double.POSITIVE_INFINITY;
+               double yMin = Double.POSITIVE_INFINITY;
+               double xMax = Double.NEGATIVE_INFINITY;
+               double yMax = Double.NEGATIVE_INFINITY;
 
-                       // Normalize the polygon so that it spans [-0.5, 0.5] x 
[-0.5, 0.5].
-                       double xMin = Double.POSITIVE_INFINITY;
-                       double yMin = Double.POSITIVE_INFINITY;
-                       double xMax = Double.NEGATIVE_INFINITY;
-                       double yMax = Double.NEGATIVE_INFINITY;
+               for (int i = 0; i < polyCoords.length;) {
+                       xMin = Math.min(xMin, coords[i]);
+                       xMax = Math.max(xMax, coords[i++]);
+                       yMin = Math.min(yMin, coords[i]);
+                       yMax = Math.max(yMax, coords[i++]);
+               }
 
-                       for (int i = 0; i < polyCoords.length;) {
-                               xMin = Math.min(xMin, coords[i]);
-                               xMax = Math.max(xMax, coords[i++]);
-                               yMin = Math.min(yMin, coords[i]);
-                               yMax = Math.max(yMax, coords[i++]);
-                       }
+               final double xDist = xMax - xMin;
 
-                       final double xDist = xMax - xMin;
+               if (xDist == 0.0d) 
+                       throw new IllegalArgumentException( "polygon does not 
move in the X direction");
 
-                       if (xDist == 0.0d) {
-                               throw new IllegalArgumentException(
-                                               "polygon does not move in the X 
direction");
-                       }
+               final double yDist = yMax - yMin;
 
-                       final double yDist = yMax - yMin;
+               if (yDist == 0.0d) 
+                               throw new IllegalArgumentException( "polygon 
does not move in the Y direction");
 
-                       if (yDist == 0.0d) {
-                               throw new IllegalArgumentException(
-                                               "polygon does not move in the Y 
direction");
-                       }
+               final double xMid = (xMin + xMax) / 2.0d;
+               final double yMid = (yMin + yMax) / 2.0d;
 
-                       final double xMid = (xMin + xMax) / 2.0d;
-                       final double yMid = (yMin + yMax) / 2.0d;
-
-                       for (int i = 0; i < polyCoords.length;) {
-                               double foo = (polyCoords[i] - xMid) / xDist;
-                               polyCoords[i++] = Math.min(Math.max(-0.5d, 
foo), 0.5d);
-                               foo = (polyCoords[i] - yMid) / yDist;
-                               polyCoords[i++] = Math.min(Math.max(-0.5d, 
foo), 0.5d);
-                       }
+               for (int i = 0; i < polyCoords.length;) {
+                       double foo = (polyCoords[i] - xMid) / xDist;
+                       polyCoords[i++] = Math.min(Math.max(-0.5d, foo), 0.5d);
+                       foo = (polyCoords[i] - yMid) / yDist;
+                       polyCoords[i++] = Math.min(Math.max(-0.5d, foo), 0.5d);
                }
 
-               if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
-               }
 
-               { // Test all criteria regardless of m_debug.
+               int yInterceptsCenter = 0;
 
-                       int yInterceptsCenter = 0;
+               for (int i = 0; i < vertexCount; i++) {
+                       final double x0 = polyCoords[i * 2];
+                       final double y0 = polyCoords[(i * 2) + 1];
+                       final double x1 = polyCoords[((i * 2) + 2) % 
(vertexCount * 2)];
+                       final double y1 = polyCoords[((i * 2) + 3) % 
(vertexCount * 2)];
+                       final double x2 = polyCoords[((i * 2) + 4) % 
(vertexCount * 2)];
+                       final double y2 = polyCoords[((i * 2) + 5) % 
(vertexCount * 2)];
+                       final double distP0P1 = Math.sqrt(((x1 - x0) * (x1 - 
x0)) + ((y1 - y0) * (y1 - y0)));
 
-                       for (int i = 0; i < vertexCount; i++) {
-                               final double x0 = polyCoords[i * 2];
-                               final double y0 = polyCoords[(i * 2) + 1];
-                               final double x1 = polyCoords[((i * 2) + 2) % 
(vertexCount * 2)];
-                               final double y1 = polyCoords[((i * 2) + 3) % 
(vertexCount * 2)];
-                               final double x2 = polyCoords[((i * 2) + 4) % 
(vertexCount * 2)];
-                               final double y2 = polyCoords[((i * 2) + 5) % 
(vertexCount * 2)];
-                               final double distP0P1 = Math.sqrt(((x1 - x0) * 
(x1 - x0))
-                                               + ((y1 - y0) * (y1 - y0)));
+                       // Too close to distance zero.
+                       if ((float) distP0P1 == 0.0f) { 
+                               throw new IllegalArgumentException(
+                                               "a line segment has distance 
[too close to] zero");
+                       }
 
-                               if ((float) distP0P1 == 0.0f) { // Too close to 
distance zero.
-                                       throw new IllegalArgumentException(
-                                                       "a line segment has 
distance [too close to] zero");
-                               }
+                       final double distP2fromP0P1 = ((((y0 - y1) * x2)
+                                       + ((x1 - x0) * y2) + (x0 * y1)) - (x1 * 
y0)) / distP0P1;
 
-                               final double distP2fromP0P1 = ((((y0 - y1) * x2)
-                                               + ((x1 - x0) * y2) + (x0 * y1)) 
- (x1 * y0))
-                                               / distP0P1;
+                       // Too close to parallel.
+                       if ((float) distP2fromP0P1 == 0.0f) { 
+                               throw new IllegalArgumentException(
+                                               "either a line segment has 
distance [too close to] zero or "
+                                                               + "two 
consecutive line segments are [too close to] parallel");
+                       }
 
-                               if ((float) distP2fromP0P1 == 0.0f) { // Too 
close to
-                                       // parallel.
-                                       throw new IllegalArgumentException(
-                                                       "either a line segment 
has distance [too close to] zero or "
-                                                                       + "two 
consecutive line segments are [too close to] parallel");
-                               }
+                       final double distCenterFromP0P1 = ((x0 * y1) - (x1 * 
y0)) / distP0P1;
 
-                               final double distCenterFromP0P1 = ((x0 * y1) - 
(x1 * y0))
-                                               / distP0P1;
-
-                               if (!((float) distCenterFromP0P1 > 0.0f)) {
-                                       throw new IllegalArgumentException(
-                                                       "polygon is going 
counter-clockwise or is not star-shaped with "
-                                                                       + 
"respect to center");
-                               }
-
-                               if ((Math.min(y0, y1) < 0.0d) && (Math.max(y0, 
y1) >= 0.0d)) {
-                                       yInterceptsCenter++;
-                               }
+                       if (!((float) distCenterFromP0P1 > 0.0f)) {
+                               throw new IllegalArgumentException(
+                                               "polygon is going 
counter-clockwise or is not star-shaped with "
+                                                               + "respect to 
center");
                        }
 
-                       if (yInterceptsCenter != 2) {
-                               throw new IllegalArgumentException(
-                                               "the polygon self-intersects 
(we know this because the winding "
-                                                               + "number of 
the center is not one)");
+                       if ((Math.min(y0, y1) < 0.0d) && (Math.max(y0, y1) >= 
0.0d)) {
+                               yInterceptsCenter++;
                        }
                }
 
+               if (yInterceptsCenter != 2) {
+                       throw new IllegalArgumentException(
+                                       "the polygon self-intersects (we know 
this because the winding "
+                                                       + "number of the center 
is not one)");
+               }
+
                // polyCoords now contains a polygon spanning [-0.5, 0.5] X 
[-0.5, 0.5]
                // that passes all of the criteria.
-               final int nextCustomShapeType = (int) (m_lastCustomShapeType + 
1);
+               final byte nextCustomShapeType = (byte) (m_lastCustomShapeType 
+ 1);
 
-               if (nextCustomShapeType < 0) {
-                       throw new IllegalStateException(
-                                       "too many custom node shapes are 
already defined");
-               }
+               if (nextCustomShapeType < 0) 
+                       throw new IllegalStateException( "too many custom node 
shapes are already defined");
 
                m_lastCustomShapeType++;
-               m_customShapes.put(new Integer(nextCustomShapeType), 
polyCoords);
+               nodeShapes.put(nextCustomShapeType, new 
LegacyCustomNodeShape(polyCoords,nextCustomShapeType));
 
                return nextCustomShapeType;
        }
@@ -896,12 +795,9 @@
        /**
         * Determines whether the specified shape is a custom defined node 
shape.
         */
-       public final boolean customNodeShapeExists(final Integer shape) {
+       public final boolean customNodeShapeExists(final byte shape) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
                }
 
                return (shape > s_last_shape) && (shape <= 
m_lastCustomShapeType);
@@ -912,18 +808,15 @@
         * 
         * @return DOCUMENT ME!
         */
-       public final int[] getCustomNodeShapes() {
+       public final byte[] getCustomNodeShapes() {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
                }
 
-               final int[] returnThis = new int[m_lastCustomShapeType - 
s_last_shape];
+               final byte[] returnThis = new byte[m_lastCustomShapeType - 
s_last_shape];
 
                for (int i = 0; i < returnThis.length; i++) {
-                       returnThis[i] = (int) (s_last_shape + 1 + i);
+                       returnThis[i] = (byte) (s_last_shape + 1 + i);
                }
 
                return returnThis;
@@ -935,27 +828,16 @@
         * square. Returns null if specified shape is not a previously defined
         * custom shape.
         */
-       public final float[] getCustomNodeShape(final int customShape) {
+       public final float[] getCustomNodeShape(final byte customShape) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
                }
 
-               final double[] dCoords = m_customShapes.get(new 
Integer(customShape));
-
-               if (dCoords == null) {
+               if ( !customNodeShapeExists(customShape) )
                        return null;
-               }
 
-               final float[] returnThis = new float[dCoords.length];
-
-               for (int i = 0; i < returnThis.length; i++) {
-                       returnThis[i] = (float) dCoords[i];
-               }
-
-               return returnThis;
+               LegacyCustomNodeShape ns = 
(LegacyCustomNodeShape)(nodeShapes.get(customShape));
+               return ns.getCoords();
        }
 
        /**
@@ -970,10 +852,7 @@
         */
        public final void importCustomNodeShapes(final GraphGraphics grafx) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
                }
 
                // I define this error check outside the scope of m_debug 
because
@@ -983,8 +862,8 @@
                                        "a custom node shape is already defined 
in this GraphGraphics");
                }
 
-               for (Map.Entry<Integer, double[]> entry : 
grafx.m_customShapes.entrySet()) {
-                       m_customShapes.put(entry.getKey(), entry.getValue());
+               for (Map.Entry<Byte, NodeShape> entry : 
grafx.nodeShapes.entrySet()) {
+                       nodeShapes.put(entry.getKey(), entry.getValue());
                        m_lastCustomShapeType++;
                }
        }
@@ -1021,69 +900,12 @@
 //      */
 //     public static Map<Byte, Shape> getArrowShapes() {
 //             final Map<Byte, Shape> shapeMap = new HashMap<Byte, Shape>();
-//             
 //             for ( Arrow a : arrows.values() )
-//                     shapeMap.put( a.getType(), a.getArrowShape() );
+//                     shapeMap.put( a.get.getType(), a.getArrowShape() );
 // 
 //             return shapeMap;
 //     }
 
-       private final static void computeRoundedRectangle(final double xMin,
-                       final double yMin, final double xMax, final double yMax,
-                       final double radius, final GeneralPath path2d) {
-               path2d.reset();
-               path2d.moveTo((float) (xMax - radius), (float) yMin);
-               path2d.curveTo((float) (((CURVE_ELLIPTICAL - 1.0d) * radius) + 
xMax),
-                               (float) yMin, (float) xMax,
-                               (float) (((1.0d - CURVE_ELLIPTICAL) * radius) + 
yMin),
-                               (float) xMax, (float) (radius + yMin));
-               path2d.lineTo((float) xMax, (float) (yMax - radius));
-               path2d.curveTo((float) xMax,
-                               (float) (((CURVE_ELLIPTICAL - 1.0d) * radius) + 
yMax),
-                               (float) (((CURVE_ELLIPTICAL - 1.0d) * radius) + 
xMax),
-                               (float) yMax, (float) (xMax - radius), (float) 
yMax);
-               path2d.lineTo((float) (radius + xMin), (float) yMax);
-               path2d.curveTo((float) (((1.0d - CURVE_ELLIPTICAL) * radius) + 
xMin),
-                               (float) yMax, (float) xMin,
-                               (float) (((CURVE_ELLIPTICAL - 1.0d) * radius) + 
yMax),
-                               (float) xMin, (float) (yMax - radius));
-               path2d.lineTo((float) xMin, (float) (radius + yMin));
-               path2d.curveTo((float) xMin,
-                               (float) (((1.0d - CURVE_ELLIPTICAL) * radius) + 
yMin),
-                               (float) (((1.0d - CURVE_ELLIPTICAL) * radius) + 
xMin),
-                               (float) yMin, (float) (radius + xMin), (float) 
yMin);
-               path2d.closePath();
-       }
-
-       /*
-        * This method is used to construct an inner shape for node border.
-        * output[0] is the x return value and output[1] is the y return value. 
The
-        * line prev->curr cannot be parallel to curr->next.
-        */
-       private final static void computeInnerPoint(final double[] output,
-                       final double xPrev, final double yPrev, final double 
xCurr,
-                       final double yCurr, final double xNext, final double 
yNext,
-                       final double borderWidth) {
-               final double segX1 = xCurr - xPrev;
-               final double segY1 = yCurr - yPrev;
-               final double segLength1 = Math.sqrt((segX1 * segX1) + (segY1 * 
segY1));
-               final double segX2 = xNext - xCurr;
-               final double segY2 = yNext - yCurr;
-               final double segLength2 = Math.sqrt((segX2 * segX2) + (segY2 * 
segY2));
-               final double segX2Normal = segX2 / segLength2;
-               final double segY2Normal = segY2 / segLength2;
-               final double xNextPrime = (segX2Normal * segLength1) + xPrev;
-               final double yNextPrime = (segY2Normal * segLength1) + yPrev;
-               final double segPrimeX = xNextPrime - xCurr;
-               final double segPrimeY = yNextPrime - yCurr;
-               final double distancePrimeToSeg1 = (((segX1 * yNextPrime)
-                               - (segY1 * xNextPrime) + (xPrev * yCurr)) - 
(xCurr * yPrev))
-                               / segLength1;
-               final double multFactor = borderWidth / distancePrimeToSeg1;
-               output[0] = (multFactor * segPrimeX) + xCurr;
-               output[1] = (multFactor * segPrimeY) + yCurr;
-       }
-
        /**
         * This is the method that will render an edge very quickly. Translucent
         * colors are not supported by the low detail rendering methods.
@@ -1113,16 +935,9 @@
        public final void drawEdgeLow(final float x0, final float y0,
                        final float x1, final float y1, final Color edgeColor) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
+                       checkCleared();
 
-                       if (!m_cleared) {
-                               throw new IllegalStateException(
-                                               "clear() has not been called 
previously");
-                       }
-
                        if (edgeColor.getAlpha() != 255) {
                                throw new IllegalArgumentException("edgeColor 
is not opaque");
                        }
@@ -1720,59 +1535,22 @@
        }
 
        /*
-        * ---| \ | \| /| / | ---|
         * 
-        * The same transform that was used to draw the delta arrowhead (for
-        * ARROW_MONO) can be used modulo scaling to edge thickness.
         */
-       private final Shape computeUntransformedDeltaWedgeCap() {
-               m_path2d.reset();
-               m_path2d.moveTo(-2.0f, -0.5f);
-               m_path2d.lineTo(0.0f, -0.5f);
-               m_path2d.lineTo(0.0f, 0.5f);
-               m_path2d.lineTo(-2.0f, 0.5f);
-               m_path2d.lineTo(0.0f, 0.0f);
-               m_path2d.closePath();
-
-               return m_path2d;
+       private final static double getT(final byte arrowType) { 
+               Arrow a = arrows.get(arrowType);
+               if ( a != null )
+                       return a.getTOffset();
+               else
+                       return 0.125;
        }
 
        /*
-        * arrowType must be one of the primitive arrow types or ARROW_NONE (no
-        * ARROW_BIDIRECTIONAL or ARROW_MONO allowed).
-        */
-       private final static double getT(final int arrowType) { // I could
-               // implement
-               // this as an
-               // array instead
-               // of a switch
-               // statement.
-
-               switch (arrowType) {
-               case ARROW_NONE:
-                       return 0.0d;
-
-               case ARROW_DELTA:
-                       return 2.0d;
-
-               case ARROW_DIAMOND:
-                       return 2.0d;
-
-               case ARROW_DISC:
-                       return 0.5d;
-
-               default: // ARROW_TEE.
-
-                       return 0.125d;
-               }
-       }
-
-       /*
         * If arrow0Type is ARROW_NONE, arrow0Size should be zero. If 
arrow1Type is
         * ARROW_NONE, arrow1Size should be zero.
         */
-       private final boolean computeCubicPolyEdgePath(final int arrow0Type,
-                       final float arrow0Size, final int arrow1Type,
+       private final boolean computeCubicPolyEdgePath(final byte arrow0Type,
+                       final float arrow0Size, final byte arrow1Type,
                        final float arrow1Size, final float x0, final float y0,
                        final EdgeAnchors anchors, final float x1, final float 
y1,
                        final double curveFactor) {
@@ -2021,250 +1799,6 @@
                        return ns.computeEdgeIntersection( xMin, yMin, xMax, 
yMax, ptX, ptY, returnVal);
        }
 
-       /*
-        * Computes the intersection of the line segment from (x1,y1) to (x2,y2)
-        * with the line segment from (x3,y3) to (x4,y4). If no intersection 
exists,
-        * returns false. Otherwise returns true, and returnVal[0] is set to be 
the
-        * X coordinate of the intersection point and returnVal[1] is set to be 
the
-        * Y coordinate of the intersection point. If more than one intersection
-        * point exists, "the intersection point" is defined to be the 
intersection
-        * point closest to (x1,y1). A note about overlapping line segments. 
Because
-        * of floating point numbers' inability to be totally accurate, it is 
quite
-        * difficult to represent overlapping line segments with floating point
-        * coordinates without using an absolute-precision math package. 
Because of
-        * this, poorly behaved outcome may result when computing the 
intersection
-        * of two [nearly] overlapping line segments. The only way around this 
would
-        * be to round intersection points to the nearest 32-bit floating point
-        * quantity. But then dynamic range is greatly compromised.
-        */
-       private final static boolean segmentIntersection(final double[] 
returnVal,
-                       double x1, double y1, double x2, double y2, double x3, 
double y3,
-                       double x4, double y4) {
-               // Arrange the segment endpoints such that in segment 1, y1 >= 
y2
-               // and such that in segment 2, y3 >= y4.
-               boolean s1reverse = false;
-
-               if (y2 > y1) {
-                       s1reverse = !s1reverse;
-
-                       double temp = x1;
-                       x1 = x2;
-                       x2 = temp;
-                       temp = y1;
-                       y1 = y2;
-                       y2 = temp;
-               }
-
-               if (y4 > y3) {
-                       double temp = x3;
-                       x3 = x4;
-                       x4 = temp;
-                       temp = y3;
-                       y3 = y4;
-                       y4 = temp;
-               }
-
-               /*
-                * 
-                * Note: While this algorithm for computing an intersection is
-                * completely bulletproof, it's not a straighforward 'classic'
-                * bruteforce method. This algorithm is well-suited for an
-                * implementation using fixed-point arithmetic instead of 
floating-point
-                * arithmetic because all computations are constrained to a 
certain
-                * dynamic range relative to the input parameters.
-                * 
-                * We're going to reduce the problem in the following way:
-                * 
-                * 
-                * (x1,y1) + \ \ \ (x3,y3) x1 x3 ---------+------+----------- 
yMax
-                * ---------+------+----------- yMax \ | \ | \ | \ | \ | \ | \ 
| \ \ | \ |
-                * =====\ \ | \| > \| + =====/ + (x,y) |\ / |\ | \ | \ | \ | \
-                * ----------------+---+------- yMin 
----------------+---+------ yMin |
-                * (x2,y2) x4 x2 | | + If W := (x2-x4) / ((x2-x4) + (x3-x1)) , 
then
-                * (x4,y4) x = x2 + W*(x1-x2) and y = yMin + W*(yMax-yMin)
-                * 
-                * 
-                */
-               final double yMax = Math.min(y1, y3);
-               final double yMin = Math.max(y2, y4);
-
-               if (yMin > yMax) {
-                       return false;
-               }
-
-               if (y1 > yMax) {
-                       x1 = x1 + (((x2 - x1) * (yMax - y1)) / (y2 - y1));
-                       y1 = yMax;
-               }
-
-               if (y3 > yMax) {
-                       x3 = x3 + (((x4 - x3) * (yMax - y3)) / (y4 - y3));
-                       y3 = yMax;
-               }
-
-               if (y2 < yMin) {
-                       x2 = x1 + (((x2 - x1) * (yMin - y1)) / (y2 - y1));
-                       y2 = yMin;
-               }
-
-               if (y4 < yMin) {
-                       x4 = x3 + (((x4 - x3) * (yMin - y3)) / (y4 - y3));
-                       y4 = yMin;
-               }
-
-               // Handling for yMin == yMax. That is, in the reduced problem, 
both
-               // segments are horizontal.
-               if (yMin == yMax) {
-                       // Arrange the segment endpoints such that in segment 
1, x1 <= x2
-                       // and such that in segment 2, x3 <= x4.
-                       if (x2 < x1) {
-                               s1reverse = !s1reverse;
-
-                               double temp = x1;
-                               x1 = x2;
-                               x2 = temp;
-                               temp = y1;
-                               y1 = y2;
-                               y2 = temp;
-                       }
-
-                       if (x4 < x3) {
-                               double temp = x3;
-                               x3 = x4;
-                               x4 = temp;
-                               temp = y3;
-                               y3 = y4;
-                               y4 = temp;
-                       }
-
-                       final double xMin = Math.max(x1, x3);
-                       final double xMax = Math.min(x2, x4);
-
-                       if (xMin > xMax) {
-                               return false;
-                       } else {
-                               if (s1reverse) {
-                                       returnVal[0] = Math.max(xMin, xMax);
-                               } else {
-                                       returnVal[0] = Math.min(xMin, xMax);
-                               }
-
-                               returnVal[1] = yMin; // == yMax
-
-                               return true;
-                       }
-               }
-
-               // It is now true that yMin < yMax because we've fully handled
-               // the yMin == yMax case above.
-               // Following if statement checks for a "twist" in the line 
segments.
-               if (((x1 < x3) && (x2 < x4)) || ((x3 < x1) && (x4 < x2))) {
-                       return false;
-               }
-
-               // The segments are guaranteed to intersect.
-               if ((x1 == x3) && (x2 == x4)) { // The segments overlap.
-
-                       if (s1reverse) {
-                               returnVal[0] = x2;
-                               returnVal[1] = y2;
-                       } else {
-                               returnVal[0] = x1;
-                               returnVal[1] = y1;
-                       }
-               }
-
-               // The segments are guaranteed to intersect in exactly one 
point.
-               final double W = (x2 - x4) / ((x2 - x4) + (x3 - x1));
-               returnVal[0] = x2 + (W * (x1 - x2));
-               returnVal[1] = yMin + (W * (yMax - yMin));
-
-               return true;
-       }
-
-       /*
-        * Computes the intersection of the line segment from (x1,y1) to (x2,y2)
-        * with the circle at center (cX,cY) and radius specified. Returns the
-        * number of intersection points. The returnVal parameter passed in 
should
-        * be of length 4, and values written to it are such: returnVal[0] - x
-        * component of first intersection point returnVal[1] - y component of 
first
-        * intersection point returnVal[2] - x component of second intersection
-        * point returnVal[3] - y component of second intersection point
-        * Furthermore, if more than one point is returned, then the first point
-        * returned shall be closer to (x1,y1). Note: I don't like the
-        * implementation of this method because the computation blows up when 
the
-        * line segment endpoints are close together. Luckily, the way that this
-        * method is used from within this class prevents such blowing up. 
However,
-        * I have named this method bad_*() because I don't want this code to 
become
-        * a generic routine that is used outside the scope of this class.
-        */
-       private final static int bad_circleIntersection(final double[] 
returnVal,
-                       final double x1, final double y1, final double x2, 
final double y2,
-                       final double cX, final double cY, final double radius) {
-               final double vX = x2 - x1;
-               final double vY = y2 - y1;
-
-               if ((vX == 0.0d) && (vY == 0.0d)) {
-                       throw new IllegalStateException(
-                                       "the condition of both line segment 
endpoint being the same "
-                                                       + "will not occur if 
polygons are star-shaped with no marginal "
-                                                       + "conditions");
-               }
-
-               final double a = (vX * vX) + (vY * vY);
-               final double b = 2 * ((vX * (x1 - cX)) + (vY * (y1 - cY)));
-               final double c = ((cX * cX) + (cY * cY) + (x1 * x1) + (y1 * y1))
-                               - (2 * ((cX * x1) + (cY * y1))) - (radius * 
radius);
-               final double sq = (b * b) - (4 * a * c);
-
-               if (sq < 0.0d) {
-                       return 0;
-               }
-
-               final double sqrt = Math.sqrt(sq);
-
-               if (sqrt == 0.0d) { // Exactly one solution for infinite line.
-
-                       final double u = -b / (2 * a);
-
-                       if (!((u <= 1.0d) && (u >= 0.0d))) {
-                               return 0;
-                       }
-
-                       returnVal[0] = x1 + (u * vX);
-                       returnVal[1] = y1 + (u * vY);
-
-                       return 1;
-               } else { // Two solutions for infinite line.
-
-                       double u1 = (-b + sqrt) / (2 * a);
-                       double u2 = (-b - sqrt) / (2 * a);
-
-                       if (u2 < u1) {
-                               double temp = u1;
-                               u1 = u2;
-                               u2 = temp;
-                       }
-
-                       // Now u1 is less than or equal to u2.
-                       int solutions = 0;
-
-                       if ((u1 <= 1.0d) && (u1 >= 0.0d)) {
-                               returnVal[0] = x1 + (u1 * vX);
-                               returnVal[1] = y1 + (u1 * vY);
-                               solutions++;
-                       }
-
-                       if ((u2 <= 1.0d) && (u2 >= 0.0d)) {
-                               returnVal[solutions * 2] = x1 + (u2 * vX);
-                               returnVal[(solutions * 2) + 1] = y1 + (u2 * vY);
-                               solutions++;
-                       }
-
-                       return solutions;
-               }
-       }
-
        /**
         * This method will render text very quickly. Translucent colors are not
         * supported by the low detail rendering methods.
@@ -2298,16 +1832,8 @@
        public final void drawTextLow(final Font font, final String text,
                        final float xCenter, final float yCenter, final Color 
color) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
-
-                       if (!m_cleared) {
-                               throw new IllegalStateException(
-                                               "clear() has not been called 
previously");
-                       }
-
+                       checkDispatchThread();
+                       checkCleared();
                        if (color.getAlpha() != 255) {
                                throw new IllegalStateException("color is not 
opaque");
                        }
@@ -2324,8 +1850,7 @@
 
                final FontMetrics fMetrics = m_gMinimal.getFontMetrics();
                m_gMinimal.setColor(color);
-               m_gMinimal
-                               .drawString(
+               m_gMinimal.drawString(
                                                text,
                                                (int) ((-0.5d * 
fMetrics.stringWidth(text)) + m_ptsBuff[0]),
                                                (int) ((0.5d * 
fMetrics.getHeight())
@@ -2341,10 +1866,7 @@
         */
        public final FontRenderContext getFontRenderContextLow() {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
                }
 
                if (m_gMinimal == null) {
@@ -2412,20 +1934,11 @@
                        final String text, final float xCenter, final float 
yCenter,
                        final float theta, final Paint paint, final boolean 
drawTextAsShape) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
+                       checkDispatchThread();
+                       checkCleared();
+                       if (scaleFactor < 0.0) {
+                               throw new IllegalArgumentException("scaleFactor 
must be positive");
                        }
-
-                       if (!m_cleared) {
-                               throw new IllegalStateException(
-                                               "clear() has not been called 
previously");
-                       }
-
-                       if (!(scaleFactor >= 0.0d)) {
-                               throw new IllegalArgumentException(
-                                               "scaleFactor must be positive");
-                       }
                }
 
                m_g2d.translate(xCenter, yCenter);
@@ -2473,10 +1986,7 @@
         */
        public final FontRenderContext getFontRenderContextFull() {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
+                       checkDispatchThread();
                }
 
                return m_fontRenderContextFull;
@@ -2502,27 +2012,23 @@
        public final void drawCustomGraphicFull(final Shape shape,
                        final float xOffset, final float yOffset, final Paint 
paint) {
                if (m_debug) {
-                       if (!EventQueue.isDispatchThread()) {
-                               throw new IllegalStateException(
-                                               "calling thread is not AWT 
event dispatcher");
-                       }
-
-                       if (!m_cleared) {
-                               throw new IllegalStateException(
-                                               "clear() has not been called 
previously");
-                       }
+                       checkDispatchThread();
+                       checkCleared();
                }
-
+               
                m_g2d.translate(xOffset, yOffset);
-               m_g2d.setPaint(paint);
-               m_g2d.fill(shape);
+               if(paint instanceof TexturePaint) {
+                       final BufferedImage bImg = ((TexturePaint) 
paint).getImage();
+                       m_g2d.drawImage(bImg,
+                                       shape.getBounds().x, 
shape.getBounds().y, shape.getBounds().width, shape.getBounds().height, null);
+               } else {
+                       m_g2d.setPaint(paint);
+                       m_g2d.fill(shape);
+               }
+
                m_g2d.setTransform(m_currNativeXform);
        }
 
-       private enum ShapeTypes {
-               NODE_SHAPE, ARROW_SHAPE, LINE_STROKE;
-       }
-
        private Stroke getStroke(float borderWidth) {
                Stroke s = borderStrokes.get(borderWidth);
                if ( s == null ) {

-- 
You received this message because you are subscribed to the Google Groups 
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/cytoscape-cvs?hl=en.

Reply via email to