You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2021/12/12 18:12:11 UTC
[sis] branch geoapi-4.0 updated: More reliable detecting of Java2D geometries backed by single-precision floating point numbers.
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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new ccb51c0 More reliable detecting of Java2D geometries backed by single-precision floating point numbers.
ccb51c0 is described below
commit ccb51c02dde7065bc72e601def4e4755935b32e5
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sun Dec 12 19:10:30 2021 +0100
More reliable detecting of Java2D geometries backed by single-precision floating point numbers.
---
.../sis/internal/feature/j2d/EmptyShape.java | 4 +-
.../apache/sis/internal/feature/j2d/Factory.java | 5 +-
.../sis/internal/feature/j2d/ShapeProperties.java | 4 +-
.../sis/internal/feature/j2d/ShapeWrapper.java | 11 ++-
.../apache/sis/internal/feature/j2d/Wrapper.java | 5 +-
.../sis/internal/feature/jts/ShapeAdapter.java | 22 +++++-
.../sis/internal/feature/jts/ShapeConverter.java | 4 +-
.../internal/referencing/j2d/AbstractShape.java | 82 ++++++++++++++++++++++
.../internal/referencing/j2d/ShapeUtilities.java | 16 +----
.../sis/internal/referencing/j2d/package-info.java | 2 +-
.../referencing/j2d/AbstractShapeTest.java} | 38 ++++++----
.../referencing/j2d/ShapeUtilitiesTest.java | 13 +---
.../sis/test/suite/ReferencingTestSuite.java | 3 +-
13 files changed, 155 insertions(+), 54 deletions(-)
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/EmptyShape.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/EmptyShape.java
index 94642c3..5ef0e34 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/EmptyShape.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/EmptyShape.java
@@ -16,13 +16,13 @@
*/
package org.apache.sis.internal.feature.j2d;
-import java.awt.Shape;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.NoSuchElementException;
+import org.apache.sis.internal.referencing.j2d.AbstractShape;
/**
@@ -33,7 +33,7 @@ import java.util.NoSuchElementException;
* @since 1.1
* @module
*/
-public final class EmptyShape implements Shape, PathIterator {
+public final class EmptyShape extends AbstractShape implements PathIterator {
/**
* The unique empty shape instance.
*/
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/Factory.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/Factory.java
index 6434c64..607d7f1 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/Factory.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/Factory.java
@@ -29,6 +29,7 @@ import org.apache.sis.setup.GeometryLibrary;
import org.apache.sis.internal.feature.Geometries;
import org.apache.sis.internal.feature.GeometryType;
import org.apache.sis.internal.feature.GeometryWrapper;
+import org.apache.sis.internal.referencing.j2d.AbstractShape;
import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
import org.apache.sis.internal.util.CollectionsExt;
import org.apache.sis.math.Vector;
@@ -243,7 +244,7 @@ public final class Factory extends Geometries<Shape> {
}
boolean isFloat = true;
for (final Shape geometry : shapes) {
- if (!ShapeUtilities.isFloat(geometry)) {
+ if (!AbstractShape.isFloat(geometry)) {
isFloat = false;
break;
}
@@ -286,7 +287,7 @@ public final class Factory extends Geometries<Shape> {
if (geometry == null) {
boolean isFloat = true;
for (final Object component : data) {
- isFloat = ShapeUtilities.isFloat(component);
+ isFloat = AbstractShape.isFloat(component);
if (!isFloat) break;
}
final Path2D path = createPath(isFloat, 20);
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 6ccb702..8cdc881 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
@@ -23,7 +23,7 @@ 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.internal.referencing.j2d.AbstractShape;
import org.apache.sis.util.StringBuilders;
@@ -96,7 +96,7 @@ final class ShapeProperties {
private List<?> coordinates(final double flatness) {
final PathIterator it = geometry.getPathIterator(null, flatness);
isPolygon = true;
- if (ShapeUtilities.isFloat(geometry)) {
+ if (AbstractShape.isFloat(geometry)) {
return coordinatesAsFloats(it);
} else {
return coordinatesAsDoubles(it);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/ShapeWrapper.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/ShapeWrapper.java
index d8487a3..835b027 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/ShapeWrapper.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/ShapeWrapper.java
@@ -22,6 +22,7 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.PathIterator;
import java.awt.geom.AffineTransform;
+import org.apache.sis.internal.referencing.j2d.AbstractShape;
/**
@@ -33,7 +34,7 @@ import java.awt.geom.AffineTransform;
* @since 1.2
* @module
*/
-abstract class ShapeWrapper implements Shape {
+abstract class ShapeWrapper extends AbstractShape {
/**
* The source of coordinate values.
*/
@@ -49,6 +50,14 @@ abstract class ShapeWrapper implements Shape {
}
/**
+ * Returns {@code true} if this shape backed by primitive {@code float} values.
+ */
+ @Override
+ protected boolean isFloat() {
+ return isFloat(source);
+ }
+
+ /**
* Returns a rectangle that completely encloses this {@code Shape}.
* This is not necessarily the smallest bounding box if an accurate
* computation would be too expansive.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/Wrapper.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/Wrapper.java
index a37af34..d9d2b82 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/Wrapper.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/j2d/Wrapper.java
@@ -34,6 +34,7 @@ import org.apache.sis.internal.feature.GeometryWithCRS;
import org.apache.sis.internal.feature.GeometryWrapper;
import org.apache.sis.internal.filter.sqlmm.SQLMM;
import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
+import org.apache.sis.internal.referencing.j2d.AbstractShape;
import org.apache.sis.internal.jdk9.JDK9;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.Debug;
@@ -163,7 +164,7 @@ final class Wrapper extends GeometryWithCRS<Shape> {
* Implementation of {@link #mergePolylines(Iterator)} also shared by {@link PointWrapper}.
*/
static Shape mergePolylines(Object next, final Iterator<?> polylines) {
- boolean isFloat = ShapeUtilities.isFloat(next);
+ boolean isFloat = AbstractShape.isFloat(next);
Path2D path = isFloat ? new Path2D.Float() : new Path2D.Double();
boolean lineTo = false;
add: for (;;) {
@@ -191,7 +192,7 @@ add: for (;;) {
/*
* Convert the path from single-precision to double-precision if needed.
*/
- if (isFloat && !ShapeUtilities.isFloat(next)) {
+ if (isFloat && !AbstractShape.isFloat(next)) {
path = new Path2D.Double(path);
isFloat = false;
}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/ShapeAdapter.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/ShapeAdapter.java
index 57551cf..e2bbf57 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/ShapeAdapter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/ShapeAdapter.java
@@ -23,12 +23,16 @@ import java.awt.geom.PathIterator;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import org.apache.sis.internal.feature.j2d.EmptyShape;
+import org.apache.sis.internal.referencing.j2d.AbstractShape;
import org.apache.sis.internal.referencing.j2d.IntervalRectangle;
import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.CoordinateSequence;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.LinearRing;
+import org.locationtech.jts.geom.Point;
/**
@@ -43,7 +47,7 @@ import org.locationtech.jts.geom.LinearRing;
* @since 1.2
* @module
*/
-final class ShapeAdapter implements Shape {
+final class ShapeAdapter extends AbstractShape {
/**
* A lightweight JTS geometry factory using the default
* {@link org.locationtech.jts.geom.impl.CoordinateArraySequenceFactory}.
@@ -69,6 +73,22 @@ final class ShapeAdapter implements Shape {
}
/**
+ * Returns {@code true} if this shape backed by primitive {@code float} values.
+ */
+ @Override
+ protected boolean isFloat() {
+ final CoordinateSequence cs;
+ if (geometry instanceof Point) {
+ cs = ((Point) geometry).getCoordinateSequence();
+ } else if (geometry instanceof LineString) {
+ cs = ((LineString) geometry).getCoordinateSequence();
+ } else {
+ return super.isFloat();
+ }
+ return Factory.isFloat(cs);
+ }
+
+ /**
* Returns an integer rectangle that completely encloses the shape.
* There is no guarantee that the rectangle is the smallest bounding box that encloses the shape.
*/
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/ShapeConverter.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/ShapeConverter.java
index 2103f85..2b29d73 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/ShapeConverter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/ShapeConverter.java
@@ -23,7 +23,7 @@ import java.util.ArrayList;
import java.awt.geom.PathIterator;
import java.awt.geom.IllegalPathStateException;
import org.apache.sis.internal.jdk9.JDK9;
-import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
+import org.apache.sis.internal.referencing.j2d.AbstractShape;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
@@ -115,7 +115,7 @@ abstract class ShapeConverter {
}
final PathIterator iterator = shape.getPathIterator(null, flatness);
final ShapeConverter converter;
- if (ShapeUtilities.isFloat(shape)) {
+ if (AbstractShape.isFloat(shape)) {
converter = new ShapeConverter.Float(factory, iterator);
} else {
converter = new ShapeConverter.Double(factory, iterator);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/AbstractShape.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/AbstractShape.java
new file mode 100644
index 0000000..a32e3be
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/AbstractShape.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.referencing.j2d;
+
+import java.awt.Shape;
+
+
+/**
+ * Base class for some (not all) shape implementations in Apache SIS.
+ * This base class provides a mechanism for determining if a shape stores
+ * coordinate values as simple-precision or double-precision floating point numbers.
+ *
+ * @author Martin Desruisseaux (MPO, IRD, Geomatys)
+ * @version 1.2
+ * @since 1.2
+ * @module
+ */
+public abstract class AbstractShape implements Shape {
+ /**
+ * Base classes of Java2D implementations known to store coordinates
+ * as single-precision floating point numbers.
+ */
+ private static final Class<?>[] FLOAT_SHAPES = {
+ java.awt.geom.Point2D.Float.class,
+ java.awt.geom.Line2D.Float.class,
+ java.awt.geom.QuadCurve2D.Float.class,
+ java.awt.geom.CubicCurve2D.Float.class,
+ java.awt.geom.Rectangle2D.Float.class,
+ java.awt.geom.RoundRectangle2D.Float.class,
+ java.awt.geom.Arc2D.Float.class,
+ java.awt.geom.Ellipse2D.Float.class,
+ java.awt.geom.Path2D.Float.class
+ };
+
+ /**
+ * Creates a new shape.
+ */
+ protected AbstractShape() {
+ }
+
+ /**
+ * Returns {@code true} if this shape backed by primitive {@code float} values.
+ *
+ * @return {@code true} if this shape is backed by {@code float} coordinate values.
+ */
+ protected boolean isFloat() {
+ return false;
+ }
+
+ /**
+ * 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}.
+ *
+ * @param shape the shape for which to determine the backing primitive type.
+ * @return {@code true} if the given shape is presumed backed by {@code float} coordinate values.
+ */
+ public static boolean isFloat(final Object shape) {
+ if (shape instanceof AbstractShape) {
+ return ((AbstractShape) shape).isFloat();
+ }
+ for (final Class<?> c : FLOAT_SHAPES) {
+ if (c.isInstance(shape)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
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 7915e2a..a6ecc95 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
@@ -35,7 +35,7 @@ import static java.lang.Double.isInfinite;
* Static methods operating on shapes from the {@link java.awt.geom} package.
*
* @author Martin Desruisseaux (MPO, IRD, Geomatys)
- * @version 1.0
+ * @version 1.2
* @since 0.5
* @module
*/
@@ -408,7 +408,7 @@ public final class ShapeUtilities extends Static {
final int code = it.currentSegment(buffer);
it.next();
if (it.isDone()) {
- if (isFloat(path)) {
+ if (AbstractShape.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]);
@@ -427,16 +427,4 @@ 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 3d4904d..24dbb46 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 1.1
+ * @version 1.2
*
* @see org.apache.sis.internal.feature.j2d
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/package-info.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/AbstractShapeTest.java
similarity index 57%
copy from core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/package-info.java
copy to core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/AbstractShapeTest.java
index 3d4904d..5df0e55 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/package-info.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/j2d/AbstractShapeTest.java
@@ -14,23 +14,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.sis.internal.referencing.j2d;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Line2D;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.opengis.test.Assert.*;
+
/**
- * A set of helper classes having a dependency to Java2D.
- * We keep those classes in a separated package for making easier to identify
- * which parts may need to be replaced in a JavaFX applications.
- *
- * <strong>Do not use!</strong>
- *
- * This package is for internal use by SIS only. Classes in this package
- * may change in incompatible ways in any future version without notice.
+ * Tests the {@link AbstractShape} class.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
- *
- * @see org.apache.sis.internal.feature.j2d
- *
- * @since 0.3
+ * @version 1.2
+ * @since 1.2
* @module
*/
-package org.apache.sis.internal.referencing.j2d;
+public final strictfp class AbstractShapeTest extends TestCase {
+ /**
+ * Tests {@link ShapeUtilities#isFloat(Object)}.
+ */
+ @Test
+ public void testIsFloat() {
+ assertTrue (AbstractShape.isFloat(new Point2D.Float()));
+ assertFalse(AbstractShape.isFloat(new Point2D.Double()));
+ assertTrue (AbstractShape.isFloat(new Line2D.Float()));
+ assertFalse(AbstractShape.isFloat(new Line2D.Double()));
+ }
+}
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 4d94f74..a0653a9 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 1.0
+ * @version 1.2
* @since 0.5
* @module
*/
@@ -241,15 +241,4 @@ 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()));
- }
}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java b/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
index c10e4bc..261adfd 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
@@ -25,13 +25,14 @@ import org.junit.BeforeClass;
* All tests from the {@code sis-referencing} module, in rough dependency order.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
* @since 0.3
* @module
*/
@Suite.SuiteClasses({
org.apache.sis.internal.referencing.LazySetTest.class,
org.apache.sis.internal.referencing.FormulasTest.class,
+ org.apache.sis.internal.referencing.j2d.AbstractShapeTest.class,
org.apache.sis.internal.referencing.j2d.ShapeUtilitiesTest.class,
org.apache.sis.internal.referencing.AxisDirectionsTest.class,
org.apache.sis.internal.referencing.VerticalDatumTypesTest.class,