Class MapLineItem
- All Implemented Interfaces:
IFeedbackProvider,IDrawable,EventListener
Conceptual model
Unlike edu.cnu.mdi.item.LineItem, which stores a straight segment in
ordinary world (projection-space) coordinates, MapLineItem stores its
geometry in geographic coordinates:
_startLatLon— geographic start point in radians (x = longitude, y = latitude)_endLatLon— geographic end point in radians (x = longitude, y = latitude)
When drawn, the item is projected and sampled as a great-circle route through
MapGraphics, giving the familiar "airline route" appearance on a map.
Interaction model
- Creation — use the ordinary straight-line rubberband.
The tool converts its two screen endpoints to geographic coordinates via
MapContainer.localToLatLon(java.awt.Point, java.awt.geom.Point2D.Double)and constructs aMapLineItem. - Drag — moves both geographic endpoints by the great-circle displacement implied by the mouse movement, preserving great-circle length and initial bearing exactly.
- Resize — replaces the selected endpoint with the current geographic cursor location.
- Rotate — rotates both endpoints around the geodesic midpoint by the screen-space angle dragged, preserving great-circle length from the midpoint to each endpoint. See Rotation semantics below.
Focus and selection handles
The item focus is the exact geodesic midpoint of the arc (computed via
MapGraphics.greatCircleEndPoint(java.awt.geom.Point2D.Double, double, double) at half the arc length). The two
selection handles are the projected screen positions of the geographic
endpoints.
Rotation semantics
Rotation is well-defined and physically meaningful for a great-circle line.
The pivot is the geodesic midpoint (the item focus). The angular delta is
the screen-space three-point angle dragged by the user (identical to how
the base PathBasedItem handles rotation). The two half-lengths from
the midpoint to each endpoint are preserved; only the bearings change.
Because a great-circle has two distinct initial bearings (from start→midpoint
and from end→midpoint), both must be rotated independently using
MapGraphics.greatCircleAzimuth(java.awt.geom.Point2D.Double, java.awt.geom.Point2D.Double) and MapGraphics.greatCircleEndPoint(java.awt.geom.Point2D.Double, double, double).
This keeps the arc symmetric around its pivot for any rotation angle.
The AItem._azimuth field inherited from AItem is used as the
cumulative screen-space rotation angle (in degrees) for display purposes
(e.g. the rotation handle position). The geographic geometry is the
authoritative state; _azimuth is purely a display aid that accumulates
across multiple rotate gestures.
Geometry and caching
The projected route is cached as a MapGraphics.ProjectedMapShape after drawing.
That cached shape is used for hit testing and bounds. The cache is cleared
whenever the item is marked dirty.
Note on getWorldBounds()
The inherited AItem.getWorldBounds() contract requires a
projection-space bounding rectangle. For a great-circle arc this rectangle
is not computable without a projection reference, so this method returns
a simple longitude/latitude bounding box of the two endpoints.
This is conservative: it may miss the arc's apex if the arc bulges
significantly above or below the chord (e.g. a trans-polar route).
All visibility and hit-testing that matters uses the screen-space
getBounds(IContainer) path through the cached projected shape,
which is exact.
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected Point2D.DoubleGeographic end endpoint in radians (x = longitude, y = latitude).protected MapGraphics.ProjectedMapShapeCached projected route produced during the most recent draw or bounds query.protected Point2D.DoubleGeographic start endpoint in radians (x = longitude, y = latitude).Fields inherited from class edu.cnu.mdi.item.AItem
_connectable, _deletable, _dirty, _displayName, _doubleClickable, _draggable, _enabled, _focus, _FOCUSFILL, _lastDrawnPolygon, _layer, _line, _locked, _modification, _path, _popupMenu, _resizable, _resizePolicy, _rightClickable, _rotatable, _selectable, _selected, _style, _styleEditable, _visible, rotateIcon, RPSIZE, RPSIZE2, SPSIZE, SPSIZE2 -
Constructor Summary
ConstructorsConstructorDescriptionMapLineItem(Layer layer, Point2D.Double startLatLon, Point2D.Double endLatLon) Creates a map-native great-circle line item.MapLineItem(Layer layer, Point2D.Double startLatLon, Point2D.Double endLatLon, Object... keyVals) Creates a map-native great-circle line item with optional item property key/value pairs. -
Method Summary
Modifier and TypeMethodDescriptionbooleancontains(IContainer container, Point screenPoint) Tests whether the rendered route or its selection handles contain the given screen point.protected static Point2D.DoubleReturns a defensive copy of a geographic point.voiddrawItem(Graphics2D g2, IContainer container) Draws this item as a seam-aware great-circle route.protected voidensureProjectedShape(IContainer container) Ensures that_projectedShapeis populated, building it from the current geographic endpoints if necessary.getBounds(IContainer container) Returns the device-space bounds of the projected route.Returns a defensive copy of the geographic end endpoint.voidgetFeedbackStrings(IContainer container, Point pp, Point2D.Double wp, List<String> feedbackStrings) Provides mouse-over feedback showing the great-circle length and the geographic coordinates of both endpoints.getRotatePoint(IContainer container) Returns the rotation handle position in device coordinates.Point[]getSelectionPoints(IContainer container) Returns the two endpoint handle positions in device coordinates.Returns a defensive copy of the geographic start endpoint.Returns an approximate world-space bounding rectangle.protected Point2D.DoublelocalToLatLon(MapContainer mc, Point p) Converts a device-space point to a geographic longitude/latitude in radians.voidmodify()Continues an interactive modification.voidPrepares this item for removal, releasing geographic geometry references.protected PointprojectLatLon(MapContainer mc, Point2D.Double latLon) Projects a geographic point (x = longitude, y = latitudein radians) to a device-space pixel coordinate.voidsetDirty(boolean dirty) Marks the item dirty and clears the cached projected route.voidsetEndLatLon(Point2D.Double endLatLon) Replaces the geographic end endpoint and marks the item dirty.voidsetStartLatLon(Point2D.Double startLatLon) Replaces the geographic start endpoint and marks the item dirty.booleanshouldDraw(Graphics2D g2, IContainer container) Returnstrueif this item's projected pixel bounds intersect the visible component area.voidClassify and begin a drag, resize, or rotate modification.voidtranslateWorld(double dx, double dy) Translates the item by raw longitude and latitude offsets in radians.protected voidRecomputes the item focus as the exact geodesic midpoint of the arc.Methods inherited from class edu.cnu.mdi.mapping.item.AMapItem
getFocusPointMethods inherited from class edu.cnu.mdi.item.AItem
acceptModification, applyGeometryProperties, applyProperties, applyStyleProperties, createPopupMenu, doubleClicked, draw, drawSelections, enclosed, equals, focusFill, geometryChanged, getAzimuth, getContainer, getDisplayName, getFocus, getItemModification, getLastDrawnPolygon, getLayer, getLine, getPath, getPopupMenu, getResizePolicy, getStyle, getStyleSafe, getView, hashCode, inASelectRect, inRotatePoint, inSelectPoint, isConnectable, isDeletable, isDirty, isDoubleClickable, isDraggable, isEnabled, isLocked, isResizable, isRightClickable, isRotatable, isSelectable, isSelected, isStyleEditable, isTrackable, isVisible, modificationRejected, prepareForPopup, setAzimuth, setConnectable, setDeletable, setDisplayName, setDoubleClickable, setDraggable, setEnabled, setFillFocus, setFocus, setLocked, setModification, setResizable, setResizePolicy, setRightClickable, setRotatable, setSelectable, setSelected, setStyle, setStyleEditable, setVisible, stopModification, translateLocal
-
Field Details
-
_startLatLon
Geographic start endpoint in radians (x = longitude, y = latitude). -
_endLatLon
Geographic end endpoint in radians (x = longitude, y = latitude). -
_projectedShape
Cached projected route produced during the most recent draw or bounds query.Invalidated whenever the item is marked dirty via
setDirty(boolean). Rebuilt lazily byensureProjectedShape(edu.cnu.mdi.container.IContainer).
-
-
Constructor Details
-
MapLineItem
Creates a map-native great-circle line item.- Parameters:
layer- the layer this item lives on; must not benullstartLatLon- geographic start point in radians (x = longitude, y = latitude)endLatLon- geographic end point in radians (x = longitude, y = latitude)
-
MapLineItem
public MapLineItem(Layer layer, Point2D.Double startLatLon, Point2D.Double endLatLon, Object... keyVals) Creates a map-native great-circle line item with optional item property key/value pairs.- Parameters:
layer- the layer this item lives on; must not benullstartLatLon- geographic start point in radiansendLatLon- geographic end point in radianskeyVals- optionalPropertyUtilskey/value pairs
-
-
Method Details
-
getStartLatLon
Returns a defensive copy of the geographic start endpoint.- Returns:
- the start point in radians; never
nullafter construction
-
getEndLatLon
Returns a defensive copy of the geographic end endpoint.- Returns:
- the end point in radians; never
nullafter construction
-
setStartLatLon
Replaces the geographic start endpoint and marks the item dirty.- Parameters:
startLatLon- the new start point in radians
-
setEndLatLon
Replaces the geographic end endpoint and marks the item dirty.- Parameters:
endLatLon- the new end point in radians
-
drawItem
Draws this item as a seam-aware great-circle route.The rendered path is built through
MapGraphicsand cached in_projectedShapefor subsequent hit-testing and bounds queries.- Specified by:
drawItemin classAItem- Parameters:
g2- the graphics contextcontainer- the rendering container; must be aMapContainer
-
shouldDraw
Returnstrueif this item's projected pixel bounds intersect the visible component area.- Specified by:
shouldDrawin classAItem- Parameters:
g2- the graphics context (not used directly)container- the rendering container- Returns:
trueif the route is (at least partially) visible
-
contains
Tests whether the rendered route or its selection handles contain the given screen point.Handle hit-testing is checked first so endpoint handles remain easy to select. If no handle is hit, the test falls through to a pixel proximity check against the projected great-circle route.
-
getBounds
Returns the device-space bounds of the projected route. -
getSelectionPoints
Returns the two endpoint handle positions in device coordinates.Unlike a polyline, a map line exposes only its two geographic endpoints as resize handles, even though the rendered route between them is curved.
- Overrides:
getSelectionPointsin classAItem- Parameters:
container- the rendering container- Returns:
- the two endpoint handle positions, or
nullif either endpoint cannot be projected
-
getRotatePoint
Returns the rotation handle position in device coordinates.The handle is placed at the projected screen position of the geodesic midpoint (the item focus), which is the pivot around which rotation occurs. This gives the user a natural handle: grab it and drag in an arc around the line's midpoint.
- Overrides:
getRotatePointin classAItem- Parameters:
container- the rendering container- Returns:
- the screen position of the rotation handle, or
nullif the focus cannot be projected
-
modify
public void modify()Continues an interactive modification.Drag
Moves the start endpoint by the great-circle displacement between the drag start and current mouse positions (converted to geographic coordinates). The end endpoint is then recomputed from the new start using the preserved great-circle azimuth and length, keeping the arc's shape invariant across latitudes.
Resize
Replaces the selected endpoint (index 0 = start, 1 = end) with the current geographic cursor location. The opposite endpoint is unchanged.
Rotate
Rotates both endpoints around the geodesic midpoint (the item focus) by the screen-space three-point angle dragged by the user. Both half-arc lengths (midpoint→start and midpoint→end) are preserved; only the bearings change. The
AItem._azimuthfield accumulates the total screen-space rotation for display purposes. -
getWorldBounds
Returns an approximate world-space bounding rectangle.This returns a simple longitude/latitude bounding box of the two endpoints. It is provided only to satisfy the
AItemcontract. It may under-estimate the true extent of high-latitude arcs that bulge significantly above or below the chord between the endpoints. All visibility and hit-testing that matters uses the exact screen-space bounds available throughgetBounds(IContainer).- Specified by:
getWorldBoundsin classAItem- Returns:
- a lon/lat bounding rectangle in radians, or
nullif either endpoint is absent
-
translateWorld
public void translateWorld(double dx, double dy) Translates the item by raw longitude and latitude offsets in radians.This is a pragmatic translation: for small distances and mid-latitude items it works well. At high latitudes the longitudinal scale diverges from the latitudinal scale, so a northward mouse drag may introduce a small longitudinal error. A future implementation could convert the pixel delta to a geodesic bearing and length, then call
MapGraphics.greatCircleEndPoint(java.awt.geom.Point2D.Double, double, double), but that requires aMapContainerreference not available here.- Specified by:
translateWorldin classAItem- Parameters:
dx- longitude offset in radiansdy- latitude offset in radians
-
getFeedbackStrings
public void getFeedbackStrings(IContainer container, Point pp, Point2D.Double wp, List<String> feedbackStrings) Provides mouse-over feedback showing the great-circle length and the geographic coordinates of both endpoints.- Specified by:
getFeedbackStringsin interfaceIFeedbackProvider- Overrides:
getFeedbackStringsin classAItem- Parameters:
container- the rendering containerpp- current mouse position in device coordinateswp- current mouse position in container world coordinates (not used here)feedbackStrings- the list to populate
-
updateFocus
protected void updateFocus()Recomputes the item focus as the exact geodesic midpoint of the arc.The midpoint is obtained by projecting half the total great-circle arc length along the initial bearing from the start endpoint.
- Overrides:
updateFocusin classAMapItem
-
setDirty
public void setDirty(boolean dirty) Marks the item dirty and clears the cached projected route. -
prepareForRemoval
public void prepareForRemoval()Prepares this item for removal, releasing geographic geometry references.- Specified by:
prepareForRemovalin interfaceIDrawable- Overrides:
prepareForRemovalin classAItem
-
ensureProjectedShape
Ensures that_projectedShapeis populated, building it from the current geographic endpoints if necessary.- Parameters:
container- the rendering container
-
projectLatLon
Projects a geographic point (x = longitude, y = latitudein radians) to a device-space pixel coordinate.Returns
nullif the point projects to a non-finite coordinate (e.g. the point is on the far hemisphere of an orthographic projection).- Parameters:
mc- the map containerlatLon- geographic point in radians- Returns:
- the device-space point, or
nullif projection fails
-
localToLatLon
Converts a device-space point to a geographic longitude/latitude in radians.- Parameters:
mc- the map containerp- the device-space point- Returns:
- the geographic point in radians, or
nullif the container or point is null
-
copy
Returns a defensive copy of a geographic point.- Parameters:
p- the source point; may benull- Returns:
- a copied point, or
nullif the source isnull
-
startModification
public void startModification()Classify and begin a drag, resize, or rotate modification.Priority: rotate (if start point is in rotation handle) → resize (if start point is in a selection handle) → drag (otherwise).
This method is a no-op if
AItem._modificationisnull.Overridden to attach the
MapLineItem.MapLineStartStatesnapshot with the current screen-space azimuth baked in, so that sequential rotate gestures accumulate correctly.- Overrides:
startModificationin classAItem
-