javax.measure.quantity.Angle Java Examples

The following examples show how to use javax.measure.quantity.Angle. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: DefaultPrimeMeridian.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Invoked by JAXB for setting the Greenwich longitude and its unit of measurement.
 */
private void setGreenwichMeasure(final Measure measure) {
    if (greenwichLongitude == 0 && angularUnit == null) {
        greenwichLongitude = measure.value;
        angularUnit = measure.getUnit(Angle.class);
        if (angularUnit == null) {
            /*
             * Missing unit: if the Greenwich longitude is zero, any angular unit gives the same result
             * (assuming that the missing unit was not applying an offset), so we can select a default.
             * If the Greenwich longitude is not zero, presume egrees but log a warning.
             */
            angularUnit = Units.DEGREE;
            if (greenwichLongitude != 0) {
                Measure.missingUOM(DefaultPrimeMeridian.class, "setGreenwichMeasure");
            }
        }
    } else {
        MetadataUtilities.propertyAlreadySet(DefaultPrimeMeridian.class, "setGreenwichMeasure", "greenwichLongitude");
    }
}
 
Example #2
Source File: UnitsTest.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Tests getting a unit for a given quantity type.
 */
@Test
public void testGetForQuantity() {
    assertSame("Length",            Units.METRE,             Units.get(Length.class));
    assertSame("Mass",              Units.KILOGRAM,          Units.get(Mass.class));
    assertSame("Time",              Units.SECOND,            Units.get(Time.class));
    assertSame("Temperature",       Units.KELVIN,            Units.get(Temperature.class));
    assertSame("Area",              Units.SQUARE_METRE,      Units.get(Area.class));
    assertSame("Volume",            Units.CUBIC_METRE,       Units.get(Volume.class));
    assertSame("Speed",             Units.METRES_PER_SECOND, Units.get(Speed.class));
    assertSame("LuminousIntensity", Units.CANDELA,           Units.get(LuminousIntensity.class));
    assertSame("LuminousFlux",      Units.LUMEN,             Units.get(LuminousFlux.class));
    assertSame("SolidAngle",        Units.STERADIAN,         Units.get(SolidAngle.class));
    assertSame("Angle",             Units.RADIAN,            Units.get(Angle.class));
    assertSame("Dimensionless",     Units.UNITY,             Units.get(Dimensionless.class));
}
 
