sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1548775 [2/6] - in /sis/branches/JDK6: ./ core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/geometry/ core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gml/ core/sis-metadata/src/main/java/org/apache/sis/metadata/ cor...
Date Sat, 07 Dec 2013 01:51:00 GMT
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -16,16 +16,13 @@
  */
 package org.apache.sis.internal.referencing;
 
-import java.util.Map;
-import java.util.HashMap;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem;
+import org.apache.sis.util.Characters;
 import org.apache.sis.util.Static;
 
 import static org.opengis.referencing.cs.AxisDirection.*;
-
-// Related to JDK7
-import org.apache.sis.internal.jdk7.Objects;
+import static org.apache.sis.util.CharSequences.*;
 
 
 /**
@@ -46,30 +43,31 @@ public final class AxisDirections extend
     /**
      * For each direction, the opposite direction.
      */
-    private static final Map<AxisDirection,AxisDirection> opposites = new HashMap<AxisDirection,AxisDirection>(35);
+    private static final AxisDirection[] OPPOSITES = new AxisDirection[DISPLAY_DOWN.ordinal() + 1];
     static {
-        opposites.put(OTHER, OTHER);
-        final AxisDirection[] dir = {
-            NORTH,            SOUTH,
-            NORTH_NORTH_EAST, SOUTH_SOUTH_WEST,
-            NORTH_EAST,       SOUTH_WEST,
-            EAST_NORTH_EAST,  WEST_SOUTH_WEST,
-            EAST,             WEST,
-            EAST_SOUTH_EAST,  WEST_NORTH_WEST,
-            SOUTH_EAST,       NORTH_WEST,
-            SOUTH_SOUTH_EAST, NORTH_NORTH_WEST,
-            UP,               DOWN,
-            FUTURE,           PAST,
-            COLUMN_POSITIVE,  COLUMN_NEGATIVE,
-            ROW_POSITIVE,     ROW_NEGATIVE,
-            DISPLAY_RIGHT,    DISPLAY_LEFT,
-            DISPLAY_DOWN,     DISPLAY_UP // y values increase toward down.
-        };
-        for (int i=0; i<dir.length; i++) {
-            if (opposites.put(dir[i], dir[i ^ 1]) != null) {
-                throw new AssertionError(i);
-            }
-        }
+        put(OTHER,            OTHER);
+        put(NORTH,            SOUTH);
+        put(NORTH_NORTH_EAST, SOUTH_SOUTH_WEST);
+        put(NORTH_EAST,       SOUTH_WEST);
+        put(EAST_NORTH_EAST,  WEST_SOUTH_WEST);
+        put(EAST,             WEST);
+        put(EAST_SOUTH_EAST,  WEST_NORTH_WEST);
+        put(SOUTH_EAST,       NORTH_WEST);
+        put(SOUTH_SOUTH_EAST, NORTH_NORTH_WEST);
+        put(UP,               DOWN);
+        put(FUTURE,           PAST);
+        put(COLUMN_POSITIVE,  COLUMN_NEGATIVE);
+        put(ROW_POSITIVE,     ROW_NEGATIVE);
+        put(DISPLAY_RIGHT,    DISPLAY_LEFT);
+        put(DISPLAY_UP,       DISPLAY_DOWN);
+    }
+
+    /**
+     * Stores the given directions in the {@link #OPPOSITES} array.
+     */
+    private static void put(final AxisDirection dir, final AxisDirection opposite) {
+        OPPOSITES[dir.ordinal()] = opposite;
+        OPPOSITES[opposite.ordinal()] = dir;
     }
 
     /**
@@ -107,16 +105,14 @@ public final class AxisDirections extend
      *   <tr align="center"><td width='50%'>{@code OTHER}</td><td width='50%'>{@code OTHER}</td></tr>
      * </table>
      *
-     * @param  dir The direction for which to return the absolute direction.
-     * @return The direction from the above table.
+     * @param  dir The direction for which to return the absolute direction, or {@code null}.
+     * @return The direction from the above table, or {@code null} if the given direction was null.
      */
     public static AxisDirection absolute(final AxisDirection dir) {
-        if (dir != null) {
-            final AxisDirection opposite = opposite(dir);
-            if (opposite != null) {
-                if (opposite.ordinal() < dir.ordinal()) {
-                    return opposite;
-                }
+        final AxisDirection opposite = opposite(dir);
+        if (opposite != null) {
+            if (opposite.ordinal() < dir.ordinal()) {
+                return opposite;
             }
         }
         return dir;
@@ -128,23 +124,64 @@ public final class AxisDirections extend
      * The same applies to {@code EAST}-{@code WEST}, {@code UP}-{@code DOWN} and {@code FUTURE}-{@code PAST},
      * <i>etc.</i> If the given axis direction has no opposite, then this method returns {@code null}.
      *
-     * @param  dir The direction for which to return the opposite direction.
+     * @param  dir The direction for which to return the opposite direction, or {@code null}.
      * @return The opposite direction, or {@code null} if none or unknown.
      */
-    public static AxisDirection opposite(final AxisDirection dir) {
-        return opposites.get(dir);
+    public static AxisDirection opposite(AxisDirection dir) {
+        if (dir != null) {
+            final int ordinal = dir.ordinal();
+            if (ordinal >= 0 && ordinal < OPPOSITES.length) {
+                dir = OPPOSITES[ordinal];
+            }
+        }
+        return dir;
     }
 
     /**
      * Returns {@code true} if the given direction is an "opposite" direction.
-     * If this method can not determine if the given direction is an "opposite"
-     * one, then it conservatively returns {@code true}.
+     * If the given argument is {@code null} or is not a known direction, then
+     * this method conservatively returns {@code false}.
      *
      * @param  dir The direction to test, or {@code null}.
      * @return {@code true} if the given direction is an "opposite".
      */
     public static boolean isOpposite(final AxisDirection dir) {
-        return Objects.equals(dir, opposite(absolute(dir)));
+        final AxisDirection opposite = opposite(dir);
+        return (opposite != null) && opposite.ordinal() < dir.ordinal();
+    }
+
+    /**
+     * Returns {@code true} if the given direction is a spatial axis direction (including vertical and geocentric axes).
+     * The current implementation conservatively returns {@code true} for every non-null directions except a hard-coded
+     * set of directions which are known to be non-spatial. We conservatively accept unknown axis directions because
+     * some of them are created from strings like "South along 90°E".
+     *
+     * <p>If the {@code image} argument is {@code true}, then this method additionally accepts grid and display
+     * axis directions.</p>
+     *
+     * <p>The rules implemented by this method may change in any future SIS version.</p>
+     *
+     * @param  dir The direction to test, or {@code null}.
+     * @param  image {@code true} for accepting grid and image axis directions in addition to spatial ones.
+     * @return {@code true} if the given direction is presumed for spatial CS.
+     */
+    public static boolean isSpatialOrCustom(final AxisDirection dir, final boolean image) {
+        if (dir == null) return false;
+        final int ordinal = dir.ordinal();
+        return ordinal < FUTURE.ordinal() || ordinal > (image ? PAST : DISPLAY_DOWN).ordinal();
+    }
+
+    /**
+     * Returns {@code true} if the given direction is {@code COLUMN_POSITIVE}, {@code COLUMN_NEGATICE},
+     * {@code ROW_POSITIVE} or {@code ROW_NEGATIVE}.
+     *
+     * @param  dir The direction to test, or {@code null}.
+     * @return {@code true} if the given direction is presumed for grid CS.
+     */
+    public static boolean isGrid(final AxisDirection dir) {
+        if (dir == null) return false;
+        final int ordinal = dir.ordinal();
+        return ordinal >= COLUMN_POSITIVE.ordinal() && ordinal <= ROW_NEGATIVE.ordinal();
     }
 
     /**
@@ -174,4 +211,106 @@ public final class AxisDirections extend
         }
         return fallback;
     }
+
+    /**
+     * Searches for a axis direction having the given name in the specified list of directions.
+     * This method compares the given name with the name of each {@code AxisDirection} in a lenient way:
+     *
+     * <ul>
+     *   <li>Comparisons are case-insensitive.</li>
+     *   <li>Any character which is not a letter or a digit is ignored. For example {@code "NorthEast"},
+     *       {@code "North-East"} and {@code "NORTH_EAST"} are considered equivalent.</li>
+     *   <li>This method accepts abbreviations as well, for example if the given {@code name} is {@code "W"},
+     *       then it will be considered equivalent to {@code "WEST"}.</li>
+     * </ul>
+     *
+     * @param  name The name of the axis direction to search.
+     * @param  directions The list of axis directions in which to search.
+     * @return The first axis direction having a name matching the given one, or {@code null} if none.
+     */
+    public static AxisDirection find(final String name, final AxisDirection[] directions) {
+        for (final AxisDirection candidate : directions) {
+            final String identifier = candidate.name();
+            if (equalsFiltered(name, identifier, Characters.Filter.LETTERS_AND_DIGITS, true)
+                    || isAcronymForWords(name, identifier))
+            {
+                return candidate;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Searches pre-defined {@link AxisDirection} for a given name. This method searches for a match in the set
+     * of known axis directions as returned by {@link AxisDirections#values()}, plus a few special cases like
+     * "<cite>Geocentre &gt; equator/90°E</cite>". The later are used in the EPSG database for geocentric CRS.
+     *
+     * <p>This method does not know about {@link DirectionAlongMeridian}. The later is a parser which may create
+     * new directions, while this method searches only in a set of predefined directions and never create new ones.</p>
+     *
+     * @param  name The name of the axis direction to search.
+     * @return The first axis direction having a name matching the given one, or {@code null} if none.
+     */
+    public static AxisDirection valueOf(String name) {
+        name = trimWhitespaces(name.replace('_', ' '));
+        final AxisDirection[] directions = AxisDirection.values();
+        AxisDirection candidate = find(name, directions);
+        if (candidate == null) {
+            /*
+             * No match found when using the pre-defined axis name. Searches among
+             * the set of geocentric directions. Expected directions are:
+             *
+             *    Geocentre > equator/PM      or    Geocentre > equator/0°E
+             *    Geocentre > equator/90dE    or    Geocentre > equator/90°E
+             *    Geocentre > north pole
+             */
+            int d = name.indexOf('>');
+            if (d >= 0 && equalsIgnoreCase(name, 0, skipTrailingWhitespaces(name, 0, d), "Geocentre")) {
+                final int length = name.length();
+                d = skipLeadingWhitespaces(name, d+1, length);
+                int s = name.indexOf('/', d);
+                if (s < 0) {
+                    if (equalsIgnoreCase(name, d, length, "north pole")) {
+                        return GEOCENTRIC_Z; // "Geocentre > north pole"
+                    }
+                } else if (equalsIgnoreCase(name, d, skipTrailingWhitespaces(name, d, s), "equator")) {
+                    s = skipLeadingWhitespaces(name, s+1, length);
+                    if (equalsIgnoreCase(name, s, length, "PM")) {
+                        return GEOCENTRIC_X; // "Geocentre > equator/PM"
+                    }
+                    /*
+                     * At this point, the name may be "Geocentre > equator/0°E",
+                     * "Geocentre > equator/90°E" or "Geocentre > equator/90dE".
+                     * Parse the number, limiting the scan to 6 characters for
+                     * avoiding a NumberFormatException.
+                     */
+                    final int stopAt = Math.min(s + 6, length);
+                    for (int i=s; i<stopAt; i++) {
+                        final char c = name.charAt(i);
+                        if (c < '0' || c > '9') {
+                            if (i == s) break;
+                            final int n = Integer.parseInt(name.substring(s, i));
+                            i = skipLeadingWhitespaces(name, i, length);
+                            if (equalsIgnoreCase(name, i, length, "°E") || equalsIgnoreCase(name, i, length, "dE")) {
+                                switch (n) {
+                                    case  0: return GEOCENTRIC_X; // "Geocentre > equator/0°E"
+                                    case 90: return GEOCENTRIC_Y; // "Geocentre > equator/90°E"
+                                }
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns {@code true} if the given sub-sequence is equal to the given keyword, ignoring case.
+     */
+    private static boolean equalsIgnoreCase(final String name, final int lower, final int upper, final String keyword) {
+        final int length = upper - lower;
+        return (length == keyword.length()) && name.regionMatches(true, lower, keyword, 0, length);
+    }
 }

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -32,7 +32,9 @@ import org.apache.sis.metadata.iso.citat
 import org.apache.sis.referencing.cs.DefaultCartesianCS;
 import org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis;
 
+import static java.util.Collections.singletonMap;
 import static javax.measure.unit.NonSI.DEGREE_ANGLE;
+import static org.opengis.referencing.cs.CoordinateSystemAxis.NAME_KEY;
 
 
 /**
@@ -209,10 +211,10 @@ public enum Convention {
      * <var>{@linkplain DefaultCoordinateSystemAxis#NORTHING Northing}</var>
      * in metres, where the "Other" axis is toward prime meridian.
      */
-    private static final DefaultCartesianCS LEGACY = new DefaultCartesianCS("Legacy",
-            new DefaultCoordinateSystemAxis("X", AxisDirection.OTHER, SI.METRE),
-            new DefaultCoordinateSystemAxis("Y", AxisDirection.EAST,  SI.METRE),
-            new DefaultCoordinateSystemAxis("Z", AxisDirection.NORTH, SI.METRE));
+    private static final DefaultCartesianCS LEGACY = new DefaultCartesianCS(singletonMap(NAME_KEY, "Legacy geocentric"),
+            new DefaultCoordinateSystemAxis(singletonMap(NAME_KEY, "Geocentric X"), "X", AxisDirection.OTHER, SI.METRE),
+            new DefaultCoordinateSystemAxis(singletonMap(NAME_KEY, "Geocentric Y"), "Y", AxisDirection.EAST,  SI.METRE),
+            new DefaultCoordinateSystemAxis(singletonMap(NAME_KEY, "Geocentric Z"), "Z", AxisDirection.NORTH, SI.METRE));
 
     /**
      * If non-null, forces {@code PRIMEM} and {@code PARAMETER} angular units to this field

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -18,6 +18,7 @@ package org.apache.sis.io.wkt;
 
 import java.io.Console;
 import java.io.PrintWriter;
+import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.parameter.GeneralParameterValue;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
@@ -54,6 +55,7 @@ import org.apache.sis.internal.util.X364
  * @version 0.4
  * @module
  */
+@XmlTransient
 public class FormattableObject {
     /**
      * The formatter for the {@link #toWKT()} and {@link #toString()} methods.

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -16,10 +16,9 @@
  */
 
 /**
- * <a href="http://www.geoapi.org/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
- * Known Text</cite> (WKT)</a> parsing and formatting. This package provides the internal mechanism used
- * by SIS implementation. Most users do not need to know about it, except if they want to customize the
- * parsing process or the WKT output. For example this package allows to:
+ * <cite>Well Known Text</cite> (WKT) parsing and formatting.
+ * This package provides the internal mechanism used by SIS implementation. Most users do not need to know about it,
+ * except if they want to customize the parsing process or the WKT output. For example this package allows to:
  *
  * <ul>
  *   <li>{@linkplain org.apache.sis.io.wkt.WKTFormat#setConvention Format the parameters using the names

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -25,6 +25,7 @@ import java.util.Locale;
 import java.io.Serializable;
 import javax.xml.bind.annotation.XmlID;
 import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@@ -36,6 +37,7 @@ import org.opengis.referencing.ObjectFac
 import org.opengis.referencing.AuthorityFactory;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.ReferenceIdentifier;
+import org.apache.sis.internal.jaxb.referencing.RS_IdentifierSingleton;
 import org.apache.sis.io.wkt.FormattableObject;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.util.Immutable;
@@ -104,8 +106,15 @@ import org.apache.sis.internal.jdk7.Obje
 @Immutable
 @ThreadSafe
 @XmlType(name="IdentifiedObjectType", propOrder={
-    "identifier",
-    "name"
+    "identifiers",
+    "name",
+    "remarks"
+})
+@XmlSeeAlso({
+    AbstractReferenceSystem.class,
+    org.apache.sis.referencing.datum.AbstractDatum.class,
+    org.apache.sis.referencing.datum.DefaultEllipsoid.class,
+    org.apache.sis.referencing.datum.DefaultPrimeMeridian.class
 })
 public class AbstractIdentifiedObject extends FormattableObject implements IdentifiedObject,
         LenientComparable, Deprecable, Serializable
@@ -119,7 +128,6 @@ public class AbstractIdentifiedObject ex
      * The name for this object or code. Should never be {@code null}.
      *
      * @see #getName()
-     * @see #getIdentifier()
      */
     @XmlElement
     private final ReferenceIdentifier name;
@@ -139,13 +147,15 @@ public class AbstractIdentifiedObject ex
      * "no identifiers" because we may get both on unmarshalling.</p>
      *
      * @see #getIdentifiers()
-     * @see #getIdentifier()
      */
+    @XmlElement(name = "identifier")
+    @XmlJavaTypeAdapter(RS_IdentifierSingleton.class)
     private final Set<ReferenceIdentifier> identifiers;
 
     /**
      * Comments on or information about this object, or {@code null} if none.
      */
+    @XmlElement(name = "remarks")
     private final InternationalString remarks;
 
     /**
@@ -157,6 +167,18 @@ public class AbstractIdentifiedObject ex
     private transient int hashCode;
 
     /**
+     * Constructs a new object in which every attributes are set to a null value.
+     * <strong>This is not a valid object.</strong> This constructor is strictly
+     * reserved to JAXB, which will assign values to the fields using reflexion.
+     */
+    AbstractIdentifiedObject() {
+        name        = null;
+        alias       = null;
+        identifiers = null;
+        remarks     = null;
+    }
+
+    /**
      * Constructs an object from the given properties. Keys are strings from the table below.
      * The map given in argument shall contain an entry at least for the
      * {@value org.opengis.referencing.IdentifiedObject#NAME_KEY} key.
@@ -419,18 +441,6 @@ public class AbstractIdentifiedObject ex
     }
 
     /**
-     * Returns the first identifier found, or {@code null} if none.
-     * This method is invoked by JAXB at marshalling time.
-     *
-     * @see #name
-     */
-    @XmlElement(name = "identifier")
-    final ReferenceIdentifier getIdentifier() {
-        final Iterator<ReferenceIdentifier> it = iterator(identifiers);
-        return (it != null && it.hasNext()) ? it.next() : null;
-    }
-
-    /**
      * Returns comments on or information about this object, including data source information.
      *
      * @return The remarks, or {@code null} if none.
@@ -479,24 +489,65 @@ public class AbstractIdentifiedObject ex
 
     /**
      * Returns {@code true} if either the {@linkplain #getName() primary name} or at least
-     * one {@linkplain #getAlias() alias} matches the specified string.
-     * This method returns {@code true} if the given name is equal to one of the following names,
-     * regardless of any authority:
+     * one {@linkplain #getAlias() alias} matches the given string according heuristic rules.
+     * The default implementation returns {@code true} if the given {@code name} is equal,
+     * ignoring aspects documented below, to one of the following names:
      *
      * <ul>
-     *   <li>The {@linkplain #getName() primary name} of this object.</li>
-     *   <li>The {@linkplain org.opengis.util.GenericName#toFullyQualifiedName() fully qualified name} of an alias.</li>
-     *   <li>The {@linkplain org.opengis.util.ScopedName#tail() tail} of an alias.</li>
-     *   <li>The tail of the previous tail, recursively up to the {@linkplain org.opengis.util.ScopedName#tip() tip}.</li>
+     *   <li>The {@linkplain #getName() primary name}'s {@linkplain NamedIdentifier#getCode() code}
+     *       (without {@linkplain NamedIdentifier#getCodeSpace() codespace}).</li>
+     *   <li>Any {@linkplain #getAlias() alias}'s {@linkplain NamedIdentifier#tip() tip}
+     *       (without {@linkplain NamedIdentifier#scope() scope} and namespace).</li>
      * </ul>
      *
+     * The comparison ignores the following aspects:
+     * <ul>
+     *   <li>Lower/upper cases.</li>
+     *   <li>Some Latin diacritical signs (e.g. {@code "Réunion"} and {@code "Reunion"} are considered equal).</li>
+     *   <li>All characters that are not {@linkplain Character#isLetterOrDigit(int) letters or digits}
+     *       (e.g. {@code "Mercator (1SP)"} and {@code "Mercator_1SP"} are considered equal).</li>
+     *   <li>Namespaces or scopes, because this method is typically invoked with either the value of an other
+     *       <code>IdentifiedObject.getName().getCode()</code> or with the <cite>Well Known Text</cite> (WKT)
+     *       projection or parameter name.</li>
+     * </ul>
+     *
+     * {@section Usage}
+     * This method is invoked by SIS when comparing in {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} mode
+     * two objects that can be differentiated only by some identifier (name or alias), like
+     * {@linkplain org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis coordinate system axes},
+     * {@linkplain org.apache.sis.referencing.datum.AbstractDatum datum},
+     * {@linkplain org.apache.sis.parameter.AbstractParameterDescriptor parameters} and
+     * {@linkplain org.apache.sis.referencing.operation.DefaultOperationMethod operation methods}.
+     * See {@link #equals(Object, ComparisonMode)} for more information.
+     *
+     * <p>This method is also invoked when searching a parameter or operation method for a given name.
+     * For example the same projection is known as {@code "Mercator (variant A)"} (the primary name according EPSG)
+     * and {@code "Mercator (1SP)"} (the legacy name prior EPSG 7.6). Since the later is still in frequent use, SIS
+     * accepts it as an alias of the <cite>Mercator (variant A)</cite> projection.</p>
+     *
+     * {@section Overriding by subclasses}
+     * Some subclasses add more flexibility to the comparisons:
+     * <ul>
+     *   <li>{@linkplain org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#isHeuristicMatchForName(String)
+     *       Comparisons of coordinate system axis names} consider {@code "Lat"}, {@code "Latitude"} and
+     *       {@code "Geodetic latitude"} as synonymous, and likewise for longitude.</li>
+     *   <li>{@linkplain org.apache.sis.referencing.datum.DefaultGeodeticDatum#isHeuristicMatchForName(String)
+     *       Comparisons of geodetic datum names} ignore the {@code "D_"} prefix, if any.
+     *       This prefix appears in ESRI datum name (e.g. {@code "D_WGS_1984"}).</li>
+     * </ul>
+     *
+     * {@section Future evolutions}
+     * This method implements heuristic rules learned from experience while trying to provide inter-operability
+     * with different data producers. Those rules may be adjusted in any future SIS version according experience
+     * gained while working with more data producers.
+     *
      * @param  name The name to compare with the object name or aliases.
      * @return {@code true} if the primary name of at least one alias matches the specified {@code name}.
      *
-     * @see IdentifiedObjects#nameMatches(IdentifiedObject, String)
+     * @see IdentifiedObjects#isHeuristicMatchForName(IdentifiedObject, String)
      */
-    public boolean nameMatches(final String name) {
-        return IdentifiedObjects.nameMatches(this, alias, name);
+    public boolean isHeuristicMatchForName(final String name) {
+        return IdentifiedObjects.isHeuristicMatchForName(this, alias, name);
     }
 
     /**
@@ -515,17 +566,20 @@ public class AbstractIdentifiedObject ex
      * </ul>
      *
      * {@section Exceptions to the above rules}
-     * Some subclasses (especially {@link org.apache.sis.referencing.datum.AbstractDatum}
-     * and {@link org.apache.sis.parameter.AbstractParameterDescriptor}) will test for the
-     * {@linkplain #getName() name}, since objects with different name have completely
-     * different meaning. For example nothing differentiate the {@code "semi_major"} and
-     * {@code "semi_minor"} parameters except the name. The name comparison may be loose
-     * however, i.e. we may accept a name matching an alias.
+     * Some subclasses (especially
+     * {@link org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis},
+     * {@link org.apache.sis.referencing.datum.AbstractDatum} and
+     * {@link org.apache.sis.parameter.AbstractParameterDescriptor}) will compare the
+     * {@linkplain #getName() name} even in {@code IGNORE_METADATA} mode,
+     * because objects of those types with different names have completely different meaning.
+     * For example nothing differentiate the {@code "semi_major"} and {@code "semi_minor"} parameters except the name.
+     * The name comparison may be lenient however, i.e. the rules may accept a name matching an alias.
+     * See {@link #isHeuristicMatchForName(String)} for more information.
      *
      * @param  object The object to compare to {@code this}.
      * @param  mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or
      *         {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only properties
-     *         relevant to transformations.
+     *         relevant to coordinate transformations.
      * @return {@code true} if both objects are equal.
      *
      * @see #hashCode(ComparisonMode)

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -78,6 +78,16 @@ public class AbstractReferenceSystem ext
     private final InternationalString scope;
 
     /**
+     * Constructs a new object in which every attributes are set to a null value.
+     * <strong>This is not a valid object.</strong> This constructor is strictly
+     * reserved to JAXB, which will assign values to the fields using reflexion.
+     */
+    AbstractReferenceSystem() {
+        domainOfValidity = null;
+        scope = null;
+    }
+
+    /**
      * Constructs a new reference system with the same values than the specified one.
      * This copy constructor provides a way to convert an arbitrary implementation into a SIS one
      * or a user-defined one (as a subclass), usually in order to leverage some implementation-specific API.
@@ -181,31 +191,30 @@ public class AbstractReferenceSystem ext
      * @param  object The object to compare to {@code this}.
      * @param  mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or
      *         {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only properties
-     *         relevant to transformations.
+     *         relevant to coordinate transformations.
      * @return {@code true} if both objects are equal.
      */
     @Override
     public boolean equals(final Object object, final ComparisonMode mode) {
-        if (super.equals(object, mode)) {
-            switch (mode) {
-                case STRICT: {
-                    final AbstractReferenceSystem that = (AbstractReferenceSystem) object;
-                    return Objects.equals(domainOfValidity, that.domainOfValidity) &&
-                           Objects.equals(scope,            that.scope);
-                }
-                case BY_CONTRACT: {
-                    if (!(object instanceof ReferenceSystem)) break;
-                    final ReferenceSystem that = (ReferenceSystem) object;
-                    return deepEquals(getDomainOfValidity(), that.getDomainOfValidity(), mode) &&
-                           deepEquals(getScope(),            that.getScope(), mode);
-                }
-                default: {
-                    // Domain of validity and scope are metadata, so they can be ignored.
-                    return (object instanceof ReferenceSystem);
-                }
+        if (!(object instanceof ReferenceSystem && super.equals(object, mode))) {
+            return false;
+        }
+        switch (mode) {
+            case STRICT: {
+                final AbstractReferenceSystem that = (AbstractReferenceSystem) object;
+                return Objects.equals(domainOfValidity, that.domainOfValidity) &&
+                       Objects.equals(scope,            that.scope);
+            }
+            case BY_CONTRACT: {
+                final ReferenceSystem that = (ReferenceSystem) object;
+                return deepEquals(getDomainOfValidity(), that.getDomainOfValidity(), mode) &&
+                       deepEquals(getScope(),            that.getScope(), mode);
+            }
+            default: {
+                // Domain of validity and scope are metadata, so they can be ignored.
+                return true;
             }
         }
-        return false;
     }
 
     /**

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjects.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjects.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjects.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjects.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -104,7 +104,7 @@ public enum GeodeticObjects {
      *   <tr><th>Ellipsoid axes unit:</th>     <td>{@link SI#METRE}</td></tr>
      * </table></blockquote>
      */
-    WGS84((short) 7030),
+    WGS84((short) 7030, (short) 6326),
 
     /**
      * World Geodetic System 1972.
@@ -120,7 +120,7 @@ public enum GeodeticObjects {
      *   <tr><th>Ellipsoid axes unit:</th>     <td>{@link SI#METRE}</td></tr>
      * </table></blockquote>
      */
-    WGS72((short) 7043),
+    WGS72((short) 7043, (short) 6322),
 
     /**
      * European Terrestrial Reference System 1989.
@@ -142,7 +142,7 @@ public enum GeodeticObjects {
      *        The <cite>Web Map Server</cite> <code>"CRS:83"</code> authority code uses the NAD83 datum,
      *        while the <code>"IGNF:MILLER"</code> authority code uses the GRS80 datum.}
      */
-    ETRS89((short) 7019),
+    ETRS89((short) 7019, (short) 6258),
 
     /**
      * North American Datum 1983.
@@ -165,7 +165,7 @@ public enum GeodeticObjects {
      *        The <cite>Web Map Server</cite> <code>"CRS:83"</code> authority code uses the NAD83 datum,
      *        while the <code>"IGNF:MILLER"</code> authority code uses the GRS80 datum.}
      */
-    NAD83((short) 7019),
+    NAD83((short) 7019, (short) 6269),
 
     /**
      * North American Datum 1927.
@@ -181,7 +181,7 @@ public enum GeodeticObjects {
      *   <tr><th>Ellipsoid axes unit:</th>     <td>{@link SI#METRE}</td></tr>
      * </table></blockquote>
      */
-    NAD27((short) 7008),
+    NAD27((short) 7008, (short) 6267),
 
     /**
      * European Datum 1950.
@@ -197,7 +197,7 @@ public enum GeodeticObjects {
      *   <tr><th>Ellipsoid axes unit:</th>     <td>{@link SI#METRE}</td></tr>
      * </table></blockquote>
      */
-    ED50((short) 7022),
+    ED50((short) 7022, (short) 6230),
 
     /**
      * Unspecified datum based upon the GRS 1980 Authalic Sphere. Spheres use a simpler algorithm for
@@ -215,7 +215,7 @@ public enum GeodeticObjects {
      *
      * @see org.apache.sis.referencing.datum.DefaultEllipsoid#getAuthalicRadius()
      */
-    SPHERE((short) 7048);
+    SPHERE((short) 7048, (short) 6047);
 
     /**
      * The EPSG code of the ellipsoid.
@@ -223,6 +223,11 @@ public enum GeodeticObjects {
     final short ellipsoid;
 
     /**
+     * The EPSG code of the datum.
+     */
+    final short datum;
+
+    /**
      * The cached object. This is initially {@code null}, then set to various kind of objects depending
      * on which method has been invoked. The kind of object stored in this field may change during the
      * application execution.
@@ -231,12 +236,13 @@ public enum GeodeticObjects {
 
     /**
      * Creates a new constant for the given EPSG or SIS codes.
-     * By convention, SIS codes are negative.
      *
      * @param ellipsoid The EPSG code for the ellipsoid.
+     * @param datum     The EPSG code for the datum.
      */
-    private GeodeticObjects(final short ellipsoid) {
+    private GeodeticObjects(final short ellipsoid, final short datum) {
         this.ellipsoid = ellipsoid;
+        this.datum     = datum;
     }
 
     /**
@@ -255,38 +261,40 @@ public enum GeodeticObjects {
     }
 
     /**
-     * Returns the prime meridian associated to this geodetic object.
-     * The following table summarizes the prime meridians known to this class,
-     * together with an enumeration value that can be used for fetching that prime meridian:
+     * Returns the geodetic datum associated to this geodetic object.
+     * The following table summarizes the datums known to this class,
+     * together with an enumeration value that can be used for fetching that datum:
      *
      * <blockquote><table class="sis">
-     *   <tr><th>Name or alias</th> <th>Enum</th>           <th>EPSG</th></tr>
-     *   <tr><td>Greenwich</td>     <td>{@link #WGS84}</td> <td>8901</td></tr>
+     *   <tr><th>Name or alias</th>                                     <th>Enum</th>            <th>EPSG</th></tr>
+     *   <tr><td>European Datum 1950</td>                               <td>{@link #ED50}</td>   <td>6230</td></tr>
+     *   <tr><td>European Terrestrial Reference System 1989</td>        <td>{@link #ETRS89}</td> <td>6258</td></tr>
+     *   <tr><td>North American Datum 1927</td>                         <td>{@link #NAD27}</td>  <td>6267</td></tr>
+     *   <tr><td>North American Datum 1983</td>                         <td>{@link #NAD83}</td>  <td>6269</td></tr>
+     *   <tr><td>Not specified (based on GRS 1980 Authalic Sphere)</td> <td>{@link #SPHERE}</td> <td>6047</td></tr>
+     *   <tr><td>World Geodetic System 1972</td>                        <td>{@link #WGS72}</td>  <td>6322</td></tr>
+     *   <tr><td>World Geodetic System 1984</td>                        <td>{@link #WGS84}</td>  <td>6326</td></tr>
      * </table></blockquote>
      *
-     * @return The prime meridian associated to this constant.
+     * @return The geodetic datum associated to this constant.
      *
-     * @see org.apache.sis.referencing.datum.DefaultPrimeMeridian
-     * @see DatumAuthorityFactory#createPrimeMeridian(String)
+     * @see org.apache.sis.referencing.datum.DefaultGeodeticDatum
+     * @see DatumAuthorityFactory#createGeodeticDatum(String)
      */
-    public PrimeMeridian primeMeridian() {
-        PrimeMeridian object = primeMeridian(cached);
+    public GeodeticDatum datum() {
+        GeodeticDatum object = datum(cached);
         if (object == null) {
             synchronized (this) {
-                object = primeMeridian(cached);
+                object = datum(cached);
                 if (object == null) {
-                    if (this != WGS84) {
-                        object = WGS84.primeMeridian(); // Share the same instance for all constants.
-                    } else {
-                        final DatumAuthorityFactory factory = StandardObjects.datumFactory();
-                        if (factory != null) try {
-                            cached = object = factory.createPrimeMeridian(StandardDefinitions.GREENWICH);
-                            return object;
-                        } catch (FactoryException e) {
-                            StandardObjects.failure(this, "primeMeridian", e);
-                        }
-                        object = StandardDefinitions.primeMeridian();
+                    final DatumAuthorityFactory factory = StandardObjects.datumFactory();
+                    if (factory != null) try {
+                        cached = object = factory.createGeodeticDatum(String.valueOf(datum));
+                        return object;
+                    } catch (FactoryException e) {
+                        StandardObjects.failure(this, "datum", e);
                     }
+                    object = StandardDefinitions.createGeodeticDatum(datum, ellipsoid(), primeMeridian());
                     cached = object;
                 }
             }
@@ -340,17 +348,54 @@ public enum GeodeticObjects {
     }
 
     /**
-     * Returns the prime meridian associated to the given object, or {@code null} if none.
+     * Returns the prime meridian associated to this geodetic object.
+     * The following table summarizes the prime meridians known to this class,
+     * together with an enumeration value that can be used for fetching that prime meridian:
+     *
+     * <blockquote><table class="sis">
+     *   <tr><th>Name or alias</th> <th>Enum</th>           <th>EPSG</th></tr>
+     *   <tr><td>Greenwich</td>     <td>{@link #WGS84}</td> <td>8901</td></tr>
+     * </table></blockquote>
+     *
+     * @return The prime meridian associated to this constant.
+     *
+     * @see org.apache.sis.referencing.datum.DefaultPrimeMeridian
+     * @see DatumAuthorityFactory#createPrimeMeridian(String)
      */
-    private static PrimeMeridian primeMeridian(final IdentifiedObject object) {
-        if (object instanceof PrimeMeridian) {
-            return (PrimeMeridian) object;
+    public PrimeMeridian primeMeridian() {
+        PrimeMeridian object = primeMeridian(cached);
+        if (object == null) {
+            synchronized (this) {
+                object = primeMeridian(cached);
+                if (object == null) {
+                    if (this != WGS84) {
+                        object = WGS84.primeMeridian(); // Share the same instance for all constants.
+                    } else {
+                        final DatumAuthorityFactory factory = StandardObjects.datumFactory();
+                        if (factory != null) try {
+                            cached = object = factory.createPrimeMeridian(StandardDefinitions.GREENWICH);
+                            return object;
+                        } catch (FactoryException e) {
+                            StandardObjects.failure(this, "primeMeridian", e);
+                        }
+                        object = StandardDefinitions.primeMeridian();
+                    }
+                    cached = object;
+                }
+            }
         }
+        return object;
+    }
+
+    /**
+     * Returns the datum associated to the given object, or {@code null} if none.
+     */
+    private static GeodeticDatum datum(final IdentifiedObject object) {
         if (object instanceof GeodeticDatum) {
-            return ((GeodeticDatum) object).getPrimeMeridian();
+            return (GeodeticDatum) object;
         }
         if (object instanceof GeodeticCRS) {
-            return ((GeodeticCRS) object).getDatum().getPrimeMeridian();
+            return ((GeodeticCRS) object).getDatum();
         }
         return null;
     }
@@ -362,13 +407,19 @@ public enum GeodeticObjects {
         if (object instanceof Ellipsoid) {
             return (Ellipsoid) object;
         }
-        if (object instanceof GeodeticDatum) {
-            return ((GeodeticDatum) object).getEllipsoid();
-        }
-        if (object instanceof GeodeticCRS) {
-            return ((GeodeticCRS) object).getDatum().getEllipsoid();
+        final GeodeticDatum datum = datum(object);
+        return (datum != null) ? datum.getEllipsoid() : null;
+    }
+
+    /**
+     * Returns the prime meridian associated to the given object, or {@code null} if none.
+     */
+    private static PrimeMeridian primeMeridian(final IdentifiedObject object) {
+        if (object instanceof PrimeMeridian) {
+            return (PrimeMeridian) object;
         }
-        return null;
+        final GeodeticDatum datum = datum(object);
+        return (datum != null) ? datum.getPrimeMeridian() : null;
     }
 
 

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -23,8 +23,6 @@ import java.util.Iterator;
 import java.util.Collection;
 
 import org.opengis.util.NameSpace;
-import org.opengis.util.LocalName;
-import org.opengis.util.ScopedName;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
@@ -32,11 +30,12 @@ import org.opengis.referencing.Identifie
 import org.opengis.referencing.ReferenceIdentifier;
 
 import org.apache.sis.util.Static;
+import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.metadata.iso.citation.Citations;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-import static org.apache.sis.util.CharSequences.trimWhitespaces;
+import static org.apache.sis.util.Characters.Filter.LETTERS_AND_DIGITS;
 import static org.apache.sis.internal.util.Citations.iterator;
 import static org.apache.sis.internal.util.Citations.identifierMatches;
 
@@ -289,83 +288,87 @@ public final class IdentifiedObjects ext
     }
 
     /**
-     * Returns {@code true} if either the {@linkplain IdentifiedObject#getName() primary name} or
-     * at least one {@linkplain IdentifiedObject#getAlias() alias} matches the specified string.
-     * This method returns {@code true} if the given name is equal to one of the following names,
-     * regardless of any authority:
+     * Returns {@code true} if either the {@linkplain AbstractIdentifiedObject#getName() primary name} or at least
+     * one {@linkplain AbstractIdentifiedObject#getAlias() alias} matches the given string according heuristic rules.
+     * If the given object is an instance of {@link AbstractIdentifiedObject}, then this method delegates to its
+     * {@link AbstractIdentifiedObject#isHeuristicMatchForName(String) isHeuristicMatchForName(String)} method
+     * in order to leverage the additional rules implemented by sub-classes.
+     * Otherwise the fallback implementation returns {@code true} if the given {@code name} is equal,
+     * ignoring aspects documented below, to one of the following names:
      *
      * <ul>
-     *   <li>The {@linkplain IdentifiedObject#getName() primary name} of the object.</li>
-     *   <li>The {@linkplain GenericName#toFullyQualifiedName() fully qualified name} of an alias.</li>
-     *   <li>The {@linkplain ScopedName#tail() tail} of an alias.</li>
-     *   <li>The tail of the previous tail, recursively up to the {@linkplain ScopedName#tip() tip}.</li>
+     *   <li>The {@linkplain AbstractIdentifiedObject#getName() primary name}'s {@linkplain NamedIdentifier#getCode() code}
+     *       (without {@linkplain NamedIdentifier#getCodeSpace() codespace}).</li>
+     *   <li>Any {@linkplain AbstractIdentifiedObject#getAlias() alias}'s {@linkplain NamedIdentifier#tip() tip}
+     *       (without {@linkplain NamedIdentifier#scope() scope} and namespace).</li>
      * </ul>
      *
-     * If the given object is an instance of {@link AbstractIdentifiedObject}, then this method delegates
-     * to its {@code nameMatches(String)} method. Otherwise this method fallbacks on a generic algorithm.
+     * The comparison ignores the following aspects:
+     * <ul>
+     *   <li>Lower/upper cases.</li>
+     *   <li>Some Latin diacritical signs (e.g. {@code "Réunion"} and {@code "Reunion"} are considered equal).</li>
+     *   <li>All characters that are not {@linkplain Character#isLetterOrDigit(int) letters or digits}
+     *       (e.g. {@code "Mercator (1SP)"} and {@code "Mercator_1SP"} are considered equal).</li>
+     *   <li>Namespaces or scopes, because this method is typically invoked with either the value of an other
+     *       <code>IdentifiedObject.getName().getCode()</code> or with the <cite>Well Known Text</cite> (WKT)
+     *       projection or parameter name.</li>
+     * </ul>
      *
      * @param  object The object for which to check the name or alias.
      * @param  name The name to compare with the object name or aliases.
      * @return {@code true} if the primary name of at least one alias matches the specified {@code name}.
      *
-     * @see AbstractIdentifiedObject#nameMatches(String)
+     * @see AbstractIdentifiedObject#isHeuristicMatchForName(String)
      */
-    public static boolean nameMatches(final IdentifiedObject object, final String name) {
+    public static boolean isHeuristicMatchForName(final IdentifiedObject object, final String name) {
         if (object instanceof AbstractIdentifiedObject) {
             // DefaultCoordinateSystemAxis overrides this method.
             // We really need to delegate to the overridden method.
-            return ((AbstractIdentifiedObject) object).nameMatches(name);
+            return ((AbstractIdentifiedObject) object).isHeuristicMatchForName(name);
         } else {
             ensureNonNull("object", object);
-            return nameMatches(object, object.getAlias(), name);
+            return isHeuristicMatchForName(object, object.getAlias(), name);
         }
     }
 
     /**
-     * Returns {@code true} if the {@linkplain IdentifiedObject#getName() primary name} of an
-     * object matches the primary name or one {@linkplain IdentifiedObject#getAlias() alias}
-     * of the other object.
-     *
-     * @param  o1 The first object to compare by name.
-     * @param  o2 The second object to compare by name.
-     * @return {@code true} if both objects have a common name.
-     */
-    public static boolean nameMatches(final IdentifiedObject o1, final IdentifiedObject o2) {
-        ensureNonNull("o1", o1);
-        ensureNonNull("o2", o2);
-        return nameMatches(o1, o2.getName().getCode()) ||
-               nameMatches(o2, o1.getName().getCode());
-    }
-
-    /**
-     * Returns {@code true} if the {@linkplain #getName() primary name} of the given object
-     * or one of the given alias matches the given name.
-     *
-     * @param  object The object to check.
-     * @param  alias  The list of alias in {@code object} (may be {@code null}).
-     *                This method will never modify this list. Consequently, the
-     *                given list can be a direct reference to an internal list.
-     * @param  name   The name for which to check for equality.
+     * Returns {@code true} if the {@linkplain AbstractIdentifiedObject#getName() primary name} of the given object
+     * or one of the given alias matches the given name. The comparison ignores case, some Latin diacritical signs
+     * and any characters that are not letters or digits.
+     *
+     * @param  object  The object to check.
+     * @param  aliases The list of alias in {@code object} (may be {@code null}).
+     *                 This method will never modify this list. Consequently, the
+     *                 given list can be a direct reference to an internal list.
+     * @param  name    The name for which to check for equality.
      * @return {@code true} if the primary name or at least one alias matches the given {@code name}.
      */
-    static boolean nameMatches(final IdentifiedObject object, final Collection<GenericName> alias, String name) {
-        name = trimWhitespaces(name);
-        if (name.equalsIgnoreCase(trimWhitespaces(object.getName().getCode()))) {
-            return true;
+    static boolean isHeuristicMatchForName(final IdentifiedObject object, final Collection<GenericName> aliases,
+            CharSequence name)
+    {
+        name = CharSequences.toASCII(name);
+        final ReferenceIdentifier id = object.getName();
+        if (id != null) { // Paranoiac check.
+            final CharSequence code = CharSequences.toASCII(id.getCode());
+            if (code != null) { // Paranoiac check.
+                if (CharSequences.equalsFiltered(name, code, LETTERS_AND_DIGITS, true)) {
+                    return true;
+                }
+            }
         }
-        if (alias != null) {
-            for (GenericName asName : alias) {
-                if (asName != null) { // Paranoiac check.
-                    asName = asName.toFullyQualifiedName();
-                    while (asName != null) {
-                        if (name.equalsIgnoreCase(trimWhitespaces(asName.toString()))) {
-                            return true;
-                        }
-                        if (!(asName instanceof ScopedName)) {
-                            break;
-                        }
-                        asName = ((ScopedName) asName).tail();
+        if (aliases != null) {
+            for (final GenericName alias : aliases) {
+                if (alias != null) { // Paranoiac check.
+                    final CharSequence tip = CharSequences.toASCII(alias.tip().toString());
+                    if (CharSequences.equalsFiltered(name, tip, LETTERS_AND_DIGITS, true)) {
+                        return true;
                     }
+                    /*
+                     * Note: a previous version compared also the scoped names. We removed that part,
+                     * because experience has shown that this method is used only for the "code" part
+                     * of an object name. If we really want to compare scoped name, it would probably
+                     * be better to take a GenericName argument instead than String.
+                     */
                 }
             }
         }

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -187,12 +187,12 @@ public class NamedIdentifier extends Imm
         if (authority == null) {
             return factory.createLocalName(null, code);
         }
-        final CharSequence title;
+        final String title;
         final String codeSpace = super.getCodeSpace();
         if (codeSpace != null) {
-            title = codeSpace;
+            title = codeSpace; // Whitespaces trimed by constructor.
         } else {
-            title = Citations.getIdentifier(authority);
+            title = Citations.getIdentifier(authority); // Whitespaces trimed by Citations.
         }
         NameSpace scope;
         synchronized (SCOPES) {
@@ -310,6 +310,8 @@ public class NamedIdentifier extends Imm
      * is local-independent. It contains all elements listed by {@link #getParsedNames()}
      * separated by an arbitrary character (usually {@code :} or {@code /}).
      *
+     * @return A local-independent string representation of this generic name.
+     *
      * @see IdentifiedObjects#toString(Identifier)
      */
     @Override

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -22,12 +22,13 @@ import javax.measure.unit.SI;
 import javax.measure.unit.Unit;
 import javax.measure.unit.NonSI;
 import javax.measure.quantity.Length;
-import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.datum.GeodeticDatum;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.referencing.datum.DefaultEllipsoid;
 import org.apache.sis.referencing.datum.DefaultPrimeMeridian;
+import org.apache.sis.referencing.datum.DefaultGeodeticDatum;
 
 import static org.opengis.referencing.IdentifiedObject.NAME_KEY;
 import static org.opengis.referencing.IdentifiedObject.ALIAS_KEY;
@@ -57,20 +58,49 @@ final class StandardDefinitions {
     }
 
     /**
-     * Creates the Greenwich prime meridian. This is the only prime meridian supported by SIS convenience shortcuts.
-     * If an other prime meridian is desired, the EPSG database shall be used.
+     * Returns a map of properties for the given EPSG code, name and alias.
+     *
+     * @param  code  The EPSG code.
+     * @param  name  The object name.
+     * @param  alias The alias, or {@code null} if none.
+     * @return The map of properties to give to constructors or factory methods.
      */
-    static PrimeMeridian primeMeridian() {
-        final Map<String,Object> properties = new HashMap<String,Object>(4);
-        properties.put(NAME_KEY, new NamedIdentifier(Citations.EPSG, "Greenwich")); // Name is fixed by ISO 19111.
-        properties.put(IDENTIFIERS_KEY, new NamedIdentifier(Citations.EPSG, GREENWICH));
-        return new DefaultPrimeMeridian(properties, 0, NonSI.DEGREE_ANGLE);
+    private static Map<String,Object> properties(final short code, final String name, final String alias) {
+        final Map<String,Object> map = new HashMap<String,Object>(8);
+        map.put(IDENTIFIERS_KEY, new NamedIdentifier(Citations.EPSG, String.valueOf(code)));
+        map.put(NAME_KEY, new NamedIdentifier(Citations.EPSG, name));
+        map.put(ALIAS_KEY, alias); // May be null, which is okay.
+        return map;
+    }
+
+    /**
+     * Creates a geodetic datum from hard-coded values for the given code.
+     *
+     * @param  code      The EPSG code.
+     * @param  ellipsoid The datum ellipsoid.
+     * @param  meridian  The datum prime meridian.
+     * @return The geodetic datum for the given code.
+     */
+    static GeodeticDatum createGeodeticDatum(final short code, final Ellipsoid ellipsoid, final PrimeMeridian meridian) {
+        final String name;
+        final String alias;
+        switch (code) {
+            case 6326: name = "World Geodetic System 1984";                        alias = "WGS 84"; break;
+            case 6322: name = "World Geodetic System 1972";                        alias = "WGS 72"; break;
+            case 6258: name = "European Terrestrial Reference System 1989";        alias = "ETRS89"; break;
+            case 6269: name = "North American Datum 1983";                         alias = "NAD83";  break;
+            case 6267: name = "North American Datum 1927";                         alias = "NAD27";  break;
+            case 6230: name = "European Datum 1950";                               alias = "ED50";   break;
+            case 6047: name = "Not specified (based on GRS 1980 Authalic Sphere)"; alias = null;     break;
+            default:   throw new AssertionError(code);
+        }
+        return new DefaultGeodeticDatum(properties(code, name, alias), ellipsoid, meridian);
     }
 
     /**
      * Creates an ellipsoid from hard-coded values for the given code.
      *
-     * @param  code The EPSG or SIS code.
+     * @param  code The EPSG code.
      * @return The ellipsoid for the given code.
      */
     static Ellipsoid createEllipsoid(final short code) {
@@ -89,19 +119,22 @@ final class StandardDefinitions {
             case 7048: name  = "GRS 1980 Authalic Sphere"; ivfDefinitive = false;  semiMajorAxis = other = AUTHALIC_RADIUS;          break;
             default:   throw new AssertionError(code);
         }
-        final Map<String,Object> map = new HashMap<String,Object>(8);
-        final Citation authority;
-        if (code >= 0) {
-            map.put(IDENTIFIERS_KEY, new NamedIdentifier(authority = Citations.EPSG, String.valueOf(code)));
-        } else {
-            authority = Citations.SIS;
-        }
-        map.put(NAME_KEY, new NamedIdentifier(authority, name));
-        map.put(ALIAS_KEY, alias); // May be null, which is okay.
+        final Map<String,Object> map = properties(code, name, alias);
         if (ivfDefinitive) {
             return DefaultEllipsoid.createFlattenedSphere(map, semiMajorAxis, other, unit);
         } else {
             return DefaultEllipsoid.createEllipsoid(map, semiMajorAxis, other, unit);
         }
     }
+
+    /**
+     * Creates the Greenwich prime meridian. This is the only prime meridian supported by SIS convenience shortcuts.
+     * If an other prime meridian is desired, the EPSG database shall be used.
+     */
+    static PrimeMeridian primeMeridian() {
+        final Map<String,Object> properties = new HashMap<String,Object>(4);
+        properties.put(NAME_KEY, new NamedIdentifier(Citations.EPSG, "Greenwich")); // Name is fixed by ISO 19111.
+        properties.put(IDENTIFIERS_KEY, new NamedIdentifier(Citations.EPSG, GREENWICH));
+        return new DefaultPrimeMeridian(properties, 0, NonSI.DEGREE_ANGLE);
+    }
 }

Copied: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java (from r1548689, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java?p2=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java&r1=1548689&r2=1548775&rev=1548775&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -36,7 +36,7 @@ import org.apache.sis.referencing.operat
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
 // Related to JDK7
-import java.util.Objects;
+import org.apache.sis.internal.jdk7.Objects;
 
 
 /**

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java?rev=1548775&r1=1548774&r2=1548775&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java [UTF-8] Sat Dec  7 01:50:57 2013
@@ -16,57 +16,195 @@
  */
 package org.apache.sis.referencing.cs;
 
-import java.util.Set;
-import java.util.Collection;
-import org.opengis.util.GenericName;
-import org.opengis.util.InternationalString;
-import org.opengis.referencing.ReferenceIdentifier;
+import java.util.Map;
 import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.Immutable;
+
+
+/**
+ * A 1-, 2-, or 3-dimensional Cartesian coordinate system made of straight orthogonal axes.
+ * All axes shall have the same linear unit of measure.
+ *
+ * <table class="sis"><tr>
+ *   <th>Used with</th>
+ *   <th>Permitted axis names</th>
+ * </tr><tr>
+ *   <td>{@linkplain org.geotoolkit.referencing.crs.DefaultGeocentricCRS Geocentric CRS}</td>
+ *   <td>“Geocentric X”, “Geocentric Y”, “Geocentric Z”</td>
+ * </tr><tr>
+ *   <td>{@linkplain org.geotoolkit.referencing.crs.DefaultProjectedCRS Projected CRS}</td>
+ *   <td>“Easting” or “Westing”, “Northing” or “Southing”</td>
+ * </tr><tr>
+ *   <td>{@linkplain org.geotoolkit.referencing.crs.DefaultEngineeringCRS Engineering CRS}</td>
+ *   <td>unspecified</td>
+ * </tr><tr>
+ *   <td>{@linkplain org.geotoolkit.referencing.crs.DefaultImageCRS Image CRS}</td>
+ *   <td>unspecified</td>
+ * </tr></table>
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.4 (derived from geotk-2.0)
+ * @version 0.4
+ * @module
+ */
+@Immutable
+public class DefaultCartesianCS extends DefaultAffineCS implements CartesianCS {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -6182037957705712945L;
+
+    @Deprecated
+    public static final DefaultCartesianCS GEOCENTRIC = null; // TODO: Not supported yet.
+
+    /**
+     * Constructs a one-dimensional coordinate system from a set of properties.
+     * The properties map is given unchanged to the
+     * {@linkplain AbstractCS#AbstractCS(Map,CoordinateSystemAxis[]) super-class constructor}.
+     *
+     * @param properties The properties to be given to the identified object.
+     * @param axis The axis.
+     */
+    public DefaultCartesianCS(final Map<String,?>   properties,
+                              final CoordinateSystemAxis axis)
+    {
+        super(properties, new CoordinateSystemAxis[] {axis});
+        ensurePerpendicularAxis();
+    }
 
+    /**
+     * Constructs a two-dimensional coordinate system from a set of properties.
+     * The properties map is given unchanged to the
+     * {@linkplain AbstractCS#AbstractCS(Map,CoordinateSystemAxis[]) super-class constructor}.
+     * The following table is a reminder of main (not all) properties:
+     *
+     * <table class="sis">
+     *   <tr>
+     *     <th>Property name</th>
+     *     <th>Value type</th>
+     *     <th>Returned by</th>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
+     *     <td>{@link #getName()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#ALIAS_KEY}</td>
+     *     <td>{@link org.opengis.util.GenericName} or {@link CharSequence} (optionally as array)</td>
+     *     <td>{@link #getAlias()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
+     *     <td>{@link #getIdentifiers()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td>
+     *     <td>{@link org.opengis.util.InternationalString} or {@link String}</td>
+     *     <td>{@link #getRemarks()}</td>
+     *   </tr>
+     * </table>
+     *
+     * @param properties The properties to be given to the identified object.
+     * @param axis0 The first axis.
+     * @param axis1 The second axis.
+     */
+    public DefaultCartesianCS(final Map<String,?>   properties,
+                              final CoordinateSystemAxis axis0,
+                              final CoordinateSystemAxis axis1)
+    {
+        super(properties, axis0, axis1);
+        ensurePerpendicularAxis();
+    }
 
-public class DefaultCartesianCS implements CartesianCS {
-    public static final DefaultCartesianCS GEOCENTRIC = null; // Not supported yet.
-
-    public DefaultCartesianCS(final String               name,
+    /**
+     * Constructs a three-dimensional coordinate system from a set of properties.
+     * The properties map is given unchanged to the
+     * {@linkplain AbstractCS#AbstractCS(Map,CoordinateSystemAxis[]) super-class constructor}.
+     *
+     * @param properties The properties to be given to the identified object.
+     * @param axis0 The first axis.
+     * @param axis1 The second axis.
+     * @param axis2 The third axis.
+     */
+    public DefaultCartesianCS(final Map<String,?>   properties,
                               final CoordinateSystemAxis axis0,
                               final CoordinateSystemAxis axis1,
                               final CoordinateSystemAxis axis2)
     {
+        super(properties, axis0, axis1, axis2);
+        ensurePerpendicularAxis();
     }
 
-    @Override
-    public ReferenceIdentifier getName() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
-    public Collection<GenericName> getAlias() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
-    public Set<ReferenceIdentifier> getIdentifiers() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
-    public InternationalString getRemarks() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
-    public int getDimension() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
-    public CoordinateSystemAxis getAxis(int i) throws IndexOutOfBoundsException {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
-    public String toWKT() throws UnsupportedOperationException {
-        throw new UnsupportedOperationException("Not supported yet.");
+    /**
+     * Creates a new coordinate system with the same values than the specified one.
+     * This copy constructor provides a way to convert an arbitrary implementation into a SIS one
+     * or a user-defined one (as a subclass), usually in order to leverage some implementation-specific API.
+     *
+     * <p>This constructor performs a shallow copy, i.e. the properties are not cloned.</p>
+     *
+     * @param cs The coordinate system to copy.
+     *
+     * @see #castOrCopy(CartesianCS)
+     */
+    protected DefaultCartesianCS(final CartesianCS cs) {
+        super(cs);
+        ensurePerpendicularAxis();
+    }
+
+    /**
+     * Returns a SIS coordinate system implementation with the same values than the given arbitrary implementation.
+     * If the given object is {@code null}, then this method returns {@code null}.
+     * Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged.
+     * Otherwise a new SIS implementation is created and initialized to the attribute values of the given object.
+     *
+     * @param  object The object to get as a SIS implementation, or {@code null} if none.
+     * @return A SIS implementation containing the values of the given object (may be the
+     *         given object itself), or {@code null} if the argument was null.
+     */
+    public static DefaultCartesianCS castOrCopy(final CartesianCS object) {
+        return (object == null) || (object instanceof DefaultCartesianCS)
+                ? (DefaultCartesianCS) object : new DefaultCartesianCS(object);
+    }
+
+    /**
+     * Ensures that all axes are perpendicular.
+     */
+    private void ensurePerpendicularAxis() throws IllegalArgumentException {
+        final int dimension = getDimension();
+        for (int i=0; i<dimension; i++) {
+            final AxisDirection axis0 = getAxis(i).getDirection();
+            for (int j=i; ++j<dimension;) {
+                final AxisDirection axis1 = getAxis(j).getDirection();
+                final double angle = CoordinateSystems.angle(axis0, axis1); // May be NaN, which we accept.
+                if (Math.abs(Math.abs(angle) - 90) > Formulas.ANGULAR_TOLERANCE) {
+                    throw new IllegalArgumentException(Errors.format(
+                            Errors.Keys.NonPerpendicularDirections_2, axis0, axis1));
+                }
+            }
+        }
+    }
+
+    /**
+     * Compares this coordinate system with the specified object for equality.
+     *
+     * @param  object The object to compare to {@code this}.
+     * @param  mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or
+     *         {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only properties
+     *         relevant to coordinate transformations.
+     * @return {@code true} if both objects are equal.
+     */
+    @Override
+    public boolean equals(final Object object, final ComparisonMode mode) {
+        if (object == this) {
+            return true; // Slight optimization.
+        }
+        return (object instanceof CartesianCS) && super.equals(object, mode);
     }
 }



Mime
View raw message