fr.ird.observe.client.util.tripMap.ObserveMapPane Maven / Gradle / Ivy
package fr.ird.observe.client.util.tripMap;
/*
* #%L
* ObServe Toolkit :: Common Client
* %%
* Copyright (C) 2008 - 2017 IRD, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import com.google.common.collect.Lists;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.renderer.lite.RendererUtilities;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Rule;
import org.geotools.styling.Style;
import org.geotools.swing.JMapPane;
import org.geotools.swing.event.MapPaneAdapter;
import org.geotools.swing.event.MapPaneEvent;
import static org.nuiton.i18n.I18n.n;
import static org.nuiton.i18n.I18n.t;
/**
* @author Tony Chemit - [email protected]
*/
public class ObserveMapPane extends JMapPane {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(ObserveMapPane.class);
protected static final int MARGIN = 10;
protected static final int SCALE_HEIGHT = 15;
protected static final int SCALE_WIDTH_MAX = 200;
protected static final int METERS_BY_MILES = 1852;
protected int scaleWidth;
protected String labelScaleUp;
protected double rotation;
public ObserveMapPane() {
labelScaleUp = "0 m";
scaleWidth = 100;
rotation = 0;
addMapPaneListener(new MapPaneAdapter() {
@Override
public void onDisplayAreaChanged(MapPaneEvent ev) {
updateScale();
}
});
legendItems = Lists.newArrayList();
}
protected void updateScale() {
ReferencedEnvelope displayArea = getDisplayArea();
double dpi = 2.54 / 100; // pour avoir l'echélle en metre/pixel
try {
double meterPerPixel = RendererUtilities.calculateScale(displayArea, getWidth(), getHeight(), dpi);
double maxWidthMeter = SCALE_WIDTH_MAX * meterPerPixel;
double maxWidthMiles = maxWidthMeter / METERS_BY_MILES;
int nbDigit = (int) Math.floor(Math.log10(maxWidthMiles));
int firstDigit = (int) Math.floor(maxWidthMiles / Math.pow(10, nbDigit)); // le premier chiffre significatif
int useFirstDigit;
if (firstDigit >= 5) {
useFirstDigit = 5;
} else if (firstDigit >= 2) {
useFirstDigit = 2;
} else {
useFirstDigit = 1;
}
long scaleInMiles = useFirstDigit * (long) Math.pow(10, nbDigit);
scaleWidth = (int) Math.round(scaleInMiles * METERS_BY_MILES / meterPerPixel);
labelScaleUp = String.format("%,d " + t("observe.content.map.miles"), scaleInMiles);
} catch (Exception e) {
if (log.isErrorEnabled()) {
log.error("error", e);
}
}
}
protected void paintScale(Graphics graphics) {
graphics.setColor(Color.BLACK);
FontMetrics fm = graphics.getFontMetrics();
Rectangle2D textArea = fm.getStringBounds(labelScaleUp, graphics);
int labelLeft = getWidth() - MARGIN * 2 - scaleWidth - (int) textArea.getWidth();
graphics.drawString(labelScaleUp, labelLeft, getHeight() - MARGIN);
int scalesEndX = getWidth() - MARGIN;
int scaleStartX = scalesEndX - scaleWidth;
int scalesEndY = getHeight() - MARGIN;
int scaleStartY = scalesEndY - SCALE_HEIGHT;
graphics.drawLine(scaleStartX, scaleStartY, scaleStartX, scalesEndY);
graphics.drawLine(scaleStartX, scalesEndY, scalesEndX, scalesEndY);
graphics.drawLine(scalesEndX, scalesEndY, scalesEndX, scaleStartY);
}
protected static int AXIS_LENGTH = 30;
protected static int SUB_AXIS_LENGTH = 5;
protected static int CENTER_MARGIN = 50;
protected static int INTER_AXIS_TEXT = 3;
protected static double FONT_SIZE = 12;
protected void paintCompass(Graphics graphics) {
Point center = new Point(getWidth() - CENTER_MARGIN, CENTER_MARGIN);
Font font = graphics.getFont();
Font fontRatio = font.deriveFont((float) (FONT_SIZE));
graphics.setFont(fontRatio);
FontMetrics fm = graphics.getFontMetrics();
for (CardinalPoint cardinalPoint : CardinalPoint.values()) {
Point2D direction = cardinalPoint.getDirection(rotation, AXIS_LENGTH, center);
Point2D sommet1 = cardinalPoint.getDirection(rotation - Math.PI / 4, SUB_AXIS_LENGTH, center);
Point2D sommet2 = cardinalPoint.getDirection(rotation + Math.PI / 4, SUB_AXIS_LENGTH, center);
Polygon polygon = new Polygon();
polygon.addPoint((int) center.getX(), (int) center.getY());
polygon.addPoint((int) direction.getX(), (int) direction.getY());
polygon.addPoint((int) sommet2.getX(), (int) sommet2.getY());
graphics.fillPolygon(polygon);
graphics.drawLine((int) sommet1.getX(), (int) sommet1.getY(), (int) direction.getX(), (int) direction.getY());
Rectangle2D textArea = fm.getStringBounds(cardinalPoint.getLabel(), graphics);
// on cherche la ditance entre le centre du text et sa bordure dans le direction donné
double l = cardinalPoint.distanceCenterBorder(rotation, textArea);
Point2D textCenter = cardinalPoint.getDirection(rotation, AXIS_LENGTH + INTER_AXIS_TEXT + l, center);
graphics.drawString(
cardinalPoint.getLabel(),
(int) (textCenter.getX() - textArea.getWidth() / 2),
(int) (textCenter.getY() + textArea.getHeight() / 2));
}
}
protected static int LEGEND_MARGIN = 3;
protected List legendItems;
public List getLegendItems() {
return legendItems;
}
public void setLegendItems(List legendItems) {
this.legendItems = legendItems;
}
protected void paintLegend(Graphics graphics) {
if (legendItems != null) {
int x = 0;
int y = getHeight() - ObserveMapPaneLegendItem.LEGEND_ITEM_HEIGHT * legendItems.size() - 2 * LEGEND_MARGIN;
ObserverMapPanLegendDrawer drawer = new ObserverMapPanLegendDrawer();
FontMetrics fm = graphics.getFontMetrics();
int maxLabelWidth = 0;
for (ObserveMapPaneLegendItem item : legendItems) {
Rectangle2D labelArea = fm.getStringBounds(item.getLabel(), graphics);
maxLabelWidth = Math.max((int) labelArea.getWidth(), maxLabelWidth);
}
int legendWidth = ObserveMapPaneLegendItem.LEGEND_SYMBOL_WIDTH + maxLabelWidth + ObserveMapPaneLegendItem.LEGEND_MARGIN * 2;
graphics.setColor(ObserveMapPaneLegendItem.LEGEND_BACKGROUND);
graphics.fillRect(
x,
y,
legendWidth,
LEGEND_MARGIN);
y += LEGEND_MARGIN;
for (ObserveMapPaneLegendItem item : legendItems) {
graphics.setColor(ObserveMapPaneLegendItem.LEGEND_BACKGROUND);
graphics.fillRect(
x,
y,
legendWidth,
ObserveMapPaneLegendItem.LEGEND_ITEM_HEIGHT);
BufferedImage symbole = new BufferedImage(
ObserveMapPaneLegendItem.LEGEND_SYMBOL_WIDTH,
ObserveMapPaneLegendItem.LEGEND_ITEM_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
Style style = item.getStyle();
for (FeatureTypeStyle featureTypeStyle : style.featureTypeStyles()) {
for (Rule rule : featureTypeStyle.rules()) {
if (rule.getFilter().evaluate(item.getSimpleFeature())) {
drawer.drawDirect(symbole, item.getSimpleFeature(), rule);
}
}
}
graphics.drawImage(symbole, x + LEGEND_MARGIN, y, null);
graphics.setColor(Color.BLACK);
int labelMarginBottom = ((ObserveMapPaneLegendItem.LEGEND_ITEM_HEIGHT - fm.getHeight()) / 2) + fm.getDescent();
graphics.drawString(item.getLabel(),
x + LEGEND_MARGIN + ObserveMapPaneLegendItem.LEGEND_SYMBOL_WIDTH,
y + ObserveMapPaneLegendItem.LEGEND_ITEM_HEIGHT - labelMarginBottom);
y += ObserveMapPaneLegendItem.LEGEND_ITEM_HEIGHT;
}
graphics.setColor(ObserveMapPaneLegendItem.LEGEND_BACKGROUND);
graphics.fillRect(
x,
y,
legendWidth,
LEGEND_MARGIN);
}
}
@Override
public void paint(Graphics graphics) {
super.paint(graphics);
paintScale(graphics);
paintCompass(graphics);
paintLegend(graphics);
}
protected enum CardinalPoint {
NORTH(-1, 0, 0, -1, n("observe.content.map.north")),
SOUTH(1, 0, 0, 1, n("observe.content.map.south")),
WEST(0, -1, 1, 0, n("observe.content.map.west")),
EST(0, 1, -1, 0, n("observe.content.map.east"));
protected int matrix00;
protected int matrix01;
protected int matrix10;
protected int matrix11;
protected String label;
CardinalPoint(int matrix00, int matrix01, int matrix10, int matrix11, String label) {
this.matrix00 = matrix00;
this.matrix01 = matrix01;
this.matrix10 = matrix10;
this.matrix11 = matrix11;
this.label = label;
}
public Point2D.Double getDirection(double angle, double length, Point center) {
double x = Math.sin(angle) * length;
double y = Math.cos(angle) * length;
double deltaX = matrix00 * x + matrix01 * y;
double deltaY = matrix10 * x + matrix11 * y;
return new Point2D.Double(center.getX() + deltaX, center.getY() + deltaY);
}
// on cherche la ditance entre le centre du text et sa bordure dans le direction donné
public double distanceCenterBorder(double angle, Rectangle2D textArea) {
double x = Math.sin(angle);
double y = Math.cos(angle);
double deltaW = Math.abs(textArea.getWidth() / 2 / (matrix00 * x + matrix01 * y));
double deltaH = Math.abs(textArea.getHeight() / 2 / (matrix10 * x + matrix11 * y));
return Math.min(deltaH, deltaW);
}
public String getLabel() {
return t(label);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy