Interface IMapProjection

All Known Implementing Classes:
EqualEarthProjection, LambertEqualAreaProjection, MercatorProjection, MollweideProjection, OrthographicProjection

public interface IMapProjection
Contract for the map projections used within the MDI framework.

Coordinate conventions

  • All geographic coordinates are in radians.
  • A geographic point is represented as a Point2D.Double where x = λ (longitude) and y = φ (latitude).
  • Projected "world" coordinates are also Point2D.Double values in the projection's own XY plane (e.g. [-π, π]×[MIN_Y, MAX_Y] for Mercator, or a unit disk for Orthographic). The IContainer is responsible for converting world coordinates to device pixels.

Implementing a new projection

  1. Add a constant to EProjection.
  2. Implement this interface (forward, inverse, visibility, bounds, outline, graticule drawing).
  3. Add a case to ProjectionFactory.create(EProjection, MapTheme, Point2D.Double).
  4. Add a case to 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 Type
    Method
    Description
    Creates a clip Shape in device coordinates that matches the projection's valid domain.
    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).
    void
    drawLatitudeLine(Graphics2D g2, IContainer container, double latitude)
    Draws a line of constant latitude (a parallel) at the given latitude.
    void
    drawLongitudeLine(Graphics2D g2, IContainer container, double longitude)
    Draws a line of constant longitude (a meridian) at the given longitude.
    void
    Draws the outer boundary of the projection domain.
    default void
    Fills the projection domain with the ocean color from the current MapTheme.
    Returns the EProjection enum constant that identifies this implementation, if this projection is one of MDI's built-in projections.
    Returns the MapTheme currently used by this projection for drawing outlines and graticule lines.
    Returns the bounding rectangle of the projection-space domain in world coordinates.
    default boolean
    Reports whether the projection's horizontal domain represents a complete, periodically wrapped 360-degree longitude range.
    boolean
    Tests whether a projection-space point lies within the valid domain of this projection.
    boolean
    Tests whether a geographic location is visible in this projection.
    void
    Inverse projection: projection-space (x, y) → geographic (λ, φ).
    void
    Forward projection: geographic (λ, φ) → projection-space (x, y).
    default String
    Returns a human-readable name for this projection, suitable for UI labels.
    default boolean
    Recenters this projection on the supplied geographic location.
    void
    Sets the MapTheme used by this projection for all subsequent drawing operations.
    default boolean
    Tests whether this projection can update its own centering parameters in response to a map recenter request.
    default double
    wrapLatitude(double lat)
    Wraps a latitude value to the range [-π/2, π/2].
    default double
    wrapLongitude(double lon)
    Wraps a longitude value to the canonical half-open range (-π, π].
  • Method Details

    • latLonToXY

      void latLonToXY(Point2D.Double latLon, Point2D.Double xy)
      Forward projection: geographic (λ, φ) → projection-space (x, y).

      Implementations should clamp the latitude to their valid range before computing to avoid NaN or Infinity results at the poles.

      For hemispherical projections (e.g. orthographic) a point on the far side of the globe should set xy to (Double.NaN, Double.NaN) rather than throwing, because callers test isPointVisible separately.

      Parameters:
      latLon - input geographic point in radians (x=λ, y=φ); must not be null
      xy - output projection-space point; must not be null
    • latLonFromXY

      void latLonFromXY(Point2D.Double latLon, Point2D.Double xy)
      Inverse projection: projection-space (x, y) → geographic (λ, φ).

      If the input point lies outside the valid projection domain, implementations should set latLon to (Double.NaN, Double.NaN) rather than throwing.

      Parameters:
      latLon - output geographic point in radians (x=λ, y=φ); must not be null
      xy - input projection-space point; must not be null
    • isPointVisible

      boolean isPointVisible(Point2D.Double latLon)
      Tests whether a geographic location is visible in this projection.

      Global projections (Mercator, Mollweide, Lambert) generally return true for any point within their latitude range. Hemispherical projections (Orthographic) return true only for points on the visible hemisphere.

      Parameters:
      latLon - geographic point in radians (x=λ, y=φ)
      Returns:
      true if the point is visible; false otherwise
    • isPointOnMap

      boolean isPointOnMap(Point2D.Double xy)
      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:
      true if the point is on (or inside) the map; false otherwise
    • drawMapOutline

      void drawMapOutline(Graphics2D g2, IContainer container)
      Draws the outer boundary of the projection domain.

      Typical implementations build a Path2D in world coordinates, transform each vertex to screen space via container.worldToLocal, then stroke the path using colors and widths from the current MapTheme.

      Parameters:
      g2 - graphics context to draw into
      container - container providing the world-to-local transform
    • drawLatitudeLine

      void drawLatitudeLine(Graphics2D g2, IContainer container, double latitude)
      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 context
      container - container providing the world-to-local transform
      latitude - latitude φ in radians, typically in [-π/2, π/2]
    • drawLongitudeLine

      void drawLongitudeLine(Graphics2D g2, IContainer container, double longitude)
      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 context
      container - container providing the world-to-local transform
      longitude - longitude λ in radians, typically in [-π, π]
    • createClipShape

      Shape createClipShape(IContainer container)
      Creates a clip Shape in device coordinates that matches the projection's valid domain.

      This shape is used to:

      Parameters:
      container - container providing the world-to-local transform
      Returns:
      a device-space Shape, or null if no clip is defined for this projection
    • getProjection

      EProjection getProjection()
      Returns the EProjection enum 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 modifying EProjection, ProjectionFactory, or other MDI built-in projection registries.

      Returns:
      the built-in projection type, or null for a custom application-supplied projection
    • name

      default String name()
      Returns a human-readable name for this projection, suitable for UI labels.

      The default implementation delegates to EProjection.getName() when getProjection() 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 IContainer implementations 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 the MapTheme currently used by this projection for drawing outlines and graticule lines.

      Implementations must never return null once the theme has been set.

      Returns:
      the active map theme
    • setTheme

      void setTheme(MapTheme theme)
      Sets the MapTheme used by this projection for all subsequent drawing operations.
      Parameters:
      theme - the new theme; must not be null
      Throws:
      IllegalArgumentException - if theme is null
    • fillOcean

      default void fillOcean(Graphics2D g2, IContainer container)
      Fills the projection domain with the ocean color from the current MapTheme.

      This default implementation delegates to createClipShape(edu.cnu.mdi.container.IContainer) to obtain the fill boundary and then fills it with MapTheme.getOceanColor(). Implementations that need different ocean-fill behaviour may override this method.

      Parameters:
      g2 - graphics context
      container - 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.NaN when lon is 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 MercatorProjection and MollweideProjection override 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 radians
      lon2 - second longitude in radians
      Returns:
      true if the segment crosses the seam; false otherwise
    • 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:
      true for full-width periodic projections such as Mercator and Mollweide; otherwise false
    • 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 MapContainer for backward compatibility. Custom application projections should override this method and recenterOn(Point2D.Double) if they support recentering.

      Returns:
      true if this projection supports recentering itself
    • recenterOn

      default boolean recenterOn(Point2D.Double latLon)
      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 returns false.

      Parameters:
      latLon - the requested new center in radians
      Returns:
      true if the projection accepted and applied the new center; false otherwise