Author: desruisseaux
Date: Sun Mar 4 16:12:09 2018
New Revision: 1825822
URL: http://svn.apache.org/viewvc?rev=1825822&view=rev
Log:
Add a Formatter.append(double[][]) method for geometry coordinates, together
with calculation of a default number of fraction digits and support for number
alignment (for more readable WKT). This can be used as a basis for more
extensive geometry WKT support in the future.
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -79,7 +79,8 @@ public class ReferencingServices extends
/**
* The GRS80 {@linkplain
org.apache.sis.referencing.datum.DefaultEllipsoid#getAuthalicRadius() authalic
radius},
- * which is {@value} metres.
+ * which is {@value} metres. This is close to the WGS84 authalic radius,
which is about 6371007.180918474 when
+ * computed with {@code double} precision.
*/
public static final double AUTHALIC_RADIUS = 6371007;
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -35,7 +35,7 @@ import org.apache.sis.util.Static;
*
* @author Martin Desruisseaux (Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 0.7
+ * @version 1.0
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT
2 specification</a>
* @see <a
href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy
WKT 1</a>
@@ -214,4 +214,10 @@ public final class WKTKeywords extends S
spherical = "spherical",
temporal = "temporal",
vertical = "vertical";
+
+ /**
+ * Geometries.
+ */
+ public static final String
+ Point = "Point";
}
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -36,6 +36,7 @@ import javax.measure.Unit;
import javax.measure.Quantity;
import org.opengis.util.InternationalString;
+import org.opengis.util.ControlledVocabulary;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.extent.Extent;
@@ -53,7 +54,6 @@ import org.opengis.referencing.operation
import org.opengis.referencing.operation.CoordinateOperation;
import org.opengis.referencing.operation.ConcatenatedOperation;
import org.opengis.referencing.operation.MathTransform;
-import org.opengis.util.ControlledVocabulary;
import org.apache.sis.measure.Units;
import org.apache.sis.math.DecimalFunctions;
@@ -68,7 +68,9 @@ import org.apache.sis.util.CharSequences
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.collection.IntegerList;
import org.apache.sis.internal.util.X364;
+import org.apache.sis.internal.util.Numerics;
import org.apache.sis.internal.util.Citations;
import org.apache.sis.internal.util.Constants;
import org.apache.sis.internal.util.StandardDateFormat;
@@ -97,7 +99,7 @@ import org.apache.sis.metadata.iso.exten
* </ul>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT
2 specification</a>
* @see <a
href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy
WKT 1</a>
@@ -146,9 +148,9 @@ public class Formatter implements Locali
/**
* The value of {@link Symbols#getSeparator()} without trailing spaces,
followed by the system line separator.
- * Computed by {@link Symbols#lineSeparator()} and stored for reuse.
+ * Computed by {@link Symbols#separatorNewLine()} and stored for reuse.
*/
- private final String lineSeparator;
+ private final String separatorNewLine;
/**
* The colors to use for this formatter, or {@code null} for no syntax
coloring.
@@ -287,6 +289,14 @@ public class Formatter implements Locali
private int margin;
/**
+ * Indices where to insert additional margin, or {@code null} if none. The
margin to insert will be
+ * the the width of the keyword (e.g. {@code "BOX"}), which is usually
unknown to {@code Formatter}
+ * until {@link FormattableObject} finished to write the element. This
field is usually {@code null},
+ * unless formatting geometries.
+ */
+ private IntegerList keywordSpaceAt;
+
+ /**
* {@code true} if a new line were requested during the execution of
{@link #append(FormattableObject)}.
* This is used to determine if the next {@code UNIT} and {@code ID}
elements shall appear on a new line.
*/
@@ -337,16 +347,16 @@ public class Formatter implements Locali
ArgumentChecks.ensureNonNull("convention", convention);
ArgumentChecks.ensureNonNull("symbols", symbols);
ArgumentChecks.ensureBetween("indentation", WKTFormat.SINGLE_LINE,
Byte.MAX_VALUE, indentation);
- this.locale = Locale.getDefault(Locale.Category.DISPLAY);
- this.convention = convention;
- this.authority = convention.getNameAuthority();
- this.symbols = symbols.immutable();
- this.lineSeparator = this.symbols.lineSeparator();
- this.indentation = (byte) indentation;
- this.numberFormat = symbols.createNumberFormat();
- this.dateFormat = new StandardDateFormat(symbols.getLocale());
- this.unitFormat = new UnitFormat(symbols.getLocale());
- this.buffer = new StringBuffer();
+ this.locale = Locale.getDefault(Locale.Category.DISPLAY);
+ this.convention = convention;
+ this.authority = convention.getNameAuthority();
+ this.symbols = symbols.immutable();
+ this.separatorNewLine = this.symbols.separatorNewLine();
+ this.indentation = (byte) indentation;
+ this.numberFormat = symbols.createNumberFormat();
+ this.dateFormat = new StandardDateFormat(symbols.getLocale());
+ this.unitFormat = new UnitFormat(symbols.getLocale());
+ this.buffer = new StringBuffer();
unitFormat.setStyle(UnitFormat.Style.NAME);
if (convention.usesCommonUnits) {
unitFormat.setLocale(Locale.US);
@@ -360,15 +370,15 @@ public class Formatter implements Locali
Formatter(final Locale locale, final Symbols symbols, final NumberFormat
numberFormat,
final DateFormat dateFormat, final UnitFormat unitFormat)
{
- this.locale = locale;
- this.convention = Convention.DEFAULT;
- this.authority = Convention.DEFAULT.getNameAuthority();
- this.symbols = symbols;
- this.lineSeparator = this.symbols.lineSeparator();
- this.indentation = Constants.DEFAULT_INDENTATION;
- this.numberFormat = numberFormat; // No clone
needed.
- this.dateFormat = dateFormat;
- this.unitFormat = unitFormat;
+ this.locale = locale;
+ this.convention = Convention.DEFAULT;
+ this.authority = Convention.DEFAULT.getNameAuthority();
+ this.symbols = symbols;
+ this.separatorNewLine = symbols.separatorNewLine();
+ this.indentation = Constants.DEFAULT_INDENTATION;
+ this.numberFormat = numberFormat; // No clone
needed.
+ this.dateFormat = dateFormat;
+ this.unitFormat = unitFormat;
// Do not set the buffer. It will be set by WKTFormat.format(…).
}
@@ -557,7 +567,7 @@ public class Formatter implements Locali
private void appendSeparator() {
if (buffer.length() != elementStart) {
if (requestNewLine) {
-
buffer.append(lineSeparator).append(CharSequences.spaces(margin));
+
buffer.append(separatorNewLine).append(CharSequences.spaces(margin));
} else {
buffer.append(symbols.getSeparator());
}
@@ -638,7 +648,7 @@ public class Formatter implements Locali
}
}
enclosingElements.add(object);
- if (hasContextualUnit < 0) { // Test if leftmost bit is set to 1.
+ if (hasContextualUnit < 0) { // Test if
leftmost bit is set to 1.
throw new
IllegalStateException(Errors.getResources(locale).getString(Errors.Keys.TreeDepthExceedsMaximum));
}
hasContextualUnit <<= 1;
@@ -682,6 +692,24 @@ public class Formatter implements Locali
highlightError = false;
buffer.insert(base, keyword);
/*
+ * When formatting geometry coordinates, we may need to shift all
numbers by the width
+ * of the keyword inserted above in order to keep numbers properly
aligned. Exemple:
+ *
+ * BOX[ 4.000 -10.000
+ * 50.000 2.000]
+ */
+ if (keywordSpaceAt != null) {
+ final int length = keyword.length();
+ final CharSequence additionalMargin =
CharSequences.spaces(keyword.codePointCount(0, length));
+ final int n = keywordSpaceAt.size();
+ for (int i=0; i<n;) {
+ int p = keywordSpaceAt.getInt(i);
+ p += (++i * length); // Take in account
spaces added previously.
+ buffer.insert(p, additionalMargin);
+ }
+ keywordSpaceAt.clear();
+ }
+ /*
* Format the SCOPE["…"], AREA["…"] and other elements. Some of those
information
* are available only for Datum, CoordinateOperation and
ReferenceSystem objects.
*/
@@ -692,6 +720,9 @@ public class Formatter implements Locali
appendComplement(info, (stackDepth >= 1) ?
enclosingElements.get(stackDepth - 1) : null,
(stackDepth >= 2) ?
enclosingElements.get(stackDepth - 2) : null);
}
+ /*
+ * Close the bracket, then update the queue of enclosed elements by
removing this element.
+ */
buffer.appendCodePoint(symbols.getClosingBracket(0));
indent(-1);
enclosingElements.remove(stackDepth);
@@ -1170,7 +1201,7 @@ public class Formatter implements Locali
* maximum of 8 fraction digits, which is more than enough.
*/
numberFormat.setMaximumFractionDigits(DecimalFunctions.fractionDigitsForValue(number,
2));
- numberFormat.setMinimumFractionDigits(1); // Must be after
setMaximumFractionDigits(…).
+ numberFormat.setMinimumFractionDigits(1); // Must be after
setMaximumFractionDigits(…).
numberFormat.setRoundingMode(RoundingMode.HALF_EVEN);
numberFormat.format(number, buffer, dummy);
}
@@ -1178,6 +1209,124 @@ public class Formatter implements Locali
}
/**
+ * Appends rows of numbers. Each number is separated by a space, and each
row is separated by a comma.
+ * This method is mostly for formatting geometries, but it could be used
for other objects like matrix
+ * as well. Each row usually have the same length, but this is not
mandatory.
+ *
+ * @param rows rows to append, or {@code null} if none.
+ * @param fractionDigits the number of fraction digits for each number
in a row, or {@code null} for default.
+ * If a row contains more numbers than {@code
fractionDigits.length}, then the last value in this array
+ * is repeated for all remaining row numbers.
+ *
+ * @since 1.0
+ */
+ public void append(final double[][] rows, int... fractionDigits) {
+ if (rows == null || rows.length == 0) {
+ return;
+ }
+ if (fractionDigits == null || fractionDigits.length == 0) {
+ fractionDigits = Numerics.suggestFractionDigits(rows);
+ }
+ numberFormat.setRoundingMode(RoundingMode.HALF_EVEN);
+ /*
+ * If the rows are going to be formatted on many lines, then we will
need to put some margin before each row.
+ * If the first row starts on its own line, then the margin will be
the usual indentation. But if the first
+ * row starts on the same line than previous elements (or the keyword
of this element, e.g. "BOX["), then we
+ * will need a different amount of spaces if we want to have the
numbers properly aligned.
+ */
+ final boolean isMultiLines = (indentation > WKTFormat.SINGLE_LINE) &&
(rows.length > 1);
+ final boolean needsAlignment = !requestNewLine;
+ final CharSequence marginBeforeRow;
+ if (isMultiLines) {
+ int currentLineLength = margin;
+ if (needsAlignment) {
+ final int length = buffer.length();
+ int i = length;
+ while (i > 0) { //
Locate beginning of current line.
+ final int c = buffer.codePointBefore(i);
+ if (Characters.isLineOrParagraphSeparator(c)) break;
+ i -= Character.charCount(c);
+ }
+ currentLineLength = buffer.codePointCount(i, length);
+ }
+ marginBeforeRow = CharSequences.spaces(currentLineLength);
+ } else {
+ marginBeforeRow = "";
+ }
+ /*
+ * 'formattedNumberMarks' contains, for each number in each row,
positions in the 'buffer' where
+ * the number starts and position where it ends. Those positions are
stored as (start,end) pairs.
+ * We compute those marks unconditionally for simplicity, but will
ignore them if formatting on
+ * a single line.
+ */
+ final int[][] formattedNumberMarks = new int[rows.length][];
+ int numColumns = 0;
+ for (int j=0; j<rows.length; j++) {
+ if (j == 0) {
+ appendSeparator(); // It is up to the caller to decide if
we begin with a new line.
+ } else {
+ buffer.append(separatorNewLine).append(marginBeforeRow);
+ }
+ final double[] numbers = rows[j];
+ numColumns = Math.max(numColumns, numbers.length); // Store
the length of longest row.
+ final int[] marks = new int[numbers.length << 1]; //
Positions where numbers are formatted.
+ formattedNumberMarks[j] = marks;
+ for (int i=0; i<numbers.length; i++) {
+ if (i != 0) buffer.append(Symbols.NUMBER_SEPARATOR);
+ if (i < fractionDigits.length) { //
Otherwise, same than previous number.
+ final int f = fractionDigits[i];
+ numberFormat.setMaximumFractionDigits(f);
+ numberFormat.setMinimumFractionDigits(f);
+ }
+ marks[i << 1] = buffer.length(); // Store
the start position where number is formatted.
+ setColor(ElementKind.NUMBER);
+ numberFormat.format(numbers[i], buffer, dummy);
+ resetColor();
+ marks[(i << 1) | 1] = buffer.length(); // Store
the end position where number is formatted.
+ }
+ }
+ /*
+ * If formatting on more than one line, insert the amount of spaces
required for aligning numbers.
+ * This is possible because we wrote the coordinate values with fixed
number of fraction digits.
+ */
+ if (isMultiLines) {
+ final int base = elementStart;
+ final String toWrite = buffer.substring(base); // Save
what we formatted in above loop.
+ buffer.setLength(base); // Discard
what we formatted - we will rewrite.
+ final int[] columnWidths = new int[numColumns];
+ for (final int[] marks : formattedNumberMarks) { // Compute
the maximal width of each column.
+ for (int i=0; i<marks.length; i += 2) {
+ final int k = i >> 1;
+ final int w = toWrite.codePointCount(marks[i ] -= base,
+ marks[i+1] -= base);
+ if (w > columnWidths[k]) columnWidths[k] = w;
+ }
+ }
+ if (needsAlignment && keywordSpaceAt == null) {
+ keywordSpaceAt = new IntegerList(formattedNumberMarks.length,
Integer.MAX_VALUE);
+ }
+ boolean requestAlignment = false;
+ int lastPosition = 0;
+ for (int[] marks : formattedNumberMarks) { // Recopy
the formatted text, with more spaces.
+ for (int i = 0; i<marks.length;) {
+ final int w = columnWidths[i >> 1];
+ final int s = marks[i++];
+ final int e = marks[i++];
+ buffer.append(toWrite, lastPosition, s)
+ .append(CharSequences.spaces(w -
toWrite.codePointCount(s, e)));
+ if (requestAlignment) {
+ requestAlignment = false;
+ keywordSpaceAt.add(buffer.length());
+ }
+ buffer.append(toWrite, s, e);
+ lastPosition = e;
+ }
+ requestAlignment = needsAlignment;
+ }
+ }
+ }
+
+ /**
* Appends the given number without any change to the {@link NumberFormat}
setting.
* Caller shall ensure that the following method has been invoked prior
this method call:
*
@@ -1693,6 +1842,7 @@ public class Formatter implements Locali
elementStart = 0;
colorApplied = 0;
margin = 0;
+ keywordSpaceAt = null;
requestNewLine = false;
isComplement = false;
highlightError = false;
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -67,7 +67,7 @@ import static org.apache.sis.util.Argume
* Users can create their own {@code Symbols} instance for parsing or
formatting a WKT with different symbols.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.6
+ * @version 1.0
*
* @see WKTFormat#getSymbols()
* @see WKTFormat#setSymbols(Symbols)
@@ -92,6 +92,12 @@ public class Symbols implements Localize
static final boolean SCIENTIFIC_NOTATION = true;
/**
+ * Separator between numbers in a sequence of numbers.
+ * This is used for example between the coordinates of a point.
+ */
+ static final char NUMBER_SEPARATOR = ' ';
+
+ /**
* The prefix character for the value of a WKT fragment.
*/
static final char FRAGMENT_VALUE = '$';
@@ -541,7 +547,7 @@ public class Symbols implements Localize
* Returns the value of {@link #getSeparator()} without trailing spaces,
* followed by the system line separator.
*/
- final String lineSeparator() {
+ final String separatorNewLine() {
final String separator = getSeparator();
return separator.substring(0,
CharSequences.skipTrailingWhitespaces(separator, 0, separator.length()))
.concat(System.lineSeparator());
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -106,7 +106,7 @@ import org.apache.sis.internal.util.Stan
*
* @author Martin Desruisseaux (Geomatys)
* @author Rémi Eve (IRD)
- * @version 0.8
+ * @version 1.0
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT
2 specification</a>
* @see <a
href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy
WKT 1</a>
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -82,7 +82,7 @@
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Rémi Eve (IRD)
* @author Rueben Schulz (UBC)
- * @version 0.6
+ * @version 1.0
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT
2 specification</a>
* @see <a
href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy
WKT 1</a>
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -35,6 +35,10 @@ import org.apache.sis.util.Utilities;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.internal.metadata.WKTKeywords;
+import org.apache.sis.internal.referencing.WKTUtilities;
+import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.io.wkt.Formatter;
import static java.lang.Double.doubleToLongBits;
import static org.apache.sis.util.StringBuilders.trimFractionalPart;
@@ -53,11 +57,11 @@ import static org.apache.sis.util.Argume
* serializable, is left to subclasses.</p>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
* @since 0.3
* @module
*/
-public abstract class AbstractDirectPosition implements DirectPosition {
+public abstract class AbstractDirectPosition extends FormattableObject
implements DirectPosition {
/**
* Constructs a direct position.
*/
@@ -65,6 +69,24 @@ public abstract class AbstractDirectPosi
}
/**
+ * Returns the given position as an {@code AbstractDirectPosition}
instance.
+ * If the given position is already an instance of {@code
AbstractDirectPosition},
+ * then it is returned unchanged. Otherwise the coordinate values and the
CRS
+ * of the given position are copied in a new position.
+ *
+ * @param position the position to cast, or {@code null}.
+ * @return the values of the given position as an {@code
AbstractDirectPosition} instance.
+ *
+ * @since 1.0
+ */
+ public static AbstractDirectPosition castOrCopy(final DirectPosition
position) {
+ if (position == null || position instanceof AbstractDirectPosition) {
+ return (AbstractDirectPosition) position;
+ }
+ return new GeneralDirectPosition(position);
+ }
+
+ /**
* Returns always {@code this}, the direct position for this
* {@linkplain org.opengis.geometry.coordinate.Position position}.
*
@@ -181,22 +203,28 @@ public abstract class AbstractDirectPosi
}
/**
- * Returns {@code true} if every values in the given {@code double} array
could be casted
- * to the {@code float} type without precision lost. This method treats
all {@code NaN} values
- * as equal.
- *
- * @param values the value to test for their precision.
- * @return {@code true} if every values can be casted to the {@code float}
type without precision lost.
- *
- * @see #toString(DirectPosition, boolean)
- */
- static boolean isSimplePrecision(final double... values) {
- for (final double value : values) {
- if (Double.doubleToLongBits(value) !=
Double.doubleToLongBits((float) value)) {
- return false;
- }
- }
- return true;
+ * Formats this position in the <cite>Well Known Text</cite> (WKT) format.
+ * The format is like below, where {@code x₀}, {@code x₁}, {@code x₂},
<i>etc.</i>
+ * are the ordinate values at index 0, 1, 2, <i>etc.</i>:
+ *
+ * {@preformat wkt
+ * POINT[x₀ x₁ x₂ …]
+ * }
+ *
+ * If the coordinate reference system is geodetic or projected, then
coordinate values are formatted
+ * with a precision equivalent to one centimetre on Earth (the actual
number of fraction digits is
+ * adjusted for the axis unit of measurement and the planet size if
different than Earth).
+ *
+ * @param formatter the formatter where to format the inner content of
this point.
+ * @return the WKT keyword, which is {@code "Point"} for this element.
+ *
+ * @since 1.0
+ */
+ @Override
+ protected String formatTo(final Formatter formatter) {
+ final double[][] points = new double[][] {getCoordinate()};
+ formatter.append(points,
WKTUtilities.suggestFractionDigits(getCoordinateReferenceSystem(), points));
+ return WKTKeywords.Point;
}
/**
@@ -208,10 +236,11 @@ public abstract class AbstractDirectPosi
* POINT(x₀ x₁ x₂ …)
* }
*
+ * This method formats the numbers as with {@link Double#toString(double)}
(i.e. without fixed number of fraction digits).
* The string returned by this method can be {@linkplain
GeneralDirectPosition#GeneralDirectPosition(CharSequence) parsed}
* by the {@code GeneralDirectPosition} constructor.
*
- * @return This position as a {@code POINT} in <cite>Well Known
Text</cite> (WKT) format.
+ * @return this position as a {@code POINT} in <cite>Well Known
Text</cite> (WKT) format.
*/
@Override
public String toString() {
@@ -227,7 +256,7 @@ public abstract class AbstractDirectPosi
* @param isSimplePrecision {@code true} if every ordinate values can be
casted to {@code float}.
* @return the point as a {@code POINT} in WKT format.
*
- * @see #isSimplePrecision(double[])
+ * @see Numerics#isSimplePrecision(double[])
*/
static String toString(final DirectPosition position, final boolean
isSimplePrecision) {
final StringBuilder buffer = new StringBuilder(32).append("POINT");
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -40,6 +40,9 @@ import org.apache.sis.util.Emptiable;
import org.apache.sis.util.Utilities;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.internal.referencing.WKTUtilities;
import static java.lang.Double.doubleToLongBits;
import static org.apache.sis.internal.util.Numerics.SIGN_BIT_MASK;
@@ -109,12 +112,12 @@ import static org.apache.sis.math.MathFu
* </ul>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
@XmlTransient
-public abstract class AbstractEnvelope implements Envelope, Emptiable {
+public abstract class AbstractEnvelope extends FormattableObject implements
Envelope, Emptiable {
/**
* An empty array of envelopes, to be returned by {@link
#toSimpleEnvelopes()}
* when en envelope is empty.
@@ -1133,6 +1136,7 @@ public abstract class AbstractEnvelope i
* The {@code BOX} element is not part of the standard <cite>Well Known
Text</cite> (WKT) format.
* However it is understood by many software libraries, for example GDAL
and PostGIS.</div>
*
+ * This method formats the numbers as with {@link Double#toString(double)}
(i.e. without fixed number of fraction digits).
* The string returned by this method can be {@linkplain
GeneralEnvelope#GeneralEnvelope(CharSequence) parsed}
* by the {@code GeneralEnvelope} constructor.
*
@@ -1185,6 +1189,41 @@ public abstract class AbstractEnvelope i
}
/**
+ * Formats this envelope as a "{@code BOX}" element.
+ * The output is of the form "{@code BOX}<var>n</var>{@code D[}{@linkplain
#getLowerCorner()
+ * lower corner}{@code ,}{@linkplain #getUpperCorner() upper corner}{@code
]}"
+ * where <var>n</var> is the {@linkplain #getDimension() number of
dimensions}.
+ * The number of dimension is written only if different than 2.
+ *
+ * <div class="note"><b>Note:</b>
+ * The {@code BOX} element is not part of the standard <cite>Well Known
Text</cite> (WKT) format.
+ * However it is understood by many software libraries, for example GDAL
and PostGIS.</div>
+ *
+ * If the coordinate reference system is geodetic or projected, then
coordinate values are formatted
+ * with a precision equivalent to one centimetre on Earth (the actual
number of fraction digits is
+ * adjusted for the axis unit of measurement and the planet size if
different than Earth).
+ *
+ * @param formatter the formatter where to format the inner content of
this envelope.
+ * @return the pseudo-WKT keyword, which is {@code "Box"} for this element.
+ *
+ * @since 1.0
+ */
+ @Override
+ protected String formatTo(final Formatter formatter) {
+ final double[][] points = new double[][] {
+ getLowerCorner().getCoordinate(),
+ getUpperCorner().getCoordinate()
+ };
+ formatter.append(points,
WKTUtilities.suggestFractionDigits(getCoordinateReferenceSystem(), points));
+ final int dimension = getDimension();
+ String keyword = "Box";
+ if (dimension != 2) {
+ keyword = new
StringBuilder(keyword).append(dimension).append('D').toString();
+ }
+ return keyword;
+ }
+
+ /**
* Base class for unmodifiable direct positions backed by the enclosing
envelope.
* Subclasses must override the {@link #getOrdinate(int)} method in order
to delegate
* the work to the appropriate {@link AbstractEnvelope} method.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -37,6 +37,7 @@ import org.apache.sis.referencing.Common
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.util.Numerics;
import static org.apache.sis.util.ArgumentChecks.*;
import static org.apache.sis.math.MathFunctions.isNegative;
@@ -56,7 +57,7 @@ import static org.apache.sis.internal.re
* in {@link SubEnvelope}.</p>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
* @since 0.3
* @module
*/
@@ -593,6 +594,6 @@ scanNumber: while ((i += Character.charC
*/
@Override
public String toString() {
- return toString(this,
AbstractDirectPosition.isSimplePrecision(ordinates));
+ return toString(this, Numerics.isSimplePrecision(ordinates));
}
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -292,7 +292,7 @@ public class DirectPosition2D extends Po
*/
@Override
public String toString() {
- return AbstractDirectPosition.toString(this,
AbstractDirectPosition.isSimplePrecision(x, y));
+ return AbstractDirectPosition.toString(this,
Numerics.isSimplePrecision(x, y));
}
/**
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -30,6 +30,7 @@ import java.security.PrivilegedAction;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.internal.util.Numerics;
import org.apache.sis.util.resources.Errors;
import static org.apache.sis.util.ArgumentChecks.ensureDimensionMatches;
@@ -51,7 +52,7 @@ import static org.apache.sis.util.Argume
* on the value of the containing object's {@code CoordinateReferenceSystem}.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
*
* @see DirectPosition1D
* @see DirectPosition2D
@@ -282,7 +283,7 @@ public class GeneralDirectPosition exten
*/
@Override
public String toString() {
- return toString(this, isSimplePrecision(ordinates));
+ return toString(this, Numerics.isSimplePrecision(ordinates));
}
/**
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -84,7 +84,7 @@
* @see org.apache.sis.setup.GeometryLibrary
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -19,6 +19,7 @@ package org.apache.sis.internal.referenc
import org.apache.sis.util.Static;
import org.apache.sis.measure.Latitude;
import org.apache.sis.internal.util.Numerics;
+import org.opengis.referencing.datum.Ellipsoid;
import static java.lang.Math.*;
import static org.apache.sis.math.MathFunctions.atanh;
@@ -31,7 +32,7 @@ import static org.apache.sis.internal.me
* do not want to expose publicly those arbitrary values (or at least not in a
too direct way).
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
* @since 0.4
* @module
*/
@@ -59,6 +60,13 @@ public final class Formulas extends Stat
public static final double ANGULAR_TOLERANCE = LINEAR_TOLERANCE /
(NAUTICAL_MILE * 60);
/**
+ * Default tolerance threshold for comparing ordinate values in temporal
CRS,
+ * assuming that the unit of measurement is second. Current value is
arbitrary
+ * and may change in any future Apache SIS version.
+ */
+ public static final double TEMPORAL_TOLERANCE = 60; // One
minute.
+
+ /**
* The maximal longitude value before normalization if a centimetric
precision is desired.
* This is about 4×10⁸ degrees.
*
@@ -87,6 +95,19 @@ public final class Formulas extends Stat
}
/**
+ * Returns the size of a planet described by the given ellipsoid compared
to earth.
+ * This method returns a ratio of given planet authalic radius compared to
WGS84.
+ * This can be used for adjusting {@link #LINEAR_TOLERANCE} and {@link
#ANGULAR_TOLERANCE} to another planet.
+ *
+ * @param planet ellipsoid of the other planet to compare to Earth.
+ * @return ratio of planet authalic radius on WGS84 authalic radius.
+ */
+ public static double scaleComparedToEarth(final Ellipsoid planet) {
+ return getAuthalicRadius(planet.getSemiMajorAxis(),
+ planet.getSemiMinorAxis()) /
6371007.180918474;
+ }
+
+ /**
* Returns 3ⁿ for very small (less than 10) positive values of
<var>n</var>.
* Note that this method overflow for any value equals or greater than 20.
*
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -31,8 +31,10 @@ import org.opengis.parameter.GeneralPara
import org.opengis.referencing.cs.*;
import org.opengis.referencing.crs.*;
import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.datum.Datum;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.datum.VerticalDatum;
import org.opengis.referencing.datum.VerticalDatumType;
import org.opengis.referencing.operation.CoordinateOperationFactory;
@@ -60,7 +62,7 @@ import static java.util.Collections.sing
* <p><strong>Do not rely on this API!</strong> It may change in incompatible
way in any future release.</p>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.5
* @module
*/
@@ -110,7 +112,7 @@ public final class ReferencingUtilities
if (cs != null) {
for (int i=cs.getDimension(); --i>=0;) {
final CoordinateSystemAxis axis = cs.getAxis(i);
- if (axis != null) { // Paranoiac check.
+ if (axis != null) { //
Paranoiac check.
final Unit<?> candidate = axis.getUnit();
if (candidate != null) {
if (unit == null) {
@@ -136,7 +138,7 @@ public final class ReferencingUtilities
public static int getDimension(final CoordinateReferenceSystem crs) {
if (crs != null) {
final CoordinateSystem cs = crs.getCoordinateSystem();
- if (cs != null) { // Paranoiac check.
+ if (cs != null) { //
Paranoiac check.
return cs.getDimension();
}
}
@@ -199,6 +201,31 @@ public final class ReferencingUtilities
}
/**
+ * Returns the ellipsoid used by the given coordinate reference system, or
{@code null} if none.
+ *
+ * @param crs the coordinate reference system for which to get the
ellipsoid.
+ * @return the ellipsoid, or {@code null} if none.
+ */
+ public static Ellipsoid getEllipsoid(final CoordinateReferenceSystem crs) {
+ if (crs != null) {
+ if (crs instanceof SingleCRS) {
+ final Datum datum = ((SingleCRS) crs).getDatum();
+ if (datum instanceof GeodeticDatum) {
+ final Ellipsoid e = ((GeodeticDatum) datum).getEllipsoid();
+ if (e != null) return e;
+ }
+ }
+ if (crs instanceof CompoundCRS) {
+ for (final CoordinateReferenceSystem c : ((CompoundCRS)
crs).getComponents()) {
+ final Ellipsoid e = getEllipsoid(c);
+ if (e != null) return e;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the ellipsoid used by the specified coordinate reference
system, provided that the two first dimensions
* use an instance of {@link GeographicCRS}. Otherwise (i.e. if the two
first dimensions are not geographic),
* returns {@code null}.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -49,6 +49,8 @@ import org.apache.sis.util.Static;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.internal.util.Constants;
+import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.math.DecimalFunctions;
/**
@@ -60,7 +62,7 @@ import org.apache.sis.internal.util.Cons
* We need to be specific in order to select the right "aspect" of the given
object.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.4
* @module
*/
@@ -72,6 +74,39 @@ public final class WKTUtilities extends
}
/**
+ * Returns the WKT type of the given interface.
+ *
+ * For {@link CoordinateSystem} base type, the returned value shall be one
of
+ * {@code affine}, {@code Cartesian}, {@code cylindrical}, {@code
ellipsoidal}, {@code linear},
+ * {@code parametric}, {@code polar}, {@code spherical}, {@code temporal}
or {@code vertical}.
+ *
+ * @param base the abstract base interface.
+ * @param type the interface or classes for which to get the WKT type.
+ * @return the WKT type for the given class or interface, or {@code null}
if none.
+ *
+ * @see ReferencingUtilities#toPropertyName(Class, Class)
+ */
+ public static String toType(final Class<?> base, final Class<?> type) {
+ if (type != base) {
+ final StringBuilder name =
ReferencingUtilities.toPropertyName(base, type);
+ if (name != null) {
+ int end = name.length() - 2;
+ if (CharSequences.regionMatches(name, end, "CS")) {
+ name.setLength(end);
+ if ("time".contentEquals(name)) {
+ return "temporal";
+ }
+ if (CharSequences.regionMatches(name, 0, "cartesian")) {
+ name.setCharAt(0, 'C'); // "Cartesian"
+ }
+ return name.toString();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the given coordinate reference system as a formattable object.
*
* @param object the coordinate reference system, or {@code null}.
@@ -275,35 +310,44 @@ public final class WKTUtilities extends
}
/**
- * Returns the WKT type of the given interface.
- *
- * For {@link CoordinateSystem} base type, the returned value shall be one
of
- * {@code affine}, {@code Cartesian}, {@code cylindrical}, {@code
ellipsoidal}, {@code linear},
- * {@code parametric}, {@code polar}, {@code spherical}, {@code temporal}
or {@code vertical}.
+ * Suggests an amount of fraction digits to use for formatting numbers in
each column of the given sequence
+ * of points. The number of fraction digits may be negative if we could
round the numbers to 10, <i>etc</i>.
*
- * @param base the abstract base interface.
- * @param type the interface or classes for which to get the WKT type.
- * @return the WKT type for the given class or interface, or {@code null}
if none.
- *
- * @see ReferencingUtilities#toPropertyName(Class, Class)
- */
- public static String toType(final Class<?> base, final Class<?> type) {
- if (type != base) {
- final StringBuilder name =
ReferencingUtilities.toPropertyName(base, type);
- if (name != null) {
- int end = name.length() - 2;
- if (CharSequences.regionMatches(name, end, "CS")) {
- name.setLength(end);
- if ("time".contentEquals(name)) {
- return "temporal";
- }
- if (CharSequences.regionMatches(name, 0, "cartesian")) {
- name.setCharAt(0, 'C'); // "Cartesian"
- }
- return name.toString();
+ * @param crs the coordinate reference system for each points, or
{@code null} if unknown.
+ * @param points the sequence of points. It is not required that each
point has the same dimension.
+ * @return suggested amount of fraction digits as an array as long as the
longest row.
+ */
+ public static int[] suggestFractionDigits(final CoordinateReferenceSystem
crs, final double[]... points) {
+ final int[] fractionDigits = Numerics.suggestFractionDigits(points);
+ final Ellipsoid ellipsoid = ReferencingUtilities.getEllipsoid(crs);
+ if (ellipsoid != null) {
+ /*
+ * Use heuristic precisions for geodetic or projected CRS. We do
not apply those heuristics
+ * for other kind of CRS (e.g. engineering) because we do not know
what could be the size
+ * of the object attached to the CRS.
+ */
+ final CoordinateSystem cs = crs.getCoordinateSystem();
+ final int dimension = Math.min(cs.getDimension(),
fractionDigits.length);
+ final double scale = Formulas.scaleComparedToEarth(ellipsoid);
+ for (int i=0; i<dimension; i++) {
+ final Unit<?> unit = cs.getAxis(i).getUnit();
+ double precision;
+ if (Units.isLinear(unit)) {
+ precision = Formulas.LINEAR_TOLERANCE * scale;
// In metres
+ } else if (Units.isAngular(unit)) {
+ precision = Formulas.ANGULAR_TOLERANCE * (Math.PI / 180) *
scale; // In radians
+ } else if (Units.isTemporal(unit)) {
+ precision = Formulas.TEMPORAL_TOLERANCE;
// In seconds
+ } else {
+ continue;
+ }
+ precision /= Units.toStandardUnit(unit); // In
units used by the coordinates.
+ final int f =
DecimalFunctions.fractionDigitsForDelta(precision, false);
+ if (f > fractionDigits[i]) {
+ fractionDigits[i] = f; // Use
at least the heuristic precision.
}
}
}
- return null;
+ return fractionDigits;
}
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -174,6 +174,16 @@ class SpecializableTransform extends Abs
}
return false;
}
+
+ /**
+ * Formats this envelope as a "{@code DOMAIN}" element (non-standard).
+ * This is used by {@link SpecializableTransform#formatTo(Formatter)}.
+ */
+ @Override
+ protected String formatTo(final Formatter formatter) {
+ super.formatTo(formatter);
+ return "Domain";
+ }
}
/**
@@ -485,11 +495,9 @@ next: for (final Map.Entry<Envelope,Ma
@Override
protected String formatTo(final Formatter formatter) {
for (final SubArea domain : domains) {
- formatter.newLine();
- formatter.append(generic);
- formatter.newLine();
- // TODO: format BBOX.
- formatter.append(domain.transform);
+ formatter.newLine(); formatter.append(generic);
+ formatter.newLine(); formatter.append(domain);
+ formatter.newLine(); formatter.append(domain.transform);
}
formatter.setInvalidWKT(SpecializableTransform.class, null);
return "Specializable_MT";
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -26,17 +26,52 @@ import static org.apache.sis.test.Assert
* Tests the static methods provided in {@link AbstractDirectPosition}.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
* @since 0.3
* @module
*/
public final strictfp class AbstractDirectPositionTest extends TestCase {
/**
- * Tests {@link AbstractDirectPosition#isSimplePrecision(double[])}.
+ * Tests {@link AbstractDirectPosition#parse(CharSequence)}.
*/
@Test
- public void testIsSimplePrecision() {
- assertTrue (AbstractDirectPosition.isSimplePrecision(2, 0.5, 0.25,
Double.NaN, Double.POSITIVE_INFINITY));
- assertFalse(AbstractDirectPosition.isSimplePrecision(2, 0.5, 1.0 / 3));
+ public void testParse() {
+ assertArrayEquals(new double[] {6, 10, 2},
AbstractDirectPosition.parse("POINT(6 10 2)"), STRICT);
+ assertArrayEquals(new double[] {3, 14, 2},
AbstractDirectPosition.parse("POINT M [ 3 14 2 ] "), STRICT);
+ assertArrayEquals(new double[] {2, 10, 8},
AbstractDirectPosition.parse("POINT Z 2 10 8"), STRICT);
+ assertArrayEquals(new double[] {},
AbstractDirectPosition.parse("POINT()"), STRICT);
+ assertArrayEquals(new double[] {},
AbstractDirectPosition.parse("POINT ( ) "), STRICT);
+ }
+
+ /**
+ * Tests {@link AbstractDirectPosition#parse(CharSequence)} with invalid
input strings.
+ */
+ @Test
+ public void testParsingFailures() {
+ try {
+ AbstractDirectPosition.parse("POINT(6 10 2");
+ fail("Parsing should fails because of missing parenthesis.");
+ } catch (IllegalArgumentException e) {
+ // This is the expected exception.
+ final String message = e.getMessage();
+ assertTrue(message, message.contains("POINT(6 10 2"));
+ assertTrue(message, message.contains("‘)’"));
+ }
+ try {
+ AbstractDirectPosition.parse("POINT 6 10 2)");
+ fail("Parsing should fails because of missing parenthesis.");
+ } catch (IllegalArgumentException e) {
+ // This is the expected exception.
+ }
+ try {
+ AbstractDirectPosition.parse("POINT(6 10 2) x");
+ fail("Parsing should fails because of extra characters.");
+ } catch (IllegalArgumentException e) {
+ // This is the expected exception.
+ final String message = e.getMessage();
+ assertTrue(message, message.contains("POINT(6 10 2) x"));
+ assertTrue(message, message.contains("“x”") || //
English locale
+ message.contains("« x »")); //
French locale
+ }
}
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -16,11 +16,12 @@
*/
package org.apache.sis.geometry;
+import org.apache.sis.io.wkt.Formatter;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.apache.sis.test.Assert.*;
/**
@@ -28,7 +29,7 @@ import static org.junit.Assert.*;
* This is the base class of {@link GeneralEnvelope} and {@link
ImmutableEnvelope}.
*
* @author Michael Hausegger
- * @version 0.8
+ * @version 1.0
* @since 0.8
* @module
*/
@@ -64,6 +65,21 @@ public final strictfp class ArrayEnvelop
}
/**
+ * Tests the {@link ArrayEnvelope#formatTo(Formatter)} method.
+ * Contrarily to {@code toString()}, the precision depends on the CRS.
+ */
+ @Test
+ public void testFormatWKT() {
+ ArrayEnvelope envelope = new ArrayEnvelope(new double[] {4, -10, 50,
2});
+ assertMultilinesEquals("BOX[ 4 -10,\n" +
+ " 50 2]", envelope.toWKT());
+ envelope.crs = AbstractEnvelopeTest.WGS84;
+ assertMultilinesEquals("BOX[ 4.00000000 -10.00000000,\n" +
+ " 50.00000000 2.00000000]",
envelope.toWKT());
+
+ }
+
+ /**
* Tests envelope construction from a the pseudo-Well Known Text (WKT)
representation of a Bounding Box (BBOX).
*/
@Test
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -17,6 +17,7 @@
package org.apache.sis.geometry;
import java.util.Arrays;
+import org.apache.sis.io.wkt.Formatter;
import org.apache.sis.test.TestCase;
import org.apache.sis.test.DependsOn;
import org.junit.Test;
@@ -30,7 +31,7 @@ import static org.apache.sis.geometry.Ab
* Tests the {@link GeneralDirectPosition} class.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
* @since 0.3
* @module
*/
@@ -49,10 +50,23 @@ public final strictfp class GeneralDirec
}
/**
+ * Tests the {@link GeneralDirectPosition#formatTo(Formatter)} method.
+ * Contrarily to {@code toString()}, the precision depends on the CRS.
+ */
+ @Test
+ public void testFormatWKT() {
+ final GeneralDirectPosition position = new GeneralDirectPosition(6,
10);
+ assertEquals("POINT[6 10]", position.toWKT());
+ position.setCoordinateReferenceSystem(WGS84);
+ assertEquals("POINT[6.00000000 10.00000000]", position.toWKT());
// 1 cm precision on Earth.
+ validate(position);
+ }
+
+ /**
* Tests the {@link GeneralDirectPosition#toString()} method.
*/
@Test
- public void testWktFormatting() {
+ public void testToString() {
final GeneralDirectPosition position = new GeneralDirectPosition(6,
10, 2);
assertEquals("POINT(6 10 2)", position.toString());
validate(position);
@@ -62,7 +76,7 @@ public final strictfp class GeneralDirec
* Tests the {@link
GeneralDirectPosition#GeneralDirectPosition(CharSequence)} constructor.
*/
@Test
- public void testWktParsing() {
+ public void testConstructor() {
assertEquals("POINT(6 10 2)", new GeneralDirectPosition("POINT(6 10
2)").toString());
assertEquals("POINT(3 14 2)", new GeneralDirectPosition("POINT M [ 3
14 2 ] ").toString());
assertEquals("POINT(2 10 8)", new GeneralDirectPosition("POINT Z 2 10
8").toString());
@@ -71,40 +85,6 @@ public final strictfp class GeneralDirec
}
/**
- * Tests the {@link
GeneralDirectPosition#GeneralDirectPosition(CharSequence)} constructor
- * with invalid input strings.
- */
- @Test
- @SuppressWarnings("ResultOfObjectAllocationIgnored")
- public void testWktParsingFailures() {
- try {
- new GeneralDirectPosition("POINT(6 10 2");
- fail("Parsing should fails because of missing parenthesis.");
- } catch (IllegalArgumentException e) {
- // This is the expected exception.
- final String message = e.getMessage();
- assertTrue(message, message.contains("POINT(6 10 2"));
- assertTrue(message, message.contains("‘)’"));
- }
- try {
- new GeneralDirectPosition("POINT 6 10 2)");
- fail("Parsing should fails because of missing parenthesis.");
- } catch (IllegalArgumentException e) {
- // This is the expected exception.
- }
- try {
- new GeneralDirectPosition("POINT(6 10 2) x");
- fail("Parsing should fails because of extra characters.");
- } catch (IllegalArgumentException e) {
- // This is the expected exception.
- final String message = e.getMessage();
- assertTrue(message, message.contains("POINT(6 10 2) x"));
- assertTrue(message, message.contains("“x”") || // English locale
- message.contains("« x »")); // French locale
- }
- }
-
- /**
* Tests {@link GeneralDirectPosition#clone()}.
*/
@Test
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -18,6 +18,7 @@ package org.apache.sis.internal.referenc
import org.apache.sis.internal.metadata.ReferencingServices;
import org.apache.sis.measure.Longitude;
+import org.apache.sis.referencing.datum.HardCodedDatum;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -28,7 +29,7 @@ import static org.junit.Assert.*;
* Tests {@link Formulas}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
* @since 0.4
* @module
*/
@@ -90,6 +91,14 @@ public final strictfp class FormulasTest
}
/**
+ * Tests {@link Formulas#scaleComparedToEarth(Ellipsoid)}.
+ */
+ @Test
+ public void testScaleComparedToEarth() {
+ assertEquals(1,
Formulas.scaleComparedToEarth(HardCodedDatum.WGS84.getEllipsoid()), 1E-14);
+ }
+
+ /**
* Tests {@link Formulas#getSemiMinor(double, double)}.
*/
@Test
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -39,7 +39,7 @@ import static org.apache.sis.internal.re
*
* @author Martin Desruisseaux (Geomatys)
* @version 0.8
- * @since 0.5 (derived from 0.4)
+ * @since 0.4
* @module
*/
public final strictfp class ReferencingUtilitiesTest extends TestCase {
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -17,6 +17,7 @@
package org.apache.sis.internal.referencing;
import org.opengis.referencing.cs.*;
+import org.apache.sis.referencing.crs.HardCodedCRS;
import org.apache.sis.internal.metadata.WKTKeywords;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
@@ -30,7 +31,7 @@ import static org.apache.sis.internal.re
* Tests {@link WKTUtilities}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
* @since 0.7
* @module
*/
@@ -49,10 +50,21 @@ public final strictfp class WKTUtilities
assertEquals(WKTKeywords.cylindrical, toType(CoordinateSystem.class,
CylindricalCS .class));
assertEquals(WKTKeywords.ellipsoidal, toType(CoordinateSystem.class,
EllipsoidalCS .class));
assertEquals(WKTKeywords.linear, toType(CoordinateSystem.class,
LinearCS .class));
-// assertEquals(WKTKeywords.parametric, toType(CoordinateSystem.class,
ParametricCS .class));
+ assertEquals(WKTKeywords.parametric, toType(CoordinateSystem.class,
ParametricCS .class));
assertEquals(WKTKeywords.polar, toType(CoordinateSystem.class,
PolarCS .class));
assertEquals(WKTKeywords.spherical, toType(CoordinateSystem.class,
SphericalCS .class));
assertEquals(WKTKeywords.temporal, toType(CoordinateSystem.class,
TimeCS .class));
assertEquals(WKTKeywords.vertical, toType(CoordinateSystem.class,
VerticalCS .class));
}
+
+ /**
+ * Tests {@link
WKTUtilities#suggestFractionDigits(CoordinateReferenceSystem, double[]...)}.
+ */
+ @Test
+ public void testSuggestFractionDigits() {
+ assertArrayEquals(new int[] {8, 9},
WKTUtilities.suggestFractionDigits(HardCodedCRS.WGS84, new double[][] {
+ {40, -10},
+ {50, -10.000000001}
+ }));
+ }
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -71,4 +71,27 @@ public final strictfp class Specializabl
isInverseTransformSupported = false;
verifyInDomain(CoordinateDomain.RANGE_10, -672445632505596619L);
}
+
+ /**
+ * Tests the pseudo Well-Known Text formatting.
+ * The format used by this transform is non-standard and may change in any
future Apache SIS version.
+ *
+ * @throws InvalidGeodeticParameterException if {@link
SpecializableTransform} constructor reject a parameter.
+ */
+ @Test
+ public void testWKT() throws InvalidGeodeticParameterException {
+ transform = create();
+ assertWktEquals(
+ "SPECIALIZABLE_MT[\n" +
+ " PARAM_MT[“Affine”,\n" +
+ " PARAMETER[“elt_0_0”, 10.0],\n" +
+ " PARAMETER[“elt_1_1”, 10.0]],\n" +
+ " DOMAIN[-5 -4,\n" +
+ " 5 3],\n" +
+ " PARAM_MT[“Affine”,\n" +
+ " PARAMETER[“elt_0_0”, 10.0],\n" +
+ " PARAMETER[“elt_0_2”, 0.1],\n" +
+ " PARAMETER[“elt_1_1”, 10.0],\n" +
+ " PARAMETER[“elt_1_2”, 0.1]]]");
+ }
}
Modified:
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -21,6 +21,8 @@ import java.util.HashMap;
import org.apache.sis.util.Debug;
import org.apache.sis.util.Static;
import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.math.DecimalFunctions;
+import org.opengis.referencing.operation.Matrix; // For javadoc
import static java.lang.Math.max;
import static java.lang.Math.abs;
@@ -30,7 +32,7 @@ import static java.lang.Math.abs;
* Miscellaneous utilities methods working on floating point numbers.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
@@ -156,6 +158,22 @@ public final class Numerics extends Stat
}
/**
+ * Returns {@code true} if every values in the given {@code double} array
could be casted to the
+ * {@code float} type without precision lost. This method treats all
{@code NaN} values as equal.
+ *
+ * @param values the value to test for their precision.
+ * @return {@code true} if every values can be casted to the {@code float}
type without precision lost.
+ */
+ public static boolean isSimplePrecision(final double... values) {
+ for (final double value : values) {
+ if (Double.doubleToLongBits(value) !=
Double.doubleToLongBits((float) value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Returns a copy of the given array where each value has been casted to
the {@code float} type.
*
* @param data the array to copy, or {@code null}.
@@ -428,4 +446,51 @@ public final class Numerics extends Stat
}
return bits;
}
+
+ /**
+ * Suggests an amount of fraction digits to use for formatting numbers in
each column of the given matrix.
+ * The number of fraction digits may be negative if we could round the
numbers to 10, 100, <i>etc</i>.
+ *
+ * @param rows the matrix rows. It is not required that each row has the
same length.
+ * @return suggested amount of fraction digits as an array as long as the
longest row.
+ *
+ * @see
org.apache.sis.referencing.operation.matrix.Matrices#toString(Matrix)
+ */
+ public static int[] suggestFractionDigits(final double[][] rows) {
+ int length = 0;
+ final int n = rows.length - 1;
+ for (int j=0; j <= n; j++) {
+ final int rl = rows[j].length;
+ if (rl > length) length = rl;
+ }
+ final int[] fractionDigits = new int[length];
+ for (int i=0; i<length; i++) {
+ double min = Double.POSITIVE_INFINITY;
+ double max = Double.NEGATIVE_INFINITY;
+ boolean isInteger = true;
+ for (final double[] row : rows) {
+ if (row.length > i) {
+ final double value = row[i];
+ if (value < min) min = value;
+ if (value > max) max = value;
+ if (isInteger && Math.floor(value) != value &&
!Double.isNaN(value)) {
+ isInteger = false;
+ }
+ }
+ }
+ if (!isInteger) {
+ final double delta;
+ final boolean strict;
+ if (min < max) {
+ delta = (max - min) / n;
+ strict = (n == 1);
+ } else {
+ delta = Math.max(Math.abs(min), Math.abs(max)) * 1E-6;
// The 1E-6 factor is arbitrary.
+ strict = false;
+ }
+ fractionDigits[i] =
DecimalFunctions.fractionDigitsForDelta(delta, strict);
+ }
+ }
+ return fractionDigits;
+ }
}
Modified:
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java?rev=1825822&r1=1825821&r2=1825822&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
[UTF-8] Sun Mar 4 16:12:09 2018
@@ -34,7 +34,7 @@ import static org.junit.Assert.*;
* Tests the {@link Numerics} class.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.0
* @since 0.3
* @module
*/
@@ -69,6 +69,15 @@ public final strictfp class NumericsTest
}
/**
+ * Tests {@link Numerics#isSimplePrecision(double[])}.
+ */
+ @Test
+ public void testIsSimplePrecision() {
+ assertTrue (Numerics.isSimplePrecision(2, 0.5, 0.25, Double.NaN,
Double.POSITIVE_INFINITY));
+ assertFalse(Numerics.isSimplePrecision(2, 0.5, 1.0 / 3));
+ }
+
+ /**
* Tests the {@link Numerics#epsilonEqual(double, double, ComparisonMode)}
method.
*/
@Test
@@ -162,4 +171,17 @@ public final strictfp class NumericsTest
final float recomposed = StrictMath.scalb((float) expected, e);
assertEquals(value, StrictMath.copySign(recomposed, value), 0f);
}
+
+ /**
+ * Tests {@link Numerics#suggestFractionDigits(double[][])}.
+ */
+ @Test
+ public void testSuggestFractionDigits() {
+ final int[] f = Numerics.suggestFractionDigits(new double[][] {
+ {10, 100, 0.1, 1000.1},
+ {15, 140.1, 0.4, Double.NaN},
+ {20, 400, 0.5, Double.NaN}
+ });
+ assertArrayEquals(new int[] {0, -2, 1, 3}, f);
+ }
}