All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotoolkit.referencing.operation.provider.MapProjectionParameters Maven / Gradle / Ivy

/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2012, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2012, Geomatys
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 */
package org.geotoolkit.referencing.operation.provider;

import javax.measure.unit.Unit;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterNotFoundException;

import org.geotoolkit.util.XArrays;
import org.geotoolkit.resources.Errors;
import org.geotoolkit.parameter.Parameter;
import org.geotoolkit.parameter.Parameters;
import org.geotoolkit.parameter.ParameterGroup;
import org.geotoolkit.parameter.FloatParameter;
import org.geotoolkit.internal.referencing.CRSUtilities;

import org.geotoolkit.parameter.AbstractParameterValue;
import static org.geotoolkit.referencing.operation.provider.UniversalParameters.*;
import static org.geotoolkit.referencing.operation.provider.MapProjectionDescriptor.ADD_EARTH_RADIUS;
import static org.geotoolkit.referencing.operation.provider.MapProjectionDescriptor.ADD_STANDARD_PARALLEL;


/**
 * Map projection parameters, with special processing for alternative ways to express the
 * ellipsoid axis length and the standard parallels. See {@link MapProjectionDescriptor}
 * for more information about those non-standard parameters.
 * 

* The main purpose of this class is to supported transparently the NetCDF ways to express * some parameter values. * * @author Martin Desruisseaux (Geomatys) * @version 3.20 * * @see NetCDF projection parameters * * @since 3.20 * @module */ final class MapProjectionParameters extends ParameterGroup { /** * For cross-version compatibility. */ private static final long serialVersionUID = -6801091012335717139L; /** * The earth radius parameter. This parameter is computed automatically from the * {@code "semi_major"} and {@code "semi_minor"}. When explicitely set, this parameter * value is also assigned to the {@code "semi_major"} and {@code "semi_minor"} axis lengths. * * @see org.geotoolkit.referencing.datum.DefaultEllipsoid#getAuthalicRadius() */ private final class EarthRadius extends FloatParameter { /** * For cross-version compatibility. Actually instances of this class * are not expected to be serialized, but we try to be a bit safer here. */ private static final long serialVersionUID = 5848432458976184182L; /** * Creates a new parameter. */ EarthRadius() { super(EARTH_RADIUS); } /** * Invoked when the parameter value is requested. Unconditionally computes * the authalic radius. If an Earth radius has been explicitely specified, * the result will be the same unless the user overwrote it with explicit * semi-major or semi-minor axis length. */ @Override public double doubleValue() { return CRSUtilities.getAuthalicRadius(get(SEMI_MAJOR), get(SEMI_MINOR)); } /** * Invoked when a new parameter value is set. This method sets both axis length * to the given radius. */ @Override public void setValue(final double value, final Unit unit) { super.setValue(value, unit); // Perform argument check. set(SEMI_MAJOR, value, unit); set(SEMI_MINOR, value, unit); } } /** * The inverse flattening parameter. This parameter is computed automatically from the * {@code "semi_major"} and {@code "semi_minor"}. When explicitly set, this parameter * value is used for computing the semi-minor axis length. * * @see org.geotoolkit.referencing.datum.DefaultEllipsoid#getInverseFlattening() */ private final class InverseFlattening extends FloatParameter implements ChangeListener { /** * For cross-version compatibility. Actually instances of this class * are not expected to be serialized, but we try to be a bit safer here. */ private static final long serialVersionUID = 4490056024453509851L; /** * Creates a new parameter. */ InverseFlattening() { super(INVERSE_FLATTENING); } /** * Returns the semi-major parameter, which is needed by this parameter value for * computing the semi-minor parameter. */ private AbstractParameterValue semiMajor() { return (AbstractParameterValue) parameter("semi_major"); } /** * Invoked when the parameter value is requested. Unconditionally computes the inverse * flattening from the ellipsoid axis lengths. Note that the result will be slightly * different than the specified value because of rounding errors. */ @Override public double doubleValue() { final double semiMajorAxis = get(SEMI_MAJOR); final double semiMinorAxis = get(SEMI_MINOR); double ivf = semiMajorAxis / (semiMajorAxis - semiMinorAxis); if (Double.isNaN(ivf)) { ivf = super.doubleValue(); } return ivf; } /** * Invoked when a new parameter value is set. This method computes the semi-minor * axis length from the given value. It will also register a listener in case the * semi-major axis length is updated after this method call. */ @Override public void setValue(final double value, final Unit unit) { final boolean wasNull = Double.isNaN(super.doubleValue()); super.setValue(value, unit); // Perform argument check. if (Double.isNaN(value)) { if (!wasNull) { semiMajor().removeChangeListener(this); } } else { if (wasNull) { semiMajor().addChangeListener(this); } update(value); } } /** * Computes the semi-minor axis length from the given inverse flattening value. */ private void update(final double value) { final ParameterValue semiMajor; try { semiMajor = Parameters.getOrCreate(SEMI_MAJOR, MapProjectionParameters.this); } catch (IllegalStateException e) { // Semi-major axis is not yet defined. // Ignore - we will try to compute gain later. return; } set(SEMI_MINOR, semiMajor.doubleValue()*(1 - 1/value), semiMajor.getUnit()); } /** * Invoked when the semi-major axis value changed. This method recomputes * the semi-minor axis length from the ellipsoid. */ @Override public void stateChanged(final ChangeEvent event) { update(super.doubleValue()); } } /** * The standard parallel parameter as an array of {@code double}. This parameter is computed * automatically from the {@code "standard_parallel_1"} and {@code "standard_parallel_1"} * parameters. When explicitely set, the parameter elements are given to the above-cited * parameters. */ private final class StandardParallel extends Parameter { /** * For cross-version compatibility. Actually instances of this class * are not expected to be serialized, but we try to be a bit safer here. */ private static final long serialVersionUID = -1379566730374843040L; /** * Creates a new parameter. */ StandardParallel() { super(STANDARD_PARALLEL); } /** * Invoked when the parameter value is requested. Unconditionally computes the array * from the {@code "standard_parallel_1"} and {@code "standard_parallel_1"} parameters. */ @Override public double[] getValue() { final double standardParallel1 = get(STANDARD_PARALLEL_1); final double standardParallel2 = get(STANDARD_PARALLEL_2); if (Double.isNaN(standardParallel2)) { return Double.isNaN(standardParallel1) ? XArrays.EMPTY_DOUBLE : new double[] {standardParallel1}; } return new double[] {standardParallel1, standardParallel2}; } /** * Invoked when a new parameter value is set. This method assign the array elements * to @code "standard_parallel_1"} and {@code "standard_parallel_1"} parameters. */ @Override @SuppressWarnings("fallthrough") protected void setSafeValue(final double[] value, final Unit unit) { double standardParallel1 = Double.NaN; double standardParallel2 = Double.NaN; if (value != null) { switch (value.length) { default: { throw new IllegalArgumentException(Errors.format(Errors.Keys.ILLEGAL_ARGUMENT_$1, MapProjectionDescriptor.STANDARD_PARALLEL)); } case 2: standardParallel2 = value[1]; // Fallthrough case 1: standardParallel1 = value[0]; // Fallthrough case 0: break; } } set(STANDARD_PARALLEL_1, standardParallel1, unit); set(STANDARD_PARALLEL_2, standardParallel2, unit); } } /** * The {@link EarthRadius} parameter instance, created when first needed. */ private transient ParameterValue earthRadius; /** * The {@link InverseFlattening} parameter instance, created when first needed. */ private transient ParameterValue inverseFlattening; /** * The {@link StandardParallel} parameter instance, created when first needed. */ private transient ParameterValue standardParallel; /** * Creates a new parameter value group. An instance of {@link MapProjectionDescriptor} * is mandatory, because some method in this class will need to cast the descriptor. */ MapProjectionParameters(final MapProjectionDescriptor descriptor) { super(descriptor); } /** * Returns the value associated to the given parameter descriptor. */ final double get(final ParameterDescriptor parameter) { return Parameters.doubleValue(parameter, this); } /** * Sets the value associated to the given parameter descriptor. */ final void set(final ParameterDescriptor parameter, final double value, final Unit unit) { Parameters.getOrCreate(parameter, this).setValue(value, unit); } /** * Returns the value in this group for the specified name. If the given name is one of the * "invisible" parameters, returns a dynamic parameter view without adding it to the list of * real parameter values. * * @param name The case insensitive name of the parameter to search for. * @return The parameter value for the given name. * @throws ParameterNotFoundException if there is no parameter value for the given name. */ @Override public ParameterValue parameter(String name) throws ParameterNotFoundException { name = name.trim(); final int supplement = ((MapProjectionDescriptor) getDescriptor()).supplement; if ((supplement & ADD_EARTH_RADIUS) != 0) { if (name.equalsIgnoreCase(MapProjectionDescriptor.EARTH_RADIUS)) { ParameterValue value = earthRadius; if (value == null) { value = earthRadius = new EarthRadius(); } return value; } if (name.equalsIgnoreCase(MapProjectionDescriptor.INVERSE_FLATTENING)) { ParameterValue value = inverseFlattening; if (value == null) { value = inverseFlattening = new InverseFlattening(); } return value; } } if ((supplement & ADD_STANDARD_PARALLEL) != 0) { if (name.equalsIgnoreCase(MapProjectionDescriptor.STANDARD_PARALLEL)) { ParameterValue value = standardParallel; if (value == null) { value = standardParallel = new StandardParallel(); } return value; } } return super.parameter(name); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy