Interface IMapProjection
- All Known Implementing Classes:
EqualEarthProjection,LambertEqualAreaProjection,MercatorProjection,MollweideProjection,OrthographicProjection
Coordinate conventions
- All geographic coordinates are in radians.
- A geographic point is represented as a
Point2D.Doublewherex = λ(longitude) andy = φ(latitude). - Projected "world" coordinates are also
Point2D.Doublevalues in the projection's own XY plane (e.g. [-π, π]×[MIN_Y, MAX_Y] for Mercator, or a unit disk for Orthographic). TheIContaineris responsible for converting world coordinates to device pixels.
Implementing a new projection
- Add a constant to
EProjection. - Implement this interface (forward, inverse, visibility, bounds, outline, graticule drawing).
- Add a
casetoProjectionFactory.create(EProjection, MapTheme, Point2D.Double). - Add a
caseto recenter(Point) if the projection supports re-centering.
Graticule color
Implementations of drawLatitudeLine(java.awt.Graphics2D, edu.cnu.mdi.container.IContainer, double) and
drawLongitudeLine(java.awt.Graphics2D, edu.cnu.mdi.container.IContainer, double) must use
MapTheme.getGraticuleColor() rather than hardcoding a color.
Hardcoding defeats theme switching (light / dark / blue).
-
Method Summary
Modifier and TypeMethodDescriptioncreateClipShape(IContainer container) Creates a clipShapein device coordinates that matches the projection's valid domain.default booleancrossesSeam(double lon1, double lon2) Tests whether the segment between two longitudes crosses the projection seam (the anti-meridian relative to the central longitude).voiddrawLatitudeLine(Graphics2D g2, IContainer container, double latitude) Draws a line of constant latitude (a parallel) at the given latitude.voiddrawLongitudeLine(Graphics2D g2, IContainer container, double longitude) Draws a line of constant longitude (a meridian) at the given longitude.voiddrawMapOutline(Graphics2D g2, IContainer container) Draws the outer boundary of the projection domain.default voidfillOcean(Graphics2D g2, IContainer container) Fills the projection domain with the ocean color from the currentMapTheme.Returns theEProjectionenum constant that identifies this implementation, if this projection is one of MDI's built-in projections.getTheme()Returns theMapThemecurrently used by this projection for drawing outlines and graticule lines.Returns the bounding rectangle of the projection-space domain in world coordinates.default booleanReports whether the projection's horizontal domain represents a complete, periodically wrapped 360-degree longitude range.booleanTests whether a projection-space point lies within the valid domain of this projection.booleanisPointVisible(Point2D.Double latLon) Tests whether a geographic location is visible in this projection.voidlatLonFromXY(Point2D.Double latLon, Point2D.Double xy) Inverse projection: projection-space (x, y) → geographic (λ, φ).voidlatLonToXY(Point2D.Double latLon, Point2D.Double xy) Forward projection: geographic (λ, φ) → projection-space (x, y).default Stringname()Returns a human-readable name for this projection, suitable for UI labels.default booleanrecenterOn(Point2D.Double latLon) Recenters this projection on the supplied geographic location.voidSets theMapThemeused by this projection for all subsequent drawing operations.default booleanTests whether this projection can update its own centering parameters in response to a map recenter request.default doublewrapLatitude(double lat) Wraps a latitude value to the range [-π/2, π/2].default doublewrapLongitude(double lon) Wraps a longitude value to the canonical half-open range (-π, π].
-
Method Details
-
latLonToXY
Forward projection: geographic (λ, φ) → projection-space (x, y).Implementations should clamp the latitude to their valid range before computing to avoid
NaNorInfinityresults at the poles.For hemispherical projections (e.g. orthographic) a point on the far side of the globe should set
xyto(Double.NaN, Double.NaN)rather than throwing, because callers testisPointVisibleseparately.- Parameters:
latLon- input geographic point in radians (x=λ, y=φ); must not benullxy- output projection-space point; must not benull
-
latLonFromXY
Inverse projection: projection-space (x, y) → geographic (λ, φ).If the input point lies outside the valid projection domain, implementations should set
latLonto(Double.NaN, Double.NaN)rather than throwing.- Parameters:
latLon- output geographic point in radians (x=λ, y=φ); must not benullxy- input projection-space point; must not benull
-
isPointVisible
Tests whether a geographic location is visible in this projection.Global projections (Mercator, Mollweide, Lambert) generally return
truefor any point within their latitude range. Hemispherical projections (Orthographic) returntrueonly for points on the visible hemisphere.- Parameters:
latLon- geographic point in radians (x=λ, y=φ)- Returns:
trueif the point is visible;falseotherwise
-
isPointOnMap
Tests whether a projection-space point lies within the valid domain of this projection.This is used after
latLonToXY(java.awt.geom.Point2D.Double, java.awt.geom.Point2D.Double)to guard against rendering points that fall slightly outside the projection boundary due to floating-point rounding.- Parameters:
xy- projection-space point- Returns:
trueif the point is on (or inside) the map;falseotherwise
-
drawMapOutline
Draws the outer boundary of the projection domain.Typical implementations build a
Path2Din world coordinates, transform each vertex to screen space viacontainer.worldToLocal, then stroke the path using colors and widths from the currentMapTheme.- Parameters:
g2- graphics context to draw intocontainer- container providing the world-to-local transform
-
drawLatitudeLine
Draws a line of constant latitude (a parallel) at the given latitude.Implementations should approximate the curve by sampling at a sufficient number of longitude values, projecting each sample, and connecting the resulting screen points with a polyline. The line color must be
MapTheme.getGraticuleColor()so that theme switching takes full effect.- Parameters:
g2- graphics contextcontainer- container providing the world-to-local transformlatitude- latitude φ in radians, typically in [-π/2, π/2]
-
drawLongitudeLine
Draws a line of constant longitude (a meridian) at the given longitude.Implementations should approximate the curve by sampling at a sufficient number of latitude values, projecting each sample, and connecting the resulting screen points with a polyline. The line color must be
MapTheme.getGraticuleColor()so that theme switching takes full effect.- Parameters:
g2- graphics contextcontainer- container providing the world-to-local transformlongitude- longitude λ in radians, typically in [-π, π]
-
createClipShape
Creates a clipShapein device coordinates that matches the projection's valid domain.This shape is used to:
- Clip land/ocean rendering to the map region.
- Fill the ocean background via
fillOcean(java.awt.Graphics2D, edu.cnu.mdi.container.IContainer).
- Parameters:
container- container providing the world-to-local transform- Returns:
- a device-space
Shape, ornullif no clip is defined for this projection
-
getProjection
EProjection getProjection()Returns theEProjectionenum constant that identifies this implementation, if this projection is one of MDI's built-in projections.Application-supplied projections are allowed to return
null. This permits an application to provide a projection without modifyingEProjection,ProjectionFactory, or other MDI built-in projection registries.- Returns:
- the built-in projection type, or
nullfor a custom application-supplied projection
-
name
Returns a human-readable name for this projection, suitable for UI labels.The default implementation delegates to
EProjection.getName()whengetProjection()returns a non-null value, and falls back to the simple class name otherwise.- Returns:
- projection display name; never
null
-
getXYBounds
Rectangle2D.Double getXYBounds()Returns the bounding rectangle of the projection-space domain in world coordinates.This rectangle is used by
IContainerimplementations to build the initial world-to-screen transform. The returned rectangle should tightly enclose the entire valid projected domain (e.g. [-π, π] × [MIN_Y, MAX_Y] for Mercator).- Returns:
- bounding rectangle in projection space; never
null
-
getTheme
MapTheme getTheme()Returns theMapThemecurrently used by this projection for drawing outlines and graticule lines.Implementations must never return
nullonce the theme has been set.- Returns:
- the active map theme
-
setTheme
Sets theMapThemeused by this projection for all subsequent drawing operations.- Parameters:
theme- the new theme; must not benull- Throws:
IllegalArgumentException- ifthemeisnull
-
fillOcean
Fills the projection domain with the ocean color from the currentMapTheme.This default implementation delegates to
createClipShape(edu.cnu.mdi.container.IContainer)to obtain the fill boundary and then fills it withMapTheme.getOceanColor(). Implementations that need different ocean-fill behaviour may override this method.- Parameters:
g2- graphics contextcontainer- container providing the world-to-local transform
-
wrapLongitude
default double wrapLongitude(double lon) Wraps a longitude value to the canonical half-open range (-π, π].This is the standard normalization used throughout the mapping subsystem. Note the range is half-open: -π maps to π.
- Parameters:
lon- longitude in radians- Returns:
- equivalent longitude in (-π, π], or
Double.NaNwhenlonis not finite
-
wrapLatitude
default double wrapLatitude(double lat) Wraps a latitude value to the range [-π/2, π/2].This helper exists primarily for completeness; most projection code should clamp rather than wrap latitude because values outside the range represent the interior of the Earth, not a point on the opposite side of the globe.
- Parameters:
lat- latitude in radians (any value)- Returns:
- equivalent latitude in [-π/2, π/2]
-
crossesSeam
default boolean crossesSeam(double lon1, double lon2) Tests whether the segment between two longitudes crosses the projection seam (the anti-meridian relative to the central longitude).Global cylindrical projections such as
MercatorProjectionandMollweideProjectionoverride this method to detect wrap-around so that polygon edges that cross the seam can be split rather than drawn as a horizontal streak across the map.The default implementation returns
false, which is correct for hemispherical projections (OrthographicProjection,LambertEqualAreaProjection) where no seam split is needed.- Parameters:
lon1- first longitude in radianslon2- second longitude in radians- Returns:
trueif the segment crosses the seam;falseotherwise
-
isLongitudePeriodic
default boolean isLongitudePeriodic()Reports whether the projection's horizontal domain represents a complete, periodically wrapped 360-degree longitude range.Adaptive graticule rendering uses this distinction when the entire projected width is visible. Sampling the two horizontal edges of such a projection produces the same seam longitude and can otherwise make half the world appear to be outside the visible longitude extent.
- Returns:
truefor full-width periodic projections such as Mercator and Mollweide; otherwisefalse
-
supportsRecenter
default boolean supportsRecenter()Tests whether this projection can update its own centering parameters in response to a map recenter request.Built-in MDI projections may handle recentering in
MapContainerfor backward compatibility. Custom application projections should override this method andrecenterOn(Point2D.Double)if they support recentering.- Returns:
trueif this projection supports recentering itself
-
recenterOn
Recenters this projection on the supplied geographic location.The supplied point uses the standard MDI map convention:
x = longitude λ,y = latitude φ, both in radians. The default implementation does nothing and returnsfalse.- Parameters:
latLon- the requested new center in radians- Returns:
trueif the projection accepted and applied the new center;falseotherwise
-