Added: sis/ip-review/rev/20970/SampleDimension.xhtml URL: http://svn.apache.org/viewvc/sis/ip-review/rev/20970/SampleDimension.xhtml?rev=1847794&view=auto ============================================================================== --- sis/ip-review/rev/20970/SampleDimension.xhtml (added) +++ sis/ip-review/rev/20970/SampleDimension.xhtml Fri Nov 30 09:52:08 2018 @@ -0,0 +1,1125 @@ + + +
+ +This commit contains either change irrelevant to Apache SIS (LGPL header),
+ lot of code reformatting (do not apply to SIS) or addition of new constructor.
+ Those new constructors are not kept for Apache SIS; we will use a Builder
instead.
Command line:
+svn diff --extensions "--unified --ignore-space-change --ignore-all-space --ignore-eol-style" -r20599:20970 http://svn.osgeo.org/geotools/trunk/modules/library/coverage/src/main/java/org/geotools/coverage/GridSampleDimension.java
+Revision 20599 | Revision 20970 |
---|---|
/* + * Geotools 2 - OpenSource mapping toolkit + * (C) 2003, Geotools Project Management Committee (PMC) + * (C) 2001, Institut de Recherche pour le Développement + * + * This library is free software; you can redistribute it and/or |
+/* + * GeoTools - OpenSource mapping toolkit + * http://geotools.org + * (C) 2003-2006, Geotools Project Management Committee (PMC) + * (C) 2001, Institut de Recherche pour le Développement + * + * This library is free software; you can redistribute it and/or |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* +* This package contains documentation from OpenGIS specifications. +* OpenGIS consortium's work is fully acknowledged here. +*/ |
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* This package contains documentation from OpenGIS specifications. +* OpenGIS consortium's work is fully acknowledged here. +*/ |
import java.awt.image.DataBuffer; // For javadoc
+import java.awt.image.IndexColorModel;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays; |
+import java.awt.image.DataBuffer; // For javadoc +import java.awt.image.IndexColorModel; +import java.awt.image.RenderedImage; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; |
import javax.media.jai.util.Range; + +// OpenGIS dependencies +import org.opengis.coverage.ColorInterpretation; +import org.opengis.coverage.MetadataNameNotFoundException; +import org.opengis.coverage.PaletteInterpretation; |
+import javax.media.jai.util.Range;
+
+// OpenGIS dependencies
+import org.geotools.util.SimpleInternationalString;
+import org.opengis.coverage.ColorInterpretation;
+import org.opengis.coverage.MetadataNameNotFoundException;
+import org.opengis.coverage.PaletteInterpretation; |
private final MathTransform1D sampleToGeophysics;
+
+/**
+ * Constructs a sample dimension with no category.
+ */
+public GridSampleDimension() {
+ this((CategoryList) null);
+}
+
+/** |
+private final MathTransform1D sampleToGeophysics; + +/** + * + * Decription for this sample dimension, it is particularly important to + * have the possiblity to specify a description for a smple dimension in + * order to be able to perform a band select by using human comprehensible + * descriptions instead of just numbers. As an instance a service like the + * WCS would use this feature in order to perform band subsetting as + * directed from a user request. + * + */ +private InternationalString description; + +/** + * Constructs a sample dimension with no category, using the provided + * description + * + * @param description + * Description for this Sample Dimension. + */ +public GridSampleDimension(final CharSequence description) { + this(description, (CategoryList) null); + +} + +/** + * Constructs a sample dimension with no category. + * + * @deprecated + * @see GridSampleDimension#GridSampleDimension(CharSequence) + * + */ +public GridSampleDimension() { + this(null, (CategoryList) null); + +} + +/** |
* This constructor expects only a sequence of category names for the values + * contained in a sample dimension. This allows for names to be assigned to + * numerical values. The first entry in the sequence relates to a cell value + * of zero. For example: [0]="Background", [1]="Water", [2]="Forest", [3]="Urban". + * The created sample dimension will have no unit and a default set of colors. + * + * @param names Sequence of category names for the values contained in a sample dimension, + * as {@link String} or {@link InternationalString} objects. + */ +public GridSampleDimension(final CharSequence[] names) { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE #4093999 + // ("Relax constraint on placement of this()/super() call in constructors"). + this(list(names)); +} + +/** Constructs a list of categories. Used by constructors only. */ +private static CategoryList list(final CharSequence[] names) { + final Color[] colors = new Color[names.length]; + final double scale = 255.0/colors.length; + for (int i=0; i<colors.length; i++) { + final int r = (int)Math.round(scale*i); + colors[i] = new Color(r,r,r); + } |
+* This constructor expects only a sequence of category names for the values + * contained in a sample dimension. This allows for names to be assigned to + * numerical values. The first entry in the sequence relates to a cell value + * of zero. For example: [0]="Background", [1]="Water", [2]="Forest", + * [3]="Urban". The created sample dimension will have no unit and a default + * set of colors. + * + * @param names + * Sequence of category names for the values contained in a + * sample dimension, as {@link String} or + * {@link InternationalString} objects. + * @param description + * Description for this Sample Dimension. + * + */ +public GridSampleDimension(final CharSequence description, + final CharSequence[] categoriesNames) { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE + // #4093999 + // ("Relax constraint on placement of this()/super() call in + // constructors"). + this(description, list(categoriesNames)); +} + +/** + * Constructs a sample dimension with a set of qualitative categories only. + * This constructor expects only a sequence of category names for the values + * contained in a sample dimension. This allows for names to be assigned to + * numerical values. The first entry in the sequence relates to a cell value + * of zero. For example: [0]="Background", [1]="Water", [2]="Forest", + * [3]="Urban". The created sample dimension will have no unit and a default + * set of colors. + * + * @param names + * Sequence of category names for the values contained in a + * sample dimension, as {@link String} or + * {@link InternationalString} objects. + * @deprecated + * + */ +public GridSampleDimension(final CharSequence[] categoriesNames) { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE #4093999 + // ("Relax constraint on placement of this()/super() call in constructors"). + this(null, list(categoriesNames)); +} + +/** Constructs a list of categories. Used by constructors only. */ +private static CategoryList list(final CharSequence[] names) { + final int length = names.length; + final Color[] colors = new Color[length]; + final double scale = 255.0 / length; + for (int i = 0; i < length; i++) { + final int r = (int)Math.round(scale*i); + colors[i] = new Color(r,r,r); + } |
} + +/** + * Constructs a sample dimension with a set of qualitative categories and colors. + * This constructor expects a sequence of category names for the values + * contained in a sample dimension. This allows for names to be assigned to + * numerical values. The first entry in the sequence relates to a cell value + * of zero. For example: [0]="Background", [1]="Water", [2]="Forest", [3]="Urban". + * The created sample dimension will have no unit and a default set of colors. + * + * @param names Sequence of category names for the values contained in a sample dimension, + * as {@link String} or {@link InternationalString} objects. + * @param colors Color to assign to each category. This array must have the same + * length than {@code names}. + */ +public GridSampleDimension(final CharSequence[] names, final Color[] colors) { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE #4093999 + // ("Relax constraint on placement of this()/super() call in constructors"). + this(list(names, colors)); +} + +/** Constructs a list of categories. Used by constructors only. */ +private static CategoryList list(final CharSequence[] names, final Color[] colors) { + if (names.length != colors.length) { + throw new IllegalArgumentException(Errors.format(ErrorKeys.MISMATCHED_ARRAY_LENGTH)); + } + final Category[] categories = new Category[names.length]; + for (int i=0; i<categories.length; i++) { + categories[i] = new Category(names[i], colors[i], i); + } + return list(categories, null); |
+} + +/** + * Constructs a sample dimension with a set of qualitative categories and + * colors. This constructor expects a sequence of category names for the + * values contained in a sample dimension. This allows for names to be + * assigned to numerical values. The first entry in the sequence relates to + * a cell value of zero. For example: [0]="Background", [1]="Water", + * [2]="Forest", [3]="Urban". The created sample dimension will have no unit + * and a default set of colors. + * + * @param names + * Sequence of category names for the values contained in a + * sample dimension, as {@link String} or + * {@link InternationalString} objects. + * @param colors + * Color to assign to each category. This array must have the + * same length than {@code names}. + * @param description + * Description for this Sample Dimension. + */ +public GridSampleDimension(final CharSequence description, + final CharSequence[] names, final Color[] colors) { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE + // #4093999 + // ("Relax constraint on placement of this()/super() call in + // constructors"). + this(description, list(names, colors)); +} + +/** + * Constructs a sample dimension with a set of qualitative categories and + * colors. This constructor expects a sequence of category names for the + * values contained in a sample dimension. This allows for names to be + * assigned to numerical values. The first entry in the sequence relates to + * a cell value of zero. For example: [0]="Background", [1]="Water", + * [2]="Forest", [3]="Urban". The created sample dimension will have no unit + * and a default set of colors. + * + * @param names + * Sequence of category names for the values contained in a + * sample dimension, as {@link String} or + * {@link InternationalString} objects. + * @param colors + * Color to assign to each category. This array must have the + * same length than {@code names}. + * @deprecated + */ +public GridSampleDimension(final CharSequence[] names, final Color[] colors) { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE + // #4093999 + // ("Relax constraint on placement of this()/super() call in + // constructors"). + this(null, list(names, colors)); +} + +/** Constructs a list of categories. Used by constructors only. */ +private static CategoryList list(final CharSequence[] names, + final Color[] colors) { + if (names.length != colors.length) { + throw new IllegalArgumentException(Errors + .format(ErrorKeys.MISMATCHED_ARRAY_LENGTH)); + } + final int length = names.length; + final Category[] categories = new Category[length]; + for (int i = 0; i < length; i++) { + categories[i] = new Category(names[i], colors[i], i); + } + return list(categories, null); |
} + +/** + * Constructs a sample dimension with the specified properties. For convenience, any argument + * which is not a {@code double} primitive can be {@code null}, and any {@linkplain CharSequence + * char sequence} can be either a {@link String} or {@link InternationalString} object. + * + * This constructor allows the construction of a {@code GridSampleDimension} without + * explicit construction of {@link Category} objects. An heuristic approach is used for + * dispatching the informations into a set of {@link Category} objects. However, this + * constructor still less general and provides less fine-grain control than the constructor + * expecting an array of {@link Category} objects. + * + * @param description The sample dimension title or description, or {@code null} if none. + * This is the value to be returned by {@link #getDescription}. + * @param type The grid value data type (which indicate the number of bits for the data type), + * or {@code null} for computing it automatically from the range + * {@code [minimum..maximum]}. This is the value to be returned by + * {@link #getSampleDimensionType}. + * @param color The color interpretation, or {@code null} for a default value (usually + * {@link ColorInterpretation#PALETTE_INDEX PALETTE_INDEX}). This is the value to be + * returned by {@link #getColorInterpretation}. + * @param palette The color palette associated with the sample dimension, or {@code null} + * for a default color palette (usually grayscale). If {@code categories} is + * non-null, then both arrays usually have the same length. However, this constructor + * is tolerant on this array length. This is the value to be returned (indirectly) by + * {@link #getColorModel}. + * @param categories A sequence of category names for the values contained in the sample + * dimension, or {@code null} if none. This is the values to be returned by + * {@link #getCategoryNames}. + * @param nodata the values to indicate "no data", or {@code null} if none. This is the + * values to be returned by {@link #getNoDataValues}. + * @param minimum The lower value, inclusive. The {@code [minimum..maximum]} range may or + * may not includes the {@code nodata} values; the range will be adjusted as + * needed. If {@code categories} was non-null, then {@code minimum} is + * usually 0. This is the value to be returned by {@link #getMinimumValue}. + * @param maximum The upper value, <strong>inclusive</strong> as well. The + * {@code [minimum..maximum]} range may or may not includes the {@code nodata} + * values; the range will be adjusted as needed. If {@code categories} was non-null, + * then {@code maximum} is usually equals to {@code categories.length-1}. This + * is the value to be returned by {@link #getMaximumValue}. + * @param scale The value which is multiplied to grid values, or 1 if none. This is the value + * to be returned by {@link #getScale}. + * @param offset The value to add to grid values, or 0 if none. This is the value to be + * returned by {@link #getOffset}. + * @param unit The unit information for this sample dimension, or {@code null} if none. + * This is the value to be returned by {@link #getUnits}. + * + * @throws IllegalArgumentException if the range {@code [minimum..maximum]} is not valid. + */ +public GridSampleDimension(final CharSequence description, + final SampleDimensionType type, + final ColorInterpretation color, + final Color[] palette, + final CharSequence[] categories, + final double[] nodata, + final double minimum, + final double maximum, + final double scale, + final double offset, + final Unit unit) +{ + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE #4093999 + // ("Relax constraint on placement of this()/super() call in constructors"). + this(list(description, type, color, palette, categories, nodata, + minimum, maximum, scale, offset, unit)); +} + +/** Constructs a list of categories. Used by constructors only. */ +private static CategoryList list(final CharSequence description, + SampleDimensionType type, + ColorInterpretation color, + final Color[] palette, + final CharSequence[] categories, + final double[] nodata, + double minimum, + double maximum, + final double scale, + final double offset, + final Unit unit) +{ + if (Double.isInfinite(minimum) || Double.isInfinite(maximum) || !(minimum < maximum)) { + throw new IllegalArgumentException(Errors.format(ErrorKeys.BAD_RANGE_$2, + new Double(minimum), new Double(maximum))); + } + if (Double.isNaN(scale) || Double.isInfinite(scale) || scale==0) { + throw new IllegalArgumentException(Errors.format(ErrorKeys.BAD_PARAMETER_$2, + "scale", new Double(scale))); + } + if (Double.isNaN(offset) || Double.isInfinite(offset)) { + throw new IllegalArgumentException(Errors.format(ErrorKeys.BAD_PARAMETER_$2, + "offset", new Double(offset))); + } + if (type == null) { + type = TypeMap.getSampleDimensionType(minimum, maximum); |
+} + +/** + * Constructs a sample dimension with the specified properties. For + * convenience, any argument which is not a {@code double} primitive can be + * {@code null}, and any {@linkplain CharSequence char sequence} can be + * either a {@link String} or {@link InternationalString} object. + * + * This constructor allows the construction of a {@code GridSampleDimension} + * without explicit construction of {@link Category} objects. An heuristic + * approach is used for dispatching the informations into a set of + * {@link Category} objects. However, this constructor still less general + * and provides less fine-grain control than the constructor expecting an + * array of {@link Category} objects. + * + * @param description + * The sample dimension title or description, or {@code null} if + * none. This is the value to be returned by + * {@link #getDescription}. + * @param type + * The grid value data type (which indicate the number of bits + * for the data type), or {@code null} for computing it + * automatically from the range {@code [minimum..maximum]}. This + * is the value to be returned by {@link #getSampleDimensionType}. + * @param color + * The color interpretation, or {@code null} for a default value + * (usually + * {@link ColorInterpretation#PALETTE_INDEX PALETTE_INDEX}). + * This is the value to be returned by + * {@link #getColorInterpretation}. + * @param palette + * The color palette associated with the sample dimension, or + * {@code null} for a default color palette (usually grayscale). + * If {@code categories} is non-null, then both arrays usually + * have the same length. However, this constructor is tolerant on + * this array length. This is the value to be returned + * (indirectly) by {@link #getColorModel}. + * @param categories + * A sequence of category names for the values contained in the + * sample dimension, or {@code null} if none. This is the values + * to be returned by {@link #getCategoryNames}. + * @param nodata + * the values to indicate "no data", or {@code null} if none. + * This is the values to be returned by {@link #getNoDataValues}. + * @param minimum + * The lower value, inclusive. The {@code [minimum..maximum]} + * range may or may not includes the {@code nodata} values; the + * range will be adjusted as needed. If {@code categories} was + * non-null, then {@code minimum} is usually 0. This is the value + * to be returned by {@link #getMinimumValue}. + * @param maximum + * The upper value, <strong>inclusive</strong> as well. The + * {@code [minimum..maximum]} range may or may not includes the + * {@code nodata} values; the range will be adjusted as needed. + * If {@code categories} was non-null, then {@code maximum} is + * usually equals to {@code categories.length-1}. This is the + * value to be returned by {@link #getMaximumValue}. + * @param scale + * The value which is multiplied to grid values, or 1 if none. + * This is the value to be returned by {@link #getScale}. + * @param offset + * The value to add to grid values, or 0 if none. This is the + * value to be returned by {@link #getOffset}. + * @param unit + * The unit information for this sample dimension, or + * {@code null} if none. This is the value to be returned by + * {@link #getUnits}. + * @param description + * Description for this Sample Dimension. + * + * @throws IllegalArgumentException + * if the range {@code [minimum..maximum]} is not valid. + */ +public GridSampleDimension(final CharSequence description, + final SampleDimensionType type, final ColorInterpretation color, + final Color[] palette, final CharSequence[] categories, + final double[] nodata, final double minimum, final double maximum, + final double scale, final double offset, final Unit unit) { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE + // #4093999 + // ("Relax constraint on placement of this()/super() call in + // constructors"). + this(description, list(description, type, color, palette, categories, + nodata, minimum, maximum, scale, offset, unit)); +} + +/** Constructs a list of categories. Used by constructors only. */ +private static CategoryList list(final CharSequence description, + SampleDimensionType type, ColorInterpretation color, + final Color[] palette, final CharSequence[] categories, + final double[] nodata, double minimum, double maximum, + final double scale, final double offset, final Unit unit) { + if (Double.isInfinite(minimum) || Double.isInfinite(maximum) + || !(minimum < maximum)) { + throw new IllegalArgumentException(Errors.format( + ErrorKeys.BAD_RANGE_$2, new Double(minimum), new Double( + maximum))); + } + if (Double.isNaN(scale) || Double.isInfinite(scale) || scale==0) { + throw new IllegalArgumentException(Errors.format( + ErrorKeys.BAD_PARAMETER_$2, "scale", new Double(scale))); + } + if (Double.isNaN(offset) || Double.isInfinite(offset)) { + throw new IllegalArgumentException(Errors.format( + ErrorKeys.BAD_PARAMETER_$2, "offset", new Double(offset))); + } + if (type == null) { + type = TypeMap.getSampleDimensionType(minimum, maximum); |
final int nodataCount = (nodata !=null) ? nodata.length : 0; +final List categoryList = new ArrayList(nameCount + nodataCount + 2); +/* + * STEP 1 - Add a qualitative category for each 'nodata' value. + * NAME: Fetched from 'categories' if available, otherwise default to the value. + * COLOR: Fetched from 'palette' if available, otherwise use Category default. + */ +for (int i=0; i<nodataCount; i++) { + CharSequence name = null; |
+final int nodataCount = (nodata !=null) ? nodata.length : 0; +final List categoryList = new ArrayList(nameCount + nodataCount + 2); +/* +* STEP 1 - Add a qualitative category for each 'nodata' value. NAME: +* Fetched from 'categories' if available, otherwise default to the +* value. COLOR: Fetched from 'palette' if available, otherwise use +* Category default. + */ +for (int i=0; i<nodataCount; i++) { + CharSequence name = null; |
if (name == null) { + name = value.toString(); + } + final NumberRange range = new NumberRange(value.getClass(), value, value); + final Color[] colors = ColorUtilities.subarray(palette, intValue, intValue+1); + categoryList.add(new Category(name, colors, range, (MathTransform1D)null)); +} +/* + * STEP 2 - Add a qualitative category for each category name. + * RANGE: Fetched from the index (position) in the 'categories' array. + * COLOR: Fetched from 'palette' if available, otherwise use Category default. + */ +if (nameCount != 0) { + int lower = 0; + for (int upper=1; upper<=categories.length; upper++) { + if (upper!=categories.length && + categories[lower].toString().trim().equalsIgnoreCase( + categories[upper].toString().trim())) + { + // If there is a suite of categories with identical name, create only one + // category with range [lower..upper] instead of one new category for each + // sample value. + continue; + } |
+if (name == null) { + name = value.toString(); + } + final NumberRange range = new NumberRange(value.getClass(), value, + value); + final Color[] colors = ColorUtilities.subarray(palette, intValue, + intValue + 1); + categoryList.add(new Category(name, colors, range, + (MathTransform1D) null)); +} +/* +* STEP 2 - Add a qualitative category for each category name. RANGE: +* Fetched from the index (position) in the 'categories' array. COLOR: +* Fetched from 'palette' if available, otherwise use Category default. + */ +if (nameCount != 0) { + int lower = 0; + final int length = categories.length; + for (int upper = 1; upper <= length; upper++) { + if (upper != length + && categories[lower].toString().trim() + .equalsIgnoreCase( + categories[upper].toString().trim())) { + // If there is a suite of categories with identical name, + // create only one + // category with range [lower..upper] instead of one new + // category for each + // sample value. + continue; + } |
max = ClassChanger.cast(max, classe); + } + final NumberRange range = new NumberRange(classe, min, max); + final Color[] colors = ColorUtilities.subarray(palette, lower, upper); + categoryList.add(new Category(name, colors, range, (MathTransform1D)null)); + lower = upper; + } +} +/* + * STEP 3 - Changes some qualitative categories into quantitative ones. The hard questions + * is: do we want to mark a category as "quantitative"? OpenGIS has no notion of + * "qualitative" versus "quantitative" category. As an heuristic approach, we will + * look for quantitative category if: + * + * - 'scale' and 'offset' do not map to an identity transform. Those + * coefficients can be stored in quantitative category only. + * + * - 'nodata' were specified. If the user wants to declare "nodata" values, + * then we can reasonably assume that he have real values somewhere else. + * + * - Only 1 category were created so far. A classified raster with only one + * category is useless. Consequently, it is probably a numeric raster instead. + */ +boolean needQuantitative = false; +if (scale!=1 || offset!=0 || nodataCount!=0 || categoryList.size()<=1) { + needQuantitative = true; + for (int i=categoryList.size(); --i>=0;) { + Category category = (Category) categoryList.get(i); |
+max = ClassChanger.cast(max, classe); + } + final NumberRange range = new NumberRange(classe, min, max); + final Color[] colors = ColorUtilities.subarray(palette, lower, + upper); + categoryList.add(new Category(name, colors, range, + (MathTransform1D) null)); + lower = upper; + } + } + /* + * STEP 3 - Changes some qualitative categories into quantitative ones. + * The hard questions is: do we want to mark a category as + * "quantitative"? OpenGIS has no notion of "qualitative" versus + * "quantitative" category. As an heuristic approach, we will look for + * quantitative category if: - 'scale' and 'offset' do not map to an + * identity transform. Those coefficients can be stored in quantitative + * category only. - 'nodata' were specified. If the user wants to + * declare "nodata" values, then we can reasonably assume that he have + * real values somewhere else. - Only 1 category were created so far. A + * classified raster with only one category is useless. Consequently, it + * is probably a numeric raster instead. + */ + boolean needQuantitative = false; +if (scale != 1 || offset != 0 || nodataCount != 0 + || categoryList.size() <= 1) { + needQuantitative = true; + for (int i=categoryList.size(); --i>=0;) { + Category category = (Category) categoryList.get(i); |
if (!rangeContains(xmin, xmax, nodata)) {
+ final InternationalString name = category.getName();
+ final Color[] colors = category.getColors();
+ category = new Category(name, colors, range, scale, offset);
+ categoryList.set(i, category);
+ needQuantitative = false;
+} |
+if (!rangeContains(xmin, xmax, nodata)) { + final InternationalString name = category.getName(); + final Color[] colors = category.getColors(); +category = new Category(name, colors, range, scale, + offset); + categoryList.set(i, category); + needQuantitative = false; + } |
} +} +/* + * STEP 4 - Create at most one quantitative category for the remaining sample values. + * The new category will range from 'minimum' to 'maximum' inclusive, minus + * all ranges used by previous categories. If there is no range left, then + * no new category will be created. This step will be executed only if the + * information provided by the user seem to be incomplete. + * + * Note that substractions way break a range into many smaller ranges. + * The naive algorithm used here try to keep the widest range. |
+} +} +/* +* STEP 4 - Create at most one quantitative category for the remaining +* sample values. The new category will range from 'minimum' to +* 'maximum' inclusive, minus all ranges used by previous categories. If +* there is no range left, then no new category will be created. This +* step will be executed only if the information provided by the user +* seem to be incomplete. + * + * Note that substractions way break a range into many smaller ranges. + * The naive algorithm used here try to keep the widest range. |
boolean minIncluded = true;
+boolean maxIncluded = true;
+for (int i=categoryList.size(); --i>=0;) {
+ final NumberRange range = ((Category) categoryList.get(i)).getRange();
+ final double min = range.getMinimum();
+ final double max = range.getMaximum();
+ if (max-minimum < maximum-min) { |
+boolean minIncluded = true; + boolean maxIncluded = true; + for (int i=categoryList.size(); --i>=0;) { +final NumberRange range = ((Category) categoryList.get(i)) + .getRange(); + final double min = range.getMinimum(); + final double max = range.getMaximum(); + if (max-minimum < maximum-min) { |
final Class classe = ClassChanger.getWidestClass(min, max); + min = ClassChanger.cast(min, classe); + max = ClassChanger.cast(max, classe); + final NumberRange range = new NumberRange(classe, min, minIncluded, + max, maxIncluded); + final Color[] colors = ColorUtilities.subarray(palette, + (int)Math.ceil (minimum), + (int)Math.floor(maximum)); + categoryList.add(new Category((description!=null) ? description : "(automatic)", + colors, range, scale, offset)); + needQuantitative = false; +} |
+final Class classe = ClassChanger.getWidestClass(min, max); + min = ClassChanger.cast(min, classe); + max = ClassChanger.cast(max, classe); +final NumberRange range = new NumberRange(classe, min, + minIncluded, max, maxIncluded); + final Color[] colors = ColorUtilities.subarray(palette, + (int) Math.ceil(minimum), (int) Math.floor(maximum)); +categoryList.add(new Category( + (description != null) ? description : "(automatic)", + colors, range, scale, offset)); + needQuantitative = false; + } |
* STEP 5 - Now, the list of categories should be complete. Construct a + * sample dimension appropriate for the type of palette used. + */ +final Category[] cl = (Category[]) categoryList.toArray(new Category[categoryList.size()]); +if (ColorInterpretation.PALETTE_INDEX.equals(color) || + ColorInterpretation.GRAY_INDEX.equals(color)) +{ + return list(cl, unit); +} +throw new UnsupportedOperationException("Not yet implemented"); |
+* STEP 5 - Now, the list of categories should be complete. Construct a + * sample dimension appropriate for the type of palette used. + */ +final Category[] cl = (Category[]) categoryList + .toArray(new Category[categoryList.size()]); +if (ColorInterpretation.PALETTE_INDEX.equals(color) + || ColorInterpretation.GRAY_INDEX.equals(color)) { + return list(cl, unit); + } + throw new UnsupportedOperationException("Not yet implemented"); |
} + +/** + * Constructs a sample dimension with an arbitrary set of categories, which may be both + * quantitative and qualitative. It is possible to specify more than one quantitative + * categories, providing that their sample value ranges do not overlap. Quantitative + * categories can map sample values to geophysics values using arbitrary relation (not + * necessarly linear). + * + * @param categories The list of categories. + * @param units The unit information for this sample dimension. + * May be {@code null} if no category has units. + * This unit apply to values obtained after the + * {@link #getSampleToGeophysics sampleToGeophysics} transformation. + * @throws IllegalArgumentException if {@code categories} contains incompatible + * categories. If may be the case for example if two or more categories have + * overlapping ranges of sample values. + */ +public GridSampleDimension(Category[] categories, Unit units) throws IllegalArgumentException { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE #4093999 + // ("Relax constraint on placement of this()/super() call in constructors"). + this(list(categories, units)); +} + +/** Construct a list of categories. Used by constructors only. */ +private static CategoryList list(final Category[] categories, final Unit units) { + if (categories == null) { + return null; + } + final CategoryList list = new CategoryList(categories, units); + if (CategoryList.isScaled(categories, false)) return list; + if (CategoryList.isScaled(categories, true )) return list.inverse; + throw new IllegalArgumentException(Errors.format(ErrorKeys.MIXED_CATEGORIES)); +} + +/** + * Constructs a sample dimension with the specified list of categories. + * + * @param list The list of categories, or {@code null}. + */ +private GridSampleDimension(final CategoryList list) { + MathTransform1D main = null; + boolean isMainValid = true; + boolean qualitative = false; + if (list != null) { + for (int i=list.size(); --i>=0;) { + final MathTransform1D candidate = ((Category)list.get(i)).getSampleToGeophysics(); + if (candidate == null) { + qualitative = true; + continue; |
+} + +/** + * Constructs a sample dimension with an arbitrary set of categories, which + * may be both quantitative and qualitative. It is possible to specify more + * than one quantitative categories, providing that their sample value + * ranges do not overlap. Quantitative categories can map sample values to + * geophysics values using arbitrary relation (not necessarly linear). + * + * @param categories + * The list of categories. + * @param units + * The unit information for this sample dimension. May be + * {@code null} if no category has units. This unit apply to + * values obtained after the + * {@link #getSampleToGeophysics sampleToGeophysics} + * transformation. + * @param description + * Description for this Sample Dimension. + * @throws IllegalArgumentException + * if {@code categories} contains incompatible categories. If + * may be the case for example if two or more categories have + * overlapping ranges of sample values. + */ +public GridSampleDimension(final CharSequence description, + Category[] categories, Unit units) throws IllegalArgumentException { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE + // #4093999 + // ("Relax constraint on placement of this()/super() call in + // constructors"). + this(description, list(categories, units)); +} + +/** + * Constructs a sample dimension with an arbitrary set of categories, which + * may be both quantitative and qualitative. It is possible to specify more + * than one quantitative categories, providing that their sample value + * ranges do not overlap. Quantitative categories can map sample values to + * geophysics values using arbitrary relation (not necessarly linear). + * + * @param categories + * The list of categories. + * @param units + * The unit information for this sample dimension. May be + * {@code null} if no category has units. This unit apply to + * values obtained after the + * {@link #getSampleToGeophysics sampleToGeophysics} + * transformation. + * @deprecated + * @throws IllegalArgumentException + * if {@code categories} contains incompatible categories. If + * may be the case for example if two or more categories have + * overlapping ranges of sample values. + */ +public GridSampleDimension(Category[] categories, Unit units) + throws IllegalArgumentException { + // TODO: 'list(...)' should be inlined there if only Sun was to fix RFE + // #4093999 + // ("Relax constraint on placement of this()/super() call in + // constructors"). + this(null, list(categories, units)); +} + +/** Construct a list of categories. Used by constructors only. */ +private static CategoryList list(final Category[] categories, + final Unit units) { + if (categories == null) { + return null; + } + final CategoryList list = new CategoryList(categories, units); + if (CategoryList.isScaled(categories, false)) + return list; + if (CategoryList.isScaled(categories, true)) + return list.inverse; + throw new IllegalArgumentException(Errors + .format(ErrorKeys.MIXED_CATEGORIES)); +} + +/** + * Constructs a sample dimension with the specified list of categories. + * + * @param list + * The list of categories, or {@code null}. + * @param description + * Description for this Sample Dimension. + */ +private GridSampleDimension(final CharSequence description, + final CategoryList list) { + MathTransform1D main = null; + this.description = checkDescription(description, list); + boolean isMainValid = true; + boolean qualitative = false; + if (list != null) { + for (int i=list.size(); --i>=0;) { + final MathTransform1D candidate = ((Category) list.get(i)) + .getSampleToGeophysics(); + if (candidate == null) { + qualitative = true; + continue; |
} + +/** + * Constructs a new sample dimension with the same categories and + * units than the specified sample dimension. + * |
+} + +/** + * Checks the supplied description to see if it is null. In such a case it + * builds up a new description by using the list of categories supplied. + * This secondo description is much less human readable and it is therefore + * much better if the user provide a meaningful name for this sample + * dimension. + * + * @param description + * Supplied description. + * @param list + * List of categories for this SampleDimension. + * @return description for this sample dimension. + */ +private InternationalString checkDescription(CharSequence description, + CategoryList list) { + + // do we have a description + if (description != null) + return SimpleInternationalString.wrap(description); + + // we need to build one + // let's use the category list in order to build the name of the sample + // dimension + if (list != null) + return list.getName(); + return new SimpleInternationalString(""); + +} +/** + * Constructs a new sample dimension with the same categories and + * units than the specified sample dimension. + * |
hasQualitative = other.hasQualitative; + hasQuantitative = other.hasQuantitative; + sampleToGeophysics = other.sampleToGeophysics; +} else { + // 'inverse' will be set when needed. + categories = null; |
+ hasQualitative = other.hasQualitative;
+ hasQuantitative = other.hasQuantitative;
+ sampleToGeophysics = other.sampleToGeophysics;
+ description = other.description;
+} else {
+ // 'inverse' will be set when needed.
+ categories = null; |
} + +/** + * Wrap the specified OpenGIS's sample dimension into a Geotools's implementation + * of {@code GridSampleDimension}. + * + * @param sd The sample dimension to wrap into a Geotools implementation. + */ +public static GridSampleDimension wrap(final SampleDimension sd) { + if (sd instanceof GridSampleDimension) { |
+} + +/** + * Wrap the specified OpenGIS's sample dimension into a Geotools's + * implementation of {@code GridSampleDimension}. + * + * @param sd + * The sample dimension to wrap into a Geotools implementation. + */ +public static GridSampleDimension wrap(final SampleDimension sd) { + if (sd instanceof GridSampleDimension) { |
final int[][] palette = sd.getPalette(); +final Color[] colors; +if (palette != null) { + colors = new Color[palette.length]; + for (int i=0; i<colors.length; i++) { + // Assuming RGB. It will be checked in the constructor. + final int[] color = palette[i]; + colors[i] = new Color(color[0], color[1], color[2]); |
+final int[][] palette = sd.getPalette(); +final Color[] colors; +if (palette != null) { + final int length = palette.length; + colors = new Color[length]; + for (int i = 0; i < length; i++) { + // Assuming RGB. It will be checked in the constructor. + final int[] color = palette[i]; + colors[i] = new Color(color[0], color[1], color[2]); |
} else { + colors = null; + } + return new GridSampleDimension(sd.getDescription(), + sd.getSampleDimensionType(), + sd.getColorInterpretation(), + colors, + sd.getCategoryNames(), + sd.getNoDataValues(), + sd.getMinimumValue(), + sd.getMaximumValue(), + sd.getScale(), + sd.getOffset(), + sd.getUnits()); +} + +/** |
+} else { + colors = null; + } + return new GridSampleDimension(sd.getDescription(), sd + .getSampleDimensionType(), sd.getColorInterpretation(), colors, + sd.getCategoryNames(), sd.getNoDataValues(), sd + .getMinimumValue(), sd.getMaximumValue(), + sd.getScale(), sd.getOffset(), sd.getUnits()); +} + +/** |
* This string may be {@code null} if no description is present.
+ */
+public InternationalString getDescription() {
+ return (categories!=null) ? categories.getName() : null;
+}
+
+/** |
+ * This string may be {@code null} if no description is present.
+ */
+public InternationalString getDescription() {
+ return description;
+}
+
+/** |
* @deprecated Use {@link #getDescription()} instead.
+ */
+public String getDescription(final Locale locale) {
+ return (categories!=null) ? categories.getName().toString(locale) : null;
+}
+
+/** |
+ * @deprecated Use {@link #getDescription()} instead.
+ */
+public String getDescription(final Locale locale) {
+ return description.toString(locale);
+}
+
+/** |
*/ +public final String[] getCategoryNames(final Locale locale) throws IllegalStateException { + final InternationalString[] inter = getCategoryNames(); + final String[] names = new String[inter.length]; + for (int i=0; i<names.length; i++) { + names[i] = inter[i].toString(locale); + } + return names; |
+*/ +public final String[] getCategoryNames(final Locale locale) throws IllegalStateException { + final InternationalString[] inter = getCategoryNames(); + final int length = inter.length; + final String[] names = new String[length]; + for (int i = 0; i < length; i++) { + names[i] = inter[i].toString(locale); + } + return names; |
final double[] values)
+{
+ if (values != null) {
+ for (int i=0; i<values.length; i++) {
+ final double v = values[i];
+ if (v>=lower && v<upper) {
+ return true; |
+final double[] values) +{ + if (values != null) { + final int length = values.length; + for (int i = 0; i < length; i++) { + final double v = values[i]; + if (v>=lower && v<upper) { + return true; |
}
+if (inverse == null) {
+ if (categories != null) {
+ inverse = new GridSampleDimension(categories.inverse);
+ inverse.inverse = this;
+ } else {
+ /* |
+} +if (inverse == null) { + if (categories != null) { + inverse = new GridSampleDimension(description, + categories.inverse); + inverse.inverse = this; + } else { + /* |
if (color instanceof IndexColorModel) {
+ final IndexColorModel cm = (IndexColorModel) color;
+ final int[][] colors = new int[cm.getMapSize()][];
+ for (int i=0; i<colors.length; i++) {
+ colors[i] = new int[] {cm.getRed(i), cm.getGreen(i), cm.getBlue(i)};
+ }
+ return colors; |
+if (color instanceof IndexColorModel) { + final IndexColorModel cm = (IndexColorModel) color; + final int[][] colors = new int[cm.getMapSize()][]; + final int length = colors.length; + for (int i = 0; i < length; i++) { + colors[i] = new int[] {cm.getRed(i), cm.getGreen(i), cm.getBlue(i)}; + } + return colors; |
final MathTransform1D sampleToGeophysics = Category.createLinearTransform(scale, offset);
+final Category[] categories = (Category[]) getCategories().toArray();
+final Category[] reference = (Category[]) categories.clone();
+for (int i=0; i<categories.length; i++) {
+ if (categories[i].isQuantitative()) {
+ categories[i] = categories[i].rescale(sampleToGeophysics);
+ } |
+final MathTransform1D sampleToGeophysics = Category.createLinearTransform(scale, offset); + final Category[] categories = (Category[]) getCategories().toArray(); + final Category[] reference = (Category[]) categories.clone(); +final int length = categories.length; +for (int i = 0; i < length; i++) { + if (categories[i].isQuantitative()) { + categories[i] = categories[i].rescale(sampleToGeophysics); + } |
if (Arrays.equals(categories, reference)) {
+ return this;
+ }
+ return new GridSampleDimension(categories, getUnits());
+}
+
+/** |
+ if (Arrays.equals(categories, reference)) {
+ return this;
+ }
+ return new GridSampleDimension(description, categories, getUnits());
+}
+
+/** |
This commit propagates the package names change which was done in GeoAPI. +There is no way such change could be done differently, +since not renaming the packages cause a compilation error.
+Command line:
+svn diff --extensions "--unified --ignore-space-change --ignore-all-space --ignore-eol-style" -r24924:24925 http://svn.osgeo.org/geotools/trunk/modules/library/coverage/src/main/java/org/geotools/coverage/CategoryList.java
+Revision 24924 | Revision 24925 |
---|---|
import org.opengis.referencing.operation.MathTransform1D; +import org.opengis.referencing.operation.Matrix; +import org.opengis.referencing.operation.TransformException; +import org.opengis.spatialschema.geometry.DirectPosition; +import org.opengis.spatialschema.geometry.MismatchedDimensionException; +import org.opengis.util.InternationalString; + +// Geotools dependencies |
+import org.opengis.referencing.operation.MathTransform1D; +import org.opengis.referencing.operation.Matrix; +import org.opengis.referencing.operation.TransformException; +import org.opengis.geometry.DirectPosition; +import org.opengis.geometry.MismatchedDimensionException; +import org.opengis.util.InternationalString; + +// Geotools dependencies |
Author: | simboss |
Date: | 2008-02-01 |
Message: | -improving bands creations for simple rasters |
Fix for a spelling error in a comment. If not fixed by this commit, this error can be identified by IDE spell checker.
+ +Command line:
+svn diff --extensions "--unified --ignore-space-change --ignore-all-space --ignore-eol-style" -r29036:29037 http://svn.osgeo.org/geotools/trunk/modules/library/coverage/src/main/java/org/geotools/coverage/GridSampleDimension.java
+Revision 29036 | Revision 29037 |
---|---|
/*
+ * Checks the supplied description to see if it is null. In such a case it
+ * builds up a new description by using the list of categories supplied.
+ * This secondo description is much less human readable and it is therefore
+ * much better if the user provide a meaningful name for this sample
+ * dimension.
+ */ |
+/*
+ * Checks the supplied description to see if it is null. In such a case it
+ * builds up a new description by using the list of categories supplied.
+ * This second description is much less human readable and it is therefore
+ * much better if the user provide a meaningful name for this sample
+ * dimension.
+ */ |