/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package org.openjump.core.ui.plugin.view;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.TextLayout;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import com.vividsolutions.jump.util.MathUtil;
import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
import com.vividsolutions.jump.workbench.ui.TaskFrame;
import com.vividsolutions.jump.workbench.ui.renderer.SimpleRenderer;
public class NorthArrowRenderer extends SimpleRenderer {
public final static String CONTENT_ID = "NORTH_ARROW";
private final static String ENABLED_KEY = NorthArrowRenderer.class +" - ENABLED";
private int ARROW_SIZE = 100;
private Color FILL2 = Color.white;
private Color FILL1 = new Color(255, 204, 204);
private int HORIZONTAL_MARGIN = 8;
private int VERTICAL_MARGIN = 15;
private Color LINE_COLOR = Color.black;
private int TEXT_BOTTOM_MARGIN = 3;
private Color TEXT_COLOR = Color.blue;
private int TEXT_FONT_SIZE = 15;
private Font FONT = new Font("Dialog", Font.BOLD, TEXT_FONT_SIZE);
private Stroke stroke = new BasicStroke();
private final int ALIGN_BOTTOM_RIGHT = 0;
private final int ALIGN_TOP_RIGHT = 1;
private final int ALIGN_TOP_LEFT = 2;
private final int ALIGN_BOTTOM_LEFT = 3;
private int alignment = ALIGN_TOP_RIGHT;
private int style = 1;
public NorthArrowRenderer(LayerViewPanel panel) {
super(CONTENT_ID, panel);
}
public static boolean isEnabled(LayerViewPanel panel) {
return panel.getBlackboard().get(ENABLED_KEY, false);
}
public static void setEnabled(boolean enabled, LayerViewPanel panel) {
panel.getBlackboard().put(ENABLED_KEY, enabled);
}
protected void paint(Graphics2D g) {
paint(g, panel.getViewport().getScale());
}
public void paint(Graphics2D g, double scale) {
if (!isEnabled(panel)) {
return;
}
g.setStroke(stroke);
int x1 = arrowRight() - ARROW_SIZE / 5;
int x2 = arrowRight();
int y1 = arrowTop();
int y2 = arrowBottom();
int x3 = (int) (x1 + 0.5*(x2 - x1));
int y3 = (int) (y1 + 0.8*(y2 - y1));
switch (style) {
case 1: { //the compass rose
x1 = arrowRight() - ARROW_SIZE;
x2 = arrowRight();
y1 = arrowTop();
y2 = arrowBottom();
x3 = (int) (x1 + 0.5*(x2 - x1));
y3 = (int) (y1 + 0.5*(y2 - y1));
int width = ARROW_SIZE / 10;
int x4 = x3 - width;
int x5 = x3 + width;
int y4 = y3 - width;
int y5 = y3 + width;
//draw drop shadow
int s = 4;
int xPoints0[] = {x3+s, x4+s, x1+s, x4+s, x3+s, x5+s, x2+s, x5+s, x3+s};
int yPoints0[] = {y2+s, y5+s, y3+s, y4+s, y1+s, y4+s, y3+s, y5+s, y2+s};
drawShape(g, Color.LIGHT_GRAY, Color.LIGHT_GRAY, xPoints0, yPoints0, true, false);
//draw black filled part
int xPoints[] = {x3, x4, x3, x1, x4, x3, x3, x5, x3, x2, x5, x3, x3};
int yPoints[] = {y2, y5, y3, y3, y4, y3, y1, y4, y3, y3, y5, y3, y2};
drawShape(g, Color.black, LINE_COLOR, xPoints, yPoints, true, false);
//draw white filled part
int xPoints2[] = {x3, x3, x4, x1, x3, x4, x3, x3, x5, x2, x3, x5, x3};
int yPoints2[] = {y2, y3, y5, y3, y3, y4, y1, y3, y4, y3, y3, y5, y2};
drawShape(g, Color.white, LINE_COLOR, xPoints2, yPoints2, true, false);
//draw black outline
int xPoints3[] = {x3, x4, x1, x4, x3, x5, x2, x5, x3};
int yPoints3[] = {y2, y5, y3, y4, y1, y4, y3, y5, y2};
drawShape(g, Color.white, LINE_COLOR, xPoints3, yPoints3, false, true);
drawText(g, "N", TEXT_COLOR, MathUtil.avg(x1, x2), arrowTop() - TEXT_BOTTOM_MARGIN);
break;
}
case 2: { //the inverted V shape half filled narrower version
int xPoints[] = {x2, x1, x1, x2}; //right half V
int yPoints[] = {y2, y3, y1, y2};
drawShape(g, Color.black, LINE_COLOR, xPoints, yPoints, true, true);
int x0 = x1 - ARROW_SIZE / 5;
int xPoints2[] = {x0, x1, x1, x0}; //left half V
int yPoints2[] = {y2, y3, y1, y2};
drawShape(g, Color.white, LINE_COLOR, xPoints2, yPoints2, true, true);
drawText(g, "N", TEXT_COLOR, MathUtil.avg(x0, x2), arrowTop() - TEXT_BOTTOM_MARGIN);
break;
}
case 3: { //the inverted V shape half filled wider version
x1 = arrowRight() - ARROW_SIZE / 3;
int xPoints[] = {x2, x1, x1, x2}; //right half V
int yPoints[] = {y2, y3, y1, y2};
drawShape(g, Color.black, LINE_COLOR, xPoints, yPoints, true, true);
int x0 = x1 - ARROW_SIZE / 3;
int xPoints2[] = {x0, x1, x1, x0}; //left half V
int yPoints2[] = {y2, y3, y1, y2};
drawShape(g, Color.white, LINE_COLOR, xPoints2, yPoints2, true, true);
drawText(g, "N", TEXT_COLOR, MathUtil.avg(x0, x2), arrowTop() - TEXT_BOTTOM_MARGIN);
break;
}
default: { //shaped like a backwards 4 filled with scale bar color
y3 = (int) (y1 + 0.6*(y2 - y1));
int xPoints[] = {x1, x1, x2, x1, x1}; //4
int yPoints[] = {y2, y3, y3, y1, y2};
drawShape(g, FILL1, LINE_COLOR, xPoints, yPoints, true, true);
drawText(g, "N", TEXT_COLOR, MathUtil.avg(x1, x2), arrowBottom() - TEXT_BOTTOM_MARGIN);
}
}
}
private void drawText(Graphics2D g, String text, Color textColor,
double xCenter, double yBaseline) {
TextLayout layout = createTextLayout(text, FONT, g);
layout.draw(
g,
(float) (xCenter - (layout.getAdvance() / 2)),
(float) yBaseline);
}
private void drawShape(Graphics2D g, Color fillColor, Color lineColor,
int xPoints[],int yPoints[], boolean fill, boolean stroke) {
GeneralPath polygon =
new GeneralPath(GeneralPath.WIND_EVEN_ODD, xPoints.length);
polygon.moveTo(xPoints[0], yPoints[0]);
for (int index = 1; index < xPoints.length; index++) {
polygon.lineTo(xPoints[index], yPoints[index]);
};
polygon.closePath();
if (fill) {
g.setColor(fillColor);
g.fill(polygon);
}
if (stroke) {
g.setColor(lineColor);
g.draw(polygon);
}
}
private int arrowBottom() {
int position = 0;
switch (alignment) {
case ALIGN_TOP_LEFT: ; //fall through
case ALIGN_TOP_RIGHT: {
position = VERTICAL_MARGIN + ARROW_SIZE + TEXT_FONT_SIZE + TEXT_BOTTOM_MARGIN;
break;
}
case ALIGN_BOTTOM_LEFT: //fall through
case ALIGN_BOTTOM_RIGHT: ; //fall through
default: {
position = panel.getHeight() - VERTICAL_MARGIN;
}
}
return position;
}
private int arrowTop() {
return arrowBottom() - ARROW_SIZE;
}
private int arrowRight() {
int position = 0;
switch (alignment) {
case ALIGN_BOTTOM_LEFT: ; //fall through
case ALIGN_TOP_LEFT: {
position = ARROW_SIZE / 2 + HORIZONTAL_MARGIN;
break;
}
case ALIGN_TOP_RIGHT: ; //fall through
case ALIGN_BOTTOM_RIGHT: ; //fall through
default: {
position = panel.getWidth() - HORIZONTAL_MARGIN;
}
}
return position;
}
private TextLayout createTextLayout(String text, Font font, Graphics2D g) {
return new TextLayout(text, font, g.getFontRenderContext());
}
public int getAlignment() {
return alignment;
}
/**
* @param alignment BOTTOM_RIGHT = 0, TOP_RIGHT = 1, TOP_LEFT = 2, BOTTOM_LEFT = 3
*/
public void setAlignment(int alignment) {
this.alignment = alignment;
}
public int getARROW_SIZE() {
return ARROW_SIZE;
}
public void setARROW_SIZE(int arrow_size) {
ARROW_SIZE = arrow_size;
}
public Color getFILL1() {
return FILL1;
}
public void setFILL1(Color fill1) {
FILL1 = fill1;
}
public Color getFILL2() {
return FILL2;
}
public void setFILL2(Color fill2) {
FILL2 = fill2;
}
public Color getLINE_COLOR() {
return LINE_COLOR;
}
public void setLINE_COLOR(Color line_color) {
LINE_COLOR = line_color;
}
public Stroke getStroke() {
return stroke;
}
public void setStroke(Stroke stroke) {
this.stroke = stroke;
}
public int getStyle() {
return style;
}
/**
* @param style pass an int related to the ESRI North Arrow style.
*/
public void setStyle(int style) {
this.style = style;
}
public int getTEXT_BOTTOM_MARGIN() {
return TEXT_BOTTOM_MARGIN;
}
public void setTEXT_BOTTOM_MARGIN(int text_bottom_margin) {
TEXT_BOTTOM_MARGIN = text_bottom_margin;
}
public Color getTEXT_COLOR() {
return TEXT_COLOR;
}
public void setTEXT_COLOR(Color text_color) {
TEXT_COLOR = text_color;
}
public int getTEXT_FONT_SIZE() {
return TEXT_FONT_SIZE;
}
public void setTEXT_FONT_SIZE(int text_font_size) {
TEXT_FONT_SIZE = text_font_size;
FONT = new Font("Dialog", Font.BOLD, TEXT_FONT_SIZE);
}
public int getVERTICAL_MARGIN() {
return VERTICAL_MARGIN;
}
public void setVERTICAL_MARGIN(int vertical_margin) {
VERTICAL_MARGIN = vertical_margin;
}
}