[Arakhnę-Dev] [403] * Update the poniter event to include more information (pointer area. ..)

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


Revision: 403
Author:   galland
Date:     2013-03-31 11:26:05 +0200 (Sun, 31 Mar 2013)
Log Message:
-----------
* Update the poniter event to include more information (pointer area...)

Modified Paths:
--------------
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform2D.java
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform3D.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/AbstractLODGraphics2D.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/VirtualizableShape.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/CenteringTransform.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContext.java
    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/undo/DefaultUndoManager.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/UndoableGroup.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/event/PointerEventSwing.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
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomablePanel.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtPath.java

Modified: trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform2D.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform2D.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform2D.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -31,8 +31,6 @@
  * mathematical representation is row major, as in traditional
  * matrix mathematics.
  * <p>
- * <b>IMPORTANT: </b> The Transform2D does not support scale.
- * <p>
  * The transformation matrix is:
  * <pre><code>
  * | cos(theta) | -sin(theta) | Tx |
@@ -103,9 +101,22 @@
 	}
 
 	/** Set the position.
+	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the translation (m02,
+	 * m12). The scaling and the shearing are not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   ?    ?    x   ]
+	 *          [   ?    ?    y   ]
+	 *          [   ?    ?    ?   ]
+	 * </pre>
 	 * 
 	 * @param x
 	 * @param y
+	 * @see #makeTranslationMatrix(float, float)
 	 */
 	public void setTranslation(float x, float y) {
 		this.m02 = x;
@@ -113,8 +124,21 @@
 	}
 
 	/** Set the position.
+	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the translation (m02,
+	 * m12). The scaling and the shearing are not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   ?    ?    t.x   ]
+	 *          [   ?    ?    t.y   ]
+	 *          [   ?    ?    ?     ]
+	 * </pre>
 	 * 
 	 * @param t
+	 * @see #makeTranslationMatrix(float, float)
 	 */
 	public void setTranslation(Tuple2D<?> t) {
 		this.m02 = t.getX();
@@ -122,6 +146,13 @@
 	}
 
 	/** Translate the position.
+	 * <p>
+	 * This function is equivalent to:
+	 * <pre>
+	 * this = this *  [   0    0    dx   ]
+	 *                [   0    0    dy   ]
+	 *                [   0    0    1    ]
+	 * </pre>
 	 * 
 	 * @param dx
 	 * @param dy
@@ -132,6 +163,13 @@
 	}
 
 	/** Translate the position.
+	 * <p>
+	 * This function is equivalent to:
+	 * <pre>
+	 * this = this *  [   0    0    t.x   ]
+	 *                [   0    0    t.y   ]
+	 *                [   0    0    1     ]
+	 * </pre>
 	 * 
 	 * @param t
 	 */
