001/* 002 * GeoAPI - Java interfaces for OGC/ISO standards 003 * Copyright © 2003-2023 Open Geospatial Consortium, Inc. 004 * http://www.geoapi.org 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.opengis.referencing.datum; 019 020import java.util.Map; 021import java.util.OptionalDouble; 022import javax.measure.Unit; 023import javax.measure.quantity.Length; 024import org.opengis.referencing.IdentifiedObject; 025import org.opengis.annotation.UML; 026 027import static org.opengis.annotation.Obligation.*; 028import static org.opengis.annotation.Specification.*; 029 030 031/** 032 * Geometric figure that can be used to describe the approximate shape of a planet. 033 * For the Earth the ellipsoid is bi-axial with rotation about the polar axis. 034 * For other planet, the ellipsoid may be tri-axial. 035 * An ellipsoid requires two or three defining parameters: 036 * 037 * <ul> 038 * <li>{@linkplain #getSemiMajorAxis() Semi-major axis}.</li> 039 * <li>One of the following: 040 * <ul> 041 * <li>{@linkplain #getSemiMinorAxis() semi-minor axis}, or</li> 042 * <li>{@linkplain #getInverseFlattening() inverse flattening}.</li> 043 * </ul> 044 * </li> 045 * <li>Optionally a semi-median axis (for planetary applications).</li> 046 * </ul> 047 * 048 * For some applications, for example small-scale mapping in atlases, a spherical approximation 049 * of the geoid's surface is used, requiring only the radius of the sphere to be specified. 050 * 051 * @departure constraint 052 * ISO 19111 defines the union named {@code secondDefiningParameter} 053 * as being either {@code semiMinorAxis} or {@code inverseFlattening}. 054 * The {@code union} construct (defined in some languages like C/C++) does not exist in Java. 055 * GeoAPI changed the interface to require both ellipsoidal parameters (in addition to the {@code semiMajorAxis} 056 * parameter which is mandatory in any case), as was done in <a href="http://www.opengeospatial.org/standards/ct">OGC 01-009</a>. 057 * However, implementers could readily permit users to only provide one of the two parameters 058 * by creating a class which calculates the second parameter from the first. 059 * For precision, GeoAPI imports the {@code isIvfDefinitive} attribute from OGC 01-009 060 * to enable the user to establish which of the two parameters was used to define the instance. 061 * 062 * @author OGC Topic 2 (for abstract model and documentation) 063 * @author Martin Desruisseaux (IRD, Geomatys) 064 * @version 3.1 065 * @since 1.0 066 * 067 * @see DatumAuthorityFactory#createEllipsoid(String) 068 * @see DatumFactory#createEllipsoid(Map, double, double, Unit) 069 * @see DatumFactory#createFlattenedSphere(Map, double, double, Unit) 070 */ 071@UML(identifier="Ellipsoid", specification=ISO_19111) 072public interface Ellipsoid extends IdentifiedObject { 073 /** 074 * Returns the linear unit of the semi-major, semi-minor and semi-median axis values. 075 * 076 * @return the axis linear unit. 077 */ 078 @UML(identifier="getAxisUnit", specification=OGC_01009) 079 Unit<Length> getAxisUnit(); 080 081 /** 082 * Length of the semi-major axis of the ellipsoid. 083 * This is the equatorial radius in {@linkplain #getAxisUnit() axis linear unit}. 084 * 085 * @return length of semi-major axis. 086 * @unitof Length 087 */ 088 @UML(identifier="semiMajorAxis", obligation=MANDATORY, specification=ISO_19111) 089 double getSemiMajorAxis(); 090 091 /** 092 * Length of the semi-median axis of a triaxial ellipsoid. 093 * This parameter is not required for a biaxial ellipsoid. 094 * The default implementation returns an empty value. 095 * 096 * @return length of the semi-median axis of a triaxial ellipsoid. 097 * 098 * @since 3.1 099 */ 100 @UML(identifier="semiMedianAxis", obligation=OPTIONAL, specification=ISO_19111) 101 default OptionalDouble getSemiMedianAxis() { 102 return OptionalDouble.empty(); 103 } 104 105 /** 106 * Length of the semi-minor axis of the ellipsoid. 107 * This is the polar radius in {@linkplain #getAxisUnit() axis linear unit}. 108 * 109 * @return length of semi-minor axis. 110 * @unitof Length 111 */ 112 @UML(identifier="secondDefiningParameter.semiMinorAxis", obligation=CONDITIONAL, specification=ISO_19111) 113 double getSemiMinorAxis(); 114 115 /** 116 * Returns the value of the inverse of the flattening constant. 117 * The inverse flattening is related to the equatorial/polar radius by the formula 118 * 119 * <var>ivf</var> = <var>r</var><sub>e</sub>/(<var>r</var><sub>e</sub>-<var>r</var><sub>p</sub>). 120 * 121 * For perfect spheres (i.e. if {@link #isSphere()} returns {@code true}), 122 * the {@link Double#POSITIVE_INFINITY} value is used. 123 * 124 * @return the inverse flattening value. 125 * @unitof Scale 126 */ 127 @UML(identifier="secondDefiningParameter.inverseFlattening", obligation=CONDITIONAL, specification=ISO_19111) 128 double getInverseFlattening(); 129 130 /** 131 * Indicates if the inverse flattening (<abbr>IVF</abbr>) is definitive for this ellipsoid. 132 * Some ellipsoids use the <abbr>IVF</abbr> as the defining value, and calculate the polar 133 * radius whenever asked. Other ellipsoids use the polar radius to calculate the <abbr>IVF</abbr> 134 * whenever asked. This distinction can be important to avoid floating-point rounding errors. 135 * 136 * @return {@code true} if the {@linkplain #getInverseFlattening() inverse flattening} is definitive, 137 * or {@code false} if the {@linkplain #getSemiMinorAxis() polar radius} is definitive. 138 */ 139 @UML(identifier="CS_Ellipsoid.isIvfDefinitive", obligation=MANDATORY, specification=OGC_01009) 140 boolean isIvfDefinitive(); 141 142 /** 143 * {@code true} if the ellipsoid is degenerate and is actually a sphere. 144 * The sphere is completely defined by the {@linkplain #getSemiMajorAxis() semi-major axis}, 145 * which is the radius of the sphere. 146 * 147 * @return {@code true} if the ellipsoid is degenerate and is actually a sphere. 148 */ 149 @UML(identifier="secondDefiningParameter.isSphere", obligation=CONDITIONAL, specification=ISO_19111) 150 default boolean isSphere() { 151 return getSemiMedianAxis().isEmpty() && (isIvfDefinitive() 152 ? Double.isInfinite(getInverseFlattening()) 153 : getSemiMinorAxis() == getSemiMajorAxis()); 154 } 155}