sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1737000 - in /sis/branches/JDK8/core: sis-metadata/src/main/java/org/apache/sis/io/wkt/ sis-referencing/src/main/java/org/apache/sis/referencing/operation/ sis-referencing/src/test/java/org/apache/sis/referencing/operation/
Date Tue, 29 Mar 2016 11:24:13 GMT
Author: desruisseaux
Date: Tue Mar 29 11:24:13 2016
New Revision: 1737000

URL: http://svn.apache.org/viewvc?rev=1737000&view=rev
Log:
Test the GeographicCRS to ProjectedCRS case without datum or axis changes.

Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java?rev=1737000&r1=1736999&r2=1737000&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
[UTF-8] Tue Mar 29 11:24:13 2016
@@ -34,10 +34,13 @@ import javax.measure.unit.UnitFormat;
 import org.opengis.util.FactoryException;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.internal.util.LocalizedParseException;
 import org.apache.sis.internal.util.StandardDateFormat;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
@@ -55,7 +58,7 @@ import static org.apache.sis.util.Argume
  * @author  Rémi Eve (IRD)
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.6
- * @version 0.6
+ * @version 0.7
  * @module
  */
 abstract class AbstractParser implements Parser {
@@ -227,6 +230,20 @@ abstract class AbstractParser implements
     }
 
     /**
+     * Returns the index after the end of the fragment name starting at the given index.
+     * Current implementation assumes that the fragment name is a Unicode identifier.
+     */
+    static int endOfFragmentName(final String text, int upper) {
+        final int length = text.length();
+        while (upper < length) {
+            final int c = text.codePointAt(upper);
+            if (!Character.isUnicodeIdentifierPart(c)) break;
+            upper += Character.charCount(c);
+        }
+        return upper;
+    }
+
+    /**
      * Parses a <cite>Well Know Text</cite> (WKT).
      *
      * @param  text The text to be parsed.
@@ -238,7 +255,22 @@ abstract class AbstractParser implements
         warnings = null;
         ignoredElements.clear();
         ArgumentChecks.ensureNonEmpty("text", text);
-        final Element element = new Element("<root>", new Element(this, text, position,
null));
+        Element fragment;
+        int lower = CharSequences.skipLeadingWhitespaces(text, position.getIndex(), text.length());
+        if (lower < text.length() && text.charAt(lower) == Symbols.FRAGMENT_VALUE)
{
+            final int upper = endOfFragmentName(text, ++lower);
+            final String id = text.substring(lower, upper);
+            fragment = fragments.get(id);
+            if (fragment == null) {
+                position.setErrorIndex(lower);
+                throw new LocalizedParseException(errorLocale, Errors.Keys.NoSuchValue_1,
new Object[] {id}, lower);
+            }
+            position.setIndex(upper);
+            fragment = new Element(fragment);
+        } else {
+            fragment = new Element(this, text, position, null);
+        }
+        final Element element = new Element("<root>", fragment);
         final Object object = parseObject(element);
         element.close(ignoredElements);
         return object;

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java?rev=1737000&r1=1736999&r2=1737000&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8]
(original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8]
Tue Mar 29 11:24:13 2016
@@ -120,18 +120,18 @@ final class Element implements Serializa
         keyword = name;
         offset  = singleton.offset;
         locale  = singleton.locale;
-        list    = new LinkedList<>();   // Needs to be a modifiable list.
+        list    = new LinkedList<>();                           // Needs to be a modifiable
list.
         list.add(singleton);
     }
 
     /**
      * Creates a modifiable copy of the given element.
      */
