Author: desruisseaux
Date: Fri Oct 4 13:25:48 2013
New Revision: 1529160
URL: http://svn.apache.org/r1529160
Log:
Improvement in Matrix string representation for making easier to spot
"interesting" values.
Modified:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java
Modified:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1529160&r1=1529159&r2=1529160&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
[UTF-8] Fri Oct 4 13:25:48 2013
@@ -68,7 +68,7 @@ public final class Matrices extends Stat
/**
* Number of spaces to put between columns formatted by {@link
#toString(Matrix)}.
*/
- private static final int MARGIN = 2;
+ private static final int SPACING = 2;
/**
* Do not allows instantiation of this class.
@@ -830,6 +830,25 @@ public final class Matrices extends Stat
* Returns a unlocalized string representation of the given matrix.
* For each column, the numbers are aligned on the decimal separator.
*
+ * <p>The current implementation formats ±0 and ±1 without trailing {@code
".0"}, and all other values with
+ * a per-column uniform number of fraction digits. The ±0 and ±1 values
are treated especially because they
+ * usually imply a "<cite>no scale</cite>", "<cite>no translation</cite>"
or "<cite>orthogonal axes</cite>"
+ * meaning. A matrix in SIS is often populated mostly by ±0 and ±1 values,
with a few "interesting" values.
+ * The simpler ±0 and ±1 formatting makes easier to spot the "interesting"
values.</p>
+ *
+ * <p>The following example shows the string representation of an affine
transform which swap
+ * (<var>latitude</var>, <var>longitude</var>) axes, converts degrees to
radians and converts
+ * height values from feet to metres:</p>
+ *
+ * {@preformat math
+ * ┌ ┐
+ * │ 0 0.017453292519943295 0 0 │
+ * │ 0.017453292519943295 0 0 0 │
+ * │ 0 0 0.3048 0 │
+ * │ 0 0 0 1 │
+ * └ ┘
+ * }
+ *
* {@note Formatting on a per-column basis is convenient for the kind of
matrices used in referencing by coordinates,
* because each column is typically a displacement vector in a
different dimension of the source coordinate
* reference system. In addition, the last column is often a
translation vector having a magnitude very
@@ -841,53 +860,92 @@ public final class Matrices extends Stat
public static String toString(final Matrix matrix) {
final int numRow = matrix.getNumRow();
final int numCol = matrix.getNumCol();
- final String[] elements = new String[numRow * numCol];
- final int[] columnWidth = new int[numCol];
- final int[] maximumFractionDigits = new int[numCol];
- final int[] maximumRemainingWidth = new int[numCol]; // Minus sign (if
any) + integer digits + decimal separator + 2 spaces.
+ final String[] elements = new String [numCol * numRow];
+ final boolean[] noFractionDigits = new boolean[numCol * numRow];
+ final boolean[] hasDecimalSeparator = new boolean[numCol];
+ final int[] maximumFractionDigits = new int [numCol];
+ final int[] widthBeforeFraction = new int [numCol]; // spacing
+ ('-') + integerDigits + '.'
+ final int[] columnWidth = new int [numCol];
int totalWidth = 1;
/*
* Create now the string representation of all matrix elements and
measure the width
* of the integer field and the fraction field, then the total width
of each column.
*/
- int margin = 1; // Margin before the first column only.
+ int spacing = 1; // Spacing is 1 before the first column only, then
SPACING for other columns.
for (int i=0; i<numCol; i++) {
for (int j=0; j<numRow; j++) {
- final String element =
Double.toString(matrix.getElement(j,i)).replace("Infinity", "∞");
- elements[j*numCol + i] = element;
- int width = element.length();
- int s = element.lastIndexOf('.');
- if (s >= 0) {
- width = (maximumRemainingWidth[i] =
Math.max(maximumRemainingWidth[i], ++s + margin))
- + (maximumFractionDigits[i] =
Math.max(maximumFractionDigits[i], width - s));
+ final int flatIndex = j*numCol + i;
+ final double value = matrix.getElement(j,i);
+ String element = Double.toString(value);
+ final int width;
+ /*
+ * Special case for ±0 and ±1 (because those values appear
very often and have
+ * a particular meaning): for those values, we will ignore the
fraction digits.
+ * For all other values, we will format all fraction digits.
+ */
+ if (value == -1 || value == 0 || value == +1) {
+ noFractionDigits[flatIndex] = true;
+ width = spacing + element.length() - 2; // The -2 is for
ignoring the trailing ".0"
+ widthBeforeFraction[i] = Math.max(widthBeforeFraction[i],
width);
} else {
- // NaN or Infinity.
- width += margin;
+ /*
+ * All values other than ±0 and ±1. Store separately the
width before and after
+ * the decimal separator. The width before the separator
contains the spacing.
+ */
+ int s = element.lastIndexOf('.');
+ if (s >= 0) {
+ s++; // After the separator.
+ hasDecimalSeparator[i] = true;
+ width = (widthBeforeFraction [i] =
Math.max(widthBeforeFraction [i], spacing + s))
+ + (maximumFractionDigits[i] =
Math.max(maximumFractionDigits[i], element.length() - s));
+ } else {
+ // NaN or Infinity.
+ element = element.replace("Infinity", "∞");
+ width = spacing + element.length();
+ }
}
columnWidth[i] = Math.max(columnWidth[i], width);
+ elements[flatIndex] = element;
}
totalWidth += columnWidth[i];
- margin = MARGIN; // Margin before all columns after the first one.
+ spacing = SPACING; // Specing before all columns after the first
one.
}
/*
- * Now append the formatted elements with the appropriate amount of
spaces
- * and trailling zeros for each column.
+ * Now append the formatted elements with the appropriate amount of
spaces before each value,
+ * and trailling zeros after each value except ±0, ±1, NaN and
infinities.
*/
- final String lineSeparator = System.lineSeparator();
+ final String lineSeparator = System.lineSeparator();
final CharSequence whiteLine = CharSequences.spaces(totalWidth);
- final StringBuffer buffer = new StringBuffer((totalWidth + 2 +
lineSeparator.length()) * (numRow + 2));
+ final StringBuilder buffer = new StringBuilder((totalWidth + 2 +
lineSeparator.length()) * (numRow + 2));
buffer.append('┌').append(whiteLine).append('┐').append(lineSeparator);
- for (int k=0,j=0; j<numRow; j++) {
+ int flatIndex = 0;
+ for (int j=0; j<numRow; j++) {
buffer.append('│');
for (int i=0; i<numCol; i++) {
- final String element = elements[k++];
+ final String element = elements[flatIndex];
final int width = element.length();
- int s = element.lastIndexOf('.');
- buffer.append(CharSequences.spaces(s >= 0 ?
maximumRemainingWidth[i] - ++s : columnWidth[i] - width)).append(element);
+ int spaces, s = element.lastIndexOf('.');
+ if (s >= 0) {
+ if (hasDecimalSeparator[i]) s++;
+ spaces = widthBeforeFraction[i] - s; // Number of spaces
for alignment on the decimal separator
+ } else {
+ spaces = columnWidth[i] - width; // Number of spaces for
right alignment (NaN or ∞ cases)
+ }
+ buffer.append(CharSequences.spaces(spaces)).append(element);
+ /*
+ * Append trailing spaces for ±0 and ±1 values,
+ * or trailing zeros for all other real values.
+ */
s += maximumFractionDigits[i] - width;
- while (--s >= 0) {
- buffer.append('0');
+ if (noFractionDigits[flatIndex]) {
+ buffer.setLength(buffer.length() - 2); // Erase the
trailing ".0"
+ buffer.append(CharSequences.spaces(s + 2));
+ } else {
+ while (--s >= 0) {
+ buffer.append('0');
+ }
}
+ flatIndex++;
}
buffer.append(" │").append(lineSeparator);
}
Modified:
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java?rev=1529160&r1=1529159&r2=1529160&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java
[UTF-8] Fri Oct 4 13:25:48 2013
@@ -331,18 +331,28 @@ public final strictfp class MatricesTest
*/
@Test
public void testToString() {
- final MatrixSIS matrix = Matrices.create(4, 4, new double[] {
- 39.5193682106975150, -68.5200, 80.0, 98,
- -66.0358637477182200, Double.NaN, 43.9,
Double.NEGATIVE_INFINITY,
- 2.0741018968776337, 83.7260, 37.0, -3,
- 91.8796187759200600, -18.2674, 24.0, 36
+ assertMultilinesEquals(
+ "┌ ┐\n" +
+ "│ 1 0 0 0 │\n" +
+ "│ 0 1 0 0 │\n" +
+ "│ 0 0 1 0 │\n" +
+ "│ 0 0 0 1 │\n" +
+ "└ ┘\n", new Matrix4().toString());
+ /*
+ * Mix of values with different precision, ±0, ±1, NaN and infinities.
+ */
+ final MatrixSIS matrix = Matrices.create(4, 5, new double[] {
+ 39.5193682106975150, -68.5200, -1.0, 1, 98,
+ -66.0358637477182200, Double.NaN, 43.0, 0,
Double.NEGATIVE_INFINITY,
+ 2.0741018968776337, 83.7260, -0.0, 1, -3,
+ 91.8796187759200600, -18.2674, 24.5, 0, 36.5
});
assertMultilinesEquals(
- "┌ ┐\n" +
- "│ 39.5193682106975150 -68.5200 80.0 98.0 │\n" +
- "│ -66.0358637477182200 NaN 43.9 -∞ │\n" +
- "│ 2.0741018968776337 83.7260 37.0 -3.0 │\n" +
- "│ 91.8796187759200600 -18.2674 24.0 36.0 │\n" +
- "└ ┘\n",
matrix.toString());
+ "┌ ┐\n" +
+ "│ 39.5193682106975150 -68.5200 -1 1 98.0 │\n" +
+ "│ -66.0358637477182200 NaN 43.0 0 -∞ │\n" +
+ "│ 2.0741018968776337 83.7260 -0 1 -3.0 │\n" +
+ "│ 91.8796187759200600 -18.2674 24.5 0 36.5 │\n" +
+ "└ ┘\n",
matrix.toString());
}
}
Modified:
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java?rev=1529160&r1=1529159&r2=1529160&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java
[UTF-8] Fri Oct 4 13:25:48 2013
@@ -112,9 +112,6 @@ public final strictfp class Matrix4Test
final MatrixSIS step3 = step2.multiply(step1).inverse();
/*
* Concatenate everything, which should go back to the identity
transform.
- * We have a slight residu in the longitude translation term because
of the
- * prime meridian shift - we will set this residu to zero for this
test.
- *
* Note that the 'isIdentity()' test fail if the double-double
arithmetic is
* disabled, because some scale factors will be 0.9999999999999999
instead of 1.
*/