sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 04/04: Preserve the single-precision versus double-precision nature of Shape instances when possible.
Date Tue, 12 Feb 2019 15:50:44 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 50fe4696ab1e2c30f89b5b2421e6d9164e949c96
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Tue Feb 12 15:54:27 2019 +0100

    Preserve the single-precision versus double-precision nature of Shape instances when possible.
---
 .../java/org/apache/sis/internal/feature/ESRI.java |  44 ++++----
 .../java/org/apache/sis/internal/feature/JTS.java  |  48 ++++-----
 .../org/apache/sis/internal/feature/Java2D.java    |  65 ++++++------
 .../sis/internal/feature/j2d/ShapeProperties.java  | 111 +++++++++++++++++++--
 .../internal/referencing/j2d/ShapeUtilities.java   |  32 ++++--
 .../sis/internal/referencing/j2d/package-info.java |   2 +-
 .../referencing/j2d/ShapeUtilitiesTest.java        |  13 ++-
 7 files changed, 221 insertions(+), 94 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
index e46b73c..b7acd42 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
@@ -124,8 +124,7 @@ final class ESRI extends Geometries<Geometry> {
 
     /**
      * Creates a polyline from the given ordinate values.
-     * Each {@link Double#NaN} ordinate value start a new path.
-     * The implementation returned by this method must be an instance of {@link #rootClass}.
+     * Each {@link Double#NaN} ordinate value starts a new path.
      */
     @Override
     public Geometry createPolyline(final int dimension, final Vector... ordinates) {
@@ -166,30 +165,31 @@ final class ESRI extends Geometries<Geometry> {
         }
         final Polyline path = new Polyline();
         boolean lineTo = false;
-        for (;; next = polylines.next()) {
-            if (next != null) {
-                if (next instanceof Point) {
-                    final Point pt = (Point) next;
-                    if (pt.isEmpty()) {
-                        lineTo = false;
+add:    for (;;) {
+            if (next instanceof Point) {
+                final Point pt = (Point) next;
+                if (pt.isEmpty()) {
+                    lineTo = false;
+                } else {
+                    final double x = ((Point) next).getX();
+                    final double y = ((Point) next).getY();
+                    if (lineTo) {
+                        path.lineTo(x, y);
                     } else {
-                        final double x = ((Point) next).getX();
-                        final double y = ((Point) next).getY();
-                        if (lineTo) {
-                            path.lineTo(x, y);
-                        } else {
-                            path.startPath(x, y);
-                            lineTo = true;
-                        }
+                        path.startPath(x, y);
+                        lineTo = true;
                     }
-                } else {
-                    path.add((MultiPath) next, false);
-                    lineTo = false;
                 }
+            } else {
+                path.add((MultiPath) next, false);
+                lineTo = false;
             }
-            if (!polylines.hasNext()) {         // Should be part of the 'for' instruction,
but we need
-                break;                          // to skip this condition during the first
iteration.
-            }
+            /*
+             * 'polylines.hasNext()' check is conceptually part of 'for' instruction,
+             * except that we need to skip this condition during the first iteration.
+             */
+            do if (!polylines.hasNext()) break add;
+            while ((next = polylines.next()) == null);
         }
         return path;
     }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
index 4636cea..39c998f 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
@@ -150,8 +150,7 @@ final class JTS extends Geometries<Geometry> {
 
     /**
      * Creates a polyline from the given ordinate values.
-     * Each {@link Double#NaN} ordinate value start a new path.
-     * The implementation returned by this method must be an instance of {@link #rootClass}.
+     * Each {@link Double#NaN} ordinate value starts a new path.
      *
      * @return the geometric object for the given points.
      */
@@ -232,34 +231,35 @@ final class JTS extends Geometries<Geometry> {
         }
         final List<Coordinate> coordinates = new ArrayList<>();
         final List<LineString> lines = new ArrayList<>();
-        for (;; next = polylines.next()) {
-            if (next != null) {
-                if (next instanceof Point) {
-                    final Coordinate pt = ((Point) next).getCoordinate();
-                    if (!Double.isNaN(pt.x) && !Double.isNaN(pt.y)) {
-                        coordinates.add(pt);
+add:    for (;;) {
+            if (next instanceof Point) {
+                final Coordinate pt = ((Point) next).getCoordinate();
+                if (!Double.isNaN(pt.x) && !Double.isNaN(pt.y)) {
+                    coordinates.add(pt);
+                } else {
+                    toLineString(coordinates, lines);
+                    coordinates.clear();
+                }
+            } else {
+                final Geometry g = (Geometry) next;
+                final int n = g.getNumGeometries();
+                for (int i=0; i<n; i++) {
+                    final LineString ls = (LineString) g.getGeometryN(i);
+                    if (coordinates.isEmpty()) {
+                        lines.add(ls);
                     } else {
+                        coordinates.addAll(Arrays.asList(ls.getCoordinates()));
                         toLineString(coordinates, lines);
                         coordinates.clear();
                     }
-                } else {
-                    final Geometry g = (Geometry) next;
-                    final int n = g.getNumGeometries();
-                    for (int i=0; i<n; i++) {
-                        final LineString ls = (LineString) g.getGeometryN(i);
-                        if (coordinates.isEmpty()) {
-                            lines.add(ls);
-                        } else {
-                            coordinates.addAll(Arrays.asList(ls.getCoordinates()));
-                            toLineString(coordinates, lines);
-                            coordinates.clear();
-                        }
-                    }
                 }
             }
-            if (!polylines.hasNext()) {         // Should be part of the 'for' instruction,
but we need
-                break;                          // to skip this condition during the first
iteration.
-            }
+            /*
+             * 'polylines.hasNext()' check is conceptually part of 'for' instruction,
+             * except that we need to skip this condition during the first iteration.
+             */
+            do if (!polylines.hasNext()) break add;
+            while ((next = polylines.next()) == null);
         }
         toLineString(coordinates, lines);
         return toGeometry(lines);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
index 5734ca7..7691b60 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
@@ -28,6 +28,7 @@ import org.apache.sis.internal.feature.j2d.ShapeProperties;
 import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
 import org.apache.sis.math.Vector;
 import org.apache.sis.util.Classes;
+import org.apache.sis.util.Numbers;
 
 
 /**
@@ -36,7 +37,7 @@ import org.apache.sis.util.Classes;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.7
  * @module
  */
@@ -111,8 +112,9 @@ final class Java2D extends Geometries<Shape> {
 
     /**
      * Creates a path from the given ordinate values.
-     * Each {@link Double#NaN} ordinate value start a new path.
-     * The implementation returned by this method must be an instance of {@link #rootClass}.
+     * Each {@link Double#NaN} ordinate value starts a new path.
+     * The geometry may be backed by {@code float} or {@code double} primitive type,
+     * depending on the type used by the given vectors.
      */
     @Override
     public Shape createPolyline(final int dimension, final Vector... ordinates) {
@@ -120,8 +122,8 @@ final class Java2D extends Geometries<Shape> {
             throw unsupported(dimension);
         }
         /*
-         * Computes the total length of all vectors and verifies if all values
-         * can be casted to float without precision lost.
+         * Computes the total length of all vectors and verifies if any vector
+         * requires double-precision numbers instead of single-precision.
          */
         int length = 0;
         boolean isFloat = true;
@@ -129,13 +131,7 @@ final class Java2D extends Geometries<Shape> {
             if (v != null) {
                 length = Math.addExact(length, v.size());
                 if (isFloat) {
-                    for (int i=v.size(); --i >= 0;) {
-                        final double value = v.doubleValue(i);
-                        if (Double.doubleToRawLongBits(value) != Double.doubleToRawLongBits((float)
value)) {
-                            isFloat = false;
-                            break;
-                        }
-                    }
+                    isFloat = Numbers.getEnumConstant(v.getElementType()) <= Numbers.FLOAT;
                 }
             }
         }
@@ -187,28 +183,37 @@ final class Java2D extends Geometries<Shape> {
         if (!(next instanceof Shape || next instanceof Point2D)) {
             return null;
         }
-        final Path2D path = new Path2D.Double();
+        boolean isFloat = ShapeUtilities.isFloat(next);
+        Path2D path = isFloat ? new Path2D.Float() : new Path2D.Double();
         boolean lineTo = false;
-        for (;; next = polylines.next()) {
-            if (next != null) {
-                if (next instanceof Point2D) {
-                    final double x = ((Point2D) next).getX();
-                    final double y = ((Point2D) next).getY();
-                    if (Double.isNaN(x) || Double.isNaN(y)) {
-                        lineTo = false;
-                    } else if (lineTo) {
-                        path.lineTo(x, y);
-                    } else {
-                        path.moveTo(x, y);
-                        lineTo = true;
-                    }
-                } else {
-                    path.append((Shape) next, false);
+add:    for (;;) {
+            if (next instanceof Point2D) {
+                final double x = ((Point2D) next).getX();
+                final double y = ((Point2D) next).getY();
+                if (Double.isNaN(x) || Double.isNaN(y)) {
                     lineTo = false;
+                } else if (lineTo) {
+                    path.lineTo(x, y);
+                } else {
+                    path.moveTo(x, y);
+                    lineTo = true;
                 }
+            } else {
+                path.append((Shape) next, false);
+                lineTo = false;
             }
-            if (!polylines.hasNext()) {         // Should be part of the 'for' instruction,
but we need
-                break;                          // to skip this condition during the first
iteration.
+            /*
+             * 'polylines.hasNext()' check is conceptually part of 'for' instruction,
+             * except that we need to skip this condition during the first iteration.
+             */
+            do if (!polylines.hasNext()) break add;
+            while ((next = polylines.next()) == null);
+            /*
+             * Convert the path from single-precision to double-precision if needed.
+             */
+            if (isFloat && !ShapeUtilities.isFloat(next)) {
+                path = new Path2D.Double(path);
+                isFloat = false;
             }
         }
         return ShapeUtilities.toPrimitive(path);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/ShapeProperties.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/ShapeProperties.java
index ecfcfc4..dcc2a0d 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/ShapeProperties.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/ShapeProperties.java
@@ -19,9 +19,11 @@ package org.apache.sis.internal.feature.j2d;
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.List;
+import java.lang.reflect.Array;
 import java.awt.Shape;
 import java.awt.geom.PathIterator;
 import java.awt.geom.IllegalPathStateException;
+import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
 import org.apache.sis.util.StringBuilders;
 
 
@@ -72,20 +74,102 @@ public final class ShapeProperties {
     }
 
     /**
-     * Returns coordinates of the given geometry as a list of (<var>x</var>,<var>y</var>)
tuples in {@code double[]} arrays.
-     * This method guarantees that all arrays have at least 2 points (4 coordinates). It
should be invoked only for small or
-     * medium shapes. For large shapes, the path iterator should be used directly without
copy to arrays.
+     * Same as {@link #addPoint(double[], double[], int)} but for single-precision numbers.
+     */
+    private static float[] addPoint(final float[] source, float[] target, final int index)
{
+        if (index >= target.length) {
+            target = Arrays.copyOf(target, index*2);
+        }
+        System.arraycopy(source, 0, target, index, 2);
+        return target;
+    }
+
+    /**
+     * Returns coordinates of the given geometry as a list of (<var>x</var>,<var>y</var>)
tuples in {@code float[]}
+     * or {@code double[]} arrays. This method guarantees that all arrays have at least 2
points (4 coordinates).
+     * It should be invoked only for small or medium shapes. For large shapes, the path iterator
should be used
+     * directly without copy to arrays.
      *
      * @param  flatness   maximal distance between the approximated segments and any point
on the curve.
      * @return coordinate tuples. They are presumed polygons if {@link #isPolygon} is {@code
true}.
      */
-    private List<double[]> coordinates(final double flatness) {
-        final List<double[]> polylines = new ArrayList<>();
+    private List<?> coordinates(final double flatness) {
+        final PathIterator it = geometry.getPathIterator(null, flatness);
         isPolygon = true;
+        if (ShapeUtilities.isFloat(geometry)) {
+            return coordinatesAsFloats(it);
+        } else {
+            return coordinatesAsDoubles(it);
+        }
+    }
+
+    /**
+     * {@link #coordinates(double)} implementation for the double-precision case.
+     * The {@link #isPolygon} field needs to be set before to invoke this method.
+     */
+    private List<double[]> coordinatesAsDoubles(final PathIterator it) {
+        final List<double[]> polylines = new ArrayList<>();
         double[] polyline = new double[10];
         final double[] coords = new double[6];
+        /*
+         * Double-precision variant of this method. Source code below is identical to the
single-precision variant,
+         * but the methods invoked are different because of method overloading. Trying to
have a common code is too
+         * complex (too many code are different despite looking the same).
+         */
+        int i = 0;
+        while (!it.isDone()) {
+            switch (it.currentSegment(coords)) {
+                case PathIterator.SEG_MOVETO: {
+                    if (i > 2) {
+                        isPolygon = false;          // MOVETO without CLOSE: this is a linestring
instead than a polygon.
+                        polylines.add(Arrays.copyOf(polyline, i));
+                    }
+                    System.arraycopy(coords, 0, polyline, 0, 2);
+                    i = 2;
+                    break;
+                }
+                case PathIterator.SEG_LINETO: {
+                    polyline = addPoint(coords, polyline, i);
+                    i += 2;
+                    break;
+                }
+                case PathIterator.SEG_CLOSE: {
+                    if (i > 2) {
+                        if (polyline[0] != polyline[i-2] || polyline[1] != polyline[i-1])
{
+                            polyline = addPoint(polyline, polyline, i);
+                            i += 2;
+                        }
+                        polylines.add(Arrays.copyOf(polyline, i));
+                    }
+                    i = 0;
+                    break;
+                }
+                default: throw new IllegalPathStateException();
+            }
+            it.next();
+        }
+        if (i > 2) {
+            isPolygon = false;          // LINETO without CLOSE: this is a linestring instead
than a polygon.
+            polylines.add(Arrays.copyOf(polyline, i));
+        }
+        return polylines;
+    }
+
+    /**
+     * {@link #coordinates(double)} implementation for the single-precision case.
+     * The {@link #isPolygon} field needs to be set before to invoke this method.
+     */
+    private List<float[]> coordinatesAsFloats(final PathIterator it) {
+        final List<float[]> polylines = new ArrayList<>();
+        float[] polyline = new float[10];
+        final float[] coords = new float[6];
+        /*
+         * Single-precision variant of this method. Source code below is identical to the
double-precision variant,
+         * but the methods invoked are different because of method overloading. Trying to
have a common code is too
+         * complex (too many code are different despite looking the same).
+         */
         int i = 0;
-        for (final PathIterator it = geometry.getPathIterator(null, flatness); !it.isDone();
it.next()) {
+        while (!it.isDone()) {
             switch (it.currentSegment(coords)) {
                 case PathIterator.SEG_MOVETO: {
                     if (i > 2) {
@@ -114,6 +198,7 @@ public final class ShapeProperties {
                 }
                 default: throw new IllegalPathStateException();
             }
+            it.next();
         }
         if (i > 2) {
             isPolygon = false;          // LINETO without CLOSE: this is a linestring instead
than a polygon.
@@ -133,7 +218,7 @@ public final class ShapeProperties {
      * @see <a href="https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry">Well-known
text on Wikipedia</a>
      */
     public String toWKT(final double flatness) {
-        final List<double[]> polylines = coordinates(flatness);
+        final List<?> polylines = coordinates(flatness);
         final boolean isMulti;
         switch (polylines.size()) {
             case 0:  return "POLYGON EMPTY";
@@ -147,16 +232,22 @@ public final class ShapeProperties {
         buffer.append(isPolygon ? "POLYGON" : "LINESTRING").append(' ');
         if (isMulti) buffer.append('(');
         for (int j=0; j<polylines.size(); j++) {
-            final double[] polyline = polylines.get(j);
+            final Object polyline = polylines.get(j);
             if (j != 0) buffer.append(", ");
             buffer.append('(');
             if (isPolygon) buffer.append('(');
-            for (int i=0; i<polyline.length; i++) {
+            final int length = Array.getLength(polyline);
+            for (int i=0; i<length; i++) {
                 if (i != 0) {
                     if ((i & 1) == 0) buffer.append(',');
                     buffer.append(' ');
                 }
-                StringBuilders.trimFractionalPart(buffer.append(polyline[i]));
+                if (polyline instanceof double[]) {
+                    buffer.append(((double[]) polyline)[i]);
+                } else {
+                    buffer.append(((float[]) polyline)[i]);
+                }
+                StringBuilders.trimFractionalPart(buffer);
             }
             if (isPolygon) buffer.append(')');
             buffer.append(')');
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java
index 6478f98..49a1f7b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ShapeUtilities.java
@@ -32,7 +32,7 @@ import static java.lang.Math.*;
  * Static methods operating on shapes from the {@link java.awt.geom} package.
  *
  * @author  Martin Desruisseaux (MPO, IRD, Geomatys)
- * @version 0.5
+ * @version 1.0
  * @since   0.5
  * @module
  */
@@ -336,7 +336,7 @@ public final class ShapeUtilities extends Static {
             y2 = (px*rx2 + py*ry2) / x2;                    // use 'y2' as a temporary variable
for 'x1'
             py = (py*rx2 - px*ry2) / x2;
             px = y2;
-            y2 = 0;                                         // set as a matter of principle
(but not used).
+//          y2 = 0;                                         // Could be set to that value,
but not used.
             /*
              * Now compute the control point coordinates in our new coordinate system axis.
              */
@@ -405,10 +405,18 @@ public final class ShapeUtilities extends Static {
                     final int code = it.currentSegment(buffer);
                     it.next();
                     if (it.isDone()) {
-                        switch (code) {
-                            case PathIterator.SEG_LINETO:  return new       Line2D.Double(x1,y1,
buffer[0], buffer[1]);
-                            case PathIterator.SEG_QUADTO:  return new  QuadCurve2D.Double(x1,y1,
buffer[0], buffer[1], buffer[2], buffer[3]);
-                            case PathIterator.SEG_CUBICTO: return new CubicCurve2D.Double(x1,y1,
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
+                        if (isFloat(path)) {
+                            switch (code) {
+                                case PathIterator.SEG_LINETO:  return new       Line2D.Float((float)
x1, (float) y1, (float) buffer[0], (float) buffer[1]);
+                                case PathIterator.SEG_QUADTO:  return new  QuadCurve2D.Float((float)
x1, (float) y1, (float) buffer[0], (float) buffer[1], (float) buffer[2], (float) buffer[3]);
+                                case PathIterator.SEG_CUBICTO: return new CubicCurve2D.Float((float)
x1, (float) y1, (float) buffer[0], (float) buffer[1], (float) buffer[2], (float) buffer[3],
(float) buffer[4], (float) buffer[5]);
+                            }
+                        } else {
+                            switch (code) {
+                                case PathIterator.SEG_LINETO:  return new       Line2D.Double(x1,y1,
buffer[0], buffer[1]);
+                                case PathIterator.SEG_QUADTO:  return new  QuadCurve2D.Double(x1,y1,
buffer[0], buffer[1], buffer[2], buffer[3]);
+                                case PathIterator.SEG_CUBICTO: return new CubicCurve2D.Double(x1,y1,
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
+                            }
                         }
                     }
                 }
@@ -416,4 +424,16 @@ public final class ShapeUtilities extends Static {
         }
         return path;
     }
+
+    /**
+     * Returns {@code true} if the given shape is presumed backed by primitive {@code float}
values.
+     * The given object should be an instance of {@link Shape} or {@link Point2D}.
+     * This method use heuristic rules based on class name used in Java2D library.
+     *
+     * @param  path  the shape for which to determine the backing primitive type.
+     * @return {@code true} if the given shape is presumed backed by {@code float} type.
+     */
+    public static boolean isFloat(final Object path) {
+        return path.getClass().getSimpleName().equals("Float");
+    }
 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/package-info.java
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/package-info.java
index b20274d..1df2079 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/package-info.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/package-info.java
@@ -26,7 +26,7 @@
  * may change in incompatible ways in any future version without notice.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  *
  * @see org.apache.sis.internal.feature.j2d
  *
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
index 3f0c800..bb63bdf 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/ShapeUtilitiesTest.java
@@ -33,7 +33,7 @@ import static org.opengis.test.Assert.*;
  * Values in this test were determined empirically by running {@link ShapeUtilitiesViewer}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.5
+ * @version 1.0
  * @since   0.5
  * @module
  */
@@ -166,4 +166,15 @@ public final strictfp class ShapeUtilitiesTest extends TestCase {
         assertEquals("CtrlP2", new Point2D.Double(8, 6), ((CubicCurve2D) p).getCtrlP2());
         assertEquals("P2",     new Point2D.Double(9, 4), ((CubicCurve2D) p).getP2());
     }
+
+    /**
+     * Tests {@link ShapeUtilities#isFloat(Object)}.
+     */
+    @Test
+    public void test() {
+        assertTrue (ShapeUtilities.isFloat(new Point2D.Float()));
+        assertFalse(ShapeUtilities.isFloat(new Point2D.Double()));
+        assertTrue (ShapeUtilities.isFloat(new Line2D.Float()));
+        assertFalse(ShapeUtilities.isFloat(new Line2D.Double()));
+    }
 }


Mime
View raw message