001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2007, Geotools Project Managment Committee (PMC)
005: * (C) 2007, Geomatys
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; either
010: * version 2.1 of the License, or (at your option) any later version.
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.util;
018:
019: import javax.media.jai.util.Range;
020: import javax.units.ConversionException;
021: import javax.units.Converter;
022: import javax.units.Unit;
023:
024: import org.geotools.resources.Utilities;
025: import org.geotools.resources.ClassChanger;
026:
027: /**
028: * A range of numbers associated with a unit of measurement. Unit conversions are applied as
029: * needed by {@linkplain #union union} and {@linkplain #intersect intersection} operations.
030: *
031: * @since 2.4
032: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/util/MeasurementRange.java $
033: * @version $Id: MeasurementRange.java 26601 2007-08-19 23:16:35Z desruisseaux $
034: * @author Martin Desruisseaux
035: */
036: public class MeasurementRange extends NumberRange {
037: /**
038: * Serial number for interoperability with different versions.
039: */
040: private static final long serialVersionUID = 3980319420337513745L;
041:
042: /**
043: * The units of measurement, or {@code null} if unknown.
044: */
045: private final Unit units;
046:
047: /**
048: * Constructs an inclusive range of {@code float} values.
049: *
050: * @param minimum The minimum value, inclusive.
051: * @param maximum The maximum value, <strong>inclusive</strong>.
052: * @param units The units of measurement, or {@code null} if unknown.
053: */
054: public MeasurementRange(final float minimum, final float maximum,
055: final Unit units) {
056: super (minimum, maximum);
057: this .units = units;
058: }
059:
060: /**
061: * Constructs a range of {@code float} values.
062: *
063: * @param minimum The minimum value.
064: * @param isMinIncluded Defines whether the minimum value is included in the Range.
065: * @param maximum The maximum value.
066: * @param isMaxIncluded Defines whether the maximum value is included in the Range.
067: * @param units The units of measurement, or {@code null} if unknown.
068: */
069: public MeasurementRange(final float minimum,
070: final boolean isMinIncluded, final float maximum,
071: final boolean isMaxIncluded, final Unit units) {
072: super (minimum, isMinIncluded, maximum, isMaxIncluded);
073: this .units = units;
074: }
075:
076: /**
077: * Constructs an inclusive range of {@code double} values.
078: *
079: * @param minimum The minimum value, inclusive.
080: * @param maximum The maximum value, <strong>inclusive</strong>.
081: * @param units The units of measurement, or {@code null} if unknown.
082: */
083: public MeasurementRange(final double minimum, final double maximum,
084: final Unit units) {
085: super (minimum, maximum);
086: this .units = units;
087: }
088:
089: /**
090: * Constructs a range of {@code double} values.
091: *
092: * @param minimum The minimum value.
093: * @param isMinIncluded Defines whether the minimum value is included in the Range.
094: * @param maximum The maximum value.
095: * @param isMaxIncluded Defines whether the maximum value is included in the Range.
096: * @param units The units of measurement, or {@code null} if unknown.
097: */
098: public MeasurementRange(final double minimum,
099: final boolean isMinIncluded, final double maximum,
100: final boolean isMaxIncluded, final Unit units) {
101: super (minimum, isMinIncluded, maximum, isMaxIncluded);
102: this .units = units;
103: }
104:
105: /**
106: * Constructs a range of {@link Number} objects.
107: *
108: * @param type The element class, usually one of {@link Byte}, {@link Short},
109: * {@link Integer}, {@link Long}, {@link Float} or {@link Double}.
110: * @param minimum The minimum value.
111: * @param isMinIncluded Defines whether the minimum value is included in the Range.
112: * @param maximum The maximum value.
113: * @param isMaxIncluded Defines whether the maximum value is included in the Range.
114: * @param units The units of measurement, or {@code null} if unknown.
115: */
116: public MeasurementRange(final Class type, final Number minimum,
117: final boolean isMinIncluded, final Number maximum,
118: final boolean isMaxIncluded, final Unit units) {
119: super (type, minimum, isMinIncluded, maximum, isMaxIncluded);
120: this .units = units;
121: }
122:
123: /**
124: * Constructs a range with the same values than the specified range.
125: *
126: * @param range The range to copy. The elements must be {@link Number} instances.
127: * @param units The units of measurement, or {@code null} if unknown.
128: * @throws ClassCastException if some elements are not instances of {@link Number}.
129: */
130: public MeasurementRange(final Range range, final Unit units)
131: throws ClassCastException {
132: super (range);
133: this .units = units;
134: }
135:
136: /**
137: * Constructs a range with the same values than the specified range,
138: * casted to the specified type.
139: *
140: * @param type The element class, usually one of {@link Byte}, {@link Short},
141: * {@link Integer}, {@link Long}, {@link Float} or {@link Double}.
142: * @param range The range to copy. The elements must be {@link Number} instances.
143: * @param units The units of measurement, or {@code null} if unknown.
144: * @throws ClassCastException if some elements are not instances of {@link Number}.
145: */
146: private MeasurementRange(final Class type, final Range range,
147: final Unit units) throws ClassCastException {
148: super (type, range);
149: this .units = units;
150: }
151:
152: /**
153: * Returns the units of measurement, or {@code null} if unknown.
154: */
155: public final Unit getUnits() {
156: return units;
157: }
158:
159: /**
160: * Converts this range to the specified units. If this measurement range has null units,
161: * then the specified target units are simply assigned to the returned range with no
162: * other changes.
163: *
164: * @param targetUnit the target units.
165: * @return The converted range, or {@code this} if no conversion is needed.
166: * @throws ConversionException if the target units are not compatible with
167: * this {@linkplain #getUnits range units}.
168: */
169: public MeasurementRange convertTo(final Unit targetUnits)
170: throws ConversionException {
171: return convertAndCast(getElementClass(), targetUnits);
172: }
173:
174: /**
175: * Casts the specified range to the specified type. If this class is associated to a unit of
176: * measurement, then this method convert the {@code range} units to the same units than this
177: * instance.
178: *
179: * @param type The class to cast to. Must be one of {@link Byte}, {@link Short},
180: * {@link Integer}, {@link Long}, {@link Float} or {@link Double}.
181: * @return The casted range, or {@code range} if no cast is needed.
182: */
183: //@Override
184: NumberRange convertAndCast(final Range range, final Class type) {
185: if (range instanceof MeasurementRange) {
186: return ((MeasurementRange) range).convertAndCast(type,
187: units);
188: } else {
189: return super .convertAndCast(range, type);
190: }
191: }
192:
193: /**
194: * Casts this range to the specified type and converts to the specified units.
195: *
196: * @param type The class to cast to. Must be one of {@link Byte}, {@link Short},
197: * {@link Integer}, {@link Long}, {@link Float} or {@link Double}.
198: * @param targetUnit the target units.
199: * @return The casted range, or {@code this}.
200: * @throws ConversionException if the target units are not compatible with
201: * this {@linkplain #getUnits range units}.
202: */
203: private MeasurementRange convertAndCast(final Class type,
204: final Unit targetUnits) throws ConversionException {
205: if (targetUnits == null || targetUnits.equals(units)) {
206: if (type.equals(getElementClass())) {
207: return this ;
208: } else {
209: return new MeasurementRange(type, this , units);
210: }
211: }
212: if (units == null) {
213: return new MeasurementRange(type, this , targetUnits);
214: }
215: final Converter converter = units.getConverterTo(targetUnits);
216: if (converter.equals(Converter.IDENTITY)) {
217: return new MeasurementRange(type, this , targetUnits);
218: }
219: boolean isMinIncluded = isMinIncluded();
220: boolean isMaxIncluded = isMaxIncluded();
221: Double minimum = new Double(converter.convert(getMinimum()));
222: Double maximum = new Double(converter.convert(getMaximum()));
223: if (minimum.compareTo(maximum) > 0) {
224: final Double td = minimum;
225: minimum = maximum;
226: maximum = td;
227: final boolean tb = isMinIncluded;
228: isMinIncluded = isMaxIncluded;
229: isMaxIncluded = tb;
230: }
231: return new MeasurementRange(type, ClassChanger.cast(minimum,
232: type), isMinIncluded, ClassChanger.cast(maximum, type),
233: isMaxIncluded, targetUnits);
234: }
235:
236: /**
237: * Compares this range with the specified object for equality.
238: */
239: //@Override
240: public boolean equals(final Object other) {
241: if (super .equals(other)) {
242: if (other instanceof MeasurementRange) {
243: final MeasurementRange that = (MeasurementRange) other;
244: return Utilities.equals(this .units, that.units);
245: }
246: return true;
247: }
248: return false;
249: }
250:
251: /**
252: * Returns a string representation of this range.
253: */
254: //@Override
255: public String toString() {
256: String range = super .toString();
257: if (units != null) {
258: range = range + ' ' + units;
259: }
260: return range;
261: }
262: }
|