diff --git a/src/main/java/net/imglib2/algorithm/region/CircleCursor.java b/src/main/java/net/imglib2/algorithm/region/CircleCursor.java new file mode 100644 index 000000000..558bd496b --- /dev/null +++ b/src/main/java/net/imglib2/algorithm/region/CircleCursor.java @@ -0,0 +1,335 @@ +package net.imglib2.algorithm.region; + +import net.imglib2.Cursor; +import net.imglib2.FinalInterval; +import net.imglib2.Interval; +import net.imglib2.Localizable; +import net.imglib2.RandomAccess; +import net.imglib2.RandomAccessible; +import net.imglib2.Sampler; + +/** + * Iterates over a Bresenham 2D circle using the mid-point algorithm. + *
+ * Each point of the circle is iterated exactly once, and there is no "hole" in + * the circle. Contrary to the algorithm linked below, the circles generated by + * this cursor are "slim": each pixel of the circle is connected with + * 8-connectivity. For instance, a bitmap excerpt from such a circle looks like + * this: + * + *
+ * .......... + * OOO....... + * ...OO..... + * .....O.... + * .....O.... + *+ * + * @author Jean-Yves Tinevez + * @see Midpoint + * circle algorithm on Wikipedia. + * + */ +public class CircleCursor< T > implements Cursor< T > +{ + private final RandomAccessible< T > rai; + + private final RandomAccess< T > ra; + + private final Localizable center; + + private final long radius; + + private final int dimX; + + private final int dimY; + + private long x; + + private long y; + + private long dx; + + private long dy; + + private long f; + + private Octant octant; + + private boolean hasNext; + + private static enum Octant + { + INIT, EAST, NORTH, WEST, SOUTH, O1, O2, O3, O4, O5, O6, O7, O8; + } + + /** + * Iterates over a Bresenham circle in the target {@link RandomAccessible}. + * Each point of the circle is iterated exactly once, and there is no "hole" + * in the circle. + * + * @param rai + * the random accessible. It is the caller responsibility to + * ensure it can be accessed everywhere the circle will be + * iterated. + * @param center + * the circle center. Must be at least of dimension 2. Dimensions + * 0 and 1 are used to specify the circle center. + * @param radius + * the circle radius. The circle is written in a plane in + * dimensions 0 and 1. + */ + public CircleCursor( final RandomAccessible< T > rai, final Localizable center, final long radius ) + { + this( rai, center, radius, 0, 1 ); + } + + /** + * Iterates over a Bresenham circle in the target {@link RandomAccessible}. + * Each point of the circle is iterated exactly once, and there is no "hole" + * in the circle. + * + * @param rai + * the random accessible. It is the caller responsibility to + * ensure it can be accessed everywhere the circle will be + * iterated. + * @param center + * the circle center. Must at least contain dimensions specified + *
dimX and dimY.
+ * @param radius
+ * the circle radius.
+ * @param dimX
+ * the first dimension of the plane in which to draw the circle.
+ * @param dimY
+ * the second dimension of the plane in which to draw the circle.
+ */
+ public CircleCursor( final RandomAccessible< T > rai, final Localizable center, final long radius, final int dimX, final int dimY )
+ {
+ this.rai = rai;
+ this.center = center;
+ this.radius = radius;
+ this.dimX = dimX;
+ this.dimY = dimY;
+ // Make an interval to signal where we will access data.
+ final int numDimensions = rai.numDimensions();
+ final long[] minmax = new long[ 2 * numDimensions ];
+ for ( int d = 0; d < numDimensions; d++ )
+ {
+ if ( d == dimX || d == dimY )
+ minmax[ d ] = center.getLongPosition( d ) - radius;
+ else
+ minmax[ d ] = center.getLongPosition( d );
+ }
+ for ( int d = 0; d < numDimensions; d++ )
+ {
+ if ( d == dimX || d == dimY )
+ minmax[ d + numDimensions ] = center.getLongPosition( d ) + radius;
+ else
+ minmax[ d + numDimensions ] = center.getLongPosition( d );
+ }
+ final Interval interval = FinalInterval.createMinMax( minmax );
+ this.ra = rai.randomAccess( interval );
+ reset();
+ }
+
+ @Override
+ public void reset()
+ {
+ x = 0;
+ y = radius;
+ f = 1 - radius;
+ dx = 1;
+ dy = -2 * radius;
+ octant = Octant.INIT;
+ ra.setPosition( center );
+ hasNext = true;
+ }
+
+ @Override
+ public void fwd()
+ {
+ switch ( octant )
+ {
+ default:
+ case INIT:
+ ra.setPosition( center.getLongPosition( dimY ) + radius, dimY );
+ octant = Octant.NORTH;
+ break;
+
+ case NORTH:
+ ra.setPosition( center.getLongPosition( dimY ) - radius, dimY );
+ octant = Octant.SOUTH;
+ break;
+
+ case SOUTH:
+ ra.setPosition( center.getLongPosition( dimX ) - radius, dimX );
+ ra.setPosition( center.getLongPosition( dimY ), dimY );
+ octant = Octant.WEST;
+ break;
+
+ case WEST:
+ ra.setPosition( center.getLongPosition( dimX ) + radius, dimX );
+ octant = Octant.EAST;
+ break;
+
+ case EAST:
+ x = x + 1;
+ dx = dx + 2;
+ f = f + dx;
+ ra.setPosition( center.getLongPosition( dimX ) + x, dimX );
+ ra.setPosition( center.getLongPosition( dimY ) + y, dimY );
+ octant = Octant.O1;
+ break;
+
+ case O1:
+ ra.setPosition( center.getLongPosition( dimX ) - x, dimX );
+ octant = Octant.O2;
+ break;
+
+ case O2:
+ ra.setPosition( center.getLongPosition( dimY ) - y, dimY );
+ octant = Octant.O3;
+ break;
+
+ case O3:
+ ra.setPosition( center.getLongPosition( dimX ) + x, dimX );
+ octant = Octant.O4;
+ // Stop here if x==y, lest the 45ยบ will be iterated twice.
+ if ( x >= y )
+ hasNext = false;
+ break;
+
+ case O4:
+ ra.setPosition( center.getLongPosition( dimX ) + y, dimX );
+ ra.setPosition( center.getLongPosition( dimY ) - x, dimY );
+ octant = Octant.O5;
+ break;
+
+ case O5:
+ ra.setPosition( center.getLongPosition( dimX ) - y, dimX );
+ octant = Octant.O6;
+ break;
+
+ case O6:
+ ra.setPosition( center.getLongPosition( dimY ) + x, dimY );
+ octant = Octant.O7;
+ break;
+
+ case O7:
+ ra.setPosition( center.getLongPosition( dimX ) + y, dimX );
+ octant = Octant.O8;
+ // Stop here if dx would cross y.
+ if ( x >= y - 1 )
+ hasNext = false;
+ break;
+
+ case O8:
+ if ( f > 0 )
+ {
+ y = y - 1;
+ dy = dy + 2;
+ f = f + dy;
+ }
+ x = x + 1;
+ dx = dx + 2;
+ f = f + dx;
+ ra.setPosition( center.getLongPosition( dimX ) + x, dimX );
+ ra.setPosition( center.getLongPosition( dimY ) + y, dimY );
+ octant = Octant.O1;
+ break;
+ }
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return hasNext;
+ }
+
+ @Override
+ public void localize( final float[] position )
+ {
+ ra.localize( position );
+ }
+
+ @Override
+ public void localize( final double[] position )
+ {
+ ra.localize( position );
+ }
+
+ @Override
+ public float getFloatPosition( final int d )
+ {
+ return ra.getFloatPosition( d );
+ }
+
+ @Override
+ public double getDoublePosition( final int d )
+ {
+ return ra.getDoublePosition( d );
+ }
+
+ @Override
+ public int numDimensions()
+ {
+ return ra.numDimensions();
+ }
+
+ @Override
+ public T get()
+ {
+ return ra.get();
+ }
+
+ @Override
+ public Sampler< T > copy()
+ {
+ return ra.copy();
+ }
+
+ @Override
+ public void jumpFwd( final long steps )
+ {
+ for ( int i = 0; i < steps; i++ )
+ fwd();
+ }
+
+ @Override
+ public T next()
+ {
+ fwd();
+ return get();
+ }
+
+ @Override
+ public void localize( final int[] position )
+ {
+ ra.localize( position );
+ }
+
+ @Override
+ public void localize( final long[] position )
+ {
+ ra.localize( position );
+ }
+
+ @Override
+ public int getIntPosition( final int d )
+ {
+ return ra.getIntPosition( d );
+ }
+
+ @Override
+ public long getLongPosition( final int d )
+ {
+ return ra.getLongPosition( d );
+ }
+
+ @Override
+ public Cursor< T > copyCursor()
+ {
+ return new CircleCursor<>( rai, center, radius, dimX, dimY );
+ }
+}
diff --git a/src/main/java/net/imglib2/algorithm/region/Circles.java b/src/main/java/net/imglib2/algorithm/region/Circles.java
new file mode 100644
index 000000000..b00d59b43
--- /dev/null
+++ b/src/main/java/net/imglib2/algorithm/region/Circles.java
@@ -0,0 +1,193 @@
+package net.imglib2.algorithm.region;
+
+import net.imglib2.Cursor;
+import net.imglib2.Localizable;
+import net.imglib2.RandomAccessible;
+import net.imglib2.type.Type;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.operators.Add;
+
+/**
+ * Write circles in an image using the midpoint algorithm.
+ *
+ * @author Jean-Yves Tinevez
+ * @see Midpoint
+ * circle algorithm on Wikipedia.
+ * @see CircleCursor {@link CircleCursor}
+ */
+public class Circles
+{
+
+ /**
+ * Writes a circle in the target {@link RandomAccessible}. The circle is
+ * written by incrementing the pixel values by 1 along the circle.
+ * The circle is written in a plane in dimensions 0 and 1.
+ *
+ * @param rai
+ * the random accessible. It is the caller responsibility to
+ * ensure it can be accessed everywhere the circle will be
+ * iterated.
+ * @param center
+ * the circle center. Must be at least of dimension 2. Dimensions
+ * 0 and 1 are used to specify the circle center.
+ * @param radius
+ * the circle radius.
+ * @param dimX and dimY, used to specify the
+ * circle center.
+ * @param radius
+ * the circle radius.
+ * @param dimX
+ * the first dimension of the plane in which to draw the circle.
+ * @param dimY
+ * the second dimension of the plane in which to draw the circle.
+ * @param dimX and dimY, used to specify the
+ * circle center.
+ * @param radius
+ * the circle radius.
+ * @param dimX
+ * the first dimension of the plane in which to draw the circle.
+ * @param dimY
+ * the second dimension of the plane in which to draw the circle.
+ * @param value
+ * the value to write along the circle.
+ * @param dimX and dimY, used to specify the
+ * circle center.
+ * @param radius
+ * the circle radius.
+ * @param dimX
+ * the first dimension of the plane in which to draw the circle.
+ * @param dimY
+ * the second dimension of the plane in which to draw the circle.
+ * @param value
+ * the value to add along the circle.
+ * @param + * Each point of the ellipse is iterated exactly once, and there is no "hole" in + * the ellipse. A bitmap excerpt from such a ellipse looks like this: + * + *
+ * .......... + * OOO....... + * ...OO..... + * .....O.... + * .....O.... + *+ *
+ * The circle generated with equal X and Y radii is not strictly equivalent to
+ * the circle generated by the {@link CircleCursor}.
+ *
+ * @author Jean-Yves Tinevez
+ */
+public class EllipseCursor< T > implements Cursor< T >
+{
+ private final RandomAccessible< T > rai;
+
+ private final RandomAccess< T > ra;
+
+ private final Localizable center;
+
+ private final long radiusX;
+
+ private final long radiusY;
+
+ private final int dimX;
+
+ private final int dimY;
+
+ private long x;
+
+ private long y;
+
+ private double px;
+
+ private double py;
+
+ private double p;
+
+ private Octant octant;
+
+ private boolean hasNext;
+
+ private static enum Octant
+ {
+ INIT,
+ EAST, NORTH, WEST, SOUTH,
+ REGION1_Q1, REGION1_Q2, REGION1_Q3, REGION1_Q4,
+ REGION2_Q1, REGION2_Q2, REGION2_Q3, REGION2_Q4;
+ }
+
+ /**
+ * Iterates over a Bresenham ellipse in the target {@link RandomAccessible}.
+ * Each point of the ellipse is iterated exactly once, and there is no
+ * "hole" in the ellipse. The ellipse is written in a plane in dimensions 0
+ * and 1.
+ *
+ * @param rai
+ * the random accessible. It is the caller responsibility to
+ * ensure it can be accessed everywhere the ellipse will be
+ * iterated.
+ * @param center
+ * the ellipse center. Must be at least of dimension 2.
+ * Dimensions 0 and 1 are used to specify the ellipse center.
+ * @param radiusX
+ * the ellipse radius in the dimension 0.
+ * @param radiusY
+ * the ellipse radius in the dimension 1.
+ */
+ public EllipseCursor( final RandomAccessible< T > rai, final Localizable center, final long radiusX, final long radiusY )
+ {
+ this( rai, center, radiusX, radiusY, 0, 1 );
+ }
+
+ /**
+ * Iterates over a Bresenham ellipse in the target {@link RandomAccessible}.
+ * Each point of the ellipse is iterated exactly once, and there is no
+ * "hole" in the ellipse.
+ *
+ * @param rai
+ * the random accessible. It is the caller responsibility to
+ * ensure it can be accessed everywhere the ellipse will be
+ * iterated.
+ * @param center
+ * the ellipse center. Must be at least of dimension 2.
+ * Dimensions 0 and 1 are used to specify the ellipse center.
+ * @param radiusX
+ * the ellipse radius in dimension X.
+ * @param radiusY
+ * the ellipse radius in dimension Y.
+ * @param dimX
+ * the first dimension of the plane in which to draw the ellipse.
+ * @param dimY
+ * the second dimension of the plane in which to draw the
+ * ellipse.
+ */
+ public EllipseCursor( final RandomAccessible< T > rai, final Localizable center, final long radiusX, final long radiusY, final int dimX, final int dimY )
+ {
+ this.rai = rai;
+ this.center = center;
+ if ( radiusX > radiusY )
+ {
+ // Swap X & Y if radiusX if larger than radiusY and avoid issues
+ // with slim ellipses.
+ this.radiusX = radiusY;
+ this.radiusY = radiusX;
+ this.dimX = dimY;
+ this.dimY = dimX;
+ }
+ else
+ {
+ this.radiusX = radiusX;
+ this.radiusY = radiusY;
+ this.dimX = dimX;
+ this.dimY = dimY;
+ }
+ // Make an interval to signal where we will access data.
+ final int numDimensions = rai.numDimensions();
+ final long[] minmax = new long[ 2 * numDimensions ];
+ for ( int d = 0; d < numDimensions; d++ )
+ {
+ if ( d == dimX )
+ minmax[ d ] = center.getLongPosition( d ) - radiusX;
+ else if ( d == dimY )
+ minmax[ d ] = center.getLongPosition( d ) - radiusY;
+ else
+ minmax[ d ] = center.getLongPosition( d );
+ }
+ for ( int d = 0; d < numDimensions; d++ )
+ {
+ if ( d == dimX )
+ minmax[ d + numDimensions ] = center.getLongPosition( d ) + radiusX;
+ else if ( d == dimY )
+ minmax[ d + numDimensions ] = center.getLongPosition( d ) + radiusY;
+ else
+ minmax[ d + numDimensions ] = center.getLongPosition( d );
+ }
+ final Interval interval = FinalInterval.createMinMax( minmax );
+ this.ra = rai.randomAccess( interval );
+ reset();
+ }
+
+ @Override
+ public void reset()
+ {
+ // Prepare for region 1.
+ x = 0l;
+ y = radiusY;
+ px = 0.;
+ py = 2. * radiusX * radiusX * y;
+ p = radiusY * radiusY - ( radiusX * radiusX * radiusY ) + ( 0.25 * radiusX * radiusX );
+
+ octant = Octant.INIT;
+ ra.setPosition( center );
+ hasNext = true;
+ }
+
+ @Override
+ public void fwd()
+ {
+ switch ( octant )
+ {
+ default:
+ case INIT:
+ ra.setPosition( center.getLongPosition( dimY ) + radiusY, dimY );
+ octant = Octant.NORTH;
+ break;
+
+ case NORTH:
+ ra.setPosition( center.getLongPosition( dimY ) - radiusY, dimY );
+ octant = Octant.SOUTH;
+ break;
+
+ case SOUTH:
+ ra.setPosition( center.getLongPosition( dimX ) - radiusX, dimX );
+ ra.setPosition( center.getLongPosition( dimY ), dimY );
+ octant = Octant.WEST;
+ break;
+
+ case WEST:
+ ra.setPosition( center.getLongPosition( dimX ) + radiusX, dimX );
+ octant = Octant.EAST;
+
+ // Special case: rx = ry = 1.
+ if ( radiusX == 1 && radiusY == 1 )
+ hasNext = false;
+
+ break;
+
+ case EAST:
+ // Move to region 1.
+ x++;
+ px += 2. * radiusY * radiusY;
+ if ( p < 0 )
+ {
+ p += ( radiusY * radiusY ) + px;
+ }
+ else
+ {
+ y--;
+ py -= 2 * ( radiusX * radiusX );
+ p += ( radiusY * radiusY ) + px - py;
+ }
+
+ ra.setPosition( center.getLongPosition( dimX ) + x, dimX );
+ ra.setPosition( center.getLongPosition( dimY ) + y, dimY );
+ octant = Octant.REGION1_Q1;
+ break;
+
+ case REGION1_Q1:
+ ra.setPosition( center.getLongPosition( dimX ) - x, dimX );
+ octant = Octant.REGION1_Q2;
+ break;
+
+ case REGION1_Q2:
+ ra.setPosition( center.getLongPosition( dimY ) - y, dimY );
+ octant = Octant.REGION1_Q3;
+ break;
+
+ case REGION1_Q3:
+ ra.setPosition( center.getLongPosition( dimX ) + x, dimX );
+ octant = Octant.REGION1_Q4;
+
+ // Don't overwrite equator for small radii.
+ if ( y == 1 && x <= 2 )
+ hasNext = false;
+
+ break;
+
+ case REGION1_Q4:
+
+ if ( px < py )
+ {
+ // Back to Q1 of Region 1.
+ x++;
+ px += 2. * radiusY * radiusY;
+ if ( p < 0 )
+ {
+ p += ( radiusY * radiusY ) + px;
+ }
+ else
+ {
+ y--;
+ py -= 2 * ( radiusX * radiusX );
+ p += ( radiusY * radiusY ) + px - py;
+ }
+
+ octant = Octant.REGION1_Q1;
+ }
+ else
+ {
+ // Maybe go to Region 2.
+ p = radiusY * radiusY * ( x + 0.5 ) * ( x + 0.5 ) + radiusX * radiusX * ( y - 1 ) * ( y - 1 ) - radiusX * radiusX * radiusY * radiusY;
+ y--;
+ py -= 2. * radiusX * radiusX;
+ if ( p > 0 )
+ {
+ p += radiusX * radiusX - py;
+ }
+ else
+ {
+ x++;
+ px += 2. * radiusY * radiusY;
+ p += radiusX * radiusX - py + px;
+ }
+ octant = Octant.REGION2_Q1;
+ }
+
+ ra.setPosition( center.getLongPosition( dimX ) + x, dimX );
+ ra.setPosition( center.getLongPosition( dimY ) + y, dimY );
+ break;
+
+ case REGION2_Q1:
+ ra.setPosition( center.getLongPosition( dimX ) - x, dimX );
+ octant = Octant.REGION2_Q2;
+ break;
+
+ case REGION2_Q2:
+ ra.setPosition( center.getLongPosition( dimY ) - y, dimY );
+ octant = Octant.REGION2_Q3;
+ break;
+
+ case REGION2_Q3:
+ ra.setPosition( center.getLongPosition( dimX ) + x, dimX );
+ octant = Octant.REGION2_Q4;
+ if ( y <= 1 )
+ hasNext = false;
+ break;
+
+ case REGION2_Q4:
+ y--;
+ py -= 2. * radiusX * radiusX;
+ if ( p > 0 )
+ {
+ p += radiusX * radiusX - py;
+ }
+ else
+ {
+ x++;
+ px += 2. * radiusY * radiusY;
+ p += radiusX * radiusX - py + px;
+ }
+ octant = Octant.REGION2_Q1;
+ ra.setPosition( center.getLongPosition( dimX ) + x, dimX );
+ ra.setPosition( center.getLongPosition( dimY ) + y, dimY );
+ }
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return hasNext;
+ }
+
+ @Override
+ public void localize( final float[] position )
+ {
+ ra.localize( position );
+ }
+
+ @Override
+ public void localize( final double[] position )
+ {
+ ra.localize( position );
+ }
+
+ @Override
+ public float getFloatPosition( final int d )
+ {
+ return ra.getFloatPosition( d );
+ }
+
+ @Override
+ public double getDoublePosition( final int d )
+ {
+ return ra.getDoublePosition( d );
+ }
+
+ @Override
+ public int numDimensions()
+ {
+ return ra.numDimensions();
+ }
+
+ @Override
+ public T get()
+ {
+ return ra.get();
+ }
+
+ @Override
+ public Sampler< T > copy()
+ {
+ return ra.copy();
+ }
+
+ @Override
+ public void jumpFwd( final long steps )
+ {
+ for ( int i = 0; i < steps; i++ )
+ fwd();
+ }
+
+ @Override
+ public T next()
+ {
+ fwd();
+ return get();
+ }
+
+ @Override
+ public void localize( final int[] position )
+ {
+ ra.localize( position );
+ }
+
+ @Override
+ public void localize( final long[] position )
+ {
+ ra.localize( position );
+ }
+
+ @Override
+ public int getIntPosition( final int d )
+ {
+ return ra.getIntPosition( d );
+ }
+
+ @Override
+ public long getLongPosition( final int d )
+ {
+ return ra.getLongPosition( d );
+ }
+
+ @Override
+ public Cursor< T > copyCursor()
+ {
+ return new EllipseCursor<>( rai, center, radiusX, radiusY, dimX, dimY );
+ }
+
+ @Override
+ public String toString()
+ {
+ return super.toString() + " pos=" + Util.printCoordinates( this ) + ",\t" + octant + ",\tx = " + x + ",\ty = " + y;
+ }
+}
diff --git a/src/main/java/net/imglib2/algorithm/region/Ellipses.java b/src/main/java/net/imglib2/algorithm/region/Ellipses.java
new file mode 100644
index 000000000..8bc7968ca
--- /dev/null
+++ b/src/main/java/net/imglib2/algorithm/region/Ellipses.java
@@ -0,0 +1,209 @@
+package net.imglib2.algorithm.region;
+
+import net.imglib2.Cursor;
+import net.imglib2.Localizable;
+import net.imglib2.RandomAccessible;
+import net.imglib2.type.Type;
+import net.imglib2.type.numeric.RealType;
+import net.imglib2.type.operators.Add;
+
+/**
+ * Write ellipses in an image using the midpoint algorithm.
+ *
+ * @author Jean-Yves Tinevez
+ * @see EllipseCursor {@link EllipseCursor}
+ * @see EllipseCursor {@link EllipseCursor}
+ */
+public class Ellipses
+{
+
+ /**
+ * Writes an ellipse in the target {@link RandomAccessible}. The ellipse is
+ * written by incrementing the pixel values by 1 along the ellipse.
+ * The ellipse is written in a plane in dimensions 0 and 1.
+ *
+ * @param rai
+ * the random accessible. It is the caller responsibility to
+ * ensure it can be accessed everywhere the ellipse will be
+ * iterated.
+ * @param center
+ * the ellipse center. Must be at least of dimension 2.
+ * Dimensions 0 and 1 are used to specify the ellipse center.
+ * @param radiusX
+ * the ellipse X radius.
+ * @param radiusY
+ * the ellipse Y radius.
+ * @param dimX and dimY, used to specify the
+ * ellipse center.
+ * @param radiusX
+ * the ellipse X radius.
+ * @param radiusY
+ * the ellipse Y radius.
+ * @param dimX
+ * the first dimension of the plane in which to draw the ellipse.
+ * @param dimY
+ * the second dimension of the plane in which to draw the
+ * ellipse.
+ * @param dimX and dimY, used to specify the
+ * ellipse center.
+ * @param radiusX
+ * the ellipse X radius.
+ * @param radiusY
+ * the ellipse Y radius.
+ * @param dimX
+ * the first dimension of the plane in which to draw the ellipse.
+ * @param dimY
+ * the second dimension of the plane in which to draw the
+ * ellipse.
+ * @param value
+ * the value to write along the ellipse.
+ * @param dimX and dimY, used to specify the
+ * ellipse center.
+ * @param radiusX
+ * the ellipse X radius.
+ * @param radiusY
+ * the ellipse Y radius.
+ * @param dimX
+ * the first dimension of the plane in which to draw the ellipse.
+ * @param dimY
+ * the second dimension of the plane in which to draw the
+ * ellipse.
+ * @param value
+ * the value to add along the ellipse.
+ * @param