001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2001, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.parameter;
018:
019: // J2SE dependencies
020: import java.io.IOException;
021: import java.util.Collection;
022: import java.util.List;
023: import java.util.Set;
024:
025: // OpenGIS dependencies
026: import org.opengis.parameter.GeneralParameterDescriptor;
027: import org.opengis.parameter.GeneralParameterValue;
028: import org.opengis.parameter.ParameterDescriptor;
029: import org.opengis.parameter.ParameterDescriptorGroup;
030: import org.opengis.parameter.ParameterNotFoundException;
031: import org.opengis.parameter.ParameterValue;
032: import org.opengis.referencing.ReferenceIdentifier;
033: import org.opengis.referencing.operation.Matrix;
034: import org.opengis.util.InternationalString;
035:
036: // Geotools dependencies
037: import org.geotools.io.TableWriter;
038: import org.geotools.referencing.operation.matrix.MatrixFactory;
039: import org.geotools.resources.UnmodifiableArrayList;
040: import org.geotools.resources.Utilities;
041: import org.geotools.resources.XArray;
042:
043: /**
044: * The values for a group of {@linkplain MatrixParameterDescriptors matrix parameters}. This value
045: * group is extensible, i.e. the number of <code>"elt_<var>row</var>_<var>col</var>"</code>
046: * parameters depends on the <code>"num_row"</code> and <code>"num_col"</code> parameter values.
047: * Consequently, this {@linkplain ParameterGroup parameter value group} is also its own mutable
048: * {@linkplain ParameterDescriptorGroup operation parameter group}.
049: *
050: * @since 2.1
051: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/parameter/MatrixParameters.java $
052: * @version $Id: MatrixParameters.java 24973 2007-03-30 21:57:48Z chorner $
053: * @author Martin Desruisseaux
054: *
055: * @see MatrixParameterDescriptors
056: */
057: public class MatrixParameters extends ParameterGroup implements
058: ParameterDescriptorGroup {
059: /**
060: * Serial number for interoperability with different versions.
061: */
062: private static final long serialVersionUID = -7747712999115044943L;
063:
064: /**
065: * The parameter values. Will be constructed only when first requested.
066: */
067: private ParameterValue[][] matrixValues;
068:
069: /**
070: * The value for the {@link MatrixParameterDescriptors#numRow} parameter.
071: * Consider this field as final. It is not only for {@link #clone} implementation.
072: */
073: private ParameterValue numRow;
074:
075: /**
076: * The value for the {@link MatrixParameterDescriptors#numCol} parameter.
077: * Consider this field as final. It is not only for {@link #clone} implementation.
078: */
079: private ParameterValue numCol;
080:
081: /**
082: * Constructs default values for the specified
083: * {@linkplain MatrixParameterDescriptors matrix parameter descriptors}.
084: */
085: public MatrixParameters(final MatrixParameterDescriptors descriptor) {
086: super (descriptor);
087: numRow = (ParameterValue) parameter(0);
088: numCol = (ParameterValue) parameter(1);
089: }
090:
091: /**
092: * Returns a description of this parameter value group. Returns always {@code this},
093: * since the description depends on <code>"num_row"</code> and <code>"num_col"</code>
094: * parameter values.
095: */
096: public GeneralParameterDescriptor getDescriptor() {
097: return this ;
098: }
099:
100: /**
101: * Forward the call to the {@linkplain MatrixParameterDescriptors matrix parameter descriptors}
102: * specified at construction time.
103: */
104: public ReferenceIdentifier getName() {
105: return descriptor.getName();
106: }
107:
108: /**
109: * Forward the call to the {@linkplain MatrixParameterDescriptors matrix parameter descriptors}
110: * specified at construction time.
111: */
112: public Collection/*<GenericName>*/getAlias() {
113: return descriptor.getAlias();
114: }
115:
116: /**
117: * Forward the call to the {@linkplain MatrixParameterDescriptors matrix parameter descriptors}
118: * specified at construction time.
119: */
120: public Set/*<Identifier>*/getIdentifiers() {
121: return descriptor.getIdentifiers();
122: }
123:
124: /**
125: * Forward the call to the {@linkplain MatrixParameterDescriptors matrix parameter descriptors}
126: * specified at construction time.
127: */
128: public InternationalString getRemarks() {
129: return descriptor.getRemarks();
130: }
131:
132: /**
133: * Forward the call to the {@linkplain MatrixParameterDescriptors matrix parameter descriptors}
134: * specified at construction time.
135: */
136: public int getMinimumOccurs() {
137: return descriptor.getMinimumOccurs();
138: }
139:
140: /**
141: * Forward the call to the {@linkplain MatrixParameterDescriptors matrix parameter descriptors}
142: * specified at construction time.
143: */
144: public int getMaximumOccurs() {
145: return descriptor.getMaximumOccurs();
146: }
147:
148: /**
149: * Returns the parameter in this group for the specified name. The name can be a matrix element
150: * if it uses the following syntax: <code>"elt_<var>row</var>_<var>col</var>"</code> where
151: * <code>"elt_"</code> is the {@linkplain MatrixParameterDescriptors#prefix prefix} for all
152: * matrix elements, and <var>row</var> and <var>col</var> are row and column indices
153: * respectively. For example <code>"elt_2_1"</code> is the element name for the value at line 2
154: * and row 1. The row and column index are 0 based.
155: *
156: * @param name The case insensitive name of the parameter to search for.
157: * @return The parameter for the given name.
158: * @throws ParameterNotFoundException if there is no parameter for the given name.
159: */
160: public GeneralParameterDescriptor descriptor(final String name)
161: throws ParameterNotFoundException {
162: return ((MatrixParameterDescriptors) descriptor).descriptor(
163: name, numRow.intValue(), numCol.intValue());
164: }
165:
166: /**
167: * Returns the value in this group for the specified name. The name can be a matrix element
168: * if it uses the following syntax: <code>"elt_<var>row</var>_<var>col</var>"</code> where
169: * <code>"elt_"</code> is the {@linkplain MatrixParameterDescriptors#prefix prefix} for all
170: * matrix elements, and <var>row</var> and <var>col</var> are row and column indices
171: * respectively. For example <code>"elt_2_1"</code> is the element name for the value at line
172: * 2 and row 1. The row and column index are 0 based.
173: *
174: * @param name The case insensitive name of the parameter to search for.
175: * @return The parameter value for the given name.
176: * @throws ParameterNotFoundException if there is no parameter for the given name.
177: */
178: public ParameterValue parameter(String name)
179: throws ParameterNotFoundException {
180: ensureNonNull("name", name);
181: name = name.trim();
182: final MatrixParameterDescriptors descriptor = ((MatrixParameterDescriptors) this .descriptor);
183: final String prefix = descriptor.prefix;
184: RuntimeException cause = null;
185: if (name.regionMatches(true, 0, prefix, 0, prefix.length())) {
186: final int split = name.indexOf(descriptor.separator, prefix
187: .length());
188: if (split >= 0)
189: try {
190: final int row = Integer.parseInt(name.substring(
191: prefix.length(), split));
192: final int col = Integer.parseInt(name
193: .substring(split + 1));
194: return parameter(row, col);
195: } catch (NumberFormatException exception) {
196: cause = exception;
197: } catch (IndexOutOfBoundsException exception) {
198: cause = exception;
199: }
200: }
201: /*
202: * The parameter name is not a matrix element name. Search in the super
203: * class for other parameters, especially "num_row" and "num_col".
204: */
205: try {
206: return super .parameter(name);
207: } catch (ParameterNotFoundException exception) {
208: if (cause != null)
209: try {
210: exception.initCause(cause);
211: } catch (IllegalStateException ignore) {
212: // A cause has already be given to the exception. Forget the cause then.
213: }
214: throw exception;
215: }
216: }
217:
218: /**
219: * Returns the value in this group for a matrix element at the specified index.
220: * Row and column index are 0 based.
221: *
222: * @param row The row indice.
223: * @param column The column indice
224: * @return The parameter value for the specified matrix element (never {@code null}).
225: * @throws IndexOutOfBoundsException if {@code row} or {@code column} is out of bounds.
226: */
227: public final ParameterValue parameter(final int row,
228: final int column) throws IndexOutOfBoundsException {
229: return parameter(row, column, numRow.intValue(), numCol
230: .intValue());
231: }
232:
233: /**
234: * Implementation of {@link #parameter(int,int)}.
235: *
236: * @param row The row indice.
237: * @param column The column indice
238: * @param numRow The maximum number of rows.
239: * @param numCol The maximum number of columns.
240: * @return The parameter value for the specified matrix element.
241: * @throws IndexOutOfBoundsException if {@code row} or {@code column} is out of bounds.
242: */
243: private ParameterValue parameter(final int row, final int column,
244: final int numRow, final int numCol)
245: throws IndexOutOfBoundsException {
246: MatrixParameterDescriptors.checkIndice("row", row, numRow);
247: MatrixParameterDescriptors
248: .checkIndice("column", column, numCol);
249: if (matrixValues == null) {
250: matrixValues = new ParameterValue[numRow][];
251: }
252: if (row >= matrixValues.length) {
253: matrixValues = (ParameterValue[][]) XArray.resize(
254: matrixValues, numRow);
255: }
256: ParameterValue[] rowValues = matrixValues[row];
257: if (rowValues == null) {
258: matrixValues[row] = rowValues = new ParameterValue[numCol];
259: }
260: if (column >= rowValues.length) {
261: matrixValues[row] = rowValues = (ParameterValue[]) XArray
262: .resize(rowValues, numCol);
263: }
264: ParameterValue param = rowValues[column];
265: if (param == null) {
266: rowValues[column] = param = new FloatParameter(
267: ((MatrixParameterDescriptors) descriptor)
268: .descriptor(row, column, numRow, numCol));
269: }
270: return param;
271: }
272:
273: /**
274: * Returns the parameters descriptors in this group. The amount of parameters depends
275: * on the value of <code>"num_row"</code> and <code>"num_col"</code> parameters.
276: */
277: public List/*<GeneralParameterDescriptor>*/descriptors() {
278: return ((MatrixParameterDescriptors) descriptor).descriptors(
279: numRow.intValue(), numCol.intValue());
280: }
281:
282: /**
283: * Returns the parameters values in this group. The amount of parameters depends
284: * on the value of <code>"num_row"</code> and <code>"num_col"</code> parameters.
285: * The parameter array will contains only matrix elements which have been requested at
286: * least once by one of {@code parameter(...)} methods. Never requested elements
287: * are left to their default value and omitted from the returned array.
288: */
289: public List/*<GeneralParameterValue>*/values() {
290: final int numRow = this .numRow.intValue();
291: final int numCol = this .numCol.intValue();
292: final ParameterValue[] parameters = new ParameterValue[numRow
293: * numCol + 2];
294: int k = 0;
295: parameters[k++] = this .numRow;
296: parameters[k++] = this .numCol;
297: if (matrixValues != null) {
298: final int maxRow = Math.min(numRow, matrixValues.length);
299: for (int j = 0; j < maxRow; j++) {
300: final ParameterValue[] rowValues = matrixValues[j];
301: if (rowValues != null) {
302: final int maxCol = Math.min(numCol,
303: rowValues.length);
304: for (int i = 0; i < maxCol; i++) {
305: final ParameterValue value = rowValues[i];
306: if (value != null) {
307: parameters[k++] = value;
308: }
309: }
310: }
311: }
312: }
313: return new UnmodifiableArrayList((ParameterValue[]) XArray
314: .resize(parameters, k));
315: }
316:
317: /**
318: * Forward the call to the {@linkplain MatrixParameterDescriptors matrix parameter descriptors}
319: * specified at construction time.
320: */
321: public GeneralParameterValue createValue() {
322: return descriptor.createValue();
323: }
324:
325: /**
326: * Create a matrix from this group of parameters.
327: *
328: * @return A matrix created from this group of parameters.
329: */
330: public Matrix getMatrix() {
331: final int numRow = this .numRow.intValue();
332: final int numCol = this .numCol.intValue();
333: final Matrix matrix = MatrixFactory.create(numRow, numCol);
334: if (matrixValues != null) {
335: for (int j = 0; j < numRow; j++) {
336: final ParameterValue[] row = matrixValues[j];
337: if (row != null) {
338: for (int i = 0; i < numCol; i++) {
339: final ParameterValue element = row[i];
340: if (element != null) {
341: matrix.setElement(j, i, element
342: .doubleValue());
343: }
344: }
345: }
346: }
347: }
348: return matrix;
349: }
350:
351: /**
352: * Set all parameter values to the element value in the specified matrix.
353: * After this method call, {@link #values} will returns only the elements
354: * different from the default value.
355: *
356: * @param matrix The matrix to copy in this group of parameters.
357: */
358: public void setMatrix(final Matrix matrix) {
359: final MatrixParameterDescriptors matrixDescriptor = ((MatrixParameterDescriptors) this .descriptor);
360: final int numRow = matrix.getNumRow();
361: final int numCol = matrix.getNumCol();
362: this .numRow.setValue(numRow);
363: this .numCol.setValue(numCol);
364: for (int row = 0; row < numRow; row++) {
365: for (int col = 0; col < numCol; col++) {
366: final double element = matrix.getElement(row, col);
367: ParameterDescriptor descriptor = matrixDescriptor
368: .descriptor(row, col);
369: final Object defaultValue = descriptor
370: .getDefaultValue();
371: if (defaultValue instanceof Number) {
372: double value = ((Number) defaultValue)
373: .doubleValue();
374: if (Double.doubleToLongBits(element) == Double
375: .doubleToLongBits(value)) {
376: /*
377: * Value matches the default value, so there is no need to keep it.
378: * Remove entry to keep things sparse.
379: */
380: if (matrixValues != null
381: && matrixValues[row] != null) {
382: matrixValues[row][col] = null;
383: }
384: continue;
385: }
386: }
387: if (matrixValues == null) {
388: matrixValues = new ParameterValue[numRow][];
389: }
390: if (matrixValues[row] == null) {
391: matrixValues[row] = new ParameterValue[numCol];
392: }
393: matrixValues[row][col] = new FloatParameter(descriptor,
394: element);
395: }
396: }
397: }
398:
399: /**
400: * Compare this object with the specified one for equality.
401: */
402: public boolean equals(final Object object) {
403: if (object == this ) {
404: return true; // Slight optimization.
405: }
406: if (super .equals(object)) {
407: final MatrixParameters that = (MatrixParameters) object;
408: final int numRow = this .numRow.intValue();
409: final int numCol = this .numCol.intValue();
410: for (int j = 0; j < numRow; j++) {
411: for (int i = 0; i < numCol; i++) {
412: if (!Utilities.equals(this .parameter(j, i, numRow,
413: numCol), that.parameter(j, i, numRow,
414: numCol))) {
415: return false;
416: }
417: }
418: }
419: return true;
420: }
421: return false;
422: }
423:
424: /**
425: * Returns a clone of this parameter group.
426: */
427: public Object clone() {
428: final MatrixParameters copy = (MatrixParameters) super .clone();
429: if (copy.matrixValues != null) {
430: copy.numRow = (ParameterValue) copy.parameter(0);
431: copy.numCol = (ParameterValue) copy.parameter(1);
432: copy.matrixValues = (ParameterValue[][]) copy.matrixValues
433: .clone();
434: for (int j = 0; j < copy.matrixValues.length; j++) {
435: ParameterValue[] array = copy.matrixValues[j];
436: if (array != null) {
437: copy.matrixValues[j] = array = (ParameterValue[]) array
438: .clone();
439: for (int i = 0; i < array.length; i++) {
440: if (array[i] != null) {
441: array[i] = (ParameterValue) array[i]
442: .clone();
443: }
444: }
445: }
446: }
447: }
448: return copy;
449: }
450:
451: /**
452: * Write the content of this parameter to the specified table.
453: *
454: * @param table The table where to format the parameter value.
455: * @throws IOException if an error occurs during output operation.
456: */
457: protected void write(final TableWriter table) throws IOException {
458: table.write(getName(descriptor));
459: table.nextColumn();
460: table.write('=');
461: table.nextColumn();
462: table.write(getMatrix().toString());
463: table.nextLine();
464: }
465: }
|