@@ -176,8 +214,21 @@
 
 	/**
 	 * Set the rotation for the object (theta).
+	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the rotation (m00,
+	 * m01, m10, m11). The translation is not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   cos(theta)  -sin(theta)  ?   ]
+	 *          [   sin(theta)  cos(theta)   ?   ]
+	 *          [   ?           ?            ?   ]
+	 * </pre>
 	 * 
 	 * @param theta
+	 * @see #makeRotationMatrix(float)
 	 */
 	public void setRotation(float theta) {
 		float cosTheta = (float)Math.cos(theta);
@@ -190,6 +241,13 @@
 
 	/**
 	 * Rotate the object (theta).
+	 * <p>
+	 * This function is equivalent to:
+	 * <pre>
+	 * this = this *  [   cos(theta)    -sin(theta)    0   ]
+	 *                [   sin(theta)    cos(theta)     0   ]
+	 *                [   0             0              1   ]
+	 * </pre>
 	 * 
 	 * @param theta
 	 */
@@ -253,14 +311,21 @@
 
 	/** Set the scale.
 	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the scaling (m00,
+	 * m11). The shearing and the translation are not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
 	 * <pre>
-	 *          [   sx   0    0   ]
-	 *          [   0    sy   0   ]
-	 *          [   0    0    1   ]
+	 *          [   sx  ?   ?   ]
+	 *          [   ?   sy  ?   ]
+	 *          [   ?   ?   ?   ]
 	 * </pre>
 	 * 
 	 * @param sx
 	 * @param sy
+	 * @see #makeScaleMatrix(float, float)
 	 */
 	public void setScale(float sx, float sy) {
 		this.m00 = sx;
@@ -269,13 +334,20 @@
 
 	/** Set the scale.
 	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the scaling (m00,
+	 * m11). The shearing and the translation are not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
 	 * <pre>
-	 *          [   sx   0    0   ]
-	 *          [   0    sy   0   ]
-	 *          [   0    0    1   ]
+	 *          [   t.x  ?    ?   ]
+	 *          [   ?    t.y  ?   ]
+	 *          [   ?    ?    ?   ]
 	 * </pre>
 	 * 
 	 * @param t
+	 * @see #makeScaleMatrix(float, float)
 	 */
 	public void setScale(Tuple2D<?> t) {
 		this.m00 = t.getX();
@@ -283,12 +355,12 @@
 	}
 
 	/** Concatenates this transform with a scaling transformation.
-	 * This is equivalent to calling concatenate(S), where S is an
-	 * <code>Transform2D</code> represented by the following matrix:
+	 * <p>
+	 * This function is equivalent to:
 	 * <pre>
-	 *          [   sx   0    0   ]
-	 *          [   0    sy   0   ]
-	 *          [   0    0    1   ]
+	 * this = this *  [   sx   0    0   ]
+	 *                [   0    sy   0   ]
+	 *                [   0    0    1   ]
 	 * </pre>
 	 * 
 	 * @param sx
@@ -302,12 +374,12 @@
 	}
 
 	/** Concatenates this transform with a scaling transformation.
-	 * This is equivalent to calling concatenate(S), where S is an
-	 * <code>Transform2D</code> represented by the following matrix:
+	 * <p>
+	 * This function is equivalent to:
 	 * <pre>
-	 *          [   sx   0    0   ]
-	 *          [   0    sy   0   ]
-	 *          [   0    0    1   ]
+	 * this = this *  [   t.x   0     0   ]
+	 *                [   0     t.y   0   ]
+	 *                [   0     0     1   ]
 	 * </pre>
 	 * 
 	 * @param t
@@ -360,14 +432,21 @@
 
 	/** Set the shearing elements.
 	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the shearing (m01,
+	 * m10). The scaling and the translation are not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
 	 * <pre>
-	 *          [   0    shx  0   ]
-	 *          [   shy  0    0   ]
-	 *          [   0    0    1   ]
+	 *          [   ?    shx  ?   ]
+	 *          [   shy  ?    ?   ]
+	 *          [   ?    ?    ?   ]
 	 * </pre>
 	 * 
 	 * @param shx
 	 * @param shy
+	 * @see #makeShearMatrix(float, float)
 	 */
 	public void setShear(float shx,  float shy) {
 		this.m01 = shx;
@@ -376,13 +455,20 @@
 
 	/** Set the shearing elements.
 	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the shearing (m01,
+	 * m10). The scaling and the translation are not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
 	 * <pre>
-	 *          [   0    shx  0   ]
-	 *          [   shy  0    0   ]
-	 *          [   0    0    1   ]
+	 *          [   ?    t.x  ?   ]
+	 *          [   t.y  ?    ?   ]
+	 *          [   ?    ?    ?   ]
 	 * </pre>
 	 * 
 	 * @param t
+	 * @see #makeShearMatrix(float, float)
 	 */
 	public void setShear(Tuple2D<?> t) {
 		this.m01 = t.getX();
@@ -390,12 +476,12 @@
 	}
 
 	/** Concatenates this transform with a shearing transformation.
-	 * This is equivalent to calling concatenate(S), where S is an
-	 * <code>Transform2D</code> represented by the following matrix:
+	 * <p>
+	 * This function is equivalent to:
 	 * <pre>
-	 *          [   1    shx  0   ]
-	 *          [   shy  1    0   ]
-	 *          [   0    0    1   ]
+	 * this = this *  [   1    shx  0   ]
+	 *                [   shy  1    0   ]
+	 *                [   0    0    1   ]
 	 * </pre>
 	 * 
 	 * @param shx
@@ -416,12 +502,12 @@
 	}
 
 	/** Concatenates this transform with a shearing transformation.
-	 * This is equivalent to calling concatenate(S), where S is an
-	 * <code>Transform2D</code> represented by the following matrix:
+	 * <p>
+	 * This function is equivalent to:
 	 * <pre>
-	 *          [   1    shx  0   ]
-	 *          [   shy  1    0   ]
-	 *          [   0    0    1   ]
+	 * this = this *  [   1    t.x  0   ]
+	 *                [   t.y  1    0   ]
+	 *                [   0    0    1   ]
 	 * </pre>
 	 * 
 	 * @param t
@@ -475,9 +561,21 @@
 	/**
 	 * Sets the value of this matrix to a counter clockwise rotation about the x
 	 * axis, and no translation
+	 * <p>
+	 * This function changes all the elements of 
+	 * the matrix, icluding the translation. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   cos(theta)  -sin(theta)  0   ]
+	 *          [   sin(theta)  cos(theta)   0   ]
+	 *          [   0           0            1   ]
+	 * </pre>
 	 * 
 	 * @param angle
 	 *            the angle to rotate about the X axis in radians
+	 * @see #setRotation(float)
 	 */
 	public final void makeRotationMatrix(float angle) {
 		float sinAngle, cosAngle;
@@ -500,9 +598,22 @@
 
 	/**
 	 * Sets the value of this matrix to the given translation, without rotation.
+	 * <p>
+	 * This function changes all the elements of 
+	 * the matrix including the scaling and the shearing. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   1    0    x   ]
+	 *          [   0    1    y   ]
+	 *          [   0    0    1   ]
+	 * </pre>
 	 * 
 	 * @param dx is the translation along X.
 	 * @param dy is the translation along Y.
+	 * @see #setTranslation(float, float)
+	 * @see #setTranslation(Tuple2D)
 	 */
 	public final void makeTranslationMatrix(float dx, float dy) {
 		this.m00 = 1f;
@@ -520,9 +631,23 @@
 
 	/**
 	 * Sets the value of this matrix to the given scaling, without rotation.
+	 * <p>
+	 * This function changes all the elements of 
+	 * the matrix, including the shearing and the
+	 * translation. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   sx  0   0   ]
+	 *          [   0   sy  0   ]
+	 *          [   0   0   1   ]
+	 * </pre>
 	 * 
 	 * @param sx is the scaling along X.
 	 * @param sy is the scaling along Y.
+	 * @see #setScale(float, float)
+	 * @see #setScale(Tuple2D)
 	 */
 	public final void makeScaleMatrix(float sx, float sy) {
 		this.m00 = sx;
@@ -540,9 +665,23 @@
 
 	/**
 	 * Sets the value of this matrix to the given scaling, without rotation.
+	 * <p>
+	 * This function changes all the elements of 
+	 * the matrix incuding the scaling and the
+	 * translation. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   1    shx  0   ]
+	 *          [   shy  1    0   ]
+	 *          [   0    0    1   ]
+	 * </pre>
 	 * 
 	 * @param shx is the shearing along X.
 	 * @param shy is the shearing along Y.
+	 * @see #setShear(float, float)
+	 * @see #setShear(Tuple2D)
 	 */
 	public final void makeShearMatrix(float shx, float shy) {
 		this.m00 = 1f;
@@ -572,7 +711,14 @@
 		t.set(x, y);
 	}
 
-	/** Multiply this matrix by the tuple <x,y> and return the result (r = this*<x,y>).
+	/** Multiply this matrix by the tuple <x,y> and return the result.
+	 * <p>
+	 * This function is equivalent to:
+	 * <pre>
+	 * result = this *  [   x   ]
+	 *                  [   y   ]
+	 *                  [   1   ]
+	 * </pre>
 	 * 
 	 * @param x
 	 * @param y
@@ -587,7 +733,14 @@
 
 	/**
 	 * Multiply this matrix by the tuple t and and place the result into the
-	 * tuple "result" (result = this*t).
+	 * tuple "result".
+	 * <p>
+	 * This function is equivalent to:
+	 * <pre>
+	 * result = this *  [   t.x   ]
+	 *                  [   t.y   ]
+	 *                  [   1     ]
+	 * </pre>
 	 * 
 	 * @param t
 	 *            the tuple to be multiplied by this matrix

Modified: trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform3D.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform3D.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform3D.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -113,10 +113,24 @@
 	}
 
 	/** Set the position.
+	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the translation.
+	 * The scaling and the shearing are not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   ?    ?    x   ]
+	 *          [   ?    ?    y   ]
+	 *          [   ?    ?    z   ]
+	 *          [   ?    ?    ?   ]
+	 * </pre>
 	 * 
 	 * @param x
 	 * @param y
 	 * @param z
+	 * @see #makeTranslationMatrix(float, float, float)
 	 */
 	public void setTranslation(float x, float y, float z) {
 		this.m03 = x;
@@ -125,8 +139,22 @@
 	}
 	
 	/** Set the position.
+	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the translation.
+	 * The scaling and the shearing are not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   ?    ?    t.x   ]
+	 *          [   ?    ?    t.y   ]
+	 *          [   ?    ?    t.z   ]
+	 *          [   ?    ?    ?     ]
+	 * </pre>
 	 * 
 	 * @param t
+	 * @see #makeTranslationMatrix(float, float, float)
 	 */
 	public void setTranslation(Tuple3D<?> t) {
 		this.m03 = t.getX();
@@ -135,6 +163,14 @@
 	}
 
 	/** Translate the position.
+	 * <p>
+	 * This function is equivalent to:
+	 * <pre>
+	 * this = this *  [   0    0    0    dx   ]
+	 *                [   0    0    0    dy   ]
+	 *                [   0    0    0    dz   ]
+	 *                [   0    0    0    1    ]
+	 * </pre>
 	 * 
 	 * @param dx
 	 * @param dy
@@ -147,6 +183,14 @@
 	}
 	
 	/** Translate the position.
+	 * <p>
+	 * This function is equivalent to:
+	 * <pre>
+	 * this = this *  [   0    0    0    t.x   ]
+	 *                [   0    0    0    t.y   ]
+	 *                [   0    0    0    t.z   ]
+	 *                [   0    0    0    1     ]
+	 * </pre>
 	 * 
 	 * @param t
 	 */
@@ -201,6 +245,20 @@
 
     /**
      * Set the rotation for the object but do not change the translation.
+	 * <p>
+	 * This function changes only the elements of 
+	 * the matrix related to the rotation.
+	 * The translation is not changed. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value, and r is the translation
+	 * of the quaternion as a 3x3 matrix):
+	 * <pre>
+	 *          [   r   r   r   ?   ]
+	 *          [   r   r   r   ?   ]
+	 *          [   r   r   r   ?   ]
+	 *          [   ?   ?   ?   ?   ]
+	 * </pre>
      * 
      * @param rotation
      * @see #makeRotationMatrix(Quaternion)
@@ -221,6 +279,15 @@
 
     /**
      * Rotate the object.
+	 * <p>
+	 * This function is equivalent to (where r is the translation
+	 * of the quaternion as a 3x3 matrix):
+	 * <pre>
+	 * this = this *  [   r    r     r     0   ]
+	 *                [   r    r     r     0   ]
+	 *                [   r    r     r     0   ]
+	 *                [   0    0     0     1   ]
+	 * </pre>
      * 
      * @param rotation
      */
@@ -232,8 +299,22 @@
     
     /**
 	 * Sets the value of this matrix to a rotation matrix, and no translation.
+	 * <p>
+	 * This function changes all the elements of 
+	 * the matrix, including the translation. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value, and r a value from
+	 * the quaternion):
+	 * <pre>
+	 *          [   r  r  r  0   ]
+	 *          [   r  r  r  0   ]
+	 *          [   r  r  r  0   ]
+	 *          [   0  0  0  1   ]
+	 * </pre>
 	 * 
 	 * @param rotation
+	 * @see #setRotation(Quaternion)
 	 */
 	public final void makeRotationMatrix(Quaternion rotation) {
 		this.m00 = (1.0f - 2.0f*rotation.getY()*rotation.getY() - 2.0f*rotation.getZ()*rotation.getZ());
@@ -260,10 +341,24 @@
 	
     /**
 	 * Sets the value of this matrix to the given translation, without rotation.
+	 * <p>
+	 * This function changes all the elements of 
+	 * the matrix including the scaling and the shearing. 
+	 * <p>
+	 * After a call to this function, the matrix will
+	 * contains (? means any value):
+	 * <pre>
+	 *          [   1    0    0    dx   ]
+	 *          [   0    1    0    dy   ]
+	 *          [   0    0    1    dz   ]
+	 *          [   0    0    0    1    ]
+	 * </pre>
 	 * 
 	 * @param dx is the position to put in the matrix.
 	 * @param dy is the position to put in the matrix.
 	 * @param dz is the position to put in the matrix.
+	 * @see #setTranslation(float, float, float)
+	 * @see #setTranslation(Tuple3D)
 	 */
 	public final void makeTranslationMatrix(float dx, float dy, float dz) {
 		this.m00 = 1f;

Modified: trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/AbstractLODGraphics2D.java
===================================================================
--- trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/AbstractLODGraphics2D.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/AbstractLODGraphics2D.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -151,6 +151,16 @@
 		this(target, target_component, false, false, lod);
 	}
 	
+	/** Replies the graphics object that is really used to render.
+	 * <p>
+	 * The implementation of the replied object is based on the AWT/Swing API.
+	 * 
+	 * @return the rendering graphics
+	 */
+	public Graphics2D getRenderingGraphics() {
+		return this.getRenderingGraphics();
+	}
+	
 	/** {@inheritDoc}
 	 */
 	@Override

Modified: trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/VirtualizableShape.java
===================================================================
--- trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/VirtualizableShape.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/VirtualizableShape.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -25,8 +25,9 @@
 package org.arakhne.afc.ui.awt;
 
 import java.awt.Shape;
-import java.awt.geom.Rectangle2D;
 
+import org.arakhne.afc.ui.CenteringTransform;
+
 /** Shape that may be transformed from screen to a logical
  * coordinate space.
  *
@@ -36,39 +37,27 @@
  * @mavenartifactid $ArtifactId$
  */
 public interface VirtualizableShape extends Shape {
-	
+
 	/** Replies a shape that is the same of this shape
 	 * on the screen.
 	 * 
-	 * @param flipX indicates if the X screen axis is inverted.
-	 * @param flipY indicates if the Y screen axis is inverted.
-	 * @param documentScreenRectangle is the area covered by the document in screen space.
-	 * @param translationX is the translation X in the context.
-	 * @param translationY is the translation Y in the context.
+	 * @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 shape.
 	 */
-	public VirtualizableShape toScreen(
-			boolean flipX, boolean flipY,
-			Rectangle2D documentScreenRectangle,
-			float translationX, float translationY,
-			float zoom);
-	
+	public VirtualizableShape toScreen(CenteringTransform centeringTransform, float zoom);
+
 	/** Replies a shape that is the same of this shape
 	 * on the virtual area.
 	 * 
-	 * @param flipX indicates if the X screen axis is inverted.
-	 * @param flipY indicates if the Y screen axis is inverted.
-	 * @param documentScreenRectangle is the area covered by the document in screen space.
-	 * @param translationX is the translation X in the context.
-	 * @param translationY is the translation Y in the context.
+	 * @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 shape.
 	 */
-	public VirtualizableShape fromScreen(
-			boolean flipX, boolean flipY,
-			Rectangle2D documentScreenRectangle,
-			float translationX, float translationY,
-			float zoom);
+	public VirtualizableShape fromScreen(CenteringTransform centeringTransform, float zoom);
 
 }

Modified: trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/CenteringTransform.java
===================================================================
--- trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/CenteringTransform.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/CenteringTransform.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -22,6 +22,8 @@
 
 package org.arakhne.afc.ui;
 
+import org.arakhne.afc.math.matrix.Transform2D;
+
 /** This feature describes all the parameters that must
  * be used to center logical points on the screen view. 
  *
@@ -142,4 +144,59 @@
 		return (y - this.translationY) / this.scaleY;
 	}
 
+	/** Replies the transformation matrix which is corresponding to this
+	 * centering transformation.
+	 * 
+	 * @return the transformation matrix.
+	 */
+	public Transform2D getMatrix() {
+		return new Transform2D(
+				this.scaleX, 0, this.translationX,
+				0, this.scaleY, this.translationY);
+	}	
+
+	/** Replies the transformation matrix which is corresponding to this
+	 * centering transformation and multiply by the given factor..
+	 * 
+	 * @param factor
+	 * @return the transformation matrix.
+	 */
+	public Transform2D getMatrix(float factor) {
+		return new Transform2D(
+				this.scaleX*factor, 0, this.translationX*factor,
+				0, this.scaleY*factor, this.translationY*factor);
+	}
+	
+	/** Replies the X scaling factor in the transformation matrix of this object.
+	 * 
+	 * @return the m00 of the transformation matrix replied by {@link #getMatrix()}
+	 */
+	public float getScaleX() {
+		return this.scaleX;
+	}
+
+	/** Replies the Y scaling factor in the transformation matrix of this object.
+	 * 
+	 * @return the m11 of the transformation matrix replied by {@link #getMatrix()}
+	 */
+	public float getScaleY() {
+		return this.scaleY;
+	}
+
+	/** Replies the X translation factor in the transformation matrix of this object.
+	 * 
+	 * @return the m02 of the transformation matrix replied by {@link #getMatrix()}
+	 */
+	public float getTranslationX() {
+		return this.translationX;
+	}
+
+	/** Replies the Y translation factor in the transformation matrix of this object.
+	 * 
+	 * @return the m12 of the transformation matrix replied by {@link #getMatrix()}
+	 */
+	public float getTranslationY() {
+		return this.translationY;
+	}
+
 }
\ 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-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContext.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -22,6 +22,14 @@
 
 package org.arakhne.afc.ui;
 
+import org.arakhne.afc.math.continous.object2d.Circle2f;
+import org.arakhne.afc.math.continous.object2d.Ellipse2f;
+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;
+
 /** This interface describes a zooming context and
  * permits to make some operation in it.
  * 
@@ -80,7 +88,119 @@
 	 */
 	public float pixel2logical_y(float l);
 
-    /** Replies the graphical zoom factor.
+	/** Translates the specified path
+	 *  into the screen space.
+	 *
+	 * @param p is the path in the logical.
+	 * @param the path is screen path.
+	 */
+	public PathIterator2f logical2pixel(PathIterator2f p);
+
+	/** Translates the specified path
+	 *  into the logical space.
+	 *
+	 * @param p is the path in the screen space.
+	 * @return the path in logical space.
+	 */
+	public PathIterator2f pixel2logical(PathIterator2f p);
+
+	/** Translates the specified segment
+	 *  into the screen space.
+	 *
+	 * @param s is the segment in the logical space when input and the
+	 * same segment in screen space when output.
+	 */
+	public void logical2pixel(Segment2f s);
+
+	/** Translates the specified segment
+	 *  into the logical space.
+	 *
+	 * @param s is the segment in the screen space when input and the
+	 * same segment in logical space when output.
+	 */
+	public void pixel2logical(Segment2f s);
+
+	/** 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.
+	 */
+	public void logical2pixel(RoundRectangle2f r);
+
+	/** 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.
+	 */
+	public void pixel2logical(RoundRectangle2f r);
+
+	/** 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.
+	 */
+	public void logical2pixel(Point2f p);
+
+	/** 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.
+	 */
+	public void pixel2logical(Point2f p);
+
+	/** Translates the specified ellipse
+	 *  into the screen space.
+	 *
+	 * @param e is the ellipse in the logical space when input and the
+	 * same ellipse in screen space when output.
+	 */
+	public void logical2pixel(Ellipse2f e);
+
+	/** Translates the specified ellipse
+	 *  into the logical space.
+	 *
+	 * @param r is the ellipse in the screen space when input and the
+	 * same ellipse in logical space when output.
+	 */
+	public void pixel2logical(Ellipse2f e);
+
+	/** Translates the specified circle
+	 *  into the screen space.
+	 *
+	 * @param r is the rectangle in the logical space when input and the
+	 * same rectangle in screen space when output.
+	 */
+	public void logical2pixel(Circle2f r);
+
+	/** Translates the specified circle
+	 *  into the logical space.
+	 *
+	 * @param r is the rectangle in the screen space when input and the
+	 * same rectangle in logical space when output.
+	 */
+	public void pixel2logical(Circle2f r);
+
+	/** 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.
+	 */
+	public void logical2pixel(Rectangle2f r);
+
+	/** 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.
+	 */
+	public void pixel2logical(Rectangle2f r);
+
+	/** Replies the graphical zoom factor.
      * 
      * @return the scale factor.
      */

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-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/PointerEvent.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -20,7 +20,9 @@
  */
 package org.arakhne.afc.ui.event ;
 
+import org.arakhne.afc.math.continous.object2d.Shape2f;
 
+
 /** Describe the event related to the pointer (mouse or finger).
  *
  * @author $Author: galland$
@@ -49,7 +51,13 @@
 	public float getY();
 
 	/**
-     * Returns which, if any, of the mouse buttons has changed state.
+     * Returns the states of the buttons or the number
+     * of the button that is the cause of the event.
+     * <p>
+     * The semantic if the replied value depends on
+     * the background platform. For Swing, it
+     * is the number of the button. For Android,
+     * it is the states of the buttons.
      *
      * @return the number of the button, or {@code 0} for none.
      */
@@ -63,9 +71,88 @@
     
 	/**
      * Returns the orientation of the pointer.
+     * Returns the orientation of the touch area and 
+     * tool area in radians clockwise from vertical 
+     * for the pointer. An angle of 0 radians 
+     * indicates that the major axis of contact is oriented 
+     * upwards, is perfectly circular or is of unknown 
+     * orientation. A positive angle indicates that the 
+     * major axis of contact is oriented to the right. 
+     * A negative angle indicates that the major axis 
+     * of contact is oriented to the left. The full 
+     * range is from -PI/2 radians (finger pointing fully left) 
+     * to PI/2 radians (finger pointing fully right).
      *
      * @return the orientation (in radians) of the pointer.
      */
     public float getOrientation();
     
+	/** Replies the precision of the X position of the pointer.
+	 * <p>
+	 * On several devices, the X position is approximate (on
+	 * tactil devices for example). This precision permits to
+	 * estimate the hardware X coordinate.
+	 * 
+	 * @return the precision X position of the pointer.
+	 */
+	public float getXPrecision();
+	
+	/** Replies the precision of the Y position of the pointer.
+	 * <p>
+	 * On several devices, the Y position is approximate (on
+	 * tactil devices for example). This precision permits to
+	 * estimate the hardware Y coordinate.
+	 * 
+	 * @return the Y position of the pointer.
+	 */
+	public float getYPrecision();
+	
+	/** Replies the number of pointers concerned by this event.
+	 * 
+	 * @return the number of pointers.
+	 */
+	public int getPointerCount();
+	
+	/** Returns an ellipse 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.
+	 * 
+	 * @param pointerIndex is the index of the pointer for which to retreive
+	 * the tool area.
+	 * @return the area covered by the tool.
+	 */
+	public Shape2f getToolArea(int pointerIndex);
+
+	/** Returns the type of tool detected for the given pointer.
+	 * 
+	 * @param pointerIndex is the index of the pointer for which to retreive
+	 * the tool type.
+	 * @return the type of tool.
+	 */
+	public ToolType getToolType(int pointerIndex);
+
+	
+	/** Types of tools.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public enum ToolType {
+		
+		/** Unknown. */
+		UNKNOW,
+		/** Finger. */
+		FINGER,
+		/** Stylus. */
+		STYLUS,
+		/** Eraser. */
+		ERASER,
+		/** Mouse. */
+		MOUSE;
+		
+	}
+	
 }

Modified: trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/DefaultUndoManager.java
===================================================================
--- trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/DefaultUndoManager.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/DefaultUndoManager.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -103,6 +103,9 @@
 			
 			// Add the new action.
 			this.undoes.addLast(action);
+			if (action instanceof UndoableGroup) {
+				((UndoableGroup)action).end();
+			}
 		}
 		
 		fireChange();

Modified: trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/UndoableGroup.java
===================================================================
--- trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/UndoableGroup.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/UndoableGroup.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -77,8 +77,15 @@
      * Finalize the additions in the group.
      */
     public void end() {
-    	this.undoables.trimToSize();
-    	this.finalized = true;
+    	if (!this.finalized) {
+	    	this.undoables.trimToSize();
+	    	this.finalized = true;
+	    	for(Undoable u : this.undoables) {
+	    		if (u instanceof UndoableGroup) {
+	    			((UndoableGroup)u).end();
+	    		}
+	    	}
+    	}
     }
     
 	@Override

Modified: trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/event/PointerEventSwing.java
===================================================================
--- trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/event/PointerEventSwing.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/event/PointerEventSwing.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -26,6 +26,8 @@
 import java.awt.event.MouseEvent;
 import java.util.EventObject;
 
+import org.arakhne.afc.math.continous.object2d.Circle2f;
+import org.arakhne.afc.math.continous.object2d.Shape2f;
 import org.arakhne.afc.ui.event.PointerEvent;
 
 /** Swing implementation of a pointer event.
@@ -123,5 +125,30 @@
 	public int getClickCount() {
 		return this.event.getClickCount();
 	}
+
+	@Override
+	public float getXPrecision() {
+		return 0;
+	}
+
+	@Override
+	public float getYPrecision() {
+		return 0;
+	}
+
+	@Override
+	public int getPointerCount() {
+		return 1;
+	}
+
+	@Override
+	public Shape2f getToolArea(int pointerIndex) {
+		return new Circle2f(this.event.getX(), this.event.getY(), 0);
+	}
+
+	@Override
+	public ToolType getToolType(int pointerIndex) {
+		return ToolType.MOUSE;
+	}
 	
 }

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-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/InternalZoomablePanel.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -40,11 +40,19 @@
 
 import javax.swing.JPanel;
 
+import org.arakhne.afc.math.continous.object2d.Circle2f;
+import org.arakhne.afc.math.continous.object2d.Ellipse2f;
+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.ui.CenteringTransform;
 import org.arakhne.afc.ui.Graphics2DLOD;
+import org.arakhne.afc.ui.ZoomableContextUtil;
 import org.arakhne.afc.ui.awt.DoubleDimension;
 import org.arakhne.afc.ui.awt.FloatDimension;
-import org.arakhne.afc.ui.awt.ZoomableContextUtil;
+import org.arakhne.afc.ui.awt.ZoomableAwtContextUtil;
 
 /** Component for displaying a zoomable graphical area.
  * <p>
@@ -69,34 +77,30 @@
  * @mavenartifactid $ArtifactId$
  */
 final class InternalZoomablePanel extends JPanel implements ZoomableViewport {
-    
+
 	//-------------------------------------------------------------------
-    // Attributes
-    //-------------------------------------------------------------------
+	// Attributes
+	//-------------------------------------------------------------------
 
 	private static final long serialVersionUID = -2740411873564016759L;
 
 	/** Zoomable panel.
-     */
-    private final WeakReference<ZoomablePanel> zoomPanel;
+	 */
+	private final WeakReference<ZoomablePanel> zoomPanel;
 
-    /** Flip the X coordinates
-     */
-    private final boolean flipX;
+	/** Transformation to center the objects in the view.
+	 */
+	private final CenteringTransform centeringTransform = new CenteringTransform();
 
-    /** Flip the Y coordinates
-     */
-    private final boolean flipY;
-    
-    /** This is the current zoom factor.
-     */
-    private float zoomFactor = 1.f;
-    
-    /** This is the stepping amount eahc time the
-     * user want to zoom out or in.
-     */
-    private float zoomFactorStep = 1.05f;
+	/** This is the current zoom factor.
+	 */
+	private float zoomFactor = 1.f;
 
+	/** This is the stepping amount eahc time the
+	 * user want to zoom out or in.
+	 */
+	private float zoomFactorStep = 1.05f;
+
 	/** Minimal scaling factor.
 	 */
 	private float minScaleFactor = 0.001f;
@@ -106,72 +110,70 @@
 	private float maxScaleFactor = 100.f;
 
 	/** This is the scale factor used to fit the document into
-     * the screen space.
-     */
-    private float fitToWindowFactor = 1f;
-    
-    /** Last restangle passed to {@link #refreshFactors(Rectangle2D)}
-     * when the screen window was empty (typically occurs when
-     * the window was never displayed).
-     */
-    private Rectangle2D lastRefreshRequestRectangle = null;
-    
-    /** This is the document point which is displayed
-     * at the center of the viewport.
-     * <p>
-     * This point corresponds to the workspace coordinate space. 
-     */
-    private Point2f focusPoint = null;
-    
-    /** Size of the drawing area.
-     */
-    private Dimension2D drawingArea = null;
-    
-    /** Buffer for the drawing area.
-     */
-    private SoftReference<Rectangle2D> drawRectangleBuffer = null;
-    
-    /** This attribute permits to store the graphical
-     * translation which is required to center the
-     * {@link #focusPoint} at the center of the
-     * graphical viewport. This variable is set
-     * at the begining of {@link #paint(Graphics)}.
-     * Using its value outside a drawing function have
-     * no sens.
-     */
-    private Dimension2D translationToCenter = null;
-    
-    //-------------------------------------------------------------------
-    // Constructors
-    //-------------------------------------------------------------------
-    
-    /** Create a InternalZoomablePanel and add it into the specified
-     * scroll pane.
-     * 
-     * @param zoompane is the zoom panel that owns this panel.
-     * @param flipX indicates if the X coordinates may be flipped, ie.
-     * the X axis may be inverted. 
-     * @param flipY indicates if the Y coordinates may be flipped, ie.
-     * the Y axis may be inverted. 
-     */
-    public InternalZoomablePanel(ZoomablePanel zoompane, boolean flipX, boolean flipY) {
-    	this.flipX = flipX;
-    	this.flipY = flipY;
-    	this.zoomPanel = new WeakReference<ZoomablePanel>(zoompane);
-    }
-    
-    //-------------------------------------------------------------------
-    // Getter/Setter
-    //-------------------------------------------------------------------
-    
-    /** Replies the scaling factor to apply to have the document fitting the view.
-     * 
-     * @return s
-     */
-    public float getFitInWindowFactor() {
-    	return this.fitToWindowFactor;
-    }
-    
+	 * the screen space.
+	 */
+	private float fitToWindowFactor = 1f;
+
+	/** Last restangle passed to {@link #refreshFactors(Rectangle2D)}
+	 * when the screen window was empty (typically occurs when
+	 * the window was never displayed).
+	 */
+	private Rectangle2D lastRefreshRequestRectangle = null;
+
+	/** This is the document point which is displayed
+	 * at the center of the viewport.
+	 * <p>
+	 * This point corresponds to the workspace coordinate space. 
+	 */
+	private Point2f targetInDocument = null;
+
+	/** Size of the drawing area.
+	 */
+	private Dimension2D drawingArea = null;
+
+	/** Buffer for the drawing area.
+	 */
+	private SoftReference<Rectangle2D> drawRectangleBuffer = null;
+
+	/** Indicates if the X axis is inverted.
+	 */
+	private final boolean flipX; 
+
+	/** Indicates if the Y axis is inverted.
+	 */
+	private final boolean flipY; 
+
+	//-------------------------------------------------------------------
+	// Constructors
+	//-------------------------------------------------------------------
+
+	/** Create a InternalZoomablePanel and add it into the specified
+	 * scroll pane.
+	 * 
+	 * @param zoompane is the zoom panel that owns this panel.
+	 * @param flipX indicates if the X coordinates may be flipped, ie.
+	 * the X axis may be inverted. 
+	 * @param flipY indicates if the Y coordinates may be flipped, ie.
+	 * the Y axis may be inverted. 
+	 */
+	public InternalZoomablePanel(ZoomablePanel zoompane, boolean flipX, boolean flipY) {
+		this.flipX = flipX;
+		this.flipY = flipY;
+		this.zoomPanel = new WeakReference<ZoomablePanel>(zoompane);
+	}
+
+	//-------------------------------------------------------------------
+	// Getter/Setter
+	//-------------------------------------------------------------------
+
+	/** Replies the scaling factor to apply to have the document fitting the view.
+	 * 
+	 * @return s
+	 */
+	public float getFitInWindowFactor() {
+		return this.fitToWindowFactor;
+	}
+
 	/** Replies the current zoom factor.
 	 * 
 	 * @return current zoom factor.
@@ -184,18 +186,18 @@
 	 * {@inheritDoc}
 	 */
 	@Override
-    public final boolean isXAxisInverted() {
-    	return this.flipX;
-    }
+	public final boolean isXAxisInverted() {
+		return this.flipX;
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public final boolean isYAxisInverted() {
-    	return this.flipY;
-    }
-    
+	public final boolean isYAxisInverted() {
+		return this.flipY;
+	}
+
 	/**
 	 * {@inheritDoc}
 	 */
@@ -208,51 +210,51 @@
 	 * {@inheritDoc}
 	 */
 	@Override
-    public Point2D getFocusPointPixel() {
-    	Rectangle2D bounds = getBounds();
-    	return new Point2D.Double(bounds.getCenterX(),bounds.getCenterY());
-    }
+	public Point2D getFocusPointPixel() {
+		Rectangle2D bounds = getBounds();
+		return new Point2D.Double(bounds.getCenterX(),bounds.getCenterY());
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public Point2f getFocusPoint() {
-    	if (this.focusPoint==null) return null;
-    	return new Point2f(this.focusPoint);
-    }
+	public Point2f getFocusPoint() {
+		if (this.targetInDocument==null) return null;
+		return new Point2f(this.targetInDocument);
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public void setFocusPoint(float x, float y) {
-		if (this.focusPoint==null || x!=this.focusPoint.getX()
-			|| y!=this.focusPoint.getY()) {
-			Point2f old = this.focusPoint;
-	    	if (this.focusPoint==null)
-	    		this.focusPoint = new Point2f(x,y);
-	    	else
-	    		this.focusPoint.set(x, y);
-	    	this.drawRectangleBuffer = null;
-	    	firePropertyChange("targetPoint", old, this.focusPoint); //$NON-NLS-1$
+	public void setFocusPoint(float x, float y) {
+		if (this.targetInDocument==null || x!=this.targetInDocument.getX()
+				|| y!=this.targetInDocument.getY()) {
+			Point2f old = this.targetInDocument;
+			if (this.targetInDocument==null)
+				this.targetInDocument = new Point2f(x,y);
+			else
+				this.targetInDocument.set(x, y);
+			this.drawRectangleBuffer = null;
+			firePropertyChange("targetPoint", old, this.targetInDocument); //$NON-NLS-1$
 		}
-    }
+	}
 
-    /** Remove the focus point.
-     */
-    void clearFocusPoint() {
-    	if (this.focusPoint!=null) {
-			Point2f old = this.focusPoint;
-	    	this.focusPoint = null;
-	    	this.drawRectangleBuffer = null;
-	    	firePropertyChange("targetPoint", old, this.focusPoint); //$NON-NLS-1$
-    	}
-    }
+	/** Remove the focus point.
+	 */
+	void clearFocusPoint() {
+		if (this.targetInDocument!=null) {
+			Point2f old = this.targetInDocument;
+			this.targetInDocument = null;
+			this.drawRectangleBuffer = null;
+			firePropertyChange("targetPoint", old, this.targetInDocument); //$NON-NLS-1$
+		}
+	}
 
-    //-------------------------------------------------------------------
-    // Paint
-    //-------------------------------------------------------------------
+	//-------------------------------------------------------------------
+	// Paint
+	//-------------------------------------------------------------------
 
 	/**
 	 * {@inheritDoc}
@@ -261,31 +263,31 @@
 	public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException {
 		if (pageIndex==0) {
 			Graphics2D g2d = (Graphics2D)g;
-			
+
 			// Shift Graphic to line up with beginning of print-imageable region
-	        g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
-	        
-	        // Be sure that the document feat to the print-imageable region
+			g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
+
+			// Be sure that the document feat to the print-imageable region
 			Rectangle2D r = getDocumentRect();
 			float width = logical2pixel_size((float)r.getWidth());
 			float height = logical2pixel_size((float)r.getHeight());
-	        float pageWidth = (float)pageFormat.getImageableWidth();
-	        float pageHeight = (float)pageFormat.getImageableHeight();
-	        float scale = 
-	        	((pageWidth / width)>(pageHeight / height))
-	        	? (pageHeight / height)
-	        	: (pageWidth / width);
+			float pageWidth = (float)pageFormat.getImageableWidth();
+			float pageHeight = (float)pageFormat.getImageableHeight();
+			float scale = 
+					((pageWidth / width)>(pageHeight / height))
+					? (pageHeight / height)
+							: (pageWidth / width);
 
-	        	
-			g2d.setColor(Color.BLACK);
-			g2d.drawRect(0,0,(int)pageWidth,(int)pageHeight);
-			
-			g2d.scale(scale, scale);
-	        
-	        // Print the document
-			print(g2d, new Rectangle2D.Float(0, 0, width, height));			
-			
-			return PAGE_EXISTS;
+
+					g2d.setColor(Color.BLACK);
+					g2d.drawRect(0,0,(int)pageWidth,(int)pageHeight);
+
+					g2d.scale(scale, scale);
+
+					// Print the document
+					print(g2d, new Rectangle2D.Float(0, 0, width, height));			
+
+					return PAGE_EXISTS;
 		}
 		return NO_SUCH_PAGE;
 	}
@@ -309,122 +311,137 @@
 		float doc_y = logical2pixel_y((float)r.getMinY());
 		float width = logical2pixel_size((float)r.getWidth());
 		float height = logical2pixel_size((float)r.getHeight());
-		
+
 		// Be sure that the printing area is enclosed inside the document bounds.
 		r = new Rectangle2D.Double(0,0,width,height).createIntersection(print_area);
 
 		// Be sure that the new origin (0,0) corresponds
 		// to upper-left corner of the print area
 		g.translate(-doc_x-r.getX(),-doc_y-r.getY());
-		
+
 		print(g);
 	}
 
 	/**
-     * Invoke this method to print the component. This method will
-     * result in invocations to <code>printComponent</code>,
-     * <code>printBorder</code> and <code>printChildren</code>. It is
-     * not recommended that you override this method, instead override
-     * one of the previously mentioned methods. This method sets the
-     * component's state such that the double buffer will not be used, eg
-     * painting will be done directly on the passed in <code>Graphics</code>.
-     *
-     * @param g the <code>Graphics</code> context in which to paint
-     */
-    @Override
+	 * Invoke this method to print the component. This method will
+	 * result in invocations to <code>printComponent</code>,
+	 * <code>printBorder</code> and <code>printChildren</code>. It is
+	 * not recommended that you override this method, instead override
+	 * one of the previously mentioned methods. This method sets the
+	 * component's state such that the double buffer will not be used, eg
+	 * painting will be done directly on the passed in <code>Graphics</code>.
+	 *
+	 * @param g the <code>Graphics</code> context in which to paint
+	 */
+	@Override
 	public void print(Graphics g) {
 		synchronized(this.getTreeLock()) {
-	    	ZoomablePanel panel = this.zoomPanel.get();
-			
-	    	boolean opaque = isOpaque();
-	    	boolean antialiasing = panel.isAntiAliased();
-	    	Graphics2DLOD lod = panel.getLOD();
-			
-	    	setOpaque(false);
-	    	panel.setAntiAliased(true);
-	    	panel.setLOD(Graphics2DLOD.HIGH_LEVEL_OF_DETAIL);
-			
-	    	super.print(g);
-			
+			ZoomablePanel panel = this.zoomPanel.get();
+
+			boolean opaque = isOpaque();
+			boolean antialiasing = panel.isAntiAliased();
+			Graphics2DLOD lod = panel.getLOD();
+
+			setOpaque(false);
+			panel.setAntiAliased(true);
+			panel.setLOD(Graphics2DLOD.HIGH_LEVEL_OF_DETAIL);
+
+			super.print(g);
+
 			setOpaque(opaque);
-	    	panel.setAntiAliased(antialiasing);
-	    	panel.setLOD(lod);
+			panel.setAntiAliased(antialiasing);
+			panel.setLOD(lod);
 		}
-    }
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
 	public final void paint(Graphics g) {
 
-    	if (getIgnoreRepaint()) return;
-    	
-        Graphics2D g2d = (Graphics2D)g;
+		if (getIgnoreRepaint()) return;
 
-        // Compute the factors because the last
-    	// calls to the refreshFactors() was made
-    	// when the screen window is empty
-    	if (this.lastRefreshRequestRectangle!=null) {
-    		Rectangle2D r = this.lastRefreshRequestRectangle;
-    		if (refreshFactors(r)) changeWorkspaceSize(r);
-    	}
-    	
-    	Color color = getBackground();
-    	if (color!=null) g2d.setBackground(color);
-    	
-    	super.paint(g);
+		Graphics2D g2d = (Graphics2D)g;
 
-    	// Be sure that the document coordinate system was computed
-    	float delta_x, delta_y;
-    	if (this.focusPoint!=null) {
-	    	
-	    	// Get the dimensions of the logical space and the screen space
-    		Rectangle2D screen_bounds = getBounds();
-	
-	    	// Compute the translation for centering the logical
-	    	// space inside the screen space
-	    	
-	    	
-	    	
-	    	float delta_prime = (float)screen_bounds.getCenterX();
-	    	delta_x = pixel2logical_size(delta_prime) - this.focusPoint.getX();
-	    	
-	    	delta_prime = (float)screen_bounds.getCenterY();
-	    	delta_y = pixel2logical_size(delta_prime) - this.focusPoint.getY();
-	    	
-	    	if (this.translationToCenter==null) this.translationToCenter = new DoubleDimension();
-	    	this.translationToCenter.setSize(delta_x,delta_y);
-	    	
-    	}
-    	else {
-    		delta_x = delta_y = 0;
-    	}
+		// Compute the factors because the last
+		// calls to the refreshFactors() was made
+		// when the screen window is empty
+		if (this.lastRefreshRequestRectangle!=null) {
+			Rectangle2D r = this.lastRefreshRequestRectangle;
+			if (refreshFactors(r)) changeWorkspaceSize(r);
+		}
 
-    	ZoomablePanel panel = this.zoomPanel.get();
+		Color color = getBackground();
+		if (color!=null) g2d.setBackground(color);
 
-    	if (panel!=null) {
-    		
-    		boolean isPrinting =
-    			(panel.hasFlag(ZoomablePanel.FLAG_IS_PRINTING)||
-   				 panel.hasFlag(ZoomablePanel.FLAG_IS_PRINTING_ALL));
-    		
-        	// Create the new graphical context
-    		panel.paintAllComponents(
-        			g2d, this,
-        			this.zoomFactor,this.fitToWindowFactor,
-        			delta_x,
-    				delta_y,
-    				panel.isAntiAliased(),
-    				isPrinting,
-    				panel.getLOD());
-    	}
-    }
-	
-    //-------------------------------------------------------------------
-    // Sizes
-    //-------------------------------------------------------------------
-	
+		super.paint(g);
+
+		// Be sure that the document coordinate system was computed
+		if (this.targetInDocument!=null) {
+
+			// Get the dimensions of the logical space and the screen space
+			Rectangle2D screen_bounds = getBounds();
+
+			// Compute the translation for centering the logical
+			// space inside the screen space
+
+
+			// Compute the translation for centering the logical
+			// space inside the screen space
+
+			double delta_prime = pixel2logical_size((int)screen_bounds.getCenterX());
+			if (isXAxisInverted()) {
+				this.centeringTransform.setCenteringX(
+						true,
+						-1,
+						(float)(delta_prime + this.targetInDocument.getX()));
+			}
+			else {
+				this.centeringTransform.setCenteringX(
+						false,
+						1,
+						(float)(delta_prime - this.targetInDocument.getX()));
+			}
+
+			delta_prime = pixel2logical_size((int)screen_bounds.getCenterY());
+			if (isYAxisInverted()) {
+				this.centeringTransform.setCenteringY(
+						true,
+						-1,
+						(float)(delta_prime + this.targetInDocument.getY()));
+			}
+			else {
+				this.centeringTransform.setCenteringY(
+						false,
+						1,
+						(float)(delta_prime - this.targetInDocument.getY()));
+			}
+		}
+
+		ZoomablePanel panel = this.zoomPanel.get();
+
+		if (panel!=null) {
+
+			boolean isPrinting =
+					(panel.hasFlag(ZoomablePanel.FLAG_IS_PRINTING)||
+							panel.hasFlag(ZoomablePanel.FLAG_IS_PRINTING_ALL));
+
+			// Create the new graphical context
+			panel.paintAllComponents(
+					g2d, this,
+					this.centeringTransform,
+					this.zoomFactor,
+					panel.isAntiAliased(),
+					isPrinting,
+					panel.getLOD());
+		}
+	}
+
+	//-------------------------------------------------------------------
+	// Sizes
+	//-------------------------------------------------------------------
+
 	/** Refresh the factors for the zoom and the fit of the document
 	 * into the screen space.
 	 * <p>
@@ -436,204 +453,197 @@
 	 * @param document_bounds is the bounds of the document (in document's units)
 	 * @return a status that indicates if this function succeeded or not.
 	 */
-    boolean refreshFactors(Rectangle2D document_bounds) {
-    	Rectangle2D screen_window = getBounds();
-        
-        if ((screen_window==null)||(screen_window.isEmpty())) {
-        	this.lastRefreshRequestRectangle = document_bounds;
-        	return false;
-        }
-    	this.lastRefreshRequestRectangle = null;
-    	float oldFactor = this.zoomFactor;
-    	this.zoomFactor = 1.f;
-		Point2f oldTarget = this.focusPoint;
-		
-		if (this.focusPoint==null) this.focusPoint = new Point2f();
+	boolean refreshFactors(Rectangle2D document_bounds) {
+		Rectangle2D screen_window = getBounds();
 
+		if ((screen_window==null)||(screen_window.isEmpty())) {
+			this.lastRefreshRequestRectangle = document_bounds;
+			return false;
+		}
+		this.lastRefreshRequestRectangle = null;
+		float oldFactor = this.zoomFactor;
+		this.zoomFactor = 1.f;
+		Point2f oldTarget = this.targetInDocument;
+
+		if (this.targetInDocument==null) this.targetInDocument = new Point2f();
+
 		if ((document_bounds==null)||(document_bounds.isEmpty())) {
 			this.fitToWindowFactor = 1.f;
-    		
-			this.focusPoint.set(
+
+			this.targetInDocument.set(
 					(float)screen_window.getCenterX(),
 					(float)screen_window.getCenterY());
 		}
-    	else {    		
-			
-    		this.fitToWindowFactor = (float)(screen_window.getWidth() / document_bounds.getWidth());
+		else {    		
+
+			this.fitToWindowFactor = (float)(screen_window.getWidth() / document_bounds.getWidth());
 			float fit = (float)(screen_window.getHeight() / document_bounds.getHeight());
 			if (fit<this.fitToWindowFactor) this.fitToWindowFactor = fit;
-			
-			this.focusPoint.set(
+
+			this.targetInDocument.set(
 					(float)document_bounds.getCenterX(),
 					(float)document_bounds.getCenterY());
-    	}
+		}
 
 		this.drawRectangleBuffer = null;
-		
+
 		if (oldFactor!=this.zoomFactor) {
 			this.zoomPanel.get().firePropertyChange("zoomFactor", oldFactor, this.zoomFactor); //$NON-NLS-1$
 		}
-		if (!this.focusPoint.equals(oldTarget)) {
-			this.zoomPanel.get().firePropertyChange("targetPoint", oldTarget, this.focusPoint); //$NON-NLS-1$
+		if (!this.targetInDocument.equals(oldTarget)) {
+			this.zoomPanel.get().firePropertyChange("targetPoint", oldTarget, this.targetInDocument); //$NON-NLS-1$
 		}
-		
+
 		return true;
-    }
-	
-    /** Change the workspace area if necessary.
-     *  <p>
-     *  This method is called each time the workspace
-     *  could be extended in one of the four cardinal
-     *  directions.
-     *  <p>
-     *  The size of the workspace and/or the origin point
-     *  are updated if the given Rectangle is outside
-     *  the current workspace.
-     *  <p>
-     *  The scroll bar was not refreshed.
-     *
-     * @param requiredArea the area that must be in workspace. If
-     *        <code>null</code>, the required area will be computed
-     *        with {@link #getDocumentRect()}.
-     * @return <code>true</code> if the bounds have changed; otherwise
-     * <code>false</code>.
-     */
-    boolean changeWorkspaceSize(Rectangle2D requiredArea) {
-    	ZoomablePanel zoompanel = this.zoomPanel.get();
-	    if (zoompanel==null) return false;
-	    Rectangle2D r = requiredArea;
+	}
+
+	/** Change the workspace area if necessary.
+	 *  <p>
+	 *  This method is called each time the workspace
+	 *  could be extended in one of the four cardinal
+	 *  directions.
+	 *  <p>
+	 *  The size of the workspace and/or the origin point
+	 *  are updated if the given Rectangle is outside
+	 *  the current workspace.
+	 *  <p>
+	 *  The scroll bar was not refreshed.
+	 *
+	 * @param requiredArea the area that must be in workspace. If
+	 *        <code>null</code>, the required area will be computed
+	 *        with {@link #getDocumentRect()}.
+	 * @return <code>true</code> if the bounds have changed; otherwise
+	 * <code>false</code>.
+	 */
+	boolean changeWorkspaceSize(Rectangle2D requiredArea) {
+		ZoomablePanel zoompanel = this.zoomPanel.get();
+		if (zoompanel==null) return false;
+		Rectangle2D r = requiredArea;
 		if (r==null) r = getDocumentRect() ;
 		if (r==null) return false;
 
-	    // ompute the dimensions of the document in the screen space
+		// ompute the dimensions of the document in the screen space
 		float documentScreenWidth = logical2pixel_size((float)r.getWidth());
 		float documentScreenHeight = logical2pixel_size((float)r.getHeight());
 
 		// Reset the size of the drawing area
-    	if (this.drawingArea==null) this.drawingArea = new DoubleDimension(documentScreenWidth,documentScreenHeight);
-    	else this.drawingArea.setSize(documentScreenWidth,documentScreenHeight) ;
-    	this.drawRectangleBuffer = null;
-		
+		if (this.drawingArea==null) this.drawingArea = new DoubleDimension(documentScreenWidth,documentScreenHeight);
+		else this.drawingArea.setSize(documentScreenWidth,documentScreenHeight) ;
+		this.drawRectangleBuffer = null;
+
 		// Set the location of the scroll bars
 		return zoompanel.revalidateWorkspace();
-     }
-    
+	}
+
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public Dimension2D getDrawingAreaSize() {
-    	return this.drawingArea==null ? new DoubleDimension() : this.drawingArea;
-    }
+	public Dimension2D getDrawingAreaSize() {
+		return this.drawingArea==null ? new DoubleDimension() : this.drawingArea;
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public Rectangle2D getDrawingAreaRect() {
+	public Rectangle2D getDrawingAreaRect() {
 		Rectangle2D b = (this.drawRectangleBuffer==null) ? null : this.drawRectangleBuffer.get();
-    	if (b!=null) return b;
-    	
-    	Rectangle2D world = getDocumentRect();
-    	Rectangle2D viewport = getBounds();
-    	
-    	if ((world==null)||(world.isEmpty()))
+		if (b!=null) return b;
+
+		Rectangle2D world = getDocumentRect();
+		Rectangle2D viewport = getBounds();
+
+		if ((world==null)||(world.isEmpty()))
 			return viewport;
 
-    	if (this.focusPoint==null) {
-    		refreshFactors(world);
-    	}
-    	
-    	if (this.focusPoint==null)
+		if (this.targetInDocument==null) {
+			refreshFactors(world);
+		}
+
+		if (this.targetInDocument==null)
 			return viewport;
 
-    	if (this.drawingArea==null) {
-    		float documentScreenWidth = logical2pixel_size((float)world.getWidth());
-    		float documentScreenHeight = logical2pixel_size((float)world.getHeight());
-    		this.drawingArea = new DoubleDimension(documentScreenWidth, documentScreenHeight);
-    	}
-    	
-    	Rectangle2D world_relative = new Rectangle2D.Double(
-    			world.getX() - this.focusPoint.getX(),
-    			world.getY() - this.focusPoint.getY(),
-    			world.getWidth(), world.getHeight());
-    	
-    	float dx = (float)(this.drawingArea.getWidth() / world.getWidth());
-    	float dy = (float)(this.drawingArea.getHeight() / world.getHeight());
-    	
-    	b = new Rectangle2D.Float(
-    			(float)(world_relative.getX()*dx+viewport.getCenterX()),
-    			(float)(world_relative.getY()*dy+viewport.getCenterY()),
-    			(float)this.drawingArea.getWidth(),
-    			(float)this.drawingArea.getHeight());
-    	this.drawRectangleBuffer = new SoftReference<Rectangle2D>(b);
-    	return b;
-    }
-    
+		if (this.drawingArea==null) {
+			float documentScreenWidth = logical2pixel_size((float)world.getWidth());
+			float documentScreenHeight = logical2pixel_size((float)world.getHeight());
+			this.drawingArea = new DoubleDimension(documentScreenWidth, documentScreenHeight);
+		}
+
+		Rectangle2D world_relative = new Rectangle2D.Double(
+				world.getX() - this.targetInDocument.getX(),
+				world.getY() - this.targetInDocument.getY(),
+				world.getWidth(), world.getHeight());
+
+		float dx = (float)(this.drawingArea.getWidth() / world.getWidth());
+		float dy = (float)(this.drawingArea.getHeight() / world.getHeight());
+
+		b = new Rectangle2D.Float(
+				(float)(world_relative.getX()*dx+viewport.getCenterX()),
+				(float)(world_relative.getY()*dy+viewport.getCenterY()),
+				(float)this.drawingArea.getWidth(),
+				(float)this.drawingArea.getHeight());
+		this.drawRectangleBuffer = new SoftReference<Rectangle2D>(b);
+		return b;
+	}
+
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public float logical2pixel_size(float l) {
-		return ZoomableContextUtil.logical2pixel_size(l, true, this.fitToWindowFactor * this.zoomFactor);
-    }
+	public float logical2pixel_size(float l) {
+		return ZoomableContextUtil.logical2pixel_size(l, this.fitToWindowFactor * this.zoomFactor);
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public float logical2pixel_x(float l) {
-    	return ZoomableContextUtil.logical2pixel_x(l,
-    			true, this.flipX,
-    			getDrawingAreaRect(),
-    			(float)((this.translationToCenter==null) ? 0 : this.translationToCenter.getWidth()),
-    			this.fitToWindowFactor * this.zoomFactor);
-    }
+	public float logical2pixel_x(float l) {
+		return ZoomableContextUtil.logical2pixel_x(l,
+				this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public float logical2pixel_y(float l) {
-    	return ZoomableContextUtil.logical2pixel_y(l,
-    			true, this.flipY,
-    			getDrawingAreaRect(),
-    			(float)((this.translationToCenter==null) ? 0 : this.translationToCenter.getHeight()),
-    			this.fitToWindowFactor * this.zoomFactor);
-    }
+	public float logical2pixel_y(float l) {
+		return ZoomableContextUtil.logical2pixel_y(l,
+				this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public float pixel2logical_size(float l) {
-		return ZoomableContextUtil.pixel2logical_size(l, true, this.fitToWindowFactor * this.zoomFactor);
-    }
+	public float pixel2logical_size(float l) {
+		return ZoomableContextUtil.pixel2logical_size(l,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public float pixel2logical_x(float p) {
-    	return ZoomableContextUtil.pixel2logical_x(p,
-    			true, this.flipX,
-    			getDrawingAreaRect(),
-    			(float)((this.translationToCenter==null) ? 0 : this.translationToCenter.getWidth()),
-    			this.fitToWindowFactor * this.zoomFactor);
-    }
+	public float pixel2logical_x(float p) {
+		return ZoomableContextUtil.pixel2logical_x(p,
+				this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public float pixel2logical_y(float p) {
-    	return ZoomableContextUtil.pixel2logical_y(p,
-    			true, this.flipY,
-    			getDrawingAreaRect(),
-    			(float)((this.translationToCenter==null) ? 0 : this.translationToCenter.getHeight()),
-    			this.fitToWindowFactor * this.zoomFactor);
-    }
-    
+	public float pixel2logical_y(float p) {
+		return ZoomableContextUtil.pixel2logical_y(p,
+				this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
 	/**
 	 * Translate the given shape from the logical coordinate space
 	 * to the screen coordinate space.
@@ -642,18 +652,9 @@
 	 * @return the translation of rLogic
 	 */
 	public <T extends Shape> T logical2pixel(T rLogic) {
-		float deltaX, deltaY;
-		if (this.translationToCenter!=null) {
-			deltaX = (float)this.translationToCenter.getWidth();
-			deltaY = (float)this.translationToCenter.getHeight();
-		}
-		else {
-			deltaX = deltaY = 0f;
-		}
-		return ZoomableContextUtil.logical2pixel(
-				rLogic, true, this.flipX, this.flipY,
-				getDrawingAreaRect(),
-				deltaX, deltaY,
+		return ZoomableAwtContextUtil.logical2pixel(
+				rLogic, 
+				this.centeringTransform,
 				getScalingFactor());
 	}
 
@@ -665,8 +666,8 @@
 	 * @return the translation of fLogic
 	 */
 	public Font logical2pixel(Font fLogic) {
-		return ZoomableContextUtil.logical2pixel(
-				fLogic, true, getScalingFactor());
+		return ZoomableAwtContextUtil.logical2pixel(
+				fLogic, getScalingFactor());
 	}
 
 	/**
@@ -677,21 +678,12 @@
 	 * @return the translation of rScreen
 	 */
 	public <T extends Shape> T pixel2logical(T rScreen) {
-		float deltaX, deltaY;
-		if (this.translationToCenter!=null) {
-			deltaX = (float)this.translationToCenter.getWidth();
-			deltaY = (float)this.translationToCenter.getHeight();
-		}
-		else {
-			deltaX = deltaY = 0f;
-		}
-		return ZoomableContextUtil.pixel2logical(
-				rScreen, true, this.flipX, this.flipY,
-				getDrawingAreaRect(),
-				deltaX, deltaY,
+		return ZoomableAwtContextUtil.pixel2logical(
+				rScreen,
+				this.centeringTransform,
 				getScalingFactor());
 	}
-	
+
 	/**
 	 * Translate the given font from the screen coordinate space
 	 * to the logical coordinate space.
@@ -700,29 +692,11 @@
 	 * @return the translation of f_screen
 	 */
 	public Font pixel2logical(Font f_screen) {
-		return ZoomableContextUtil.pixel2logical(
-				f_screen, true,
+		return ZoomableAwtContextUtil.pixel2logical(
+				f_screen,
 				getScalingFactor());
 	}
 
-	/**
-	 * Replies the translation to center the view.
-	 * 
-	 * @return the translation.
-	 */
-	public float getTranslationToCenterX() {
-		return (float)((this.translationToCenter!=null) ? this.translationToCenter.getWidth() : 0f);
-	}
-
-	/**
-	 * Replies the translation to center the view.
-	 * 
-	 * @return the translation.
-	 */
-	public float getTranslationToCenterY() {
-		return (float)((this.translationToCenter!=null) ? this.translationToCenter.getHeight() : 0f);
-	}
-
 	/** Translates the specified screen rectangle
 	 *  into the logical rectangle.
 	 *
@@ -752,85 +726,85 @@
 	}
 
 	//-------------------------------------------------------------------
-    // Document
-    //-------------------------------------------------------------------
-	
+	// Document
+	//-------------------------------------------------------------------
+
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public Rectangle2D getDocumentRect() {
-    	ZoomablePanel zoompanel = this.zoomPanel.get();
-    	if (zoompanel==null) return null;
-    	return zoompanel.getDocumentRect();
-    }
-		
-    //-------------------------------------------------------------------
-    // Zoom
-    //-------------------------------------------------------------------
-    
+	public Rectangle2D getDocumentRect() {
+		ZoomablePanel zoompanel = this.zoomPanel.get();
+		if (zoompanel==null) return null;
+		return zoompanel.getDocumentRect();
+	}
+
+	//-------------------------------------------------------------------
+	// Zoom
+	//-------------------------------------------------------------------
+
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public void setScalingFactor(float factor) {
-    	setScalingFactor(factor,true);
-    }
+	public void setScalingFactor(float factor) {
+		setScalingFactor(factor,true);
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public void setScalingFactor(float factor, boolean enable_repaint) {
-    	if (factor>0 && this.zoomFactor!=factor) {
-    		float old = this.zoomFactor;
-    		this.zoomFactor = factor;
-    		
-    		Rectangle2D screen_window = getBounds();    		
-    		Rectangle2D document_bounds = getDocumentRect();
-    		Point2f oldFocus = this.focusPoint;
+	public void setScalingFactor(float factor, boolean enable_repaint) {
+		if (factor>0 && this.zoomFactor!=factor) {
+			float old = this.zoomFactor;
+			this.zoomFactor = factor;
 
-    		if (this.focusPoint==null) {
-    			this.focusPoint = new Point2f();
-        		if (document_bounds==null) {
-        			this.focusPoint.set(
-	        				pixel2logical_x((float)screen_window.getCenterX()),
-	        				pixel2logical_y((float)screen_window.getCenterY()));        			
-        		}
-        		else {
-        			this.focusPoint.set(
-	        				(float)document_bounds.getCenterX(),
-	        				(float)document_bounds.getCenterY());
-        		}
-    		}
+			Rectangle2D screen_window = getBounds();    		
+			Rectangle2D document_bounds = getDocumentRect();
+			Point2f oldFocus = this.targetInDocument;
 
-    		if (enable_repaint) {
-    			FloatDimension doc_bounds = new FloatDimension();
-	    		
-	    		if (document_bounds==null) {
-		    		doc_bounds.setSize(
-		    				screen_window.getWidth(),
-		    				screen_window.getHeight());
-	    		}
-	    		else {
-		    		doc_bounds.setSize(
-		    				logical2pixel_size((float)document_bounds.getWidth()),
-		    				logical2pixel_size((float)document_bounds.getHeight()));
-	    		}
-	
-	    		changeWorkspaceSize(document_bounds);
-	    		if ((doc_bounds.getWidth()<=screen_window.getWidth())&&
-	        	    (doc_bounds.getHeight()<=screen_window.getHeight()))
-	    			repaint();
-    		}
-    		
-    		this.zoomPanel.get().firePropertyChange("zoomFactor", old, this.zoomFactor); //$NON-NLS-1$
-    		if (!this.focusPoint.equals(oldFocus)) {
-    			this.zoomPanel.get().firePropertyChange("targetPoint", old, this.focusPoint); //$NON-NLS-1$
-    		}
-    	}
-    }
-	
+			if (this.targetInDocument==null) {
+				this.targetInDocument = new Point2f();
+				if (document_bounds==null) {
+					this.targetInDocument.set(
+							pixel2logical_x((float)screen_window.getCenterX()),
+							pixel2logical_y((float)screen_window.getCenterY()));        			
+				}
+				else {
+					this.targetInDocument.set(
+							(float)document_bounds.getCenterX(),
+							(float)document_bounds.getCenterY());
+				}
+			}
+
+			if (enable_repaint) {
+				FloatDimension doc_bounds = new FloatDimension();
+
+				if (document_bounds==null) {
+					doc_bounds.setSize(
+							screen_window.getWidth(),
+							screen_window.getHeight());
+				}
+				else {
+					doc_bounds.setSize(
+							logical2pixel_size((float)document_bounds.getWidth()),
+							logical2pixel_size((float)document_bounds.getHeight()));
+				}
+
+				changeWorkspaceSize(document_bounds);
+				if ((doc_bounds.getWidth()<=screen_window.getWidth())&&
+						(doc_bounds.getHeight()<=screen_window.getHeight()))
+					repaint();
+			}
+
+			this.zoomPanel.get().firePropertyChange("zoomFactor", old, this.zoomFactor); //$NON-NLS-1$
+			if (!this.targetInDocument.equals(oldFocus)) {
+				this.zoomPanel.get().firePropertyChange("targetPoint", old, this.targetInDocument); //$NON-NLS-1$
+			}
+		}
+	}
+
 	/** Change the zooming factor to have the specified
 	 * ratio between 1 pixel and 1 unit in the document.
 	 * <p>
@@ -845,50 +819,50 @@
 		float factor = onePixel * ratio;
 		setScalingFactor(factor);
 	}
-    
+
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public void zoomIn() {
-    	zoomIn(true);
-    }
+	public void zoomIn() {
+		zoomIn(true);
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public void zoomOut() {
-    	zoomOut(true);
-    }
-    
+	public void zoomOut() {
+		zoomOut(true);
+	}
+
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public void zoomIn(boolean enable_repaint) {
-    	if (this.zoomFactorStep>0) {
-    		setScalingFactor( this.zoomFactor * this.zoomFactorStep, enable_repaint ) ;
-    	}
-    }
+	public void zoomIn(boolean enable_repaint) {
+		if (this.zoomFactorStep>0) {
+			setScalingFactor( this.zoomFactor * this.zoomFactorStep, enable_repaint ) ;
+		}
+	}
 
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public void zoomOut(boolean enable_repaint) {
-    	if (this.zoomFactorStep>0) {
-    		setScalingFactor( this.zoomFactor / this.zoomFactorStep, enable_repaint ) ;
-    	}
-    }
-    
+	public void zoomOut(boolean enable_repaint) {
+		if (this.zoomFactorStep>0) {
+			setScalingFactor( this.zoomFactor / this.zoomFactorStep, enable_repaint ) ;
+		}
+	}
+
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
-    public void refreshPanelContent() {
-    	setScalingFactor(this.zoomFactor, true);
-    }
+	public void refreshPanelContent() {
+		setScalingFactor(this.zoomFactor, true);
+	}
 
 	/** {@inheritDoc}
 	 */
@@ -941,14 +915,98 @@
 
 	@Override
 	public float getFocusX() {
-		if (this.focusPoint==null) return Float.NaN;
-		return this.focusPoint.getX();
+		if (this.targetInDocument==null) return Float.NaN;
+		return this.targetInDocument.getX();
 	}
 
 	@Override
 	public float getFocusY() {
-		if (this.focusPoint==null) return Float.NaN;
-		return this.focusPoint.getY();
+		if (this.targetInDocument==null) return Float.NaN;
+		return this.targetInDocument.getY();
 	}
-    
+
+	@Override
+	public PathIterator2f logical2pixel(PathIterator2f p) {
+		return ZoomableContextUtil.logical2pixel(p, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public PathIterator2f pixel2logical(PathIterator2f p) {
+		return ZoomableContextUtil.pixel2logical(p, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Segment2f s) {
+		ZoomableContextUtil.logical2pixel(s, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Segment2f s) {
+		ZoomableContextUtil.pixel2logical(s, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(RoundRectangle2f r) {
+		ZoomableContextUtil.logical2pixel(r, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(RoundRectangle2f r) {
+		ZoomableContextUtil.pixel2logical(r, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Point2f p) {
+		ZoomableContextUtil.logical2pixel(p, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Point2f p) {
+		ZoomableContextUtil.pixel2logical(p, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Ellipse2f e) {
+		ZoomableContextUtil.logical2pixel(e, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Ellipse2f e) {
+		ZoomableContextUtil.pixel2logical(e, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Circle2f r) {
+		ZoomableContextUtil.logical2pixel(r, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Circle2f r) {
+		ZoomableContextUtil.pixel2logical(r, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Rectangle2f r) {
+		ZoomableContextUtil.logical2pixel(r, this.centeringTransform,
+				this.fitToWindowFactor * this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Rectangle2f r) {
+		ZoomableContextUtil.pixel2logical(r, 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-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomableGraphics2D.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -55,15 +55,24 @@
 import javax.swing.ImageIcon;
 import javax.swing.plaf.FontUIResource;
 
+import org.arakhne.afc.math.continous.object2d.Circle2f;
+import org.arakhne.afc.math.continous.object2d.Ellipse2f;
+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.ui.CenteringTransform;
 import org.arakhne.afc.ui.Graphics2DLOD;
 import org.arakhne.afc.ui.StringAnchor;
 import org.arakhne.afc.ui.TextAlignment;
 import org.arakhne.afc.ui.ZoomableContext;
+import org.arakhne.afc.ui.ZoomableContextUtil;
 import org.arakhne.afc.ui.awt.AbstractLODGraphics2D;
 import org.arakhne.afc.ui.awt.AwtUtil;
 import org.arakhne.afc.ui.awt.DoubleDimension;
 import org.arakhne.afc.ui.awt.VirtualScreenGraphics2D;
-import org.arakhne.afc.ui.awt.ZoomableContextUtil;
+import org.arakhne.afc.ui.awt.ZoomableAwtContextUtil;
 
 /** This graphic context permits to display
  *  something with a good zoom look.
@@ -82,10 +91,6 @@
 
 	////////////////////////////////////////////////////////////
 	// Constants
-	
-	/** Indicates if by default the {@link ZoomableGraphics2D} enables zooming.
-	 */
-	public static boolean DEFAULT_ZOOM = true;
 
 	/** Indicates if by default the {@link ZoomableGraphics2D} enables image scaling.
 	 */
@@ -98,7 +103,7 @@
 	/** Indicates if by default the {@link ZoomableGraphics2D} enables icon centering.
 	 */
 	public static boolean DEFAULT_ICON_CENTERING = true;
-	
+
 	/** Default scaling factor applied to the application's font
 	 * to obtain the default size for the fonts inside the zoomable panel.
 	 */
@@ -107,34 +112,14 @@
 	////////////////////////////////////////////////////////////
 	// Attributes
 
-	/** Indicates if the X axis be be inverted.
+	/** Transformation to center the objects in the view.
 	 */
-	protected final boolean flipX;
+	protected final CenteringTransform centeringTransform;
 
-	/** Indicates if the Y axis be be inverted.
-	 */
-	protected final boolean flipY;
-	
-	/** Is the rectangle covered by the document in the screen space.
-	 */
-	protected final Rectangle2D documentScreenRectangle;
-		
 	/** This is the zoom factor.
 	 */
 	protected final float zoomFactor;
 
-	/** Scale factor to fit the document into a screen.
-	 */
-	protected final float fitToWindowFactor;
-
-	/** Translation to center the logical space.
-	 */
-	protected final float deltaX;
-
-	/** Translation to center the logical space.
-	 */
-	protected final float deltaY;
-
 	/** Scaling sensitivity.
 	 */
 	private final float scalingSensitivity;
@@ -155,14 +140,10 @@
 	 */
 	private final float focusY;
 
-	/** Does the zoom feature was activated?
-	 */
-	protected boolean canZoom = DEFAULT_ZOOM;
-
 	/** Indicates if drawn images must be scaled or not.
 	 */
 	private boolean scaleImage = DEFAULT_IMAGE_SCALING;
-	
+
 	/** Indicates if drawn icons must be scaled or not.
 	 */
 	private boolean scaleIcon = DEFAULT_ICON_SCALING;
@@ -172,7 +153,7 @@
 	private boolean centerIcon = DEFAULT_ICON_CENTERING;
 
 	private final float defaultFontSize;
-	private final Rectangle2D tmpRectangle = new Rectangle2D.Double();
+	private final Rectangle2D tmpRectangle = new Rectangle2D.Float();
 
 	////////////////////////////////////////////////////////////
 	// Constructor
@@ -181,134 +162,121 @@
 	 *
 	 * @param target is the graphics in which draws will be done.
 	 * @param target_component is the target component (used to display an icon).
+	 * @param centeringTransform is the transformation used to center the objects in the view.
 	 * @param zoom is the zoom factor.
-	 * @param fit_to_window_factor is the factor used to scale the map coordinates.
-	 * @param delta_x is the translation length to center the logical model inside the screen space
-	 * @param delta_y is the translation length to center the logical model inside the screen space
 	 * @param antialiasing permits to force the anti-aliasing flag for the target graphical context
 	 * @param is_for_printing indicates if this graphics environment is for printing or not.
 	 * @param lod indicates the desired LOD used by this graphical context.
-	 * @param flipX indicates if the X axis may be inverted or not.
-	 * @param flipY indicates if the Y axis may be inverted or not.
-	 * @param documentScreenRectangle is the rectangle covered by the document in the screen space.
 	 * @param scalingSensitivity is the sensitivity of the zooming functions.
 	 * @param minScalingFactor is the minimal scaling factor.
 	 * @param maxScalingFactor is the maximal scaling factor.
 	 * @param focusX is the X coordinate of the point that is at the center of the view.
 	 * @param focusY is the Y coordinate of the point that is at the center of the view.
 	 */
-	public ZoomableGraphics2D(Graphics2D target, Component target_component, float zoom, float fit_to_window_factor, float delta_x, float delta_y, boolean antialiasing, boolean is_for_printing, Graphics2DLOD lod, boolean flipX, boolean flipY, Rectangle2D documentScreenRectangle,
-			float scalingSensitivity, float minScalingFactor, float maxScalingFactor,
+	public ZoomableGraphics2D(
+			Graphics2D target,
+			Component target_component,
+			CenteringTransform centeringTransform,
+			float zoom,
+			boolean antialiasing,
+			boolean is_for_printing, 
+			Graphics2DLOD lod,
+			float scalingSensitivity,
+			float minScalingFactor,
+			float maxScalingFactor,
 			float focusX, float focusY) {
 		super(target, target_component, antialiasing, is_for_printing, lod);
+		this.centeringTransform = centeringTransform;
 		this.scalingSensitivity = scalingSensitivity;
 		this.minScalingFactor = minScalingFactor;
 		this.maxScalingFactor = maxScalingFactor;
 		this.focusX = focusX;
 		this.focusY = focusY;
 		this.defaultFontSize = DEFAULT_FONT_SCALE_FACTOR * target.getFont().getSize2D();
-		this.flipX = flipX;
-		this.flipY = flipY;
-		this.documentScreenRectangle = documentScreenRectangle;
 		this.zoomFactor = zoom;
-		this.fitToWindowFactor = fit_to_window_factor;
-		this.deltaX = delta_x;
-		this.deltaY = delta_y;
-		if (canZoom()) {
-			this.target.setFont(ZoomableContextUtil.logical2pixel(
-					getOriginalUnscaledFont(),
-					canZoom(),
-					this.fitToWindowFactor * this.zoomFactor));
-		}
+		this.target.setFont(ZoomableAwtContextUtil.logical2pixel(
+				getOriginalUnscaledFont(),
+				this.zoomFactor));
 	}
 
 	/** Construct a new ZoomableGraphics2D.
 	 *
 	 * @param target is the graphics in which draws will be done.
 	 * @param target_component is the target component (used to display an icon).
+	 * @param centeringTransform is the transformation used to center the objects in the view.
 	 * @param zoom is the zoom factor.
-	 * @param fit_to_window_factor is the factor used to scale the map coordinates.
-	 * @param delta_x is the translation length to center the logical model inside the screen space
-	 * @param delta_y is the translation length to center the logical model inside the screen space
 	 * @param antialiasing permits to force the anti-aliasing flag for the target graphical context
 	 * @param lod indicates the desired LOD used by this graphical context.
-	 * @param flipX indicates if the X axis may be inverted or not.
-	 * @param flipY indicates if the Y axis may be inverted or not.
-	 * @param documentScreenRectangle is the rectangle covered by the document in the screen space.
 	 * @param scalingSensitivity is the sensitivity of the zooming functions.
 	 * @param minScalingFactor is the minimal scaling factor.
 	 * @param maxScalingFactor is the maximal scaling factor.
 	 * @param focusX is the X coordinate of the point that is at the center of the view.
 	 * @param focusY is the Y coordinate of the point that is at the center of the view.
 	 */
-	public ZoomableGraphics2D(Graphics2D target, Component target_component, float zoom, float fit_to_window_factor, float delta_x, float delta_y, boolean antialiasing, Graphics2DLOD lod, boolean flipX, boolean flipY, Rectangle2D documentScreenRectangle,
-			float scalingSensitivity, float minScalingFactor, float maxScalingFactor,
-			float focusX, float focusY) {
+	public ZoomableGraphics2D(
+			Graphics2D target,
+			Component target_component,
+			CenteringTransform centeringTransform,
+			float zoom, 
+			boolean antialiasing,
+			Graphics2DLOD lod,
+			float scalingSensitivity,
+			float minScalingFactor,
+			float maxScalingFactor,
+			float focusX,
+			float focusY) {
 		super(target, target_component, antialiasing, lod);
+		this.centeringTransform = centeringTransform;
 		this.scalingSensitivity = scalingSensitivity;
 		this.minScalingFactor = minScalingFactor;
 		this.maxScalingFactor = maxScalingFactor;
 		this.focusX = focusX;
 		this.focusY = focusY;
 		this.defaultFontSize = getFont().getSize2D();
-		this.flipX = flipX;
-		this.flipY = flipY;
-		this.documentScreenRectangle = documentScreenRectangle;
 		this.zoomFactor = zoom;
-		this.fitToWindowFactor = fit_to_window_factor;
-		this.deltaX = delta_x;
-		this.deltaY = delta_y;
-		if (canZoom()) {
-			this.target.setFont(ZoomableContextUtil.logical2pixel(
-					getOriginalUnscaledFont(),
-					canZoom(),
-					this.fitToWindowFactor * this.zoomFactor));
-		}
+		this.target.setFont(ZoomableAwtContextUtil.logical2pixel(
+				getOriginalUnscaledFont(),
+				this.zoomFactor));
 	}
 
 	/** Construct a new ZoomableGraphics2D.
 	 *
 	 * @param target is the graphics in which draws will be done.
 	 * @param target_component is the target component (used to display an icon).
+	 * @param centeringTransform is the transformation used to center the objects in the view.
 	 * @param zoom is the zoom factor.
-	 * @param fit_to_window_factor is the factor used to scale the map coordinates.
-	 * @param delta_x is the translation length to center the logical model inside the screen space
-	 * @param delta_y is the translation length to center the logical model inside the screen space
 	 * @param lod indicates the desired LOD used by this graphical context.
-	 * @param flipX indicates if the X axis may be inverted or not.
-	 * @param flipY indicates if the Y axis may be inverted or not.
-	 * @param documentScreenRectangle is the rectangle covered by the document in the screen space.
 	 * @param scalingSensitivity is the sensitivity of the zooming functions.
 	 * @param minScalingFactor is the minimal scaling factor.
 	 * @param maxScalingFactor is the maximal scaling factor.
 	 * @param focusX is the X coordinate of the point that is at the center of the view.
 	 * @param focusY is the Y coordinate of the point that is at the center of the view.
 	 */
-	public ZoomableGraphics2D(Graphics2D target, Component target_component, float zoom, float fit_to_window_factor, float delta_x, float delta_y, Graphics2DLOD lod, boolean flipX, boolean flipY, Rectangle2D documentScreenRectangle,
-			float scalingSensitivity, float minScalingFactor, float maxScalingFactor,
-			float focusX, float focusY) {
+	public ZoomableGraphics2D(
+			Graphics2D target,
+			Component target_component,
+			CenteringTransform centeringTransform,
+			float zoom, 
+			Graphics2DLOD lod,
+			float scalingSensitivity,
+			float minScalingFactor,
+			float maxScalingFactor,
+			float focusX,
+			float focusY) {
 		super(target, target_component, lod);
+		this.centeringTransform = centeringTransform;
 		this.scalingSensitivity = scalingSensitivity;
 		this.minScalingFactor = minScalingFactor;
 		this.maxScalingFactor = maxScalingFactor;
 		this.focusX = focusX;
 		this.focusY = focusY;
 		this.defaultFontSize = getFont().getSize2D();
-		this.flipX = flipX;
-		this.flipY = flipY;
-		this.documentScreenRectangle = documentScreenRectangle;
 		this.zoomFactor = zoom;
-		this.fitToWindowFactor = fit_to_window_factor;
-		this.deltaX = delta_x;
-		this.deltaY = delta_y;
-		if (canZoom()) {
-			this.target.setFont(ZoomableContextUtil.logical2pixel(
-					getOriginalUnscaledFont(),
-					canZoom(),
-					this.fitToWindowFactor * this.zoomFactor));
-		}
+		this.target.setFont(ZoomableAwtContextUtil.logical2pixel(
+				getOriginalUnscaledFont(),
+				this.zoomFactor));
 	}
-	
+
 	/**
 	 * {@inheritDoc}
 	 */
@@ -316,7 +284,7 @@
 	protected float polyX(float x) {
 		return logical2pixel_x(x);
 	}
-	
+
 	/**
 	 * {@inheritDoc}
 	 */
@@ -332,27 +300,27 @@
 	public final StringAnchor getStringAnchor() {
 		return StringAnchor.UPPER_LEFT;
 	}
-	
-    /** Replies if this figure could drawn or not.
-     * <p>
-     * This function assumes that a drawable figure
-     * must have a bounding box with its width and
-     * height greaters or equals to a specified size.
-     * This size depends on the adviced level of details:
-     * {@link Graphics2DLOD#LOW_LEVEL_OF_DETAIL},
-     * {@link Graphics2DLOD#NORMAL_LEVEL_OF_DETAIL}
-     * or {@link Graphics2DLOD#HIGH_LEVEL_OF_DETAIL}.
-     *
-     * @param rect is the rect to draw.
-     * @return <code>true</code> if the figure is drawable, otherwhise
-     * <code>false</code>.
-     */ 
-    @Override
+
+	/** Replies if this figure could drawn or not.
+	 * <p>
+	 * This function assumes that a drawable figure
+	 * must have a bounding box with its width and
+	 * height greaters or equals to a specified size.
+	 * This size depends on the adviced level of details:
+	 * {@link Graphics2DLOD#LOW_LEVEL_OF_DETAIL},
+	 * {@link Graphics2DLOD#NORMAL_LEVEL_OF_DETAIL}
+	 * or {@link Graphics2DLOD#HIGH_LEVEL_OF_DETAIL}.
+	 *
+	 * @param rect is the rect to draw.
+	 * @return <code>true</code> if the figure is drawable, otherwhise
+	 * <code>false</code>.
+	 */ 
+	@Override
 	public boolean hit(Rectangle2D rect) {
-    	return super.hit(logical2pixel(rect));
-    }
+		return super.hit(logical2pixel(rect));
+	}
 
-    ////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////
 	// Graphics API
 
 	/** Creates the current graphics context.
@@ -360,14 +328,12 @@
 	@Override
 	public Graphics create() {
 		ZoomableGraphics2D z = new ZoomableGraphics2D((Graphics2D)this.target.create(),
-				this.targetComponent.get(),this.zoomFactor,
-				this.fitToWindowFactor,this.deltaX,this.deltaY,
+				this.targetComponent.get(),
+				this.centeringTransform,
+				this.zoomFactor,
 				isAntiAliased(),
 				isPrinting(),
 				getLOD(),
-				this.flipX,
-				this.flipY,
-				this.documentScreenRectangle,
 				this.scalingSensitivity,
 				this.minScalingFactor,
 				this.maxScalingFactor,
@@ -376,7 +342,6 @@
 		z.setImageOriginalSize(isImageOriginalSize());
 		z.setIconCentered(isIconCentered());
 		z.setIconOriginalSize(isIconOriginalSize());
-		z.setZoom(canZoom());
 		return z;
 	}
 
@@ -393,10 +358,8 @@
 	@Override
 	public void clearRect( float x, float y, float width, float height ) {
 		this.tmpRectangle.setRect(x, y, width, height);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		this.target.clearRect(
 				(int)this.tmpRectangle.getMinX(),
 				(int)this.tmpRectangle.getMinY(),
@@ -416,10 +379,8 @@
 	@Override
 	public void clipRect( float x, float y, float width, float height ) {
 		this.tmpRectangle.setRect(x, y, width, height);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		Rectangle2D c = new Rectangle2D.Double(
 				this.tmpRectangle.getMinX(),
 				this.tmpRectangle.getMinY(),
@@ -442,19 +403,16 @@
 	 */
 	@Override
 	public void copyArea( float x, float y, float width, float height, float dx, float dy ) {
-		float z = this.fitToWindowFactor * this.zoomFactor;
 		this.tmpRectangle.setRect(x, y, width, height);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, z);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		this.target.copyArea(
 				(int)this.tmpRectangle.getMinX(),
 				(int)this.tmpRectangle.getMinY(),
 				(int)this.tmpRectangle.getWidth(),
 				(int)this.tmpRectangle.getHeight(),
-				(int)ZoomableContextUtil.logical2pixel_size(dx, canZoom(), z),
-				(int)ZoomableContextUtil.logical2pixel_size(dy, canZoom(), z)) ;
+				(int)ZoomableContextUtil.logical2pixel_size(dx, this.zoomFactor),
+				(int)ZoomableContextUtil.logical2pixel_size(dy, this.zoomFactor)) ;
 	}
 
 	/** Draws the outline of an arc.
@@ -471,10 +429,8 @@
 	@Override
 	public void drawArc( float x, float y, float width, float height, float startAngle, float arcAngle ) {
 		this.tmpRectangle.setRect(x, y, width, height);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		Arc2D arc = new Arc2D.Double(
 				this.tmpRectangle.getMinX(),
 				this.tmpRectangle.getMinY(),
@@ -509,24 +465,21 @@
 		if (imgWidth==-1) return false;
 		int imgHeight = img.getHeight(obs);
 		if (imgHeight==-1) return false;
-		
-		float z = this.fitToWindowFactor * this.zoomFactor;
+
 		Image drawableImage;
-		
+
 		if (this.scaleImage) {
 			this.tmpRectangle.setRect(x, y, imgWidth, imgHeight);
 		}
 		else {
-			float sx = ZoomableContextUtil.pixel2logical_size(imgWidth, canZoom(), z);
-			float sy = ZoomableContextUtil.pixel2logical_size(imgHeight, canZoom(), z);
+			float sx = ZoomableContextUtil.pixel2logical_size(imgWidth, this.zoomFactor);
+			float sy = ZoomableContextUtil.pixel2logical_size(imgHeight, this.zoomFactor);
 			this.tmpRectangle.setRect(x, y, sx, sy);
 		}
 
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, z);
-		
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
+
 		if (this.tmpRectangle.isEmpty()) return true;
 
 		if (this.scaleImage) {
@@ -546,7 +499,7 @@
 
 		int ix = (int)this.tmpRectangle.getMinX();
 		int iy = (int)this.tmpRectangle.getMinX();
-		
+
 		return this.target.drawImage(drawableImage, ix, iy, bgColor, obs);
 	}
 
@@ -576,24 +529,21 @@
 		if (imgWidth==-1) return false;
 		int imgHeight = img.getHeight(obs);
 		if (imgHeight==-1) return false;
-		
-		float z = this.fitToWindowFactor * this.zoomFactor;
+
 		Image drawableImage;
-		
+
 		if (this.scaleImage) {
 			this.tmpRectangle.setRect(x, y, imgWidth, imgHeight);
 		}
 		else {
-			float sx = ZoomableContextUtil.pixel2logical_size(imgWidth, canZoom(), z);
-			float sy = ZoomableContextUtil.pixel2logical_size(imgHeight, canZoom(), z);
+			float sx = ZoomableContextUtil.pixel2logical_size(imgWidth, this.zoomFactor);
+			float sy = ZoomableContextUtil.pixel2logical_size(imgHeight, this.zoomFactor);
 			this.tmpRectangle.setRect(x, y, sx, sy);
 		}
 
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, z);
-		
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
+
 		if (this.tmpRectangle.isEmpty()) return true;
 
 		if (this.scaleImage) {
@@ -613,7 +563,7 @@
 
 		int ix = (int)this.tmpRectangle.getMinX();
 		int iy = (int)this.tmpRectangle.getMinY();
-		
+
 		return this.target.drawImage(drawableImage, ix, iy, obs);
 	}
 
@@ -633,10 +583,8 @@
 	@Override
 	public boolean drawImage( Image img, float x, float y, float width, float height, Color bgColor, ImageObserver obs ) {
 		this.tmpRectangle.setRect(x, y, width, height);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 
 		int w, h;
 		if (this.scaleImage) {
@@ -672,10 +620,8 @@
 	@Override
 	public boolean drawImage( Image img, float x, float y, float width, float height, ImageObserver obs ) {
 		this.tmpRectangle.setRect(x, y, width, height);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 
 		int w, h;
 		if (this.scaleImage) {
@@ -723,10 +669,8 @@
 			Color bgColor,
 			ImageObserver obs ) {
 		this.tmpRectangle.setRect(Math.min(dx1, dx2), Math.min(dy1, dy2), Math.abs(dx2-dx1), Math.abs(dy2-dy1));
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 
 		return this.target.drawImage( img, 
 				(int)((dx1<=dx2) ? this.tmpRectangle.getMinX() : this.tmpRectangle.getMaxX()),
@@ -765,10 +709,8 @@
 			int sx2, int sy2,
 			ImageObserver obs ) {
 		this.tmpRectangle.setRect(Math.min(dx1, dx2), Math.min(dy1, dy2), Math.abs(dx2-dx1), Math.abs(dy2-dy1));
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 
 		return this.target.drawImage( img, 
 				(int)((dx1<=dx2) ? this.tmpRectangle.getMinX() : this.tmpRectangle.getMaxX()),
@@ -789,23 +731,20 @@
 	 * @see #setIconCentered(boolean)
 	 */
 	public void drawIcon( Icon icon, float x, float y) {
-		float z = this.fitToWindowFactor * this.zoomFactor;
 		Icon drawableIcon;
-		
+
 		if (this.scaleIcon) {
 			this.tmpRectangle.setRect(x, y, icon.getIconWidth(), icon.getIconHeight());
 		}
 		else {
-			float sx = ZoomableContextUtil.pixel2logical_size(icon.getIconWidth(), canZoom(), z);
-			float sy = ZoomableContextUtil.pixel2logical_size(icon.getIconHeight(), canZoom(), z);
+			float sx = ZoomableContextUtil.pixel2logical_size(icon.getIconWidth(), this.zoomFactor);
+			float sy = ZoomableContextUtil.pixel2logical_size(icon.getIconHeight(), this.zoomFactor);
 			this.tmpRectangle.setRect(x, y, sx, sy);
 		}
 
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
-		
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
+
 		if (this.tmpRectangle.isEmpty()) return;
 
 		if (this.scaleIcon && icon instanceof ImageIcon) {
@@ -826,7 +765,7 @@
 			ix -= drawableIcon.getIconWidth() / 2;
 			iy -= drawableIcon.getIconHeight() / 2;
 		}
-		
+
 		drawableIcon.paintIcon(
 				this.targetComponent.get(),
 				this.target, 
@@ -882,10 +821,8 @@
 	@Override
 	public void drawOval( float x, float y, float w, float h ) {
 		this.tmpRectangle.setRect(x, y, w, h);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		Ellipse2D oval = new Ellipse2D.Double(
 				this.tmpRectangle.getMinX(),
 				this.tmpRectangle.getMinY(),
@@ -908,17 +845,15 @@
 	@Override
 	public void drawRoundRect( float x, float y, float w, float h, float arcWidth, float arcHeight ) {
 		this.tmpRectangle.setRect(x, y, w, h);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		RoundRectangle2D r = new RoundRectangle2D.Double(
 				this.tmpRectangle.getMinX(),
 				this.tmpRectangle.getMinY(),
 				this.tmpRectangle.getWidth(),
 				this.tmpRectangle.getHeight(),
-				ZoomableContextUtil.logical2pixel_size(arcWidth, canZoom(), this.fitToWindowFactor*this.zoomFactor),
-				ZoomableContextUtil.logical2pixel_size(arcHeight, canZoom(), this.fitToWindowFactor*this.zoomFactor)) ;
+				ZoomableContextUtil.logical2pixel_size(arcWidth, this.zoomFactor),
+				ZoomableContextUtil.logical2pixel_size(arcHeight, this.zoomFactor)) ;
 		this.target.draw(r);
 	}
 
@@ -936,10 +871,8 @@
 	@Override
 	public void fillArc( float x, float y, float width, float height, float startAngle, float arcAngle ) {
 		this.tmpRectangle.setRect(x, y, width, height);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		Arc2D a = new Arc2D.Double(
 				this.tmpRectangle.getMinX(),
 				this.tmpRectangle.getMinY(),
@@ -963,10 +896,8 @@
 	@Override
 	public void fillOval( float x, float y, float w, float h ) {
 		this.tmpRectangle.setRect(x, y, w, h);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		Ellipse2D oval = new Ellipse2D.Double(
 				this.tmpRectangle.getMinX(),
 				this.tmpRectangle.getMinY(),
@@ -987,10 +918,8 @@
 	@Override
 	public void fillRect( float x, float y, float w, float h ) {
 		this.tmpRectangle.setRect(x, y, w, h);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		this.target.fill(this.tmpRectangle);
 	}
 
@@ -1020,10 +949,8 @@
 	@Override
 	public void drawRect( float x, float y, float w, float h ) {
 		this.tmpRectangle.setRect(x, y, w, h);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		this.target.draw(this.tmpRectangle);
 	}
 
@@ -1041,17 +968,15 @@
 	@Override
 	public void fillRoundRect( float x, float y, float w, float h, float arcWidth, float arcHeight ) {
 		this.tmpRectangle.setRect(x, y, w, h);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		RoundRectangle2D r = new RoundRectangle2D.Double(
 				this.tmpRectangle.getMinX(),
 				this.tmpRectangle.getMinY(),
 				this.tmpRectangle.getWidth(),
 				this.tmpRectangle.getHeight(),
-				ZoomableContextUtil.logical2pixel_size(arcWidth, canZoom(), this.fitToWindowFactor*this.zoomFactor),
-				ZoomableContextUtil.logical2pixel_size(arcWidth, canZoom(), this.fitToWindowFactor*this.zoomFactor));
+				ZoomableContextUtil.logical2pixel_size(arcWidth, this.zoomFactor),
+				ZoomableContextUtil.logical2pixel_size(arcWidth, this.zoomFactor));
 		this.target.fill(r);
 	}
 
@@ -1074,10 +999,8 @@
 	@Override
 	public void setClip( float x, float y, float width, float height ) {
 		this.tmpRectangle.setRect(x, y, width, height);
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		this.target.setClip((Shape)this.tmpRectangle.clone());
 	}
 
@@ -1098,7 +1021,7 @@
 	public final void setFont( Font f ) {
 		setFont(f, true);
 	}
-	
+
 	/** Set the current font.
 	 * 
 	 * @param f
@@ -1107,15 +1030,14 @@
 	 */
 	protected void setFont(Font f, boolean enableScaling) {
 		Font sf = f;
-		if (canZoom() && enableScaling) {
-			sf = ZoomableContextUtil.logical2pixel(
+		if (enableScaling) {
+			sf = ZoomableAwtContextUtil.logical2pixel(
 					sf,
-					canZoom(),
-					this.fitToWindowFactor * this.zoomFactor);
+					this.zoomFactor);
 		}
 		this.target.setFont( sf ) ;
 	}
-	
+
 	/** {@inheritDoc}
 	 */
 	@Override
@@ -1129,13 +1051,10 @@
 	@Override
 	public Font getFont() {
 		Font font = this.target.getFont();
-		if (canZoom()) {
-			font = ZoomableContextUtil.pixel2logical(
-					font,
-					canZoom(),
-					this.fitToWindowFactor * this.zoomFactor);
-			font = new FontUIResource(font);
-		}
+		font = ZoomableAwtContextUtil.pixel2logical(
+				font,
+				this.zoomFactor);
+		font = new FontUIResource(font);
 		return font;
 	}
 
@@ -1175,14 +1094,11 @@
 	public void draw( Shape s ) {
 		this.target.draw( logical2pixel( s ) ) ;
 	}
-	
+
 	@Override
 	public void draw(PathIterator s) {
-		this.target.draw( ZoomableContextUtil.logical2pixel(
-				s, canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle,
-				this.deltaX, this.deltaY, 
-				this.fitToWindowFactor * this.zoomFactor) );
+		this.target.draw( ZoomableAwtContextUtil.logical2pixel(
+				s, this.centeringTransform, this.zoomFactor) );
 	}
 
 	/** Renders the text of the specified glyph.
@@ -1194,15 +1110,12 @@
 	@Override
 	public void drawGlyphVector( GlyphVector glyph, float x, float y ) {
 		if (glyph.getNumGlyphs()>0) {
-			float z = this.zoomFactor*this.fitToWindowFactor;
 			Rectangle2D bounds = glyph.getPixelBounds(glyph.getFontRenderContext(), x, y);
 			this.tmpRectangle.setRect(bounds);
-			ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-					canZoom(), this.flipX, this.flipY,
-					this.documentScreenRectangle, this.deltaX,
-					this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+			ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+					this.centeringTransform, this.zoomFactor);
 			AffineTransform o = getTransform();
-			this.target.scale(z,z) ;
+			this.target.scale(this.zoomFactor, this.zoomFactor) ;
 			this.target.drawGlyphVector(glyph,
 					(float)(this.tmpRectangle.getMinX() + this.tmpRectangle.getWidth()),
 					(float)(this.tmpRectangle.getMinY() + this.tmpRectangle.getHeight())) ; 
@@ -1221,23 +1134,19 @@
 	 */
 	@Override
 	public void drawImage( BufferedImage img, BufferedImageOp op, float x, float y ) {
-		float z = this.fitToWindowFactor * this.zoomFactor;
 		BufferedImage drawableImage;
-		
+
 		if (this.scaleImage) {
 			this.tmpRectangle.setRect(x, y, img.getWidth(), img.getHeight());
 		}
 		else {
-			float sx = ZoomableContextUtil.pixel2logical_size(img.getWidth(), canZoom(), z);
-			float sy = ZoomableContextUtil.pixel2logical_size(img.getHeight(), canZoom(), z);
+			float sx = ZoomableContextUtil.pixel2logical_size(img.getWidth(), this.zoomFactor);
+			float sy = ZoomableContextUtil.pixel2logical_size(img.getHeight(), this.zoomFactor);
 			this.tmpRectangle.setRect(x, y, sx, sy);
 		}
 
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, z);
-		
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle, this.centeringTransform, this.zoomFactor);
+
 		if (this.tmpRectangle.isEmpty()) return;
 
 		if (this.scaleImage) {
@@ -1254,10 +1163,22 @@
 
 		int ix = (int)this.tmpRectangle.getMinX();
 		int iy = (int)this.tmpRectangle.getMinY();
-		
+
 		this.target.drawImage(drawableImage, op, ix, iy);
 	}
+	
+	private AffineTransform toPixelTransform(AffineTransform trans) {
+		AffineTransform mat;
+		if (this.scaleImage)
+			mat = ZoomableAwtContextUtil.getMatrix(this.centeringTransform, this.zoomFactor);
+		else
+			mat = ZoomableAwtContextUtil.getMatrixNoScaling(this.centeringTransform, this.zoomFactor);
+			
+		mat.concatenate(trans);
 
+		return mat;
+	}
+
 	/** Draws the given image.
 	 *
 	 * @param img the image to draw.
@@ -1269,33 +1190,9 @@
 	 */
 	@Override
 	public boolean drawImage( Image img, AffineTransform xform, ImageObserver obs ) {
-		AffineTransform o = getTransform();
-		float z = this.zoomFactor * this.fitToWindowFactor;
-		float translateX = logical2pixel_x((float)xform.getTranslateX());
-		float translateY = logical2pixel_y((float)xform.getTranslateY());
-
-		AffineTransform yform = new AffineTransform(
-				xform.getScaleX(),xform.getShearY(),
-				xform.getShearX(),xform.getScaleY(),
-				xform.getTranslateX()+translateX,xform.getTranslateY()+translateY);
-
-		if ((canZoom())&&(this.scaleImage)) {
-			yform.scale(z, z);
-		}
-
-		if (this.flipX || this.flipY) {
-			float cx = (float)this.documentScreenRectangle.getCenterX();
-			float cy = (float)this.documentScreenRectangle.getCenterY();
-			yform.translate(-cx, -cy);
-			yform.scale(this.flipX ? -1. : 1., this.flipY ? -1. : 1.);
-			yform.translate(cx,cy);
-		}
-		
-		boolean b = this.target.drawImage( img, yform, obs ) ;
-		setTransform(o);
-		return b;
+		return this.target.drawImage( img, toPixelTransform(xform), obs ) ;
 	}
-
+	
 	/** Renders a RenderableImage.
 	 *
 	 * @param img the image to draw.
@@ -1305,30 +1202,7 @@
 	 */
 	@Override
 	public void drawRenderableImage( RenderableImage img, AffineTransform xform ) {
-		AffineTransform o = getTransform();
-		float z = this.zoomFactor * this.fitToWindowFactor;
-		float translateX = logical2pixel_x((float)xform.getTranslateX());
-		float translateY = logical2pixel_y((float)xform.getTranslateY());
-
-		AffineTransform yform = new AffineTransform(
-				xform.getScaleX(),xform.getShearY(),
-				xform.getShearX(),xform.getScaleY(),
-				xform.getTranslateX()+translateX,xform.getTranslateY()+translateY);
-
-		if ((canZoom())&&(this.scaleImage)) {
-			yform.scale(z, z);
-		}
-
-		if (this.flipX || this.flipY) {
-			float cx = (float)this.documentScreenRectangle.getCenterX();
-			float cy = (float)this.documentScreenRectangle.getCenterY();
-			yform.translate(-cx, -cy);
-			yform.scale(this.flipX ? -1. : 1., this.flipY ? -1. : 1.);
-			yform.translate(cx,cy);
-		}
-		
-		this.target.drawRenderableImage( img, yform ) ;
-		setTransform(o);
+		this.target.drawRenderableImage( img, toPixelTransform(xform) ) ;
 	}
 
 	/** Renders a RenderedImage.
@@ -1340,30 +1214,7 @@
 	 */
 	@Override
 	public void drawRenderedImage( RenderedImage img, AffineTransform xform ) {
-		AffineTransform o = getTransform();
-		float z = this.zoomFactor * this.fitToWindowFactor;
-		float translateX = logical2pixel_x((float)xform.getTranslateX());
-		float translateY = logical2pixel_y((float)xform.getTranslateY());
-
-		AffineTransform yform = new AffineTransform(
-				xform.getScaleX(),xform.getShearY(),
-				xform.getShearX(),xform.getScaleY(),
-				xform.getTranslateX()+translateX,xform.getTranslateY()+translateY);
-
-		if ((canZoom())&&(this.scaleImage)) {
-			yform.scale(z, z);
-		}
-
-		if (this.flipX || this.flipY) {
-			float cx = (float)this.documentScreenRectangle.getCenterX();
-			float cy = (float)this.documentScreenRectangle.getCenterY();
-			yform.translate(-cx, -cy);
-			yform.scale(this.flipX ? -1. : 1., this.flipY ? -1. : 1.);
-			yform.translate(cx,cy);
-		}
-		
-		this.target.drawRenderedImage( img, yform ) ;
-		setTransform(o);
+		this.target.drawRenderedImage( img, toPixelTransform(xform) ) ;
 	}
 
 	/** Draws the given string.
@@ -1378,15 +1229,13 @@
 		Rectangle2D r = fm.getMaxCharBounds(this);
 		this.tmpRectangle.setRect(x, y, r.getWidth()*(s.getEndIndex()-s.getBeginIndex()+1), fm.getHeight());
 		int baseline = fm.getMaxDescent();
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		this.target.drawString(s,
 				(float)this.tmpRectangle.getMinX(),
 				(float)(this.tmpRectangle.getMaxY()-baseline)); 
 	}
-	
+
 	/** Draws the given string.
 	 *
 	 * @param s the string to draw.
@@ -1399,10 +1248,8 @@
 		this.tmpRectangle.setRect(x, y, fm.stringWidth(s), fm.getHeight());
 		fm = getPixelFontMetrics();
 		int baseline = fm.getMaxDescent();
-		ZoomableContextUtil.logical2pixel_r(this.tmpRectangle,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+		ZoomableAwtContextUtil.logical2pixel(this.tmpRectangle,
+				this.centeringTransform, this.zoomFactor);
 		this.target.drawString(s,
 				(float)this.tmpRectangle.getMinX(),
 				(float)(this.tmpRectangle.getMaxY()-baseline)); 
@@ -1422,11 +1269,8 @@
 	 */
 	@Override
 	public void fill( PathIterator path ) {
-		this.target.fill( ZoomableContextUtil.logical2pixel(
-				path, canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle,
-				this.deltaX, this.deltaY, 
-				this.fitToWindowFactor * this.zoomFactor) ) ;
+		this.target.fill( ZoomableAwtContextUtil.logical2pixel( path,
+				this.centeringTransform, this.zoomFactor) ) ;
 	}
 
 	/** Adds a rotation into the current
@@ -1440,7 +1284,7 @@
 	public void rotate( float theta, float rx, float ry ) {
 		this.target.rotate( theta, logical2pixel_x( rx ), logical2pixel_y( ry ) ) ;
 	}
-	
+
 	/**
 	 * {@inheritDoc}
 	 */
@@ -1616,58 +1460,14 @@
 		this.centerIcon = isCentered;
 	}
 
-	/** Replies if the zoom feature was activated.
-	 * 
-	 * @return <code>true</code> if the zoom feature was activated, otherwise <code>false</code>
-	 */
-	public boolean canZoom() {
-		return this.canZoom ;
-	}
-
-	/** Changes the activation state of the zooming feature.
-	 * 
-	 * @param activate is <code>true</code> if the zoom feature must be activated, otherwise <code>false</code>
-	 */
-	public void setZoom( boolean activate) {
-		if (activate!=this.canZoom) {
-			this.canZoom = activate ;
-			Font f = getOriginalUnscaledFont();
-			if (activate) {
-				f = ZoomableContextUtil.logical2pixel(
-						f,
-						canZoom(),
-						this.fitToWindowFactor * this.zoomFactor);
-			}
-			this.target.setFont(f);
-		}
-	}
-
 	/**
 	 * {@inheritDoc}
 	 */
 	@Override
 	public float getScalingFactor() {
-		return this.zoomFactor * this.fitToWindowFactor;
+		return this.zoomFactor;
 	}
 
-	/**
-	 * Replies the translation to center the view.
-	 * 
-	 * @return the translation.
-	 */
-	public float getTranslationToCenterX() {
-		return this.deltaX;
-	}
-
-	/**
-	 * Replies the translation to center the view.
-	 * 
-	 * @return the translation.
-	 */
-	public float getTranslationToCenterY() {
-		return this.deltaY;
-	}
-
 	//------------------------------------------------------
 	// Function releated to the change of coordinates
 	//------------------------------------------------------
@@ -1677,7 +1477,7 @@
 	 */
 	@Override
 	public float logical2pixel_size(float l) {
-		return ZoomableContextUtil.logical2pixel_size(l, canZoom(), this.fitToWindowFactor * this.zoomFactor);
+		return ZoomableContextUtil.logical2pixel_size(l, this.zoomFactor);
 	}
 
 	/**
@@ -1686,9 +1486,7 @@
 	@Override
 	public float logical2pixel_x(float l) {
 		return ZoomableContextUtil.logical2pixel_x(l,
-				canZoom(), this.flipX,
-				this.documentScreenRectangle,
-				this.deltaX, this.fitToWindowFactor * this.zoomFactor);
+				this.centeringTransform, this.zoomFactor);
 	}
 
 	/**
@@ -1697,9 +1495,7 @@
 	@Override
 	public float logical2pixel_y(float l) {
 		return ZoomableContextUtil.logical2pixel_y(l,
-				canZoom(), this.flipY,
-				this.documentScreenRectangle,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+				this.centeringTransform, this.zoomFactor);
 	}
 
 	/**
@@ -1707,7 +1503,7 @@
 	 */
 	@Override
 	public float pixel2logical_size(float l) {
-		return ZoomableContextUtil.pixel2logical_size(l, canZoom(), this.fitToWindowFactor * this.zoomFactor);
+		return ZoomableContextUtil.pixel2logical_size(l, this.zoomFactor);
 	}
 
 	/**
@@ -1716,8 +1512,7 @@
 	@Override
 	public float pixel2logical_x(float p) {
 		return ZoomableContextUtil.pixel2logical_x(p,
-				canZoom(), this.flipX, this.documentScreenRectangle,
-				this.deltaX, this.zoomFactor * this.fitToWindowFactor);
+				this.centeringTransform, this.zoomFactor);
 	}
 
 	/**
@@ -1726,8 +1521,7 @@
 	@Override
 	public float pixel2logical_y(float p) {
 		return ZoomableContextUtil.pixel2logical_y(p,
-				canZoom(), this.flipY, this.documentScreenRectangle,
-				this.deltaY, this.zoomFactor * this.fitToWindowFactor);
+				this.centeringTransform, this.zoomFactor);
 	}
 
 	/** Translates the specified point
@@ -1737,7 +1531,6 @@
 	 * @return a point into the screen space.
 	 */
 	public Point2D logical2pixel(Point2D s) {
-		if ( ! canZoom() ) return s ;
 		return new Point2D.Double(
 				logical2pixel_x((float)s.getX()),
 				logical2pixel_y((float)s.getY()));
@@ -1751,11 +1544,8 @@
 	 * @return the translation of s
 	 */
 	public <T extends Shape> T logical2pixel(T s) {
-		return ZoomableContextUtil.logical2pixel(
-				s, canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle,
-				this.deltaX, this.deltaY, 
-				this.fitToWindowFactor * this.zoomFactor);
+		return ZoomableAwtContextUtil.logical2pixel(
+				s, this.centeringTransform, this.zoomFactor);
 	}
 
 	/**
@@ -1766,9 +1556,7 @@
 	 * @return the translation of f
 	 */
 	public Font logical2pixel(Font f) {
-		return ZoomableContextUtil.logical2pixel(
-				f, canZoom(),  
-				this.fitToWindowFactor * this.zoomFactor);
+		return ZoomableAwtContextUtil.logical2pixel(f, this.zoomFactor);
 	}
 
 	/** Translates the specified point
@@ -1778,7 +1566,6 @@
 	 * @return a point into the logical space.
 	 */
 	public Point2D pixel2logical(Point2D s) {
-		if ( ! canZoom() ) return s ;
 		return new Point2D.Double(
 				pixel2logical_x((int)s.getX()),
 				pixel2logical_y((int)s.getY()));
@@ -1792,11 +1579,8 @@
 	 * @return the translation of s
 	 */
 	public <T extends Shape> T pixel2logical(T s) {
-		return ZoomableContextUtil.pixel2logical(
-				s, canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle,
-				this.deltaX, this.deltaY,
-				this.fitToWindowFactor * this.zoomFactor);
+		return ZoomableAwtContextUtil.pixel2logical(
+				s, this.centeringTransform, this.zoomFactor);
 	}
 
 	/**
@@ -1807,11 +1591,79 @@
 	 * @return the translation of f
 	 */
 	public Font pixel2logical(Font f) {
-		return ZoomableContextUtil.pixel2logical(
-				f, canZoom(), 
-				this.fitToWindowFactor * this.zoomFactor);
+		return ZoomableAwtContextUtil.pixel2logical(f, this.zoomFactor);
 	}
 
+	@Override
+	public PathIterator2f logical2pixel(PathIterator2f p) {
+		return ZoomableContextUtil.logical2pixel(p, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public PathIterator2f pixel2logical(PathIterator2f p) {
+		return ZoomableContextUtil.pixel2logical(p, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Segment2f s) {
+		ZoomableContextUtil.logical2pixel(s, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Segment2f s) {
+		ZoomableContextUtil.pixel2logical(s, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(RoundRectangle2f r) {
+		ZoomableContextUtil.logical2pixel(r, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(RoundRectangle2f r) {
+		ZoomableContextUtil.pixel2logical(r, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Point2f p) {
+		ZoomableContextUtil.logical2pixel(p, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Point2f p) {
+		ZoomableContextUtil.pixel2logical(p, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Ellipse2f e) {
+		ZoomableContextUtil.logical2pixel(e, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Ellipse2f e) {
+		ZoomableContextUtil.pixel2logical(e, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Circle2f r) {
+		ZoomableContextUtil.logical2pixel(r, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Circle2f r) {
+		ZoomableContextUtil.pixel2logical(r, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void logical2pixel(Rectangle2f r) {
+		ZoomableContextUtil.logical2pixel(r, this.centeringTransform, this.zoomFactor);
+	}
+
+	@Override
+	public void pixel2logical(Rectangle2f r) {
+		ZoomableContextUtil.pixel2logical(r, this.centeringTransform, this.zoomFactor);
+	}
+
 	/**
 	 * Return the rectangle that corresponds to the displayed
 	 * area.
@@ -1830,11 +1682,9 @@
 		if (d==null) return null;
 		Rectangle2D r = new Rectangle2D.Double(
 				0, 0, d.getWidth()-1, d.getHeight()-1);
-		ZoomableContextUtil.pixel2logical_r(
+		ZoomableAwtContextUtil.pixel2logical(
 				r,
-				canZoom(), this.flipX, this.flipY,
-				this.documentScreenRectangle, this.deltaX,
-				this.deltaY, this.fitToWindowFactor * this.zoomFactor);
+				this.centeringTransform, this.zoomFactor);
 		return r;
 	}
 
@@ -1851,13 +1701,14 @@
 			this.targetComponent.get();
 		if (c==null) return null;
 		Dimension2D d = c.getSize();
-		if (d==null) return null;
-		float z = this.fitToWindowFactor * this.zoomFactor;
-		return new DoubleDimension(
-				ZoomableContextUtil.pixel2logical_size(
-						(float)d.getWidth(), canZoom(), z),
-				ZoomableContextUtil.pixel2logical_size(
-						(float)d.getHeight(), canZoom(), z));
+		if (d!=null) {
+			return new DoubleDimension(
+					ZoomableContextUtil.pixel2logical_size(
+							(float)d.getWidth(), this.zoomFactor),
+							ZoomableContextUtil.pixel2logical_size(
+									(float)d.getHeight(), this.zoomFactor));
+		}
+		return d;
 	}
 
 	/** Replies the current zooming context.
@@ -1875,27 +1726,22 @@
 		String[] lines = text.split("\n"); //$NON-NLS-1$
 		float margin = (backgroundColor!=null || borderColor!=null) ? CARTRIDGE_MARGIN : 0;
 		Rectangle2D cartidgeBounds = new Rectangle2D.Double();
-		float px = ZoomableContextUtil.logical2pixel_x(
-				x,
-				canZoom(), this.flipX, this.documentScreenRectangle,
-				this.deltaX,
-				this.fitToWindowFactor * this.zoomFactor);
-		float py = ZoomableContextUtil.logical2pixel_y(
-				y,
-				canZoom(), this.flipY, this.documentScreenRectangle,
-				this.deltaY,
-				this.fitToWindowFactor * this.zoomFactor);
+		float px, py;
+		px = ZoomableContextUtil.logical2pixel_x(
+				x, this.centeringTransform, this.zoomFactor);
+		py = ZoomableContextUtil.logical2pixel_y(
+				y, this.centeringTransform, this.zoomFactor);
 		// Force font metric to not be scaled
 		Font oldFont = getFont();
 		Font unscaledFont = oldFont.deriveFont(this.defaultFontSize);
 		setFont(unscaledFont, false);
 		// Compute cartridge
 		cartridgeBounds(lines, px, py, margin, cartidgeBounds);
-		
+
 		drawCartridge(lines, cartidgeBounds, margin, textColor, backgroundColor, borderColor, alignment);
 		setFont(oldFont, false);
 	}
-	
+
 	/** Replies the unscaled font.
 	 * 
 	 * @return the unscaled font.
@@ -2165,12 +2011,12 @@
 
 	@Override
 	public boolean isXAxisInverted() {
-		return this.flipX;
+		return this.centeringTransform.isXAxisFlipped();
 	}
 
 	@Override
 	public boolean isYAxisInverted() {
-		return this.flipY;
+		return this.centeringTransform.isYAxisFlipped();
 	}
 
 }

Modified: trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomablePanel.java
===================================================================
--- trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomablePanel.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomablePanel.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -62,6 +62,7 @@
 import javax.swing.border.Border;
 
 import org.arakhne.afc.math.continous.object2d.Point2f;
+import org.arakhne.afc.ui.CenteringTransform;
 import org.arakhne.afc.ui.Graphics2DLOD;
 import org.arakhne.afc.ui.ZoomableContext;
 import org.arakhne.afc.ui.swing.zoompanel.ScrollingMethod.ScrollingMethodListener;
@@ -731,34 +732,28 @@
 	 *
 	 * @param target is the graphics in which draws will be done.
 	 * @param target_component is the target component (used to display an icon).
+	 * @param centeringTransform is the transformation to use to draw the objects at the center of the view.
 	 * @param zoom is the zoom factor.
-	 * @param fit_to_window_factor is the factor used to scale the map coordinates.
-	 * @param delta_x is the translation length to center the logical model inside the screen space
-	 * @param delta_y is the translation length to center the logical model inside the screen space
 	 * @param useAntialiasing permits to force the anti-aliasing flag for the target graphical context
 	 * @param is_for_printing indicates if this graphics environment is for printing or not.
 	 * @param lodLevel indicates the desired LOD used by this graphical context.
 	 */
 	protected void paintAllComponents(Graphics2D target, Component target_component, 
-			float zoom, float fit_to_window_factor, float delta_x, float delta_y, boolean useAntialiasing, boolean is_for_printing, Graphics2DLOD lodLevel) {
+			CenteringTransform centeringTransform, float zoom, 
+			boolean useAntialiasing, boolean is_for_printing, Graphics2DLOD lodLevel) {
     	// Create the new graphical context
     	ZoomableGraphics2D gzoom = new ZoomableGraphics2D(
     			target, target_component,
-    			zoom,fit_to_window_factor,
-    			delta_x,
-				delta_y,
+    			centeringTransform,
+    			zoom,
 				useAntialiasing,
 				is_for_printing,
 				lodLevel,
-				this.zoomPanel.isXAxisInverted(),
-				this.zoomPanel.isYAxisInverted(),
-				this.zoomPanel.getDrawingAreaRect(),
 				this.zoomPanel.getScalingSensitivity(),
 				this.zoomPanel.getMinScalingFactor(),
 				this.zoomPanel.getMaxScalingFactor(),
 				this.zoomPanel.getFocusX(),
 				this.zoomPanel.getFocusY());
-    	
 		paintAllComponents(gzoom);
 	}
 	

Modified: trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtPath.java
===================================================================
--- trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtPath.java	2013-03-29 10:09:01 UTC (rev 402)
+++ trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtPath.java	2013-03-31 09:26:05 UTC (rev 403)
@@ -30,8 +30,10 @@
 import org.arakhne.afc.math.continous.object2d.Path2f;
 import org.arakhne.afc.math.continous.object2d.Rectangle2f;
 import org.arakhne.afc.math.matrix.Transform2D;
+import org.arakhne.afc.ui.CenteringTransform;
+import org.arakhne.afc.ui.ZoomableContextUtil;
 import org.arakhne.afc.ui.awt.VirtualizableShape;
-import org.arakhne.afc.ui.awt.ZoomableContextUtil;
+import org.arakhne.afc.ui.awt.ZoomableAwtContextUtil;
 
 /** Public implementation of a Path2D.
  *
@@ -140,18 +142,12 @@
 	}
 
 	@Override
-	public VirtualizableShape toScreen(boolean flipX, boolean flipY,
-			Rectangle2D documentScreenRectangle, float translationX,
-			float translationY, float zoom) {
-		return new ScreenPath(
-				flipX, flipY, documentScreenRectangle,
-				translationX, translationY, zoom);
+	public VirtualizableShape toScreen(CenteringTransform centeringTransform, float zoom) {
+		return new ScreenPath(centeringTransform, zoom);
 	}
 
 	@Override
-	public VirtualizableShape fromScreen(boolean flipX, boolean flipY,
-			Rectangle2D documentScreenRectangle, float translationX,
-			float translationY, float zoom) {
+	public VirtualizableShape fromScreen(CenteringTransform centeringTransform, float zoom) {
 		return this;
 	}
 
@@ -163,43 +159,27 @@
 	 */
 	private class ScreenPath implements VirtualizableShape, NativeWrapper {
 
-		final boolean flipX;
-		final boolean flipY;
-		final Rectangle2D documentScreenRectangle;
-		final float translationX;
-		final float translationY;
-		final float zoom;
+		final CenteringTransform centeringTransform;
+		float zoom;
 		
 		/**
-		 * @param flipX indicates if the X screen axis is inverted.
-		 * @param flipY indicates if the Y screen axis is inverted.
-		 * @param documentScreenRectangle is the area covered by the document in screen space.
-		 * @param translationX is the translation X in the context.
-		 * @param translationY is the translation Y in the context.
+		 * @param centeringTransform is the transformation that permits to
+		 * center the objects on the view. 
 		 * @param zoom is the current zooming factor of the view.
 		 */
 		public ScreenPath(
-				boolean flipX, boolean flipY,
-				Rectangle2D documentScreenRectangle,
-				float translationX, float translationY,
+				CenteringTransform centeringTransform,
 				float zoom) {
-			this.flipX = flipX;
-			this.flipY = flipY;
-			this.documentScreenRectangle = (Rectangle2D)documentScreenRectangle.clone();
-			this.translationX = translationX;
-			this.translationY = translationY;
+			this.centeringTransform = centeringTransform;
 			this.zoom = zoom;
 		}
 
 		@Override
 		public Rectangle getBounds() {
 			Rectangle r = (Rectangle)AwtPath.this.getBounds().clone();
-			ZoomableContextUtil.logical2pixel_r(
+			ZoomableAwtContextUtil.logical2pixel(
 					r,
-					true,
-					this.flipX, this.flipY,
-					this.documentScreenRectangle,
-					this.translationX, this.translationY,
+					this.centeringTransform,
 					this.zoom);
 			return r;
 		}
@@ -207,12 +187,9 @@
 		@Override
 		public Rectangle2D getBounds2D() {
 			Rectangle2D r = (Rectangle2D)AwtPath.this.getBounds2D().clone();
-			ZoomableContextUtil.logical2pixel_r(
+			ZoomableAwtContextUtil.logical2pixel(
 					r,
-					true,
-					this.flipX, this.flipY,
-					this.documentScreenRectangle,
-					this.translationX, this.translationY,
+					this.centeringTransform,
 					this.zoom);
 			return r;
 		}
@@ -220,13 +197,12 @@
 		@Override
 		public boolean contains(double x, double y) {
 			float sx = ZoomableContextUtil.pixel2logical_x(
-					(float)x, true, this.flipX,
-					this.documentScreenRectangle,
-					this.translationX, this.zoom);
+					(float)x,
+					this.centeringTransform, this.zoom);
 			float sy = ZoomableContextUtil.pixel2logical_y(
-					(float)y, true, this.flipY,
-					this.documentScreenRectangle,
-					this.translationY, this.zoom);
+					(float)y,
+					this.centeringTransform,
+					this.zoom);
 			return AwtPath.this.contains(sx, sy);
 		}
 
@@ -238,12 +214,9 @@
 		@Override
 		public boolean intersects(double x, double y, double w, double h) {
 			Rectangle2D r = new Rectangle2D.Float((float)x, (float)y, (float)w, (float)h);
-			ZoomableContextUtil.pixel2logical_r(
+			ZoomableAwtContextUtil.pixel2logical(
 					r,
-					true,
-					this.flipX, this.flipY,
-					this.documentScreenRectangle,
-					this.translationX, this.translationY,
+					this.centeringTransform,
 					this.zoom);
 			return AwtPath.this.intersects(r);
 		}
@@ -251,12 +224,9 @@
 		@Override
 		public boolean intersects(Rectangle2D r) {
 			Rectangle2D rr = (Rectangle2D)r.clone();
-			ZoomableContextUtil.pixel2logical_r(
+			ZoomableAwtContextUtil.pixel2logical(
 					rr,
-					true,
-					this.flipX, this.flipY,
-					this.documentScreenRectangle,
-					this.translationX, this.translationY,
+					this.centeringTransform,
 					this.zoom);
 			return AwtPath.this.intersects(rr);
 		}
@@ -264,12 +234,9 @@
 		@Override
 		public boolean contains(double x, double y, double w, double h) {
 			Rectangle2D r = new Rectangle2D.Float((float)x, (float)y, (float)w, (float)h);
-			ZoomableContextUtil.pixel2logical_r(
+			ZoomableAwtContextUtil.pixel2logical(
 					r,
-					true,
-					this.flipX, this.flipY,
-					this.documentScreenRectangle,
-					this.translationX, this.translationY,
+					this.centeringTransform,
 					this.zoom);
 			return AwtPath.this.contains(r);
 		}
@@ -277,12 +244,9 @@
 		@Override
 		public boolean contains(Rectangle2D r) {
 			Rectangle2D rr = (Rectangle2D)r.clone();
-			ZoomableContextUtil.pixel2logical_r(
+			ZoomableAwtContextUtil.pixel2logical(
 					rr,
-					true,
-					this.flipX, this.flipY,
-					this.documentScreenRectangle,
-					this.translationX, this.translationY,
+					this.centeringTransform,
 					this.zoom);
 			return AwtPath.this.contains(rr);
 		}
@@ -294,7 +258,7 @@
 
 		@Override
 		public PathIterator getPathIterator(AffineTransform at, double flatness) {
-			float vFlatness = ZoomableContextUtil.pixel2logical_size((float)flatness, true, this.zoom);
+			float vFlatness = ZoomableContextUtil.pixel2logical_size((float)flatness, this.zoom);
 			return new ScreenPathIterator(at, AwtPath.this.getPathIterator(null,vFlatness));
 		}
 
@@ -304,16 +268,12 @@
 		}
 
 		@Override
-		public VirtualizableShape toScreen(boolean flipX, boolean flipY,
-				Rectangle2D documentScreenRectangle, float translationX,
-				float translationY, float zoom) {
+		public VirtualizableShape toScreen(CenteringTransform centeringTransform, float zoom) {
 			return this;
 		}
 
 		@Override
-		public VirtualizableShape fromScreen(boolean flipX, boolean flipY,
-				Rectangle2D documentScreenRectangle, float translationX,
-				float translationY, float zoom) {
+		public VirtualizableShape fromScreen(CenteringTransform centeringTransform, float zoom) {
 			return AwtPath.this;
 		}
 		
@@ -357,34 +317,22 @@
 					++numPts;
 					coords[4] = ZoomableContextUtil.logical2pixel_x(
 							coords[4],
-							true,
-							ScreenPath.this.flipX,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationX,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					coords[5] = ZoomableContextUtil.logical2pixel_y(
 							coords[5],
-							true,
-							ScreenPath.this.flipY,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationY,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					//$FALL-THROUGH$
 				case PathIterator.SEG_QUADTO:
 					++numPts;
 					coords[2] = ZoomableContextUtil.logical2pixel_x(
 							coords[2],
-							true,
-							ScreenPath.this.flipX,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationX,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					coords[3] = ZoomableContextUtil.logical2pixel_y(
 							coords[3],
-							true,
-							ScreenPath.this.flipY,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationY,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					//$FALL-THROUGH$
 				case PathIterator.SEG_MOVETO:
@@ -392,17 +340,11 @@
 					++numPts;
 					coords[0] = ZoomableContextUtil.logical2pixel_x(
 							coords[0],
-							true,
-							ScreenPath.this.flipX,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationX,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					coords[1] = ZoomableContextUtil.logical2pixel_y(
 							coords[1],
-							true,
-							ScreenPath.this.flipY,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationY,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					if (this.tr!=null) {
 						this.tr.transform(coords, 0, coords, 0, numPts);
@@ -424,34 +366,22 @@
 					++numPts;
 					coords[4] = ZoomableContextUtil.logical2pixel_x(
 							(float)coords[4],
-							true,
-							ScreenPath.this.flipX,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationX,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					coords[5] = ZoomableContextUtil.logical2pixel_y(
 							(float)coords[5],
-							true,
-							ScreenPath.this.flipY,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationY,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					//$FALL-THROUGH$
 				case PathIterator.SEG_QUADTO:
 					++numPts;
 					coords[2] = ZoomableContextUtil.logical2pixel_x(
 							(float)coords[2],
-							true,
-							ScreenPath.this.flipX,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationX,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					coords[3] = ZoomableContextUtil.logical2pixel_y(
 							(float)coords[3],
-							true,
-							ScreenPath.this.flipY,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationY,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					//$FALL-THROUGH$
 				case PathIterator.SEG_MOVETO:
@@ -459,17 +389,11 @@
 					++numPts;
 					coords[0] = ZoomableContextUtil.logical2pixel_x(
 							(float)coords[0],
-							true,
-							ScreenPath.this.flipX,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationX,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					coords[1] = ZoomableContextUtil.logical2pixel_y(
 							(float)coords[1],
-							true,
-							ScreenPath.this.flipY,
-							ScreenPath.this.documentScreenRectangle,
-							ScreenPath.this.translationY,
+							ScreenPath.this.centeringTransform,
 							ScreenPath.this.zoom);
 					if (this.tr!=null) {
 						this.tr.transform(coords, 0, coords, 0, numPts);


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