// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/omGraphics/labeled/LabeledOMPoly.java,v $
// $RCSfile: LabeledOMPoly.java,v $
// $Revision: 1.8 $
// $Date: 2009/01/21 01:24:41 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.omGraphics.labeled;
import java.awt.Font;
import java.awt.Paint;
import java.awt.Point;
import com.bbn.openmap.omGraphics.OMPoly;
import com.bbn.openmap.omGraphics.OMText;
import com.bbn.openmap.proj.GeoProj;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;
/**
* This is an OMPoly that has been extended to manage a text label.
*/
public class LabeledOMPoly
extends OMPoly
implements LabeledOMGraphic {
protected OMText label;
protected Point offset;
protected boolean locateAtCenter = false;
protected int index = 0;
public LabeledOMPoly() {
super();
}
/**
* Create an LabeledOMPoly from a list of float lat/lon pairs.
*
* @see OMPoly#OMPoly(double[], int, int)
*/
public LabeledOMPoly(double[] llPoints, int units, int lType) {
super(llPoints, units, lType);
}
/**
* Create an LabeledOMPoly from a list of float lat/lon pairs.
*
* @see OMPoly#OMPoly(double[], int, int, int)
*/
public LabeledOMPoly(double[] llPoints, int units, int lType, int nsegs) {
super(llPoints, units, lType, nsegs);
}
/**
* Create an LabeledOMPoly from a list of xy pairs.
*
* @see com.bbn.openmap.omGraphics.OMPoly#OMPoly(int[])
*/
public LabeledOMPoly(int[] xypoints) {
super(xypoints);
}
/**
* Create an x/y LabeledOMPoly.
*
* @see OMPoly#OMPoly(int[], int[])
*/
public LabeledOMPoly(int[] xPoints, int[] yPoints) {
super(xPoints, yPoints);
}
/**
* Create an x/y LabeledOMPoly at an offset from lat/lon.
*
* @see OMPoly#OMPoly(double, double, int[], int)
*/
public LabeledOMPoly(double latPoint, double lonPoint, int[] xypoints, int cMode) {
super(latPoint, lonPoint, xypoints, cMode);
}
/**
* Create an x/y LabeledOMPoly at an offset from lat/lon.
*
* @see OMPoly#OMPoly(double, double, int[], int[], int)
*/
public LabeledOMPoly(double latPoint, double lonPoint, int[] xPoints, int[] yPoints, int cMode) {
super(latPoint, lonPoint, xPoints, yPoints, cMode);
}
/**
* Set the String for the label.
*/
public void setText(String label) {
getLabel().setData(label);
}
/**
* Get the String for the label.
*/
public String getText() {
return getLabel().getData();
}
protected OMText getLabel() {
if (label == null) {
label = new OMText(-1, -1, "", OMText.JUSTIFY_LEFT);
}
return label;
}
/**
* Set the Font for the label.
*/
public void setFont(Font f) {
getLabel().setFont(f);
}
/**
* Get the Font for the label.
*/
public Font getFont() {
return getLabel().getFont();
}
/**
* Set the justification setting for the label.
*
* @see com.bbn.openmap.omGraphics.OMText#JUSTIFY_LEFT
* @see com.bbn.openmap.omGraphics.OMText#JUSTIFY_CENTER
* @see com.bbn.openmap.omGraphics.OMText#JUSTIFY_RIGHT
*/
public void setJustify(int just) {
getLabel().setJustify(just);
}
/**
* Get the justification setting for the label.
*
* @see com.bbn.openmap.omGraphics.OMText#JUSTIFY_LEFT
* @see com.bbn.openmap.omGraphics.OMText#JUSTIFY_CENTER
* @see com.bbn.openmap.omGraphics.OMText#JUSTIFY_RIGHT
*/
public int getJustify() {
return getLabel().getJustify();
}
/**
* Tell the LabeledOMGraphic to calculate the location of the String that
* would put it in the middle of the OMGraphic.
*/
public void setLocateAtCenter(boolean set) {
locateAtCenter = set;
if (set) {
setJustify(OMText.JUSTIFY_CENTER);
getLabel().setFMHeight(OMText.ASCENT);
}
}
/**
* Get whether the LabeledOMGraphic is placing the label String in the
* center of the OMGraphic.
*/
public boolean isLocateAtCenter() {
return locateAtCenter;
}
/**
* Calculate the projected area of the poly. Algorithm used is from some
* australian astronomy website =)
* http://astronomy.swin.edu.au/~pbourke/geometry/polyarea
*/
protected double calculateProjectedArea() {
int j = 0;
double area = 0.0;
float[] xpts = xpoints[0];
float[] ypts = ypoints[0];
int npoints = xpts.length;
for (int i = 0; i < npoints; ++i) {
j = (i + 1) % npoints;
area += xpts[i] * ypts[j];
area -= ypts[i] * xpts[j];
}
return area / 2.0;
// area = area / 2.0;
// return (area < 0.0 ? -area : area);
}
/**
* Get the calculated center where the label string is drawn. Algorithm used
* is from some australian astronomy website =)
* http://astronomy.swin.edu.au/~pbourke/geometry/polyarea
*/
public Point getCenter() {
// if the OMPoly isn't generated, then you can't calculate it.
// We're working in x/y space here, so it looks right.
if (getNeedToRegenerate()) {
return null;
}
float cx = 0.0f;
float cy = 0.0f;
float A = (float) calculateProjectedArea();
int j = 0;
float factor = 0;
float[] xpts = xpoints[0];
float[] ypts = ypoints[0];
int npoints = xpts.length;
for (int i = 0; i < npoints; ++i) {
j = (i + 1) % npoints;
factor = xpts[i] * ypts[j] - xpts[j] * ypts[i];
cx += (xpts[i] + xpts[j]) * factor;
cy += (ypts[i] + ypts[j]) * factor;
}
A *= 6.0f;
factor = 1 / A;
// bbenyo: take the absolute value cause I was getting
// negative values
// for polys with all positive vertices
// cx = Math.abs(cx * factor);
// cy = Math.abs(cy * factor);
// DFD and RS - let the area calculation return negative
// values, and don't do this absolute value calculation.
// Negative values get returned when the points are
// counterclockwise, indicating holes. We may want labels
// offscreen however, and the abs pushes them onscreen.
cx *= factor;
cy *= factor;
Point center = new Point(Math.round(cx), Math.round(cy));
return center;
}
/**
* Set the index of the OMGraphic coordinates where the drawing point of the
* label should be attached. The meaning of the point differs between
* OMGraphic types.
*/
public void setIndex(int index) {
this.index = index;
}
/**
* Get the index of the OMGraphic where the String will be rendered. The
* meaning of the index differs from OMGraphic type to OMGraphic type.
*/
public int getIndex() {
return index;
}
/**
* Set the x, y pixel offsets where the String should be rendered, from the
* location determined from the index point, or from the calculated center
* point. Point.x is the horizontal offset, Point.y is the vertical offset.
*/
public void setOffset(Point p) {
offset = p;
}
/**
* Get the x, y pixel offsets set for the rendering of the point.
*/
public Point getOffset() {
if (offset == null) {
offset = new Point();
}
return offset;
}
/**
* Set the angle by which the text is to rotated.
*
* @param angle the number of radians the text is to be rotated. Measured
* clockwise from horizontal. Positive numbers move the positive x
* axis toward the positive y axis.
*/
public void setRotationAngle(double angle) {
getLabel().setRotationAngle(angle);
}
/**
* Get the current rotation of the text.
*
* @return the text rotation.
*/
public double getRotationAngle() {
return getLabel().getRotationAngle();
}
boolean matchPolyPaint = true;
/**
* Set the line paint for the polygon. If the text paint hasn't been
* explicitly set, then the text paint will be set to this paint, too.
*/
public void setLinePaint(Paint paint) {
super.setLinePaint(paint);
if (matchPolyPaint) {
getLabel().setLinePaint(paint);
}
}
/**
* If not set to null, the text will be painted in a different color. If set
* to null, the text paint will match the poly edge paint.
*
* @param paint the Paint object for the text
*/
public void setTextPaint(Paint paint) {
if (paint != null) {
matchPolyPaint = false;
getLabel().setLinePaint(paint);
}
}
/**
* Used for the actual text location.
*/
Point handyPoint = new Point();
/**
* Calculate where the text point ought to go.
*/
protected Point getTextPoint(Projection proj) {
// Assuming that the rendertype is not unknown...
if (renderType == RENDERTYPE_LATLON && proj instanceof GeoProj) {
int numPoints = rawllpts.length / 2;
if (rawllpts.length < 2) {
// off screen...
handyPoint.setLocation(-10, -10);
return handyPoint;
}
if (locateAtCenter) {
handyPoint = getCenter();
// New getCenter algorithm works better.
// for (i = 0; i < rawllpts.length; i+=2) {
// proj.forward(rawllpts[i], rawllpts[i+1],
// handyPoint, true);
// avgy += handyPoint.getY();
// avgx += handyPoint.getX();
// }
// avgy = avgy/numPoints;
// avgx = avgx/numPoints;
// handyPoint.setLocation(avgx, avgy);
} else {
if (index < 0)
index = 0;
if (index > numPoints)
index = numPoints - 1;
((GeoProj) proj).forward(rawllpts[2 * index], rawllpts[2 * index + 1], handyPoint, true);
}
} else {
float[][] x = xpoints;
float[][] y = ypoints;
if (x[0].length < 2) {
// off screen...
handyPoint.setLocation(-10, -10);
return handyPoint;
}
if (locateAtCenter) {
handyPoint = getCenter();
// New getCenter algorithm works better.
// for (i = 0; i < x[0].length; i++) {
// avgx += x[0][i];
// avgy += y[0][i];
// }
// handyPoint.setLocation(avgx/x[0].length,
// avgy/x[0].length);
} else {
if (index < 0)
index = 0;
if (index >= x[0].length)
index = x[0].length - 1;
handyPoint.setLocation(x[0][index], y[0][index]);
}
}
return handyPoint;
}
public boolean generate(Projection proj) {
boolean ret = super.generate(proj);
Point p = getTextPoint(proj);
if (p != null) {
label.setX((int) (p.getX() + getOffset().getX()));
label.setY((int) (p.getY() + getOffset().getY()));
if (Debug.debugging("labeled")) {
Debug.output("Setting label(" + label.getData() + ") to " + p);
}
label.generate(proj);
}
return ret;
}
public void render(java.awt.Graphics g) {
super.render(g);
label.render(g);
}
}