-    private Element(final Element toCopy) {
+    Element(final Element toCopy) {
         keyword = toCopy.keyword;
         offset  = toCopy.offset;
         locale  = toCopy.locale;
-        list    = new LinkedList<>(toCopy.list);   // Needs to be a modifiable list.
+        list    = new LinkedList<>(toCopy.list);                // Needs to be a modifiable
list.
         final ListIterator<Object> it = list.listIterator();
         while (it.hasNext()) {
             final Object value = it.next();
@@ -226,12 +226,7 @@ final class Element implements Serializa
                  * to environment variables in Unix. If we find the "$" character, get the
identifier behind "$"
                  * and insert the corresponding WKT fragment here.
                  */
-                int upper = ++lower;      // Increment of 1 is okay because FRAGMENT_VALUE
is a 'char'.
-                while (upper < length) {
-                    final int c = text.codePointAt(upper);
-                    if (!Character.isUnicodeIdentifierPart(c)) break;
-                    upper += Character.charCount(c);
-                }
+                final int upper = AbstractParser.endOfFragmentName(text, ++lower);
                 final String id = text.substring(lower, upper);
                 Element fragment = parser.fragments.get(id);
                 if (fragment == null) {
@@ -268,7 +263,7 @@ final class Element implements Serializa
                      * parsed text.
                      */
                     final int n = Character.charCount(closingQuote);
-                    lower += Character.charCount(firstChar) - n;    // This will usually
let 'lower' unchanged.
+                    lower += Character.charCount(firstChar) - n;        // This will usually
let 'lower' unchanged.
                     CharSequence content = null;
                     do {
                         final int upper = text.indexOf(closingQuote, lower += n);
@@ -276,7 +271,7 @@ final class Element implements Serializa
                             throw missingCharacter(closingQuote, lower, position);
                         }
                         if (content == null) {
-                            content = text.substring(lower, upper);   // First text fragment,
and usually the only one.
+                            content = text.substring(lower, upper);     // First text fragment,
and usually the only one.
                         } else {
                             /*
                              * We will enter in this block only if we found at least one
double quote.
@@ -309,7 +304,7 @@ final class Element implements Serializa
                     switch (valueType) {
                         case TEMPORAL: value = parser.parseDate  (text, position); break;
                         case NUMERIC:  value = parser.parseNumber(text, position); break;
-                        default: throw new AssertionError(valueType);  // Should never happen.
+                        default: throw new AssertionError(valueType);                   
   // Should never happen.
                     }
                     if (value == null) {
                         // Do not update the error index; it is already updated by NumberFormat.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java?rev=1737000&r1=1736999&r2=1737000&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java
[UTF-8] Tue Mar 29 11:24:13 2016
@@ -727,6 +727,9 @@ public class CoordinateOperationInferenc
             }
         }
         properties.put(ReferencingServices.OPERATION_TYPE_KEY, type);
+        if (Conversion.class.isAssignableFrom(type)) {
+            properties.replace(IdentifiedObject.NAME_KEY, AXIS_CHANGES, IDENTITY);
+        }
         return factorySIS.createSingleOperation(properties, sourceCRS, targetCRS, null, method,
transform);
     }
 
@@ -763,25 +766,26 @@ public class CoordinateOperationInferenc
                                             final CoordinateOperation step2)
             throws FactoryException
     {
-        if (isIdentity(step1)) return step2;
-        if (isIdentity(step2)) return step1;
         final MathTransform mt1 = step1.getMathTransform();
         final MathTransform mt2 = step2.getMathTransform();
+        if (step1 instanceof Conversion && mt1.isIdentity()) return step2;
+        if (step2 instanceof Conversion && mt2.isIdentity()) return step1;
         final CoordinateReferenceSystem sourceCRS = step1.getSourceCRS();
         final CoordinateReferenceSystem targetCRS = step2.getTargetCRS();
-        CoordinateOperation step = null;
-        if (step1.getName() == AXIS_CHANGES && mt1.getSourceDimensions() == mt1.getTargetDimensions())
step = step2;
-        if (step2.getName() == AXIS_CHANGES && mt2.getSourceDimensions() == mt2.getTargetDimensions())
step = step1;
-        if (step instanceof SingleOperation) {
-            /*
-             * Applies only on operation in order to avoid merging with PassThroughOperation.
-             * Also applies only if the transform to hide has identical source and target
-             * dimensions in order to avoid mismatch with the method's dimensions.
-             */
-            final MathTransformFactory mtFactory = factorySIS.getMathTransformFactory();
-            return createFromMathTransform(new HashMap<>(IdentifiedObjects.getProperties(step)),
-                   sourceCRS, targetCRS, mtFactory.createConcatenatedTransform(mt1, mt2),
-                   ((SingleOperation) step).getMethod(), SingleOperation.class);
+        /*
+         * If one of the transform performs nothing more than a change of axis order or units,
do
+         * not expose that conversion in a ConcatenatedTransform.  Instead, merge that conversion
+         * with the "main" operation. The intend is to simplify the operation chain by hidding
+         * trivial operations.
+         */
+        CoordinateOperation main = null;
+        if (step1.getName() == AXIS_CHANGES && mt1.getSourceDimensions() == mt1.getTargetDimensions())
main = step2;
+        if (step2.getName() == AXIS_CHANGES && mt2.getSourceDimensions() == mt2.getTargetDimensions())
main = step1;
+        if (main instanceof SingleOperation) {
+            final MathTransform mt = factorySIS.getMathTransformFactory().createConcatenatedTransform(mt1,
mt2);
+            return createFromMathTransform(new HashMap<>(IdentifiedObjects.getProperties(main)),
+                   sourceCRS, targetCRS, mt, ((SingleOperation) main).getMethod(),
+                   (main instanceof Transformation) ? Transformation.class : SingleOperation.class);
         }
         return factory.createConcatenatedOperation(defaultName(sourceCRS, targetCRS), step1,
step2);
     }
@@ -818,7 +822,7 @@ public class CoordinateOperationInferenc
      * are usually datum shift and must be visible.
      */
     private static boolean isIdentity(final CoordinateOperation operation) {
-        return (operation == null) || ((operation instanceof Conversion) && operation.getMathTransform().isIdentity());
+        return (operation instanceof Conversion) && operation.getMathTransform().isIdentity();
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java?rev=1737000&r1=1736999&r2=1737000&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java
[UTF-8] Tue Mar 29 11:24:13 2016
@@ -16,19 +16,29 @@
  */
 package org.apache.sis.referencing.operation;
 
+import java.text.ParseException;
 import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.SingleOperation;
+import org.opengis.referencing.operation.Projection;
+import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.io.wkt.WKTFormat;
+
+import static org.apache.sis.internal.referencing.Formulas.LINEAR_TOLERANCE;
+import static org.apache.sis.internal.referencing.Formulas.ANGULAR_TOLERANCE;
 
 // Test dependencies
 import org.apache.sis.referencing.operation.transform.MathTransformTestCase;
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.junit.BeforeClass;
 import org.junit.AfterClass;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.opengis.test.Assert.*;
 
 
 /**
@@ -47,17 +57,33 @@ import static org.junit.Assert.*;
 })
 public final strictfp class CoordinateOperationInferenceTest extends MathTransformTestCase
{
     /**
+     * Tolerance threshold for strict comparisons of floating point numbers.
+     * This constant can be used like below, where {@code expected} and {@code actual} are
{@code double} values:
+     *
+     * {@preformat java
+     *     assertEquals(expected, actual, STRICT);
+     * }
+     */
+    private static final double STRICT = 0;
+
+    /**
      * The transformation factory to use for testing.
      */
     private static DefaultCoordinateOperationFactory factory;
 
     /**
+     * The parser to use for WKT strings used in this test.
+     */
+    private static WKTFormat parser;
+
+    /**
      * Creates a new {@link DefaultCoordinateOperationFactory} to use for testing purpose.
      * The same factory will be used for all tests in this class.
      */
     @BeforeClass
     public static void createFactory() {
         factory = new DefaultCoordinateOperationFactory();
+        parser  = new WKTFormat(null, null);
     }
 
     /**
@@ -66,6 +92,14 @@ public final strictfp class CoordinateOp
     @AfterClass
     public static void disposeFactory() {
         factory = null;
+        parser  = null;
+    }
+
+    /**
+     * Returns the CRS for the given Well Known Text.
+     */
+    private static CoordinateReferenceSystem parse(final String wkt) throws ParseException
{
+        return (CoordinateReferenceSystem) parser.parseObject(wkt);
     }
 
     /**
@@ -92,4 +126,66 @@ public final strictfp class CoordinateOp
         assertSame("targetCRS",  crs, operation.getTargetCRS());
         assertTrue("isIdentity", operation.getMathTransform().isIdentity());
     }
+
+    /**
+     * Tests conversion from a geographic to a projected CRS without datum of axis changes.
+     *
+     * @throws ParseException if the CRS used in this test can not be parsed.
+     * @throws FactoryException if the operation can not be created.
+     * @throws TransformException if an error occurred while converting the test points.
+     */
+    @Test
+    @DependsOnMethod("testIdentityTransform")
+    public void testGeographicToProjected() throws ParseException, FactoryException, TransformException
{
+        /*
+         * The fist keyword in WKT below should be "GeodeticCRS" in WKT 2, but we use the
WKT 1 keyword ("GEOGCS")
+         * for allowing inclusion in ProjectedCRS.  SIS is okay with mixed WKT versions,
but this is of course not
+         * something to recommend in production.
+         */
+        parser.addFragment("Sphere",
+                "GEOGCS[“Sphere”,\n" +
+                "  Datum[“Sphere”, Ellipsoid[“Sphere”, 6370997, 0]],\n" +
+                "  CS[ellipsoidal, 2],\n" +
+                "  Axis[“Longitude (λ)”, EAST],\n" +
+                "  Axis[“Latitude (φ)”, NORTH],\n" +
+                "  Unit[“degree”, 0.017453292519943295]]");
+
+        final CoordinateReferenceSystem sourceCRS = parse("$Sphere");
+        final CoordinateReferenceSystem targetCRS = parse(
+                "ProjectedCRS[“UTM”,\n" +
+                "  $Sphere,\n" +
+                "  Conversion[“UTM”,\n" +
+                "    Method[“Transverse Mercator”],\n" +
+                "    Parameter[“Longitude of natural origin”, 170],\n" +
+                "    Parameter[“Latitude of natural origin”, 50],\n" +
+                "    Parameter[“Scale factor at natural origin”, 0.95]],\n" +
+                "  CS[Cartesian, 2],\n" +
+                "  Axis[“x”, EAST],\n" +
+                "  Axis[“y”, NORTH],\n" +
+                "  Unit[“US survey foot”, 0.304800609601219]]");
+
+        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        assertSame("sourceCRS", sourceCRS, operation.getSourceCRS());
+        assertSame("targetCRS", targetCRS, operation.getTargetCRS());
+        assertInstanceOf("operation", Projection.class, operation);
+
+        final ParameterValueGroup param = ((SingleOperation) operation).getParameterValues();
+        assertEquals("semi_major",     6370997, param.parameter("semi_major"        ).doubleValue(),
STRICT);
+        assertEquals("semi_minor",     6370997, param.parameter("semi_minor"        ).doubleValue(),
STRICT);
+        assertEquals("latitude_of_origin",  50, param.parameter("latitude_of_origin").doubleValue(),
STRICT);
+        assertEquals("central_meridian",   170, param.parameter("central_meridian"  ).doubleValue(),
STRICT);
+        assertEquals("scale_factor",      0.95, param.parameter("scale_factor"      ).doubleValue(),
STRICT);
+        assertEquals("false_easting",        0, param.parameter("false_easting"     ).doubleValue(),
STRICT);
+        assertEquals("false_northing",       0, param.parameter("false_northing"    ).doubleValue(),
STRICT);
+
+        transform = operation.getMathTransform();
+        tolerance = ANGULAR_TOLERANCE;
+        verifyTransform(new double[] {170, 50}, new double[] {0, 0});
+        validate();
+
+        transform = transform.inverse();
+        tolerance = LINEAR_TOLERANCE;
+        verifyTransform(new double[] {0, 0}, new double[] {170, 50});
+        validate();
+    }
 }



Mime
View raw message