Class ShapeFeatureRenderer

java.lang.Object
edu.cnu.mdi.mapping.shapefile.ShapeFeatureRenderer
All Implemented Interfaces:
IPickable

public class ShapeFeatureRenderer extends Object implements IPickable
Renders a list of ShapeFeature instances onto an IContainer using a supplied IMapProjection and ShapeFeatureStyle, and supports mouse-over hit testing via IPickable.

Geometry dispatch

Each feature is rendered according to its shape type:

  • Polygon — each ring is filled (if a fill color is set) and stroked (if a stroke color is set). The stroke sits on top of the fill. All rings are treated as filled; interior holes are not distinguished from outer shells.
  • Polyline — each part is drawn as an open stroked path. No fill is applied.
  • Point / MultiPoint — each point is drawn as a filled circle. An optional label from a configured DBF field is drawn beside the marker.

Pick cache

During each render(java.awt.Graphics2D, edu.cnu.mdi.container.IContainer) call this renderer builds a list of ShapeFeatureRenderer.PickCache records — one per feature with visible geometry — that pick(Point, IContainer) uses for hit testing without re-projecting coordinates. The cache is rebuilt on every render call so it always reflects the current projection state and zoom level. Calling pick before the first render returns null.

Hit-testing strategy by geometry type

  • Polygon — Path2D.contains(double, double) on each cached closed path.
  • Polyline — minimum perpendicular distance from the cursor to each cached line segment, threshold 4.0 pixels.
  • Point — Euclidean distance from the cursor to each cached screen coordinate, threshold 6.0 pixels.

Feedback text

On a hit, pick(java.awt.Point, edu.cnu.mdi.container.IContainer) assembles feedback from ShapeFeatureStyle.getFeedbackFields(). If that list is empty it falls back to ShapeFeatureStyle.getLabelField(). Multiple field values are rendered one per line as FIELD: value. The complete block uses the light-green feedback style. Fields absent from the feature are silently omitted. Returns null if no feedback configuration is present.

Seam splitting

Mercator polygon rings are unwrapped and clipped to the visible longitude/latitude domain before projection. This inserts exact vertices at both the longitude seam and the polar latitude limits, preventing path closure from drawing map-wide chords. Other seam-bearing geometries are split into path halves. All resulting paths participate in picking.

Graphics state

Color, stroke, font, and antialiasing hint are saved before rendering and fully restored on return.

Thread safety

Not thread-safe; all calls must be made on the Event Dispatch Thread.

  • Constructor Details

    • ShapeFeatureRenderer

      public ShapeFeatureRenderer(List<ShapeFeature> features, IMapProjection projection, ShapeFeatureStyle style)
      Creates a renderer for the given features using the supplied projection and style.
      Parameters:
      features - the features to render; must not be null
      projection - the map projection; must not be null
      style - the visual style; must not be null
  • Method Details

    • setStyle

      public void setStyle(ShapeFeatureStyle style)
      Replaces the current style. Takes effect on the next render call.
      Parameters:
      style - the new style; must not be null
    • getStyle

      public ShapeFeatureStyle getStyle()
      Returns the current style; never null.
    • getAvailablePropertyNames

      public List<String> getAvailablePropertyNames()
      Returns all DBF property names present in this renderer's features.

      Names retain their original spelling and DBF column order. A union is used so fields are still discovered when an unusual feature has a partial attribute map.

      Returns:
      immutable ordered property-name list; never null
    • setLabelFont

      public void setLabelFont(Font font)
      Sets the font used for on-map feature labels.
      Parameters:
      font - label font; if null the default small font is used
    • setProjection

      public void setProjection(IMapProjection projection)
      Updates the projection used for coordinate transforms and visibility tests. Must be called whenever the owning MapView2D switches projections so that this layer renders in the correct coordinate space.

      MapView2D setProjection(EProjection) calls this automatically for every layer registered via MapView2D addLayer.

      Parameters:
      projection - the new projection; must not be null
    • render

      public void render(Graphics2D g2, IContainer container)
      Renders all features in this layer and rebuilds the pick cache.

      The pick cache is cleared at the start of each call and repopulated as features are rendered, so pick(java.awt.Point, edu.cnu.mdi.container.IContainer) always reflects the most recent projection state and zoom level.

      Parameters:
      g2 - graphics context to draw into; must not be null
      container - container providing the world-to-local transform; must not be null
    • pick

      public String pick(Point mouseLocal, IContainer container)
      Returns a human-readable description of the feature under the given mouse position, or null if no feature is hit.

      The description is suitable for both the feedback pane and hover popup (e.g. "Lake Superior" or "Amazon River length: 6400 km").

      Returns null if the pick cache is empty (no render has occurred yet) or no feature is within the hit threshold. The feedback string is assembled from ShapeFeatureStyle.getFeedbackFields(), falling back to ShapeFeatureStyle.getLabelField() if no feedback fields are configured.

      Specified by:
      pick in interface IPickable
      Parameters:
      mouseLocal - the cursor position in the container's local (screen) coordinate space; must not be null
      container - the container providing coordinate transforms; must not be null
      Returns:
      a non-empty description string, or null if no feature was hit
    • getShapeType

      public int getShapeType()
      Returns the geometry type represented by this renderer.

      A shapefile normally contains one geometry type, so the first feature determines which style controls are relevant.

      Returns:
      one of the shapefile TYPE_* constants, or ShapefileGeometryReader.TYPE_NULL when empty