/*
* $Id: LabelDrawer2D.java,v 1.6 2003/08/22 23:02:32 dwd Exp $
*
* This software is provided by NOAA for full, free and open release. It is
* understood by the recipient/user that NOAA assumes no liability for any
* errors contained in the code. Although this software is released without
* conditions or restrictions in its use, it is expected that appropriate
* credit be given to its author and to the National Oceanic and Atmospheric
* Administration should the software be included by the recipient as an
* element in other product development.
*/
package sgtplot;
import graph.RTextLine;
import java.awt.*;
import java.beans.*;
import java.awt.image.PixelGrabber;
import java.awt.image.MemoryImageSource;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.geom.AffineTransform;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.font.FontRenderContext;
import java.text.AttributedString;
import jplot.Translate;
import org.freehep.graphics2d.VectorGraphics;
import sgtplot.pmel.swing.MRJUtil;
import sgtplot.util.Debug;
import sgtplot.util.Point2D;
import sgtplot.util.Rectangle2D;
/**
* Implements label drawing using Java2D functionality.
*
* @author Donald Denbo and S.Chekanov
* @version $Revision: 1.6 $, $Date: 2003/08/22 23:02:32 $
* @since 2.0
*/
public class LabelDrawer2D implements LabelDrawer, Cloneable {
/**
*
*/
private static final long serialVersionUID = 1L;
private RTextLine text;
private String label_;
private Color clr_;
private Font font_;
private transient Layer layer_;
private int orient_;
private int halign_;
private int valign_;
private Point dorigin_;
private Rectangle dbounds_;
private Point2D.Double porigin_;
private Rectangle2D.Double pbounds_;
private Polygon dpolygon_;
private double angle_;
private double sinthta_;
private double costhta_;
private double height_;
private boolean visible_;
private static boolean fixMetrics_ = MRJUtil.fixFontMetrics();
private int xoff_ = 0;
private int yoff_ = 0;
private boolean alwaysAntiAlias_ = false;
private Rectangle savedBounds_ = null;
private Point savedLoc_ = null;
public LabelDrawer2D(String lbl, double hgt, Point2D.Double loc,
int valign, int halign) {
label_ =lbl;
height_ = hgt;
porigin_ = loc;
valign_ = valign;
halign_ = halign;
text = new RTextLine();
//
dbounds_ = new Rectangle();
dorigin_ = new Point(0,0);
pbounds_ = new Rectangle2D.Double();
}
public LabelDrawer copy() {
LabelDrawer2D newLabel = null;
/*
newLabel = new LabelDrawer2D(ident_, label_, height_,
porigin_, valign_, halign_);
newLabel.setColor(clr_);
newLabel.setFont(font_);
if(orient_ == ANGLE) {
newLabel.setAngle(angle_);
} else {
newLabel.setOrientation(orient_);
}
*/
return newLabel;
}
public void draw(VectorGraphics g) throws LayerNotFoundException {
int xs, ys;
if((label_.length() <= 0) || !visible_ || g == null) return;
if(layer_ == (Layer) null) throw new LayerNotFoundException();
//
// set label heigth in physical units
//
computeBoundsD(g);
if(clr_ == null) {
g.setColor(layer_.getPane().getComponent().getForeground());
} else {
g.setColor(clr_);
}
if(orient_ == SGLabel.HORIZONTAL) {
xs = dbounds_.x + xoff_;
ys = dbounds_.y + yoff_;
drawString(g, xs, ys);
} else if(orient_ == SGLabel.VERTICAL) {
//
// draw text in offscreen image (horizontal)
//
xs = dbounds_.x + xoff_;
ys = dbounds_.y + yoff_;
drawString(g, xs, ys);
} else {
//
// Angled text, draw in offscreen image and rotate
//
xs = layer_.getXPtoD(porigin_.x);
ys = layer_.getYPtoD(porigin_.y);
drawString(g, xs, ys);
}
}
public void setText(String lbl) {
label_ = lbl;
}
public String getText() {
return label_;
}
public void setColor(Color clr) {
clr_ = clr;
}
public Color getColor() {
return clr_;
}
public void setFont(Font font) {
font_ = font;
}
public Font getFont() {
return font_;
}
public void setLayer(Layer layer) {
layer_ = layer;
if(savedBounds_ != null) {
setBounds(savedBounds_.x, savedBounds_.y,
savedBounds_.width, savedBounds_.height);
savedBounds_ = null;
}
if(savedLoc_ != null) {
setLocation(savedLoc_);
savedLoc_ = null;
}
}
public Layer getLayer() {
return layer_;
}
public void setOrientation(int orient) {
if(orient_ != orient) {
if(orient == SGLabel.HORIZONTAL) {
costhta_ = 1.0;
sinthta_ = 0.0;
} else if(orient == SGLabel.VERTICAL) {
costhta_ = 0.0;
sinthta_ = 1.0;
}
orient_ = orient;
}
}
public int getOrientation() {
return orient_;
}
public void setHAlign(int halign) {
halign_ = halign;
}
public int getHAlign() {
return halign_;
}
public void setVAlign(int valign) {
valign_ = valign;
}
public int getVAlign() {
return valign_;
}
public void setLocation(Point loc) {
if(layer_ == null) {
savedLoc_ = new Point(loc);
return;
}
computeBoundsD(VectorGraphics.create(layer_.getPane().getComponent().getGraphics()));
if(dbounds_.x != loc.x || dbounds_.y != loc.y) {
setBounds(loc.x, loc.y, dbounds_.width, dbounds_.height);
}
}
public Point getLocation() {
if(savedLoc_ != null) return savedLoc_;
return dorigin_;
}
public void setBounds(int x, int y, int width, int height) {
int swidth, sascent, xd, yd;
if(layer_ == null) {
savedBounds_ = new Rectangle(x, y, width, height);
return;
}
Graphics g = layer_.getPane().getComponent().getGraphics();
if(g == null) return;
VectorGraphics g2 = VectorGraphics.create(g);
font_ = computeFontSize(g2);
FontRenderContext frc = getFontRenderContext(g2);
TextLayout tlayout;
if(label_.length() == 0) {
tlayout = new TextLayout(" ", font_, frc);
} else {
tlayout = new TextLayout(label_, font_, frc);
}
java.awt.geom.Rectangle2D tbounds = tlayout.getBounds();
int theight = (int)tbounds.getHeight();
int twidth = (int)tbounds.getWidth();
int tx = (int)tbounds.getX();
int ty = (int)tbounds.getY();
if(fixMetrics_) ty -= (int)(0.7*tlayout.getAscent()); // hack for MacOS X java.runtime.version = 1.4.1_01-39
sascent = (int)tlayout.getAscent();
if(orient_ == SGLabel.HORIZONTAL) {
swidth = width;
xd = x;
yd = y - ty;
switch(valign_) {
case SGLabel.TOP:
yd = yd - sascent;
break;
case SGLabel.MIDDLE:
yd = yd + (ty + theight/2);
break;
case SGLabel.BOTTOM:
}
switch(halign_) {
case SGLabel.RIGHT:
xd = xd + swidth;
break;
case SGLabel.CENTER:
xd = xd + swidth/2;
break;
case SGLabel.LEFT:
}
} else {
swidth = height;
yd = y + height;
xd = x - ty;
switch(valign_) {
case SGLabel.TOP:
xd = xd - sascent;
break;
case SGLabel.MIDDLE:
xd = xd - sascent/2;
break;
case SGLabel.BOTTOM:
}
switch(halign_) {
case SGLabel.RIGHT:
yd = yd - swidth;
break;
case SGLabel.CENTER:
yd = yd - swidth/2;
break;
case SGLabel.LEFT:
}
}
if(dorigin_.x != xd || dorigin_.y != yd) {
dorigin_.x = xd;
dorigin_.y = yd;
porigin_.x = layer_.getXDtoP(xd);
porigin_.y = layer_.getYDtoP(yd);
}
}
public Rectangle getBounds() {
if(savedBounds_ != null) return savedBounds_;
if(layer_ != null) computeBoundsD(VectorGraphics.create(layer_.getPane().getComponent().getGraphics()));
return dbounds_;
}
public void setLocationP(Point2D.Double loc) {
porigin_ = loc;
}
public Point2D.Double getLocationP() {
return porigin_;
}
public Rectangle2D.Double getBoundsP() {
computeBoundsD(VectorGraphics.create(layer_.getPane().getComponent().getGraphics()));
return pbounds_;
}
public void setAngle(double angle) {
angle_ = angle;
double thta = angle_*Math.PI/180.0;
if(Math.abs(thta) < 0.001) {
orient_ = SGLabel.HORIZONTAL;
costhta_ = 1.0;
sinthta_ = 0.0;
} else if(Math.abs(thta - 90.0) < 0.001) {
orient_ = SGLabel.VERTICAL;
costhta_ = 0.0;
sinthta_ = 1.0;
} else {
orient_ = SGLabel.ANGLE;
costhta_ = Math.cos(thta);
sinthta_ = Math.sin(thta);
}
}
public double getAngle() {
return angle_;
}
public void setHeightP(double hgt) {
height_ = hgt;
}
public double getHeightP() {
return height_;
}
public void setVisible(boolean vis) {
visible_ = vis;
}
public boolean isVisible() {
return visible_;
}
private void computeBoundsD(VectorGraphics g2) {
int sascent, xd, yd;
int xorig, yorig;
int[] xt = new int[4];
int[] yt = new int[4];
int[] xn = new int[4];
int[] yn = new int[4];
//
// compute size of font and adjust to be height tall!
//
if(g2 == null) return;
font_ = computeFontSize(g2);
FontRenderContext frc = getFontRenderContext(g2);
TextLayout tlayout;
if(label_.length() == 0) {
tlayout = new TextLayout(" ", font_, frc);
} else {
tlayout = new TextLayout(label_, font_, frc);
}
java.awt.geom.Rectangle2D tbounds = tlayout.getBounds();
// System.out.println("LabelDrawer2D('" + label_ + "'): fixMetrics = " + fixMetrics_);
// System.out.println("LabelDrawer2D('" + label_ + "'): TextLayout.bounds = " + tbounds);
// System.out.println("LabelDrawer2D('" + label_ + "'): ascent, descent = " + tlayout.getAscent() + ", " + tlayout.getDescent());
// System.out.println("LabelDrawer2D('" + label_ + "'): leading, baseline = " + tlayout.getLeading() + ", " + tlayout.getBaseline());
// System.out.println("LabelDrawer2D('" + label_ + "'): TextLayout = " + tlayout);
int theight = (int)tbounds.getHeight();
int twidth = (int)tbounds.getWidth();
int tx = (int)tbounds.getX();
int ty = (int)tbounds.getY();
if(fixMetrics_) ty -= (int)(0.7*tlayout.getAscent()); // hack for MacOS X java.runtime.version = 1.4.1_01-39
sascent = (int)tlayout.getAscent();
//
xd = layer_.getXPtoD(porigin_.x);
yd = layer_.getYPtoD(porigin_.y);
//
// set device origin
//
dorigin_.x = xd;
dorigin_.y = yd;
xorig = xd;
yorig = yd;
//
switch(valign_) {
case SGLabel.TOP:
yd = yd + sascent;
break;
case SGLabel.MIDDLE:
yd = yd - (ty + theight/2);
break;
case SGLabel.BOTTOM:
}
switch(halign_) {
case SGLabel.RIGHT:
xd = xd - twidth;
break;
case SGLabel.CENTER:
xd = xd - twidth/2;
break;
case SGLabel.LEFT:
}
if(orient_ == SGLabel.HORIZONTAL) {
xoff_ = 0;
yoff_ = -ty;
} else if(orient_ == SGLabel.VERTICAL) {
xoff_ = -ty;
yoff_ = twidth;
}
xt[0] = xd + tx;
xt[1] = xt[0];
xt[2] = xt[0] + twidth;
xt[3] = xt[2];
yt[0] = yd + ty;
yt[1] = yt[0] + theight;
yt[2] = yt[1];
yt[3] = yt[0];
//
// rotate
//
for(int i=0; i < 4; i++) {
xn[i] = (int)((xt[i]-xorig)*costhta_ + (yt[i]-yorig)*sinthta_) + xorig;
yn[i] = (int)((yt[i]-yorig)*costhta_ - (xt[i]-xorig)*sinthta_) + yorig;
}
dpolygon_ = new Polygon(xn, yn, 4);
dbounds_ = dpolygon_.getBounds();
//
// compute pbounds
//
pbounds_.x = layer_.getXDtoP(dbounds_.x);
pbounds_.y = layer_.getYDtoP(dbounds_.y);
pbounds_.width = layer_.getXDtoP(dbounds_.x +
dbounds_.width) - pbounds_.x;
pbounds_.height = pbounds_.y -
layer_.getYDtoP(dbounds_.y + dbounds_.height);
}
//
// a bad method to compute the font size!
//
Font computeFontSize(VectorGraphics g2) {
Font tfont;
int pt_0, pt_1, hgt;
int count = 1;
double hgt_0, hgt_1, del_0, del_1;
double a, b;
// VectorGraphics g2 = VectorGraphics.create(g);
FontRenderContext frc = getFontRenderContext(g2);
TextLayout tlayout;
//
// first guess
//
if(g2 == null) return font_; // return original font!
hgt = layer_.getXPtoD(height_) - layer_.getXPtoD(0.0f);
pt_0 = hgt - 3;
tfont = new Font(font_.getName(), font_.getStyle(), pt_0);
if(label_.length() == 0) {
tlayout = new TextLayout(" ", tfont, frc);
} else {
tlayout = new TextLayout(label_, tfont, frc);
}
hgt = (int)(tlayout.getAscent() + tlayout.getDescent());
hgt_0 = layer_.getXDtoP(hgt) - layer_.getXDtoP(0);
pt_0 = tfont.getSize();
pt_1 = (int)((double)pt_0*(height_/hgt_0));
while((pt_0 != pt_1) && (count < 5)) {
tfont = new Font(font_.getName(), font_.getStyle(), pt_1);
if(label_.length() == 0) {
tlayout = new TextLayout(" ", tfont, frc);
} else {
tlayout = new TextLayout(label_, tfont, frc);
}
hgt = (int)(tlayout.getAscent() + tlayout.getDescent());
hgt_1 = layer_.getXDtoP(hgt) - layer_.getXDtoP(0);
del_0 = Math.abs(height_ - hgt_0);
del_1 = Math.abs(height_ - hgt_1);
if((Math.abs(pt_0 - pt_1) <= 1) && (del_0 > del_1)) return tfont;
pt_0 = pt_1;
hgt_0 = hgt_1;
pt_1 = (int)((double)pt_0*(height_/hgt_0));
count++;
}
return tfont;
}
private void drawString(VectorGraphics g2, int x, int y) {
float angle;
if(g2 == null) return;
if(orient_ == SGLabel.HORIZONTAL) {
angle = 0.0f;
} else if(orient_ == SGLabel.VERTICAL) {
angle = -90.0f;
} else {
angle = -(float)angle_;
}
// S.Chekanov
/*
RenderingHints oldRenderingHints = null;
if(angle != 0.0f || alwaysAntiAlias_) {
oldRenderingHints = g2.getRenderingHints();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
*/
AffineTransform oldTransform = g2.getTransform();
// System.out.println("\n angle = " + angle + ", text = " + label_);
// System.out.println("oldTransform = " + oldTransform);
// AttributedString as = new AttributedString(label_);
// as.addAttribute(TextAttribute.FONT, font_);
g2.translate(x, y);
// System.out.println("translated = " + g2.getTransform());
g2.rotate(Math.PI * angle/180.0);
// System.out.println("newTransform = " + g2.getTransform());
// g2.drawString(as.getIterator(), 0, 0);
text.setText( Translate.decode(label_));
text.setFont(font_);
text.setColor(clr_);
text.draw(g2,0,0);
g2.setTransform(oldTransform);
// S.Chekanov
/*
if(angle != 0.0f || alwaysAntiAlias_) {
g2.setRenderingHints(oldRenderingHints);
}
*/
}
public float getStringWidth(VectorGraphics g) {
if(g == null) return 0.0f;
font_ = computeFontSize(g);
FontRenderContext frc = getFontRenderContext(g);
TextLayout tlayout;
if(label_.length() == 0) {
tlayout = new TextLayout(" ", font_, frc);
} else {
tlayout = new TextLayout(label_, font_, frc);
}
java.awt.geom.Rectangle2D tbounds = tlayout.getBounds();
return (float)tbounds.getWidth();
}
public float getStringHeight(VectorGraphics g2) {
if(g2 == null) return 0.0f;
font_ = computeFontSize(g2);
FontRenderContext frc = getFontRenderContext(g2);
TextLayout tlayout;
if(label_.length() == 0) {
tlayout = new TextLayout(" ", font_, frc);
} else {
tlayout = new TextLayout(label_, font_, frc);
}
java.awt.geom.Rectangle2D tbounds = tlayout.getBounds();
return (float)tbounds.getHeight();
}
FontRenderContext getFontRenderContext(VectorGraphics g2) {
if(g2 == null) return null;
RenderingHints oldRenderingHints = null;
if(angle_ != 0.0 || alwaysAntiAlias_) {
oldRenderingHints = g2.getRenderingHints();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
FontRenderContext frc = g2.getFontRenderContext();
if(angle_ != 0.0 || alwaysAntiAlias_) {
g2.setRenderingHints(oldRenderingHints);
}
return frc;
}
}
Ads help maintain this website.