/*
* Copyright (c) 2016 Fraunhofer IGD
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Fraunhofer IGD <http://www.igd.fraunhofer.de/>
*/
package de.fhg.igd.mapviewer.marker;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.jdesktop.swingx.mapviewer.IllegalGeoPositionException;
import org.jdesktop.swingx.mapviewer.PixelConverter;
import de.fhg.igd.geom.BoundingBox;
import de.fhg.igd.mapviewer.marker.area.Area;
import de.fhg.igd.mapviewer.marker.area.BoxArea;
import de.fhg.igd.mapviewer.waypoints.SelectableWaypoint;
/**
* Marker that paints way-point bounding boxes
*
* @author Simon Templer
* @param <T> the context type
*/
public abstract class BoundingBoxMarker<T extends SelectableWaypoint<T>> extends AbstractMarker<T> {
/**
* @see AbstractMarker#paintMarker(Graphics2D, Object, PixelConverter, int,
* Rectangle, boolean)
*/
@Override
protected Area paintMarker(Graphics2D g, T context, PixelConverter converter, int zoom,
Rectangle gBounds, boolean calculateArea) {
if (context.isPoint()) {
return paintFallback(g, context, converter, zoom, gBounds, calculateArea);
}
BoundingBox bb = context.getBoundingBox();
int code = SelectableWaypoint.COMMON_EPSG;
GeoPosition pos1 = new GeoPosition(bb.getMinX(), bb.getMinY(), code);
GeoPosition pos2 = new GeoPosition(bb.getMaxX(), bb.getMaxY(), code);
try {
Point2D p1 = converter.geoToPixel(pos1, zoom);
Point2D p2 = converter.geoToPixel(pos2, zoom);
int minX = (int) Math.min(p1.getX(), p2.getX());
int minY = (int) Math.min(p1.getY(), p2.getY());
int maxX = (int) Math.max(p1.getX(), p2.getX());
int maxY = (int) Math.max(p1.getY(), p2.getY());
int width = maxX - minX;
int height = maxY - minY;
// decide whether it is to small to paint
if (isToSmall(width, height, zoom)) {
return paintFallback(g, context, converter, zoom, gBounds, calculateArea);
}
return doPaintMarker(g, context, converter, zoom, minX, minY, maxX, maxY, gBounds,
calculateArea);
} catch (IllegalGeoPositionException e) {
// use fallback marker instead
return paintFallback(g, context, converter, zoom, gBounds, calculateArea);
}
}
/**
* Paint the marker.
*
* @param g the graphics device
* @param context the painting context
* @param converter the pixel converter
* @param zoom the zoom level
* @param minX the bounding box minimum x pixel coordinate
* @param minY the bounding box minimum y pixel coordinate
* @param maxX the bounding box maximum x pixel coordinate
* @param maxY the bounding box maximum y pixel coordinate
* @param gBounds the graphics bounds
* @param calculateArea if the area representing the marker should be
* calculated, if <code>false</code> is given here the return
* value is ignored and should be <code>null</code>
* @return the area that represents the marker
*/
protected Area doPaintMarker(Graphics2D g, T context, PixelConverter converter, int zoom,
int minX, int minY, int maxX, int maxY, Rectangle gBounds, boolean calculateArea) {
if (applyFill(g, context)) {
g.fillRect(minX, minY, maxX - minX + 1, maxY - minY + 1);
}
if (applyStroke(g, context)) {
g.drawRect(minX, minY, maxX - minX + 1, maxY - minY + 1);
}
if (calculateArea) {
return new BoxArea(minX, minY, maxX, maxY);
}
else {
return null;
}
}
/**
* Determines if painting a fill is allowed, if yes applies the fill style
* to the given graphics.<br>
* <br>
* By default sets the paint color to
* {@link #getPaintColor(SelectableWaypoint)} and allows painting a fill.
*
* @param g the graphics
* @param context the paint context
* @return if painting a fill is allowed
*/
protected boolean applyFill(Graphics2D g, T context) {
g.setPaint(getPaintColor(context));
return true;
}
/**
* Determines if painting lines is allowed, if yes applies the stroke style
* to the given graphics.<br>
* <br>
* By default sets the drawing color to
* {@link #getBorderColor(SelectableWaypoint)} and allows painting lines.
*
* @param g the graphics
* @param context the paint context
* @return if painting lines is allowed
*/
protected boolean applyStroke(Graphics2D g, T context) {
g.setColor(getBorderColor(context));
return true;
}
/**
* Decides whether a bounding box is to small to paint
*
* @param width the width in pixels
* @param height the height in pixels
* @param zoom the zoom level
* @return if the bounding box is to small and instead the fall-back marker
* should be used
*/
protected boolean isToSmall(int width, int height, int zoom) {
return width <= 2 || height <= 2 || (width <= 4 && height <= 4);
}
/**
* Paint the fall-back marker
*
* @param g the graphics device
* @param context the way-point
* @param converter the converter
* @param zoom the zoom level
* @param gBounds the graphics bounds
* @param calculateArea if the area representing the marker should be
* calculated, if <code>false</code> is given here the return
* value is ignored and should be <code>null</code>
* @return the area that represents the marker
*/
protected Area paintFallback(Graphics2D g, T context, PixelConverter converter, int zoom,
Rectangle gBounds, boolean calculateArea) {
Marker<? super T> marker = getFallbackMarker(context);
marker.paint(g, converter, zoom, context, gBounds);
if (calculateArea) {
return marker.getArea(zoom);
}
else {
return null;
}
}
/**
* Get the paint color
*
* @param context the painting context
* @return the paint color
*/
protected abstract Color getPaintColor(T context);
/**
* Get the border color
*
* @param context the painting context
* @return the border color
*/
protected abstract Color getBorderColor(T context);
/**
* Get the fall-back marker to use for painting when geo conversion fails or
* the bounding box would be to small
*
* @param context the context object
* @return the fall-back marker
*/
protected abstract Marker<? super T> getFallbackMarker(T context);
}