Example #3
Source File: FranceGeocentricInterpolationTest.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Tests the {@link FranceGeocentricInterpolation#getOrLoad(Path, double[], double)} method and its cache.
 *
 * @throws URISyntaxException if the URL to the test file can not be converted to a path.
 * @throws FactoryException if an error occurred while computing the grid.
 * @throws TransformException if an error occurred while computing the envelope.
 */
@Test
@DependsOnMethod("testGrid")
public void testGetOrLoad() throws URISyntaxException, FactoryException, TransformException {
    final DatumShiftGridFile<Angle,Length> grid = FranceGeocentricInterpolation.getOrLoad(
            getResource(TEST_FILE), new double[] {
                    FranceGeocentricInterpolation.TX,
                    FranceGeocentricInterpolation.TY,
                    FranceGeocentricInterpolation.TZ},
                    FranceGeocentricInterpolation.PRECISION);
    verifyGrid(grid);
    assertSame("Expected a cached value.", grid, FranceGeocentricInterpolation.getOrLoad(
            getResource(TEST_FILE), new double[] {
                    FranceGeocentricInterpolation.TX,
                    FranceGeocentricInterpolation.TY,
                    FranceGeocentricInterpolation.TZ},
                    FranceGeocentricInterpolation.PRECISION));
}
 
Example #4
Source File: FranceGeocentricInterpolationTest.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Tests a small grid file with interpolations in geocentric coordinates as {@code short} values.
 *
 * <p>This method is part of a chain.
 * The previous method is {@link #testGridAsFloats()}.</p>
 *
 * @param  grid  the grid created by {@link #testGridAsFloats()}.
 * @return the given grid, but compressed as {@code short} values.
 * @throws TransformException if an error occurred while computing the envelope.
 */
@TestStep
private static DatumShiftGridFile<Angle,Length> testGridAsShorts(DatumShiftGridFile<Angle,Length> grid)
        throws TransformException
{
    grid = DatumShiftGridCompressed.compress((DatumShiftGridFile.Float<Angle,Length>) grid, new double[] {
            FranceGeocentricInterpolation.TX,           //  168 metres
            FranceGeocentricInterpolation.TY,           //   60 metres
            FranceGeocentricInterpolation.TZ},          // -320 metres
            FranceGeocentricInterpolation.PRECISION);
    assertInstanceOf("Failed to compress 'float' values into 'short' values.", DatumShiftGridCompressed.class, grid);
    assertEquals("cellPrecision", 0.0005, grid.getCellPrecision(), STRICT);
    assertEquals("getCellMean",  168, grid.getCellMean(0), STRICT);
    assertEquals("getCellMean",   60, grid.getCellMean(1), STRICT);
    assertEquals("getCellMean", -320, grid.getCellMean(2), STRICT);
    verifyGrid(grid);
    return grid;
}
 
Example #5
Source File: FranceGeocentricInterpolationTest.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Tests a small grid file with interpolations in geocentric coordinates as {@code float} values.
 *
 * <p>This method is part of a chain.
 * The next method is {@link #testGridAsShorts(DatumShiftGridFile)}.</p>
 *
 * @return the loaded grid with values as {@code float}.
 * @throws URISyntaxException if the URL to the test file can not be converted to a path.
 * @throws IOException if an error occurred while loading the grid.
 * @throws FactoryException if an error occurred while computing the grid.
 * @throws TransformException if an error occurred while computing the envelope.
 */
@TestStep
private static DatumShiftGridFile<Angle,Length> testGridAsFloats()
        throws URISyntaxException, IOException, FactoryException, TransformException
{
    final Path file = getResource(TEST_FILE);
    final DatumShiftGridFile.Float<Angle,Length> grid;
    try (BufferedReader in = Files.newBufferedReader(file)) {
        grid = FranceGeocentricInterpolation.load(in, file);
    }
    assertEquals("cellPrecision",   0.005, grid.getCellPrecision(), STRICT);
    assertEquals("getCellMean",  168.2587, grid.getCellMean(0), 0.0001);
    assertEquals("getCellMean",   58.7163, grid.getCellMean(1), 0.0001);
    assertEquals("getCellMean", -320.1801, grid.getCellMean(2), 0.0001);
    verifyGrid(grid);
    return grid;
}
 
Example #6
Source File: GeodeticObjectParser.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Parses a {@code "PrimeMeridian"} element. The syntax is given by
 * <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#53">WKT 2 specification §8.2.2</a>.
 *
 * The legacy WKT 1 pattern was:
 *
 * {@preformat wkt
 *     PRIMEM["<name>", <longitude> {,<authority>}]
 * }
 *
 * @param  mode         {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
 * @param  parent       the parent element.
 * @param  isWKT1       {@code true} if this method is invoked while parsing a WKT 1 element.
 * @param  angularUnit  the contextual unit.
 * @return the {@code "PrimeMeridian"} element as a {@link PrimeMeridian} object.
 * @throws ParseException if the {@code "PrimeMeridian"} element can not be parsed.
 *
 * @see org.apache.sis.referencing.datum.DefaultPrimeMeridian#formatTo(Formatter)
 */
private PrimeMeridian parsePrimeMeridian(final int mode, final Element parent, final boolean isWKT1, Unit<Angle> angularUnit)
        throws ParseException
{
    if (isWKT1 && usesCommonUnits) {
        angularUnit = Units.DEGREE;
    }
    final Element element = parent.pullElement(mode, WKTKeywords.PrimeMeridian, WKTKeywords.PrimeM);
    if (element == null) {
        return null;
    }
    final String name      = element.pullString("name");
    final double longitude = element.pullDouble("longitude");
    final Unit<Angle> unit = parseScaledUnit(element, WKTKeywords.AngleUnit, Units.RADIAN);
    if (unit != null) {
        angularUnit = unit;
    } else if (angularUnit == null) {
        throw parent.missingComponent(WKTKeywords.AngleUnit);
    }
    final DatumFactory datumFactory = factories.getDatumFactory();
    try {
        return datumFactory.createPrimeMeridian(parseMetadataAndClose(element, name, null), longitude, angularUnit);
    } catch (FactoryException exception) {
        throw element.parseFailed(exception);
    }
}
 
Example #7
Source File: AxisDirections.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Returns the angular unit of the specified coordinate system.
 * The preference will be given to the longitude axis, if found.
 *
 * @param  cs        the coordinate system from which to get the angular unit, or {@code null}.
 * @param  fallback  the default unit to return if no angular unit is found.
 * @return the angular unit, of {@code unit} if no angular unit was found.
 *
 * @see org.apache.sis.internal.referencing.ReferencingUtilities#getUnit(CoordinateSystem)
 *
 * @since 0.6
 */
public static Unit<Angle> getAngularUnit(final CoordinateSystem cs, Unit<Angle> fallback) {
    if (cs != null) {
        for (int i = cs.getDimension(); --i>=0;) {
            final CoordinateSystemAxis axis = cs.getAxis(i);
            if (axis != null) {                                                     // Paranoiac check.
                final Unit<?> candidate = axis.getUnit();
                if (Units.isAngular(candidate)) {
                    fallback = candidate.asType(Angle.class);
                    if (AxisDirection.EAST.equals(absolute(axis.getDirection()))) {
                        break;                                                      // Found the longitude axis.
                    }
                }
            }
        }
    }
    return fallback;
}
 
Example #8
Source File: DatumShiftGridFile.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Creates a transformation between two geodetic CRS, including the sub-grid transforms.
 * If the given grid has no sub-grid, then this method is equivalent to a direct call to
 * {@link InterpolatedTransform#createGeodeticTransformation(MathTransformFactory, DatumShiftGrid)}.
 *
 * @param  provider  the provider which is creating a transform.
 * @param  factory   the factory to use for creating the transform.
 * @param  grid      the grid of datum shifts from source to target datum.
 * @return the transformation between geodetic coordinates.
 * @throws FactoryException if an error occurred while creating a transform.
 *
 * @see InterpolatedTransform#createGeodeticTransformation(MathTransformFactory, DatumShiftGrid)
 */
public static MathTransform createGeodeticTransformation(final Class<? extends AbstractProvider> provider,
        final MathTransformFactory factory, final DatumShiftGridFile<Angle,Angle> grid) throws FactoryException
{
    MathTransform global = InterpolatedTransform.createGeodeticTransformation(factory, grid);
    final DatumShiftGridFile<Angle,Angle>[] subgrids = grid.subgrids;
    if (subgrids == null) {
        return global;
    }
    final Map<Envelope,MathTransform> specializations = new LinkedHashMap<>(Containers.hashMapCapacity(subgrids.length));
    for (final DatumShiftGridFile<Angle,Angle> sg : subgrids) try {
        final Envelope domain = sg.getDomainOfValidity(Units.DEGREE);
        final MathTransform st = createGeodeticTransformation(provider, factory, sg);
        if (specializations.putIfAbsent(domain, st) != null) {
            DatumShiftGridLoader.log(provider, Errors.getResources((Locale) null)
                    .getLogRecord(Level.FINE, Errors.Keys.DuplicatedElement_1, domain));
        }
    } catch (TransformException e) {
        throw new FactoryException(e);
    }
    return MathTransforms.specialize(global, specializations);
}
 
Example #9
Source File: DefaultPrimeMeridian.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Formats this prime meridian as a <cite>Well Known Text</cite> {@code PrimeMeridian[…]} element.
 *
 * @return {@code "PrimeMeridian"} (WKT 2) or {@code "PrimeM"} (WKT 1).
 *
 * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#53">WKT 2 specification §8.2.2</a>
 */
@Override
protected String formatTo(final Formatter formatter) {
    super.formatTo(formatter);
    final Convention  convention = formatter.getConvention();
    final boolean     isWKT1 = (convention.majorVersion() == 1);
    final Unit<Angle> contextualUnit = formatter.toContextualUnit(Units.DEGREE);
    Unit<Angle> unit = contextualUnit;
    if (!isWKT1) {
        unit = getAngularUnit();
        if (convention != Convention.INTERNAL) {
            unit = WKTUtilities.toFormattable(unit);
        }
    }
    formatter.append(getGreenwichLongitude(unit));
    if (isWKT1) {
        return WKTKeywords.PrimeM;
    }
    if (!convention.isSimplified() || !contextualUnit.equals(unit) || beConservative(formatter, contextualUnit)) {
        formatter.append(unit);
    }
    return formatter.shortOrLong(WKTKeywords.PrimeM, WKTKeywords.PrimeMeridian);
}
 
Example #10
Source File: I18nProviderImpl.java    From smarthome with Eclipse Public License 2.0 5 votes vote down vote up
private void initDimensionMap() {
    Map<SystemOfUnits, Unit<? extends Quantity<?>>> temperatureMap = new HashMap<>();
    temperatureMap.put(SIUnits.getInstance(), SIUnits.CELSIUS);
    temperatureMap.put(ImperialUnits.getInstance(), ImperialUnits.FAHRENHEIT);
    dimensionMap.put(Temperature.class, temperatureMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> pressureMap = new HashMap<>();
    pressureMap.put(SIUnits.getInstance(), HECTO(SIUnits.PASCAL));
    pressureMap.put(ImperialUnits.getInstance(), ImperialUnits.INCH_OF_MERCURY);
    dimensionMap.put(Pressure.class, pressureMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> speedMap = new HashMap<>();
    speedMap.put(SIUnits.getInstance(), SIUnits.KILOMETRE_PER_HOUR);
    speedMap.put(ImperialUnits.getInstance(), ImperialUnits.MILES_PER_HOUR);
    dimensionMap.put(Speed.class, speedMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> lengthMap = new HashMap<>();
    lengthMap.put(SIUnits.getInstance(), SIUnits.METRE);
    lengthMap.put(ImperialUnits.getInstance(), ImperialUnits.INCH);
    dimensionMap.put(Length.class, lengthMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> intensityMap = new HashMap<>();
    intensityMap.put(SIUnits.getInstance(), SmartHomeUnits.IRRADIANCE);
    intensityMap.put(ImperialUnits.getInstance(), SmartHomeUnits.IRRADIANCE);
    dimensionMap.put(Intensity.class, intensityMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> percentMap = new HashMap<>();
    percentMap.put(SIUnits.getInstance(), SmartHomeUnits.ONE);
    percentMap.put(ImperialUnits.getInstance(), SmartHomeUnits.ONE);
    dimensionMap.put(Dimensionless.class, percentMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> angleMap = new HashMap<>();
    angleMap.put(SIUnits.getInstance(), SmartHomeUnits.DEGREE_ANGLE);
    angleMap.put(ImperialUnits.getInstance(), SmartHomeUnits.DEGREE_ANGLE);
    dimensionMap.put(Angle.class, angleMap);
}
 
Example #11
Source File: FranceGeocentricInterpolation.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Returns the grid of the given name. This method returns the cached instance if it still exists,
 * or load the grid otherwise.
 *
 * @param  file      name of the datum shift grid file to load.
 * @param  averages  an "average" value for the offset in each dimension, or {@code null} if unknown.
 * @param  scale     the factor by which to multiply each compressed value before to add to the average value.
 */
@SuppressWarnings("null")
static DatumShiftGridFile<Angle,Length> getOrLoad(final Path file, final double[] averages, final double scale)
        throws FactoryException
{
    final Path resolved = DataDirectory.DATUM_CHANGES.resolve(file).toAbsolutePath();
    DatumShiftGridFile<?,?> grid = DatumShiftGridFile.CACHE.peek(resolved);
    if (grid == null) {
        final Cache.Handler<DatumShiftGridFile<?,?>> handler = DatumShiftGridFile.CACHE.lock(resolved);
        try {
            grid = handler.peek();
            if (grid == null) {
                try (BufferedReader in = Files.newBufferedReader(resolved)) {
                    DatumShiftGridLoader.startLoading(FranceGeocentricInterpolation.class, file);
                    final DatumShiftGridFile.Float<Angle,Length> g = load(in, file);
                    grid = DatumShiftGridCompressed.compress(g, averages, scale);
                } catch (IOException | NoninvertibleTransformException | RuntimeException e) {
                    // NumberFormatException, ArithmeticException, NoSuchElementException, possibly other.
                    throw DatumShiftGridLoader.canNotLoad(HEADER, file, e);
                }
                grid = grid.useSharedData();
            }
        } finally {
            handler.putAndUnlock(grid);
        }
    }
    return grid.castTo(Angle.class, Length.class);
}
 
Example #12
Source File: FranceGeocentricInterpolation.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Creates the actual math transform. The default implementation delegates to the static method defined in
 * {@link InterpolatedGeocentricTransform}, but the {@link MolodenskyInterpolation} subclass will rather
 * delegate to {@link org.apache.sis.referencing.operation.transform.InterpolatedMolodenskyTransform}.
 */
MathTransform createGeodeticTransformation(final MathTransformFactory factory,
        final Ellipsoid source, final Ellipsoid target, final boolean withHeights,
        final DatumShiftGridFile<Angle,Length> grid) throws FactoryException
{
    return InterpolatedGeocentricTransform.createGeodeticTransformation(
            factory, source, withHeights, target, withHeights, grid);
}
 
Example #13
Source File: FranceGeocentricInterpolation.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a transform from the specified group of parameter values.
 * This method creates the transform from <em>target</em> to <em>source</em>
 * (which is the direction that use the interpolation grid directly without iteration),
 * then inverts the transform.
 *
 * @param  factory  the factory to use if this constructor needs to create other math transforms.
 * @param  values   the group of parameter values.
 * @return the created math transform.
 * @throws ParameterNotFoundException if a required parameter was not found.
 * @throws FactoryException if an error occurred while loading the grid.
 */
@Override
public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
        throws ParameterNotFoundException, FactoryException
{
    boolean withHeights = false;
    final Parameters pg = Parameters.castOrWrap(values);
    final Integer dim = pg.getValue(Molodensky.DIMENSION);
    if (dim != null) switch (dim) {
        case 2:  break;
        case 3:  withHeights = true; break;
        default: throw new InvalidParameterValueException(Errors.format(
                        Errors.Keys.IllegalArgumentValue_2, "dim", dim), "dim", dim);
    }
    final Path file = pg.getMandatoryValue(FILE);
    final DatumShiftGridFile<Angle,Length> grid = getOrLoad(file,
            isRecognized(file) ? new double[] {TX, TY, TZ} : null, PRECISION);
    MathTransform tr = createGeodeticTransformation(factory,
            createEllipsoid(pg, Molodensky.TGT_SEMI_MAJOR,
                                Molodensky.TGT_SEMI_MINOR, CommonCRS.ETRS89.ellipsoid()),   // GRS 1980 ellipsoid
            createEllipsoid(pg, Molodensky.SRC_SEMI_MAJOR,
                                Molodensky.SRC_SEMI_MINOR, null),                           // Clarke 1880 (IGN) ellipsoid
            withHeights, grid);
    try {
        tr = tr.inverse();
    } catch (NoninvertibleTransformException e) {
        throw new FactoryException(e);                  // Should never happen.
    }
    return tr;
}
 
Example #14
Source File: CRSBuilder.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a prime meridian from an EPSG code or from user-defined parameters.
 * The GeoTIFF values used by this method are:
 *
 * <ul>
 *   <li>A code given by {@link GeoKeys#PrimeMeridian}.</li>
 *   <li>If above code is {@link GeoCodes#userDefined}, then:<ul>
 *     <li>a prime meridian value given by {@link GeoKeys#PrimeMeridianLong}.</li>
 *   </ul></li>
 * </ul>
 *
 * If no prime-meridian is defined, then the default is Greenwich as per GeoTIFF specification.
 *
 * @param  names  the component names to use if the prime meridian is user-defined.
 * @param  unit   the angular unit of the longitude value relative to Greenwich.
 * @return a prime meridian created from the given {@link Unit} and the above-cited GeoTIFF keys.
 * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
 * @throws FactoryException if an error occurred during objects creation with the factories.
 */
private PrimeMeridian createPrimeMeridian(final String[] names, final Unit<Angle> unit) throws FactoryException {
    final int epsg = getAsInteger(GeoKeys.PrimeMeridian);
    switch (epsg) {
        case GeoCodes.undefined:      // If not specified, should default to Greenwich but we nevertheless verify.
        case GeoCodes.userDefined: {
            final double longitude = getAsDouble(GeoKeys.PrimeMeridianLong);
            if (Double.isNaN(longitude)) {
                if (epsg != GeoCodes.undefined) {
                    missingValue(GeoKeys.PrimeMeridianLong);
                }
            } else if (longitude != 0) {
                /*
                 * If the prime meridian is not Greenwich, create that meridian but do not use the
                 * GeoKeys.GeogCitation value (unless it had a sub-element for the prime meridian).
                 * This is because the citation value is for the CRS (e.g. "WGS84") while the prime
                 * meridian names are very different (e.g. "Paris", "Madrid", etc).
                 */
                return getDatumFactory().createPrimeMeridian(properties(names[PRIMEM]), longitude, unit);
            }
            break;                      // Default to Greenwich.
        }
        default: {
            /*
             * Prime meridian defined by an EPSG code. In principle we should just use the EPSG code.
             * But if the file also provide the longitude value, verify that the value is consistent
             * with what we would expect for a prime meridian of the given EPSG code.
             */
            final PrimeMeridian pm = getDatumAuthorityFactory().createPrimeMeridian(String.valueOf(epsg));
            verify(pm, unit);
            return pm;
        }
    }
    return CommonCRS.WGS84.primeMeridian();
}
 
Example #15
Source File: NTv2.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Returns the grid of the given name. This method returns the cached instance if it still exists,
 * or load the grid otherwise.
 *
 * @param  provider  the provider which is creating a transform.
 * @param  file      name of the datum shift grid file to load.
 * @param  version   the expected version (1 or 2).
 */
@SuppressWarnings("null")
static DatumShiftGridFile<Angle,Angle> getOrLoad(final Class<? extends AbstractProvider> provider,
        final Path file, final int version) throws FactoryException
{
    final Path resolved = DataDirectory.DATUM_CHANGES.resolve(file).toAbsolutePath();
    DatumShiftGridFile<?,?> grid = DatumShiftGridFile.CACHE.peek(resolved);
    if (grid == null) {
        final Cache.Handler<DatumShiftGridFile<?,?>> handler = DatumShiftGridFile.CACHE.lock(resolved);
        try {
            grid = handler.peek();
            if (grid == null) {
                try (ReadableByteChannel in = Files.newByteChannel(resolved)) {
                    DatumShiftGridLoader.startLoading(provider, file);
                    final Loader loader = new Loader(in, file, version);
                    grid = loader.readAllGrids();
                    loader.report(provider);
                } catch (IOException | NoninvertibleTransformException | RuntimeException e) {
                    throw DatumShiftGridLoader.canNotLoad(provider.getSimpleName(), file, e);
                }
                grid = grid.useSharedData();
            }
        } finally {
            handler.putAndUnlock(grid);
        }
    }
    return grid.castTo(Angle.class, Angle.class);
}
 
Example #16
Source File: MolodenskyInterpolation.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Invoked by {@link #createMathTransform(MathTransformFactory, ParameterValueGroup)}
 * after all parameters have been processed.
 */
@Override
MathTransform createGeodeticTransformation(final MathTransformFactory factory,
        final Ellipsoid source, final Ellipsoid target, final boolean withHeights,
        final DatumShiftGridFile<Angle,Length> grid) throws FactoryException
{
    return InterpolatedMolodenskyTransform.createGeodeticTransformation(
            factory, source, withHeights, target, withHeights, grid);
}
 
Example #17
Source File: CRSBuilder.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a coordinate system (CS) with the same axis directions than the given CS but potentially different units.
 * If a coordinate system exists in the EPSG database with the requested characteristics, that CS will be returned
 * in order to have a richer set of metadata (name, minimal and maximal values, <i>etc</i>). Otherwise an CS with
 * an arbitrary name will be returned.
 *
 * @see CoordinateSystems#replaceAngularUnit(CoordinateSystem, Unit)
 */
private EllipsoidalCS replaceAngularUnit(final EllipsoidalCS cs, final Unit<Angle> unit) throws FactoryException {
    final Integer epsg = CoordinateSystems.getEpsgCode(unit, CoordinateSystems.getAxisDirections(cs));
    if (epsg != null) try {
        return getCSAuthorityFactory().createEllipsoidalCS(epsg.toString());
    } catch (NoSuchAuthorityCodeException e) {
        reader.owner.warning(null, e);
    }
    return (EllipsoidalCS) CoordinateSystems.replaceAngularUnit(cs, unit);
}
 
Example #18
Source File: I18nProviderImpl.java    From openhab-core with Eclipse Public License 2.0 5 votes vote down vote up
private void initDimensionMap() {
    Map<SystemOfUnits, Unit<? extends Quantity<?>>> temperatureMap = new HashMap<>();
    temperatureMap.put(SIUnits.getInstance(), SIUnits.CELSIUS);
    temperatureMap.put(ImperialUnits.getInstance(), ImperialUnits.FAHRENHEIT);
    dimensionMap.put(Temperature.class, temperatureMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> pressureMap = new HashMap<>();
    pressureMap.put(SIUnits.getInstance(), HECTO(SIUnits.PASCAL));
    pressureMap.put(ImperialUnits.getInstance(), ImperialUnits.INCH_OF_MERCURY);
    dimensionMap.put(Pressure.class, pressureMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> speedMap = new HashMap<>();
    speedMap.put(SIUnits.getInstance(), SIUnits.KILOMETRE_PER_HOUR);
    speedMap.put(ImperialUnits.getInstance(), ImperialUnits.MILES_PER_HOUR);
    dimensionMap.put(Speed.class, speedMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> lengthMap = new HashMap<>();
    lengthMap.put(SIUnits.getInstance(), SIUnits.METRE);
    lengthMap.put(ImperialUnits.getInstance(), ImperialUnits.INCH);
    dimensionMap.put(Length.class, lengthMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> intensityMap = new HashMap<>();
    intensityMap.put(SIUnits.getInstance(), SmartHomeUnits.IRRADIANCE);
    intensityMap.put(ImperialUnits.getInstance(), SmartHomeUnits.IRRADIANCE);
    dimensionMap.put(Intensity.class, intensityMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> percentMap = new HashMap<>();
    percentMap.put(SIUnits.getInstance(), SmartHomeUnits.ONE);
    percentMap.put(ImperialUnits.getInstance(), SmartHomeUnits.ONE);
    dimensionMap.put(Dimensionless.class, percentMap);

    Map<SystemOfUnits, Unit<? extends Quantity<?>>> angleMap = new HashMap<>();
    angleMap.put(SIUnits.getInstance(), SmartHomeUnits.DEGREE_ANGLE);
    angleMap.put(ImperialUnits.getInstance(), SmartHomeUnits.DEGREE_ANGLE);
    dimensionMap.put(Angle.class, angleMap);
}
 
Example #19
Source File: DefaultPrimeMeridianTest.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Tests WKT formatting of a prime meridian with sexagesimal units.
 * Since those units can not be formatted in a {@code UNIT["name", scale]} element,
 * the formatter should convert them to a formattable unit like degrees.
 *
 * @since 0.6
 */
@Test
@DependsOnMethod("testWKT_inGrads")
public void testWKT_withUnformattableUnit() {
    final DefaultPrimeMeridian pm = new DefaultPrimeMeridian(singletonMap(DefaultPrimeMeridian.NAME_KEY, "Test"),
            10.3, Units.valueOfEPSG(9111).asType(Angle.class));
    /*
     * In WKT 1 format, if there is no contextual unit (which is the case of this test),
     * the formatter default to decimal degrees. In WKT 2 format it depends on the PM unit.
     */
    assertWktEquals(Convention.WKT1, "PRIMEM[“Test”, 10.5]", pm);  // 10.3 DM  ==  10.5°
    assertWktEquals(Convention.WKT2, "PRIMEM[“Test”, 10.5, ANGLEUNIT[“degree”, 0.017453292519943295]]", pm);
    assertWktEquals(Convention.WKT2_SIMPLIFIED, "PrimeMeridian[“Test”, 10.5]", pm);
    assertWktEquals(Convention.INTERNAL, "PrimeMeridian[“Test”, 10.3, Unit[“D.M”, 0.017453292519943295, Id[“EPSG”, 9111]]]", pm);
}
 
Example #20
Source File: EPSGDataAccess.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a prime meridian defining the origin from which longitude values are determined.
 *
 * <div class="note"><b>Example:</b>
 * some EPSG codes for prime meridians are:
 *
 * <table class="sis">
 * <caption>EPSG codes examples</caption>
 *   <tr><th>Code</th> <th>Description</th></tr>
 *   <tr><td>8901</td> <td>Greenwich</td></tr>
 *   <tr><td>8903</td> <td>Paris</td></tr>
 *   <tr><td>8904</td> <td>Bogota</td></tr>
 *   <tr><td>8905</td> <td>Madrid</td></tr>
 *   <tr><td>8906</td> <td>Rome</td></tr>
 * </table></div>
 *
 * @param  code  value allocated by EPSG.
 * @return the prime meridian for the given code.
 * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
 * @throws FactoryException if the object creation failed for some other reason.
 *
 * @see #createGeodeticDatum(String)
 * @see org.apache.sis.referencing.datum.DefaultPrimeMeridian
 */
@Override
public synchronized PrimeMeridian createPrimeMeridian(final String code)
        throws NoSuchAuthorityCodeException, FactoryException
{
    ArgumentChecks.ensureNonNull("code", code);
    PrimeMeridian returnValue = null;
    try (ResultSet result = executeQuery("Prime Meridian", "PRIME_MERIDIAN_CODE", "PRIME_MERIDIAN_NAME",
            "SELECT PRIME_MERIDIAN_CODE," +
                  " PRIME_MERIDIAN_NAME," +
                  " GREENWICH_LONGITUDE," +
                  " UOM_CODE," +
                  " REMARKS," +
                  " DEPRECATED" +
            " FROM [Prime Meridian]" +
            " WHERE PRIME_MERIDIAN_CODE = ?", code))
    {
        while (result.next()) {
            final Integer epsg       = getInteger  (code, result, 1);
            final String  name       = getString   (code, result, 2);
            final double  longitude  = getDouble   (code, result, 3);
            final String  unitCode   = getString   (code, result, 4);
            final String  remarks    = getOptionalString (result, 5);
            final boolean deprecated = getOptionalBoolean(result, 6);
            final Unit<Angle> unit = owner.createUnit(unitCode).asType(Angle.class);
            final PrimeMeridian primeMeridian = owner.datumFactory.createPrimeMeridian(
                    createProperties("Prime Meridian", name, epsg, remarks, deprecated), longitude, unit);
            returnValue = ensureSingleton(primeMeridian, returnValue, code);
        }
    } catch (SQLException exception) {
        throw databaseFailure(PrimeMeridian.class, code, exception);
    }
    if (returnValue == null) {
        throw noSuchAuthorityCode(PrimeMeridian.class, code);
    }
    return returnValue;
}
 
Example #21
Source File: BlukiiHandler.java    From smarthome with Eclipse Public License 2.0 5 votes vote down vote up
@Override
public void onScanRecordReceived(BluetoothScanNotification scanNotification) {
    final byte[] manufacturerData = scanNotification.getManufacturerData();
    if (manufacturerData != null) {
        final BlukiiData blukiiData = decoder.decode(manufacturerData);
        if (blukiiData != null) {
            updateState(BlukiiBindingConstants.CHANNEL_ID_BATTERY, new DecimalType(blukiiData.battery));
            blukiiData.environment.ifPresent(environment -> {
                updateState(BlukiiBindingConstants.CHANNEL_ID_TEMPERATURE,
                        new QuantityType<Temperature>(environment.temperature, SIUnits.CELSIUS));
                updateState(BlukiiBindingConstants.CHANNEL_ID_HUMIDITY,
                        new QuantityType<Dimensionless>(environment.humidity, SmartHomeUnits.PERCENT));
                updateState(BlukiiBindingConstants.CHANNEL_ID_PRESSURE,
                        new QuantityType<Pressure>(environment.pressure, MetricPrefix.HECTO(SIUnits.PASCAL)));
                updateState(BlukiiBindingConstants.CHANNEL_ID_LUMINANCE,
                        new QuantityType<Illuminance>(environment.luminance, SmartHomeUnits.LUX));
            });
            blukiiData.accelerometer.ifPresent(accelerometer -> {
                updateState(BlukiiBindingConstants.CHANNEL_ID_TILTX,
                        new QuantityType<Angle>(accelerometer.tiltX, SmartHomeUnits.DEGREE_ANGLE));
                updateState(BlukiiBindingConstants.CHANNEL_ID_TILTY,
                        new QuantityType<Angle>(accelerometer.tiltY, SmartHomeUnits.DEGREE_ANGLE));
                updateState(BlukiiBindingConstants.CHANNEL_ID_TILTZ,
                        new QuantityType<Angle>(accelerometer.tiltZ, SmartHomeUnits.DEGREE_ANGLE));
            });
            blukiiData.magnetometer.ifPresent(magnetometer -> {
                // It isn't easy to get a heading from these values without any calibration, so we ignore those
                // right
                // now.
            });
        }
    }
    super.onScanRecordReceived(scanNotification);
}
 
Example #22
Source File: CRSBuilder.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Verifies if the user-defined CRS created from GeoTIFF values
 * matches the given CRS created from the EPSG geodetic dataset.
 * This method does not verify the EPSG code of the given CRS.
 *
 * @param  crs          the CRS created from the EPSG geodetic dataset.
 * @param  angularUnit  the angular unit of the latitude and longitude values.
 */
private void verify(final GeographicCRS crs, final Unit<Angle> angularUnit) throws FactoryException {
    /*
     * Note: current createUnit(…) implementation does not allow us to distinguish whether METRE ou DEGREE units
     * were specified in the GeoTIFF file or if we got the default values. We do not compare units of that reason.
     */
    final Unit<Length> linearUnit = createUnit(GeoKeys.GeogLinearUnits, GeoKeys.GeogLinearUnitSize, Length.class, Units.METRE);
    final GeodeticDatum datum = crs.getDatum();
    verifyIdentifier(crs, datum, GeoKeys.GeodeticDatum);
    verify(datum, angularUnit, linearUnit);
}
 
Example #23
Source File: CRSBuilder.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Verifies if the user-defined CRS created from GeoTIFF values
 * matches the given CRS created from the EPSG geodetic dataset.
 * This method does not verify the EPSG code of the given CRS.
 *
 * @param  crs  the CRS created from the EPSG geodetic dataset.
 */
private void verify(final GeocentricCRS crs) throws FactoryException {
    /*
     * Note: current createUnit(…) implementation does not allow us to distinguish whether METRE ou DEGREE units
     * were specified in the GeoTIFF file or if we got the default values. We do not compare units of that reason.
     */
    final Unit<Length> linearUnit = createUnit(GeoKeys.GeogLinearUnits, GeoKeys.GeogLinearUnitSize, Length.class, Units.METRE);
    final Unit<Angle> angularUnit = createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE);
    final GeodeticDatum datum = crs.getDatum();
    verifyIdentifier(crs, datum, GeoKeys.GeodeticDatum);
    verify(datum, angularUnit, linearUnit);
}
 
Example #24
Source File: CRSBuilder.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Verifies if the user-defined CRS created from GeoTIFF values
 * matches the given CRS created from the EPSG geodetic dataset.
 * This method does not verify the EPSG code of the given CRS.
 *
 * @param  crs  the CRS created from the EPSG geodetic dataset.
 */
private void verify(final ProjectedCRS crs) throws FactoryException {
    final Unit<Length> linearUnit  = createUnit(GeoKeys.LinearUnits,  GeoKeys.LinearUnitSize, Length.class, Units.METRE);
    final Unit<Angle>  angularUnit = createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE);
    final GeographicCRS baseCRS = crs.getBaseCRS();
    verifyIdentifier(crs, baseCRS, GeoKeys.GeographicType);
    verify(baseCRS, angularUnit);
    final Conversion projection = crs.getConversionFromBase();
    verifyIdentifier(crs, projection, GeoKeys.Projection);
    verify(projection, angularUnit, linearUnit);
}
 
Example #25
Source File: NTv2Test.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Writes a sub-grid of the given grid in pseudo-NTv2 format. This method is used only for creating the test file.
 * The file created by this method is not fully NTv2 compliant (in particular, we do not write complete header),
 * but we take this opportunity for testing {@code NTv2.Loader} capability to be lenient.
 *
 * <p>This method has been executed once for creating the {@code "NTF_R93-extract.gsb"} test file and should not
 * be needed anymore, but we keep it around in case we have new test files to generate. The parameter used for
 * creating the test file are:</p>
 *
 * <ul>
 *   <li>{@code gridX} = 72</li>
 *   <li>{@code gridY} = 74</li>
 *   <li>{@code nx}    =  6</li>
 *   <li>{@code ny}    =  7</li>
 * </ul>
 *
 * This ensure that the grid indices (75.7432814, 78.4451225) is included in the test file.
 * Those grid indices is the location of the (2°25′32.4187″N 48°50′40.2441″W) test point to interpolate.
 *
 * <h4>Limitations</h4>
 * This method assumes that bounding box and increments have integer values, and that any fractional part
 * is rounding errors. This is usually the case when using the {@code "SECONDS"} unit of measurement.
 * This assumption does not apply to the shift values.
 *
 * @param  grid   the full grid from which to extract a few values.
 * @param  out    where to write the test file.
 * @param  gridX  index along the longitude axis of the first cell to write.
 * @param  gridY  index along the latitude axis of the first cell to write.
 * @param  nx     number of cells to write along the longitude axis.
 * @param  ny     number of cells to write along the latitude axis.
 * @throws TransformException if an error occurred while computing the envelope.
 * @throws IOException if an error occurred while writing the test file.
 */
public static void writeSubGrid(final DatumShiftGridFile<Angle,Angle> grid, final Path out,
        final int gridX, final int gridY, final int nx, final int ny) throws IOException, TransformException
{
    Envelope envelope = new Envelope2D(null, gridX, gridY, nx - 1, ny - 1);
    envelope = Envelopes.transform(grid.getCoordinateToGrid().inverse(), envelope);
    final ByteBuffer buffer = ByteBuffer.allocate(4096);
    buffer.order(ByteOrder.LITTLE_ENDIAN);
    writeString(buffer, "NUM_OREC"); buffer.putInt(5); nextRecord(buffer);
    writeString(buffer, "NUM_SREC"); buffer.putInt(7); nextRecord(buffer);
    writeString(buffer, "NUM_FILE"); buffer.putInt(1); nextRecord(buffer);
    writeString(buffer, "GS_TYPE");  writeString(buffer, "SECONDS");
    writeString(buffer, "VERSION");  writeString(buffer, "SIS_TEST");   // Last overview record.
    writeString(buffer, "S_LAT");    buffer.putDouble(StrictMath.rint( envelope.getMinimum(1)));
    writeString(buffer, "N_LAT");    buffer.putDouble(StrictMath.rint( envelope.getMaximum(1)));
    writeString(buffer, "E_LONG");   buffer.putDouble(StrictMath.rint(-envelope.getMaximum(0)));  // Sign reversed.
    writeString(buffer, "W_LONG");   buffer.putDouble(StrictMath.rint(-envelope.getMinimum(0)));
    writeString(buffer, "LAT_INC");  buffer.putDouble(StrictMath.rint( envelope.getSpan(1) / (ny - 1)));
    writeString(buffer, "LONG_INC"); buffer.putDouble(StrictMath.rint( envelope.getSpan(0) / (nx - 1)));
    writeString(buffer, "GS_COUNT"); buffer.putInt(nx * ny); nextRecord(buffer);
    for (int y=0; y<ny; y++) {
        for (int x=0; x<nx; x++) {
            buffer.putFloat((float) grid.getCellValue(1, gridX + x, gridY + y));
            buffer.putFloat((float) grid.getCellValue(0, gridX + x, gridY + y));
            buffer.putFloat(ACCURACY);
            buffer.putFloat(ACCURACY);
        }
    }
    writeString(buffer, "END");
    nextRecord(buffer);
    try (WritableByteChannel c = Files.newByteChannel(out, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
        buffer.flip();
        c.write(buffer);
    }
}
 
Example #26
Source File: FranceGeocentricInterpolationTest.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Verifies the envelope and the interpolation performed by the given grid.
 *
 * @throws TransformException if an error occurred while computing the envelope.
 */
private static void verifyGrid(final DatumShiftGridFile<Angle,Length> grid) throws TransformException {
    final Envelope envelope = grid.getDomainOfValidity();
    assertEquals("xmin",  2.2, envelope.getMinimum(0), 1E-12);
    assertEquals("xmax",  2.5, envelope.getMaximum(0), 1E-12);
    assertEquals("ymin", 48.5, envelope.getMinimum(1), 1E-12);
    assertEquals("ymax", 49.0, envelope.getMaximum(1), 1E-12);
    /*
     * The values in the NTG_88 document are:
     *
     * (gridX=2, gridY=3)  00002    2.400000000   48.800000000  -168.252   -58.630   320.170  01   2314
     * (gridX=2, gridY=4)  00002    2.400000000   48.900000000  -168.275   -58.606   320.189  01   2314
     * (gridX=3, gridY=3)  00002    2.500000000   48.800000000  -168.204   -58.594   320.125  01   2314
     * (gridX=3, gridY=4)  00002    2.500000000   48.900000000  -168.253   -58.554   320.165  01   2314
     *
     * Directions (signs) are reversed compared to NTG_88 document.
     */
    assertEquals("translationDimensions", 3, grid.getTranslationDimensions());
    assertEquals("grid.accuracy",      0.05, grid.accuracy,              STRICT);
    assertEquals("getCellValue",    168.196, grid.getCellValue(0, 2, 1), STRICT);
    assertEquals("getCellValue",     58.778, grid.getCellValue(1, 2, 1), STRICT);
    assertEquals("getCellValue",   -320.127, grid.getCellValue(2, 2, 1), STRICT);
    /*
     * Interpolate the (ΔX, ΔY, ΔZ) at a point.
     * Directions (signs) are reversed compared to NTG_88 document.
     */
    final double[] expected = {
         168.253,       // ΔX: Toward prime meridian
          58.609,       // ΔY: Toward 90° east
        -320.170        // ΔZ: Toward north pole
    };
    final double[] point  = samplePoint(3);
    final double[] vector = grid.interpolateAt(point[0], point[1]);
    assertArrayEquals("(ΔX, ΔY, ΔZ)", expected, vector, 0.0005);
}
 
Example #27
Source File: NADCONTest.java    From sis with Apache License 2.0 4 votes vote down vote up
/**
 * Writes a sub-grid of the given grid in pseudo-NADCON ASCII format.
 * This method is used only for creating the test file, and the output is not fully NADCON compliant.
 * We take this opportunity for testing the parser capability to be lenient.
 *
 * <p>This method has been executed once for creating the {@code "conus-extract.laa"} and
 * {@code "conus-extract.loa"} test files and should not be needed anymore, but we keep it
 * around in case we have new test files to generate. The parameter used for creating the
 * test file are:</p>
 *
 * <ul>
 *   <li>{@code gridX} = 125</li>
 *   <li>{@code gridY} =  70</li>
 *   <li>{@code nx}    =   8</li>
 *   <li>{@code ny}    =  10</li>
 * </ul>
 *
 * This ensure that the grid indices (129.83277, 76.89632) is included in the test file.
 * Those grid indices is the location of the (39°13′26.71″N, 98°32′31.75″W) test point to interpolate.
 *
 * @param  grid   the full grid from which to extract a few values.
 * @param  file   where to write the test file.
 * @param  dim    0 for writing longitudes, or 1 for writing latitudes.
 * @param  gridX  index along the longitude axis of the first cell to write.
 * @param  gridY  index along the latitude axis of the first cell to write.
 * @param  nx     number of cells to write along the longitude axis.
 * @param  ny     number of cells to write along the latitude axis.
 * @throws TransformException if an error occurred while computing the envelope.
 * @throws IOException if an error occurred while writing the test file.
 */
public static void writeSubGrid(final DatumShiftGridFile<Angle,Angle> grid, final Path file, final int dim,
        final int gridX, final int gridY, final int nx, final int ny) throws IOException, TransformException
{
    Envelope envelope = new Envelope2D(null, gridX, gridY, nx - 1, ny - 1);
    envelope = Envelopes.transform(grid.getCoordinateToGrid().inverse(), envelope);
    try (BufferedWriter out = Files.newBufferedWriter(file)) {
        out.write("NADCON EXTRACTED REGION\n");
        out.write(String.format(Locale.US, "%4d %3d %3d %11.5f %11.5f %11.5f %11.5f %11.5f\n", nx, ny, 1,
                envelope.getMinimum(0), envelope.getSpan(0) / (nx - 1),
                envelope.getMinimum(1), envelope.getSpan(1) / (ny - 1),
                0.0));
        for (int y=0; y<ny; y++) {
            for (int x=0; x<nx; x++) {
                out.write(String.format(Locale.US, " %11.6f", grid.getCellValue(dim, gridX + x, gridY + y)));
            }
            out.write('\n');
        }
    }
}
 
Example #28
Source File: NTv2.java    From sis with Apache License 2.0 4 votes vote down vote up
/**
 * Reads all grids and returns the root grid. After reading all grids, this method rearrange
 * them in a child-parent relationship. The result is a tree with a single root containing
 * sub-grids (if any) as children.
 */
final DatumShiftGridFile<Angle,Angle> readAllGrids() throws IOException, FactoryException, NoninvertibleTransformException {
    final Map<String,      DatumShiftGridFile<Angle,Angle>>  grids    = new HashMap<>(Containers.hashMapCapacity(numGrids));
    final Map<String, List<DatumShiftGridFile<Angle,Angle>>> children = new LinkedHashMap<>();   // Should have few entries.
    while (grids.size() < numGrids) {
        readGrid(grids, children);
    }
    /*
     * Assign the sub-grids to their parent only after we finished to read all grids.
     * Doing this work last is more robust to cases where grids are in random order.
     *
     * Notes: if the parent-child graph contains cycles (deeper than a child declaring itself as its parent),
     *        the grids in cycles will be lost. This is because we need a grid without parent for getting the
     *        graph added in the roots list. There is currently no mechanism for detecting those problems.
     */
    final List<DatumShiftGridFile<Angle,Angle>> roots = new ArrayList<>();
    for (final Map.Entry<String, List<DatumShiftGridFile<Angle,Angle>>> entry : children.entrySet()) {
        final DatumShiftGridFile<Angle,Angle> parent = grids.get(entry.getKey());
        final List<DatumShiftGridFile<Angle,Angle>> subgrids = entry.getValue();
        if (parent != null) {
            /*
             * Verify that the children does not declare themselves as their parent.
             * It may happen if SUB_GRID and PARENT have the same value, typically a
             * null or empty value if those records were actually unspecified.
             */
            for (int i=subgrids.size(); --i >= 0;) {
                if (subgrids.get(i) == parent) {      // Want identity check, no need for equals(Object).
                    subgrids.remove(i);
                    roots.add(parent);
                    break;
                }
            }
            if (!subgrids.isEmpty()) {
                parent.setSubGrids(subgrids);
            }
        } else {
            roots.addAll(subgrids);
        }
    }
    switch (roots.size()) {
        case 0:  throw new FactoryException(Errors.format(Errors.Keys.CanNotRead_1, file));
        case 1:  return roots.get(0);
        default: return DatumShiftGridGroup.create(file, roots);
    }
}
 
Example #29
Source File: NADCON.java    From sis with Apache License 2.0 4 votes vote down vote up
/**
 * Returns the grid of the given name. This method returns the cached instance if it still exists,
 * or load the grid otherwise.
 *
 * @param latitudeShifts   name of the grid file for latitude shifts.
 * @param longitudeShifts  name of the grid file for longitude shifts.
 */
@SuppressWarnings("null")
static DatumShiftGridFile<Angle,Angle> getOrLoad(final Path latitudeShifts, final Path longitudeShifts)
        throws FactoryException
{
    final Path rlat = DataDirectory.DATUM_CHANGES.resolve(latitudeShifts).toAbsolutePath();
    final Path rlon = DataDirectory.DATUM_CHANGES.resolve(longitudeShifts).toAbsolutePath();
    final Object key = new AbstractMap.SimpleImmutableEntry<>(rlat, rlon);
    DatumShiftGridFile<?,?> grid = DatumShiftGridFile.CACHE.peek(key);
    if (grid == null) {
        final Cache.Handler<DatumShiftGridFile<?,?>> handler = DatumShiftGridFile.CACHE.lock(key);
        try {
            grid = handler.peek();
            if (grid == null) {
                final Loader loader;
                Path file = latitudeShifts;
                try {
                    // Note: buffer size must be divisible by the size of 'float' data type.
                    final ByteBuffer buffer = ByteBuffer.allocate(4096).order(ByteOrder.LITTLE_ENDIAN);
                    final FloatBuffer fb = buffer.asFloatBuffer();
                    try (ReadableByteChannel in = Files.newByteChannel(rlat)) {
                        DatumShiftGridLoader.startLoading(NADCON.class, CharSequences.commonPrefix(
                                latitudeShifts.toString(), longitudeShifts.toString()).toString() + '…');
                        loader = new Loader(in, buffer, file);
                        loader.readGrid(fb, null, longitudeShifts);
                    }
                    buffer.clear();
                    file = longitudeShifts;
                    try (ReadableByteChannel in = Files.newByteChannel(rlon)) {
                        new Loader(in, buffer, file).readGrid(fb, loader, null);
                    }
                } catch (IOException | NoninvertibleTransformException | RuntimeException e) {
                    throw DatumShiftGridLoader.canNotLoad("NADCON", file, e);
                }
                grid = DatumShiftGridCompressed.compress(loader.grid, null, loader.grid.accuracy);
                grid = grid.useSharedData();
            }
        } finally {
            handler.putAndUnlock(grid);
        }
    }
    return grid.castTo(Angle.class, Angle.class);
}
 
Example #30
Source File: NTv2Test.java    From sis with Apache License 2.0 4 votes vote down vote up
/**
 * Tests using a file containing many grids. This tests depends on the {@value #MULTIGRID_TEST_FILE}
 * to be present in the {@code $SIS_DATA/DatumChanges} directory. This test is executed only if the
 * {@link #RUN_EXTENSIVE_TESTS} flag is set.
 *
 * @throws FactoryException if an error occurred while loading or computing the grid.
 * @throws TransformException if an error occurred while computing the envelope or testing the point.
 */
@Test
public void testMultiGrids() throws FactoryException, TransformException {
    assumeTrue(RUN_EXTENSIVE_TESTS);
    final Path file = DataDirectory.DATUM_CHANGES.resolve(Paths.get(MULTIGRID_TEST_FILE));
    assumeTrue(Files.exists(file));
    final DatumShiftGridFile<Angle,Angle> grid = NTv2.getOrLoad(NTv2.class, file, 2);
    assertInstanceOf("Should contain many grids.", DatumShiftGridGroup.class, grid);
    assertEquals("coordinateUnit",  Units.ARC_SECOND, grid.getCoordinateUnit());
    assertEquals("translationUnit", Units.ARC_SECOND, grid.getTranslationUnit());
    assertEquals("translationDimensions", 2,          grid.getTranslationDimensions());
    assertTrue  ("isCellValueRatio",                  grid.isCellValueRatio());
    /*
     * Area of use declared in EPSG database for coordinate operation EPSG::1693:
     *
     *     40.04°N  to  83.17°N    and    141.01°W  to  47.74°W.
     *
     * In the assertions below, the `cellSize` value has been verified in the NTv2
     * file header but the envelope bounds have been determined empirically.
     */
    final double cellSize = 300;                                    // Number of arc-seconds in a cell.
    final Envelope envelope = grid.getDomainOfValidity();
    assertEquals("xmin", -142.25 * DEGREES_TO_SECONDS, envelope.getMinimum(0), 1E-10);
    assertEquals("xmax",  -44.00 * DEGREES_TO_SECONDS, envelope.getMaximum(0), 1E-10);
    assertEquals("ymin",   40.00 * DEGREES_TO_SECONDS, envelope.getMinimum(1), 1E-10);
    assertEquals("ymax",   84.00 * DEGREES_TO_SECONDS, envelope.getMaximum(1), 1E-10);
    /*
     * Test a point. This point is located on the 3th grid in the NTv2 file.
     * Consequently if the NTv2 implementation just pickups the first grid,
     * then this test would fail with an error around 100 metres.
     */
    final double[] position = {-134.998106062 * DEGREES_TO_SECONDS, 61.000285047 * DEGREES_TO_SECONDS};
    final double[] expected = {-135.0         * DEGREES_TO_SECONDS, 61.0         * DEGREES_TO_SECONDS};
    final double[] indices  = new double[position.length];
    grid.getCoordinateToGrid().transform(position, 0, indices, 0, 1);
    final int gridX = Math.toIntExact(Math.round(indices[0]));
    final int gridY = Math.toIntExact(Math.round(indices[1]));
    assertEquals("gridX", 1092, gridX);                                 // Value determined empirically.
    assertEquals("gridY",  252, gridY);
    /*
     * First check the value computed by `getCellValue(…)`. This method is only a fallback and
     * should not be invoked in normal usage, so a direct invocation is the only way to test it.
     */
    final double[] result = new double[] {
        position[0] - grid.getCellValue(0, gridX, gridY) * cellSize,    // Positive translation is toward west.
        position[1] + grid.getCellValue(1, gridX, gridY) * cellSize
    };
    assertArrayEquals("getCellValue", expected, result, 0.001);
    /*
     * Check `interpolateInCell(…)`, which is the method invoked by `InterpolatedTransform`
     * when `SpecializableTransform` has not been able to find the most appropriate grid.
     */
    grid.interpolateInCell(indices[0], indices[1], result);
    result[0] = position[0] - result[0] * cellSize;                     // Positive translation is toward west.
    result[1] = position[1] + result[1] * cellSize;
    assertArrayEquals("interpolateInCell", expected, result, Formulas.ANGULAR_TOLERANCE * DEGREES_TO_SECONDS);
    /*
     * Verify that the caching mechanism works for DatumShiftGridGroup too.
     */
    assertSame("Grid should be cached.", grid, NTv2.getOrLoad(NTv2.class, file, 2));
}