[Arakhnę-Dev] [404] * Add utility functions on zoomable contexts.

[ Thread Index | Date Index | More arakhne.org/dev Archives ]


Revision: 404
Author:   galland
Date:     2013-04-04 09:10:14 +0200 (Thu, 04 Apr 2013)
Log Message:
-----------
* Add utility functions on zoomable contexts.

Modified Paths:
--------------
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContext.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContextUtil.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeManager.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/PointerEvent.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/InternalZoomablePanel.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomableGraphics2D.java

Added Paths:
-----------
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/ZoomableAwtContextUtil.java

Added: trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/ZoomableAwtContextUtil.java
===================================================================
--- trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/ZoomableAwtContextUtil.java	                        (rev 0)
+++ trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/ZoomableAwtContextUtil.java	2013-04-04 07:10:14 UTC (rev 404)
@@ -0,0 +1,695 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2005-09 Stephane GALLAND.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * 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 (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * 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
+ * This program is free software; you can redistribute it and/or modify
+ */
+
+package org.arakhne.afc.ui.awt;
+
+import java.awt.Font;
+import java.awt.Polygon;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Area;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+
+import org.arakhne.afc.ui.CenteringTransform;
+
+/** Utilities for ZoomableContext with additional functions
+ * dedicated to AWT objects.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class ZoomableAwtContextUtil extends org.arakhne.afc.ui.ZoomableContextUtil {
+
+	private static void create(
+			PathIterator pathIterator,
+			CenteringTransform centeringTransform,
+			float zoom,
+			Path2D output) {
+		float[] coords = new float[8];
+		while (!pathIterator.isDone()) {
+			switch(pathIterator.currentSegment(coords)) {
+			case PathIterator.SEG_MOVETO:
+				output.moveTo(
+						logical2pixel_x(coords[0], centeringTransform, zoom),
+						logical2pixel_y(coords[1], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_LINETO:
+				output.lineTo(
+						logical2pixel_x(coords[0], centeringTransform, zoom),
+						logical2pixel_y(coords[1], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_CUBICTO:
+				output.curveTo(
+						logical2pixel_x(coords[0], centeringTransform, zoom),
+						logical2pixel_y(coords[1], centeringTransform, zoom),
+						logical2pixel_x(coords[2], centeringTransform, zoom),
+						logical2pixel_y(coords[3], centeringTransform, zoom),
+						logical2pixel_x(coords[4], centeringTransform, zoom),
+						logical2pixel_y(coords[5], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_QUADTO:
+				output.quadTo(
+						logical2pixel_x(coords[0], centeringTransform, zoom),
+						logical2pixel_y(coords[1], centeringTransform, zoom),
+						logical2pixel_x(coords[2], centeringTransform, zoom),
+						logical2pixel_y(coords[3], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_CLOSE:
+				output.closePath();
+				break;
+			default:
+				throw new IllegalArgumentException();
+			}
+			pathIterator.next();
+		}
+	}
+
+	private static void create2(
+			Shape s,
+			CenteringTransform centeringTransform,
+			float zoom,
+			Path2D output) {
+		PathIterator it = s.getPathIterator(new AffineTransform());
+		float[] coords = new float[8];
+		while (!it.isDone()) {
+			switch(it.currentSegment(coords)) {
+			case PathIterator.SEG_MOVETO:
+				output.moveTo(
+						pixel2logical_x(coords[0], centeringTransform, zoom),
+						pixel2logical_y(coords[1], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_LINETO:
+				output.lineTo(
+						pixel2logical_x(coords[0], centeringTransform, zoom),
+						pixel2logical_y(coords[1], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_CUBICTO:
+				output.curveTo(
+						pixel2logical_x(coords[0], centeringTransform, zoom),
+						pixel2logical_y(coords[1], centeringTransform, zoom),
+						pixel2logical_x(coords[2], centeringTransform, zoom),
+						pixel2logical_y(coords[3], centeringTransform, zoom),
+						pixel2logical_x(coords[4], centeringTransform, zoom),
+						pixel2logical_y(coords[5], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_QUADTO:
+				output.quadTo(
+						pixel2logical_x(coords[0], centeringTransform, zoom),
+						pixel2logical_y(coords[1], centeringTransform, zoom),
+						pixel2logical_x(coords[2], centeringTransform, zoom),
+						pixel2logical_y(coords[3], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_CLOSE:
+				output.closePath();
+				break;
+			default:
+				throw new IllegalArgumentException();
+			}
+			it.next();
+		}
+	}
+
+	/** Replies the transformation matrix which is corresponding to
+	 * the given {@link CenteringTransform} and with a zooming
+	 * factor.
+	 * <p>
+	 * <code>
+	 * | transform.scaleX*zoom   0                       transform.translationX*zoom |
+	 * | 0                       transform.scaleY*zoom   transform.translationY*zoom |
+	 * | 0                       0                       1                           |
+	 * </code>
+	 * 
+	 * @param transform
+	 * @param zoom
+	 * @return the transformation matrix.
+	 */
+	public static AffineTransform getMatrix(CenteringTransform transform, float zoom) {
+		return new AffineTransform(
+				transform.getScaleX()*zoom, 0,
+				0, transform.getScaleY()*zoom,
+				transform.getTranslationX()*zoom,
+				transform.getTranslationY()*zoom);
+	}
+	
+	/** Replies the transformation matrix which is corresponding to
+	 * the given {@link CenteringTransform} but without a zoom.
+	 * <p>
+	 * <code>
+	 * | transform.scaleX   0                 transform.translationX*zoom |
+	 * | 0                  transform.scaleY  transform.translationY*zoom |
+	 * | 0                  0                 1                           |
+	 * </code>
+	 * 
+	 * @param transform
+	 * @param zoom
+	 * @return the transformation matrix.
+	 */
+	public static AffineTransform getMatrixNoScaling(CenteringTransform transform, float zoom) {
+		return new AffineTransform(
+				transform.getScaleX(), 0,
+				0, transform.getScaleY(),
+				transform.getTranslationX()*zoom,
+				transform.getTranslationY()*zoom);
+	}
+
+	/** Translates the specified rectangle
+	 *  into the screen space.
+	 *
+	 * @param r is the rectangle in the logical space when input and the
+	 * same rectangle in screen space when output.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 */
+	public static void logical2pixel(Rectangle2D r,
+			CenteringTransform centeringTransform,
+			float zoom) {
+		assert(r!=null);
+		assert(centeringTransform!=null);
+		float x = (float)(centeringTransform.isXAxisFlipped() ? r.getMaxX() : r.getMinX());
+		float y = (float)(centeringTransform.isYAxisFlipped() ? r.getMaxY() : r.getMinY());
+		r.setFrame(
+				logical2pixel_x(x, centeringTransform, zoom),
+				logical2pixel_y(y, centeringTransform, zoom),
+				logical2pixel_size((float)r.getWidth(), zoom),
+				logical2pixel_size((float)r.getHeight(), zoom));
+	}
+
+	/** Translates the specified rectangle
+	 *  into the logical space.
+	 *
+	 * @param r is the rectangle in the screen space when input and the
+	 * same rectangle in logical space when output.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 */
+	public static void pixel2logical(Rectangle2D r,
+			CenteringTransform centeringTransform,
+			float zoom) {
+		assert(r!=null);
+		assert(centeringTransform!=null);
+		float x = (float)(centeringTransform.isXAxisFlipped() ? r.getMaxX() : r.getMinX());
+		float y = (float)(centeringTransform.isYAxisFlipped() ? r.getMaxY() : r.getMinY());
+		r.setFrame(
+				pixel2logical_x(x, centeringTransform, zoom),
+				pixel2logical_y(y, centeringTransform, zoom),
+				pixel2logical_size((float)r.getWidth(), zoom),
+				pixel2logical_size((float)r.getHeight(), zoom));
+	}
+
+	/** Translate the specified font from a logical length to a screen length.
+	 * 
+	 * @param font is the font with a size in the logical coordinate system.
+	 * @param zoom is the current zooming factor of the view.
+	 * @return the font with a size suitable for the screen coordinate system.
+	 */
+	public static Font logical2pixel(Font font, float zoom) {
+		float nSize = logical2pixel_size(font.getSize2D(), zoom);
+		return font.deriveFont(nSize);
+	}
+
+	/** Translate the specified font from a screen length to a logical length.
+	 * 
+	 * @param font is the font with a size in the screen coordinate system.
+	 * @param zoom is the current zooming factor of the view.
+	 * @return the font with a size suitable for the logical coordinate system.
+	 */
+	public static Font pixel2logical(Font font, float zoom) {
+		float nSize = pixel2logical_size(font.getSize2D(), zoom);
+		return font.deriveFont(nSize);
+	}
+
+	/** Translates the specified point
+	 *  into the screen space.
+	 *
+	 * @param p is the point in the logical space when input and the
+	 * same point in screen space when output.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 */
+	public static void logical2pixel(Point2D p,
+			CenteringTransform centeringTransform,
+			float zoom) {
+		assert(p!=null);
+		assert(centeringTransform!=null);
+		p.setLocation(
+				logical2pixel_x((float)p.getX(), centeringTransform, zoom),
+				logical2pixel_y((float)p.getY(), centeringTransform, zoom));
+	}
+
+	/** Translates the specified point
+	 *  into the logical space.
+	 *
+	 * @param p is the point in the screen space when input and the
+	 * same point in logical space when output.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 */
+	public static void pixel2logical(Point2D p,
+			CenteringTransform centeringTransform,
+			float zoom) {
+		assert(p!=null);
+		assert(centeringTransform!=null);
+		p.setLocation(
+				pixel2logical_x((float)p.getX(), centeringTransform, zoom),
+				pixel2logical_y((float)p.getY(), centeringTransform, zoom));
+	}
+
+	/** Translates the specified path
+	 *  into the screen space.
+	 *
+	 * @param p is the path in the logical.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 * @param the path is screen path.
+	 */
+	public static Path2D logical2pixel(PathIterator p,
+			CenteringTransform centeringTransform,
+			float zoom) {
+		Path2D path = new Path2D.Float();
+		float[] coords = new float[6];
+		while(!p.isDone()) {
+			switch(p.currentSegment(coords)) {
+			case PathIterator.SEG_MOVETO:
+				path.moveTo(
+						logical2pixel_x(coords[0], centeringTransform, zoom),
+						logical2pixel_y(coords[1], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_LINETO:
+				path.lineTo(
+						logical2pixel_x(coords[0], centeringTransform, zoom),
+						logical2pixel_y(coords[1], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_QUADTO:
+				path.quadTo(
+						logical2pixel_x(coords[0], centeringTransform, zoom),
+						logical2pixel_y(coords[1], centeringTransform, zoom),
+						logical2pixel_x(coords[2], centeringTransform, zoom),
+						logical2pixel_y(coords[3], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_CUBICTO:
+				path.curveTo(
+						logical2pixel_x(coords[0], centeringTransform, zoom),
+						logical2pixel_y(coords[1], centeringTransform, zoom),
+						logical2pixel_x(coords[2], centeringTransform, zoom),
+						logical2pixel_y(coords[3], centeringTransform, zoom),
+						logical2pixel_x(coords[4], centeringTransform, zoom),
+						logical2pixel_y(coords[5], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_CLOSE:
+				path.closePath();
+				break;
+			default:
+			}
+			p.next();
+		}
+		return path;
+	}
+
+	/** Translates the specified path
+	 *  into the logical space.
+	 *
+	 * @param p is the path in the screen space.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 * @return the path in logical space.
+	 */
+	public static Path2D pixel2logical(PathIterator p,
+			CenteringTransform centeringTransform,
+			float zoom) {
+		Path2D path = new Path2D.Float();
+		float[] coords = new float[6];
+		while(!p.isDone()) {
+			switch(p.currentSegment(coords)) {
+			case PathIterator.SEG_MOVETO:
+				path.moveTo(
+						pixel2logical_x(coords[0], centeringTransform, zoom),
+						pixel2logical_y(coords[1], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_LINETO:
+				path.lineTo(
+						pixel2logical_x(coords[0], centeringTransform, zoom),
+						pixel2logical_y(coords[1], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_QUADTO:
+				path.quadTo(
+						pixel2logical_x(coords[0], centeringTransform, zoom),
+						pixel2logical_y(coords[1], centeringTransform, zoom),
+						pixel2logical_x(coords[2], centeringTransform, zoom),
+						pixel2logical_y(coords[3], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_CUBICTO:
+				path.curveTo(
+						pixel2logical_x(coords[0], centeringTransform, zoom),
+						pixel2logical_y(coords[1], centeringTransform, zoom),
+						pixel2logical_x(coords[2], centeringTransform, zoom),
+						pixel2logical_y(coords[3], centeringTransform, zoom),
+						pixel2logical_x(coords[4], centeringTransform, zoom),
+						pixel2logical_y(coords[5], centeringTransform, zoom));
+				break;
+			case PathIterator.SEG_CLOSE:
+				path.closePath();
+				break;
+			default:
+			}
+			p.next();
+		}
+		return path;
+	}
+
+	/** Translates the specified shape
+	 *  into the screen space.
+	 *
+	 * @param <T> is the type of shape to convert.
+	 * @param s is the shape in the logical space.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 * @return a shape into the screen space.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T extends Shape> T logical2pixel(
+			T s, CenteringTransform centeringTransform, float zoom) {
+		if (s==null) return null;
+		SupportedShape type = SupportedShape.getTypeOf(s.getClass());
+		try {
+			switch(type) {
+			case RECTANGLE2D:
+			{
+				Rectangle2D r = (Rectangle2D)s;
+				float x = (float)((centeringTransform.isXAxisFlipped()) ? r.getMaxX() : r.getMinX());
+				float y = (float)((centeringTransform.isYAxisFlipped()) ? r.getMaxY() : r.getMinY());
+				return (T)new Rectangle2D.Double(
+						logical2pixel_x(x, centeringTransform, zoom),
+						logical2pixel_y(y, centeringTransform, zoom),
+						logical2pixel_size((float)r.getWidth(), zoom),
+						logical2pixel_size((float)r.getHeight(), zoom));
+			}
+			case ROUND_RECTANGLE:
+			{
+				RoundRectangle2D r = (RoundRectangle2D)s;
+				float x = (float)((centeringTransform.isXAxisFlipped()) ? r.getMaxX() : r.getMinX());
+				float y = (float)((centeringTransform.isYAxisFlipped()) ? r.getMaxY() : r.getMinY());
+				return (T)new RoundRectangle2D.Double(
+						logical2pixel_x(x, centeringTransform, zoom),
+						logical2pixel_y(y, centeringTransform, zoom),
+						logical2pixel_size((float)r.getWidth(), zoom),
+						logical2pixel_size((float)r.getHeight(), zoom),
+						logical2pixel_size((float)r.getArcWidth(), zoom),
+						logical2pixel_size((float)r.getArcHeight(), zoom));
+			}
+			case ELLIPSE:
+			{
+				Ellipse2D e = (Ellipse2D)s;
+				float x = (float)((centeringTransform.isXAxisFlipped()) ? e.getMaxX() : e.getMinX());
+				float y = (float)((centeringTransform.isYAxisFlipped()) ? e.getMaxY() : e.getMinY());
+				return (T)new Ellipse2D.Double(
+						logical2pixel_x(x, centeringTransform, zoom),
+						logical2pixel_y(y, centeringTransform, zoom),
+						logical2pixel_size((float)e.getWidth(), zoom),
+						logical2pixel_size((float)e.getHeight(), zoom));
+			}
+			case LINE:
+			{
+				Line2D l = (Line2D)s;
+				return (T)new Line2D.Double(
+						logical2pixel_x((float)l.getX1(), centeringTransform, zoom),
+						logical2pixel_y((float)l.getY1(), centeringTransform, zoom),
+						logical2pixel_x((float)l.getX2(), centeringTransform, zoom),
+						logical2pixel_y((float)l.getY2(), centeringTransform, zoom));
+			}
+			case ARC:
+			{
+				Arc2D a = (Arc2D)s;
+				float x = (float)((centeringTransform.isXAxisFlipped()) ? a.getMaxX() : a.getMinX());
+				float y = (float)((centeringTransform.isYAxisFlipped()) ? a.getMaxY() : a.getMinY());
+				return (T)new Arc2D.Double(
+						logical2pixel_x(x, centeringTransform, zoom),
+						logical2pixel_y(y, centeringTransform, zoom),
+						logical2pixel_size((float)a.getWidth(), zoom),
+						logical2pixel_size((float)a.getHeight(), zoom),
+						a.getAngleStart(),
+						a.getAngleExtent(),
+						a.getArcType());
+			}
+			case POLYGON:
+			{
+				Polygon p = (Polygon)s ;
+				float x, y;
+				GeneralPath p2 = new GeneralPath() ;
+				for( int i=0; i < p.npoints; ++i ) {
+					x = logical2pixel_x(p.xpoints[i], centeringTransform, zoom);
+					y = logical2pixel_y(p.ypoints[i], centeringTransform, zoom);
+					if (i==0)
+						p2.moveTo(x, y);
+					else
+						p2.lineTo(x, y);
+				}
+				p2.closePath();
+				return (T)p2 ;
+			}
+			case CUBIC_CURVE:
+			{
+				CubicCurve2D c = (CubicCurve2D)s ;
+				return (T)new CubicCurve2D.Double(
+						logical2pixel_x((float)c.getX1(), centeringTransform, zoom),
+						logical2pixel_y((float)c.getY1(), centeringTransform, zoom),
+						logical2pixel_x((float)c.getCtrlX1(), centeringTransform, zoom),
+						logical2pixel_y((float)c.getCtrlY1(), centeringTransform, zoom),
+						logical2pixel_x((float)c.getCtrlX2(), centeringTransform, zoom),
+						logical2pixel_y((float)c.getCtrlY2(), centeringTransform, zoom),
+						logical2pixel_x((float)c.getX2(), centeringTransform, zoom),
+						logical2pixel_y((float)c.getY2(), centeringTransform, zoom));
+			}
+			case QUAD_CURVE:
+			{
+				QuadCurve2D c = (QuadCurve2D)s ;
+				return (T)new QuadCurve2D.Double(
+						logical2pixel_x((float)c.getX1(), centeringTransform, zoom),
+						logical2pixel_y((float)c.getY1(), centeringTransform, zoom),
+						logical2pixel_x((float)c.getCtrlX(), centeringTransform, zoom),
+						logical2pixel_y((float)c.getCtrlY(), centeringTransform, zoom),
+						logical2pixel_x((float)c.getX2(), centeringTransform, zoom),
+						logical2pixel_y((float)c.getY2(), centeringTransform, zoom));
+			}
+			case PATH:
+			{
+				Path2D p = (Path2D)s;
+				Path2D p2 = new GeneralPath(p.getWindingRule());
+				create(
+						p.getPathIterator(null), centeringTransform, zoom, p2);
+				return (T)p2;
+			}
+			case AREA:
+			{
+				Area a = (Area)s ;
+				GeneralPath p2 = new GeneralPath();
+				create(
+						a.getPathIterator(null),
+						centeringTransform, zoom, p2);
+				return (T)new Area(p2);
+			}
+			case VIRTUALIZABLE_SHAPE:
+			{
+				VirtualizableShape vs = (VirtualizableShape)s;
+				return (T)vs.toScreen(centeringTransform, zoom);
+			}
+			default:
+				throw new IllegalArgumentException();
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+
+		throw new UnsupportedShapeException(type);
+	}
+
+	/** Translates the specified shape
+	 *  into the logical space.
+	 *
+	 * @param <T> is the type of shape to convert.
+	 * @param s is the shape in the screen space.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 * @return a shape into the logical space.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T extends Shape> T pixel2logical(
+			T s, CenteringTransform centeringTransform, float zoom) {
+		if (s==null) return null;
+		SupportedShape type = SupportedShape.getTypeOf(s.getClass());
+		try {
+			switch(type) {
+			case RECTANGLE2D:
+			{
+				Rectangle2D r = (Rectangle2D)s;
+				float x = (float)((centeringTransform.isXAxisFlipped()) ? r.getMaxX() : r.getMinX());
+				float y = (float)((centeringTransform.isYAxisFlipped()) ? r.getMaxY() : r.getMinY());
+				return (T)new Rectangle2D.Double(
+						pixel2logical_x(x, centeringTransform, zoom),
+						pixel2logical_y(y, centeringTransform, zoom),
+						pixel2logical_size((float)r.getWidth(), zoom),
+						pixel2logical_size((float)r.getHeight(), zoom));
+			}
+			case ROUND_RECTANGLE:
+			{
+				RoundRectangle2D r = (RoundRectangle2D)s;
+				float x = (float) ((centeringTransform.isXAxisFlipped()) ? r.getMaxX() : r.getMinX());
+				float y = (float) ((centeringTransform.isYAxisFlipped()) ? r.getMaxY() : r.getMinY());
+				return (T)new RoundRectangle2D.Double(
+						pixel2logical_x(x, centeringTransform, zoom),
+						pixel2logical_y(y, centeringTransform, zoom),
+						pixel2logical_size((float)r.getWidth(), zoom),
+						pixel2logical_size((float)r.getHeight(), zoom),
+						pixel2logical_size((float)r.getArcWidth(), zoom),
+						pixel2logical_size((float)r.getArcHeight(), zoom));
+			}
+			case ELLIPSE:
+			{
+				Ellipse2D e = (Ellipse2D)s;
+				float x = (float) ((centeringTransform.isXAxisFlipped()) ? e.getMaxX() : e.getMinX());
+				float y = (float) ((centeringTransform.isYAxisFlipped()) ? e.getMaxY() : e.getMinY());
+				return (T)new Ellipse2D.Double(
+						pixel2logical_x(x, centeringTransform, zoom),
+						pixel2logical_y(y, centeringTransform, zoom),
+						pixel2logical_size((float)e.getWidth(), zoom),
+						pixel2logical_size((float)e.getHeight(), zoom));
+			}
+			case LINE:
+			{
+				Line2D l = (Line2D)s;
+				return (T)new Line2D.Double(
+						pixel2logical_x((float)l.getX1(), centeringTransform, zoom),
+						pixel2logical_y((float)l.getY1(), centeringTransform, zoom),
+						pixel2logical_x((float)l.getX2(), centeringTransform, zoom),
+						pixel2logical_y((float)l.getY2(), centeringTransform, zoom));
+			}
+			case ARC:
+			{
+				Arc2D a = (Arc2D)s;
+				float x = (float) ((centeringTransform.isXAxisFlipped()) ? a.getMaxX() : a.getMinX());
+				float y = (float) ((centeringTransform.isYAxisFlipped()) ? a.getMaxY() : a.getMinY());
+				return (T)new Arc2D.Double(
+						pixel2logical_x(x, centeringTransform, zoom),
+						pixel2logical_y(y, centeringTransform, zoom),
+						pixel2logical_size((float)a.getWidth(), zoom),
+						pixel2logical_size((float)a.getHeight(), zoom),
+						a.getAngleStart(),
+						a.getAngleExtent(),
+						a.getArcType());
+			}
+			case POLYGON:
+			{
+				Polygon p = (Polygon)s ;
+				GeneralPath p2 = new GeneralPath() ;
+				float x, y;
+				for( int i=0; i < p.npoints; ++i ) {
+					x = pixel2logical_x(p.xpoints[i], centeringTransform, zoom);
+					y = pixel2logical_y(p.ypoints[i], centeringTransform, zoom);
+					if (i==0) p2.moveTo(x, y);
+					else p2.lineTo(x, y);
+				}
+				p2.closePath();
+				return (T)p2 ;
+			}
+			case CUBIC_CURVE:
+			{
+				CubicCurve2D c = (CubicCurve2D)s ;
+				return (T)new CubicCurve2D.Double(
+						pixel2logical_x((float)c.getX1(), centeringTransform, zoom),
+						pixel2logical_y((float)c.getY1(), centeringTransform, zoom),
+						pixel2logical_x((float)c.getCtrlX1(), centeringTransform, zoom),
+						pixel2logical_y((float)c.getCtrlY1(), centeringTransform, zoom),
+						pixel2logical_x((float)c.getCtrlX2(), centeringTransform, zoom),
+						pixel2logical_y((float)c.getCtrlY2(), centeringTransform, zoom),
+						pixel2logical_x((float)c.getX2(), centeringTransform, zoom),
+						pixel2logical_y((float)c.getY2(), centeringTransform, zoom));
+			}
+			case QUAD_CURVE:
+			{
+				QuadCurve2D c = (QuadCurve2D)s ;
+				return (T)new QuadCurve2D.Double(
+						pixel2logical_x((float)c.getX1(), centeringTransform, zoom),
+						pixel2logical_y((float)c.getY1(), centeringTransform, zoom),
+						pixel2logical_x((float)c.getCtrlX(), centeringTransform, zoom),
+						pixel2logical_y((float)c.getCtrlY(), centeringTransform, zoom),
+						pixel2logical_x((float)c.getX2(), centeringTransform, zoom),
+						pixel2logical_y((float)c.getY2(), centeringTransform, zoom));
+			}
+			case PATH:
+			{
+				Path2D p = (Path2D)s;
+				Path2D p2 = new GeneralPath(p.getWindingRule());
+				create2(p, centeringTransform, zoom, p2);
+				return (T)p2;
+			}
+			case AREA:
+			{
+				Area a = (Area)s ;
+				GeneralPath p2 = new GeneralPath();
+				create2(a, centeringTransform, zoom, p2);
+				return (T)new Area(p2);
+			}
+			case VIRTUALIZABLE_SHAPE:
+			{
+				VirtualizableShape vs = (VirtualizableShape)s;
+				return (T)vs.fromScreen(centeringTransform, zoom);
+			}
+			default:
+				throw new IllegalArgumentException();
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+
+		throw new UnsupportedShapeException(type);
+	}
+
+}
\ No newline at end of file

Modified: trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContext.java
===================================================================
--- trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContext.java	2013-03-31 09:26:05 UTC (rev 403)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContext.java	2013-04-04 07:10:14 UTC (rev 404)
@@ -29,6 +29,7 @@
 import org.arakhne.afc.math.continous.object2d.Rectangle2f;
 import org.arakhne.afc.math.continous.object2d.RoundRectangle2f;
 import org.arakhne.afc.math.continous.object2d.Segment2f;
+import org.arakhne.afc.math.continous.object2d.Shape2f;
 
 /** This interface describes a zooming context and
  * permits to make some operation in it.
@@ -200,6 +201,32 @@
 	 */
 	public void pixel2logical(Rectangle2f r);
 
+	/** Translates the specified shape
+	 *  into the screen space.
+	 *  <p>
+	 *  <strong>CAUTION:</strong> You must prefer to invoke 
+	 *  one of the other functions of this ZoomableContext
+	 *  to run a faster translation algorithm than the
+	 *  algorithm implemented in this function. 
+	 *
+	 * @param s is the shape in the logical space when input and the
+	 * same shape in screen space when output.
+	 */
+	public Shape2f logical2pixel(Shape2f s);
+
+	/** Translates the specified shape
+	 *  into the logical space.
+	 *  <p>
+	 *  <strong>CAUTION:</strong> You must prefer to invoke 
+	 *  one of the other functions of this ZoomableContext
+	 *  to run a faster translation algorithm than the
+	 *  algorithm implemented in this function. 
+	 *
+	 * @param s is the shape in the screen space when input and the
+	 * same shape in logical space when output.
+	 */
+	public Shape2f pixel2logical(Shape2f s);
+
 	/** Replies the graphical zoom factor.
      * 
      * @return the scale factor.

Modified: trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContextUtil.java
===================================================================
--- trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContextUtil.java	2013-03-31 09:26:05 UTC (rev 403)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContextUtil.java	2013-04-04 07:10:14 UTC (rev 404)
@@ -24,12 +24,14 @@
 
 import org.arakhne.afc.math.continous.object2d.Circle2f;
 import org.arakhne.afc.math.continous.object2d.Ellipse2f;
+import org.arakhne.afc.math.continous.object2d.Path2f;
 import org.arakhne.afc.math.continous.object2d.PathElement2f;
 import org.arakhne.afc.math.continous.object2d.PathIterator2f;
 import org.arakhne.afc.math.continous.object2d.Point2f;
 import org.arakhne.afc.math.continous.object2d.Rectangle2f;
 import org.arakhne.afc.math.continous.object2d.RoundRectangle2f;
 import org.arakhne.afc.math.continous.object2d.Segment2f;
+import org.arakhne.afc.math.continous.object2d.Shape2f;
 import org.arakhne.afc.math.generic.PathWindingRule;
 
 /** Utilities for ZoomableContext.
@@ -347,6 +349,102 @@
 				pixel2logical_size(r.getHeight(), zoom));
 	}
 
+	/** Translates the specified shape
+	 *  into the screen space.
+	 *  <p>
+	 *  <strong>CAUTION:</strong> You must prefer to invoke 
+	 *  one of the other functions of this ZoomableContext
+	 *  to run a faster translation algorithm than the
+	 *  algorithm implemented in this function. 
+	 *
+	 * @param s is the shape in the logical space to translate.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 * @return the result of the translation.
+	 */
+	public static Shape2f logical2pixel(Shape2f s,
+			CenteringTransform centeringTransform,
+			float zoom) {
+		assert(s!=null);
+		assert(centeringTransform!=null);
+		if (s instanceof Rectangle2f) {
+			Rectangle2f r = ((Rectangle2f)s).clone();
+			logical2pixel(r, centeringTransform, zoom);
+			return r;
+		}
+		if (s instanceof Circle2f) {
+			Circle2f r = ((Circle2f)s).clone();
+			logical2pixel(r, centeringTransform, zoom);
+			return r;
+		}
+		if (s instanceof Ellipse2f) {
+			Ellipse2f r = ((Ellipse2f)s).clone();
+			logical2pixel(r, centeringTransform, zoom);
+			return r;
+		}
+		if (s instanceof RoundRectangle2f) {
+			RoundRectangle2f r = ((RoundRectangle2f)s).clone();
+			logical2pixel(r, centeringTransform, zoom);
+			return r;
+		}
+		if (s instanceof Segment2f) {
+			Segment2f r = ((Segment2f)s).clone();
+			logical2pixel(r, centeringTransform, zoom);
+			return r;
+		}
+		return new Path2f(logical2pixel(s.getPathIterator(), centeringTransform, zoom));
+	}
+
+	/** Translates the specified shape
+	 *  into the logical space.
+	 *  <p>
+	 *  <strong>CAUTION:</strong> You must prefer to invoke 
+	 *  one of the other functions of this ZoomableContext
+	 *  to run a faster translation algorithm than the
+	 *  algorithm implemented in this function. 
+	 *
+	 * @param s is the shape in the screen space to translate.
+	 * @param centeringTransform is the transform to apply to the points to change from/to the coordinate
+	 * system from the "global" logical coordinate system to/from the "centered" logical coordinate
+	 * system.
+	 * @param zoom is the current zooming factor of the view.
+	 * @return the result of the translation.
+	 */
+	public static Shape2f pixel2logical(Shape2f s,
+			CenteringTransform centeringTransform,
+			float zoom) {
+		assert(s!=null);
+		assert(centeringTransform!=null);
+		if (s instanceof Rectangle2f) {
+			Rectangle2f r = ((Rectangle2f)s).clone();
+			pixel2logical(r, centeringTransform, zoom);
+			return r;
+		}
+		if (s instanceof Circle2f) {
+			Circle2f r = ((Circle2f)s).clone();
+			pixel2logical(r, centeringTransform, zoom);
+			return r;
+		}
+		if (s instanceof Ellipse2f) {
+			Ellipse2f r = ((Ellipse2f)s).clone();
+			pixel2logical(r, centeringTransform, zoom);
+			return r;
+		}
+		if (s instanceof RoundRectangle2f) {
+			RoundRectangle2f r = ((RoundRectangle2f)s).clone();
+			pixel2logical(r, centeringTransform, zoom);
+			return r;
+		}
+		if (s instanceof Segment2f) {
+			Segment2f r = ((Segment2f)s).clone();
+			pixel2logical(r, centeringTransform, zoom);
+			return r;
+		}
+		return new Path2f(logical2pixel(s.getPathIterator(), centeringTransform, zoom));
+	}
+
 	/** Translates the specified workspace location
 	 *  into the screen location.
 	 *

Modified: trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeManager.java
===================================================================
--- trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeManager.java	2013-03-31 09:26:05 UTC (rev 403)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeManager.java	2013-04-04 07:10:14 UTC (rev 404)
@@ -32,6 +32,7 @@
 import java.util.UUID;
 
 import org.arakhne.afc.math.continous.object2d.Point2f;
+import org.arakhne.afc.math.continous.object2d.Shape2f;
 import org.arakhne.afc.math.generic.Point2D;
 import org.arakhne.afc.ui.ZoomableContext;
 import org.arakhne.afc.ui.event.KeyEvent;
@@ -76,6 +77,7 @@
 	
 	private float mouseX = Float.NaN;
 	private float mouseY = Float.NaN;
+	private Shape2f mouseArea = null;
 	
 	private final ListenerCollection<EventListener> listeners = new ListenerCollection<EventListener>();
 
@@ -707,12 +709,19 @@
 			if (zc!=null) {
 				this.mouseX = zc.pixel2logical_x(e.getX());
 				this.mouseY = zc.pixel2logical_y(e.getY());
+				this.mouseArea = zc.pixel2logical(e.getToolArea(0));
 			}
 			else {
 				this.mouseX = e.getX();
 				this.mouseY = e.getY();
+				this.mouseArea = e.getToolArea(0);
 			}
 		}
+		else {
+			this.mouseX = e.getX();
+			this.mouseY = e.getY();
+			this.mouseArea = e.getToolArea(0);
+		}
 	}
 	
 	/** Replies the current position of the mouse in the document.
@@ -742,4 +751,12 @@
 		return this.mouseY;
 	}
 
+	/** Replies the area covered by the pointer.
+	 * 
+	 * @return the area covered by the pointer.
+	 */
+	public Shape2f getMouseArea() {
+		return this.mouseArea;
+	}
+
 }

Modified: trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/PointerEvent.java
===================================================================
--- trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/PointerEvent.java	2013-03-31 09:26:05 UTC (rev 403)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/PointerEvent.java	2013-04-04 07:10:14 UTC (rev 404)
@@ -113,7 +113,7 @@
 	 */
 	public int getPointerCount();
 	
-	/** Returns an ellipse that describes the size of the approaching 
+	/** Returns a shape that describes the size of the approaching 
 	 * tool for the given pointer index. The tool area represents 
 	 * the estimated size of the finger or pen that is touching the 
 	 * device independent of its actual touch area at the point of contact.

Modified: trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/InternalZoomablePanel.java
===================================================================
--- trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/InternalZoomablePanel.java	2013-03-31 09:26:05 UTC (rev 403)
+++ trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/InternalZoomablePanel.java	2013-04-04 07:10:14 UTC (rev 404)
@@ -47,6 +47,7 @@
 import org.arakhne.afc.math.continous.object2d.Rectangle2f;
 import org.arakhne.afc.math.continous.object2d.RoundRectangle2f;
 import org.arakhne.afc.math.continous.object2d.Segment2f;
+import org.arakhne.afc.math.continous.object2d.Shape2f;
 import org.arakhne.afc.ui.CenteringTransform;
 import org.arakhne.afc.ui.Graphics2DLOD;
 import org.arakhne.afc.ui.ZoomableContextUtil;
@@ -1009,4 +1010,16 @@
 				this.fitToWindowFactor * this.zoomFactor);
 	}
 
+	@Override
+	public Shape2f logical2pixel(Shape2f s) {
+		return ZoomableContextUtil.logical2pixel(s, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public Shape2f pixel2logical(Shape2f s) {
+		return ZoomableContextUtil.pixel2logical(s, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
 }

Modified: trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomableGraphics2D.java
===================================================================
--- trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomableGraphics2D.java	2013-03-31 09:26:05 UTC (rev 403)
+++ trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomableGraphics2D.java	2013-04-04 07:10:14 UTC (rev 404)
@@ -62,6 +62,7 @@
 import org.arakhne.afc.math.continous.object2d.Rectangle2f;
 import org.arakhne.afc.math.continous.object2d.RoundRectangle2f;
 import org.arakhne.afc.math.continous.object2d.Segment2f;
+import org.arakhne.afc.math.continous.object2d.Shape2f;
 import org.arakhne.afc.ui.CenteringTransform;
 import org.arakhne.afc.ui.Graphics2DLOD;
 import org.arakhne.afc.ui.StringAnchor;
@@ -1664,6 +1665,16 @@
 		ZoomableContextUtil.pixel2logical(r, this.centeringTransform, this.zoomFactor);
 	}
 
+	@Override
+	public Shape2f logical2pixel(Shape2f s) {
+		return ZoomableContextUtil.logical2pixel(s, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public Shape2f pixel2logical(Shape2f s) {
+		return ZoomableContextUtil.pixel2logical(s, this.centeringTransform, this.zoomFactor);
+	}
+
 	/**
 	 * Return the rectangle that corresponds to the displayed
 	 * area.


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/