// $Id: Arrow.java,v 1.8 2010/08/19 09:07:25 olga Exp $
package agg.editor.impl;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Color;
/**
* The Arrow specifies an arrow head on the target side of the arc.
*/
public class Arrow extends Line {
private double angle;
private Point top;
private Point leftEnd;
private Point rightEnd;
private Polygon head;
private int headLength = 12;
private double headAngle = 0.45; // 0.5
private double itsScale = 1.0;
private int tarH;
private int tarW;
/** Creates an arrow head */
public Arrow( Point begin, Point end, int targetWidth,
int targetHeight) {
super(begin.x, begin.y, end.x, end.y);
this.tarW = targetWidth;
this.tarH = targetHeight;
this.head = getHeadPolygon();
}
/** Creates an arrow head */
public Arrow(int x1, int y1, int x2, int y2,
int targetHeight, int targetWidth) {
this(new Point(x1, y1), new Point(x2, y2), targetHeight,
targetWidth);
}
/** Creates an arrow head */
public Arrow(int x1, int y1, int x2, int y2) {
this(new Point(x1, y1), new Point(x2, y2), 0, 0);
}
public Arrow(double scale, Point begin, Point end, int targetWidth,
int targetHeight, int headSize) {
super(begin.x, begin.y, end.x, end.y);
this.tarW = targetWidth;
this.tarH = targetHeight;
if (headSize > 0)
this.headLength = headSize;
this.headLength = (int) ((this.headLength / this.itsScale) * scale);
this.head = getHeadPolygon();
this.itsScale = scale;
}
public Arrow(double scale, int x1, int y1, int x2, int y2,
int targetHeight, int targetWidth, int headSize) {
this(scale, new Point(x1, y1), new Point(x2, y2), targetHeight,
targetWidth, headSize);
}
public Arrow(double scale, int x1, int y1, int x2, int y2) {
this(scale, new Point(x1, y1), new Point(x2, y2), 0, 0, 0);
}
/** Draws the arrow head */
public void draw(Graphics g) {
if (g == null || this.head == null)
return;
g.fillPolygon(this.head);
// g.drawPolygon(this.head);
}
/** Draws the arrow head */
public void draw(Graphics g, boolean filled) {
if (g == null || this.head == null)
return;
if (filled)
g.fillPolygon(this.head);
else {
Color col = g.getColor();
g.setColor(Color.WHITE);
g.fillPolygon(this.head);
g.setColor(col);
g.drawPolygon(this.head);
}
}
/** Returns the head end point of an arrow */
public Point getHeadEnd() {
return this.top;
}
/** Returns the left end point of an arrow */
public Point getLeftEnd() {
return this.leftEnd;
}
/** Returns the right end point of an arrow */
public Point getRightEnd() {
return this.rightEnd;
}
private double getAngle() {
double dX = Math.abs(this.x2 - this.x1);
double dY = Math.abs(this.y2 - this.y1);
double winkel = Math.atan(dY / dX);
// System.out.println("angle : "+winkel);
return winkel;
}
private Point getTopOfHead(int factorX, int factorY) {
this.angle = getAngle();
int halfW = this.tarW / 2;
int halfH = this.tarH / 2;
int d = (int) (Math.tan(this.angle) * halfW);
int topX = this.x2 + halfW * factorX;
int topY = this.y2 + d * factorY;
int ext = 3;
Rectangle tarRect = new Rectangle((this.x2 - halfW - ext),
(this.y2 - halfH - ext), this.tarW + ext * 2, this.tarH + ext * 2);
if (!tarRect.contains(new Point(topX, topY))) {
d = (int) (halfH / Math.tan(this.angle));
topX = this.x2 + d * factorX;
topY = this.y2 + halfH * factorY;
if (!tarRect.contains(new Point(topX, topY)))
return null;
}
// System.out.println("top : "+topX+" , "+topY);
return new Point(topX, topY);
}
private Point getLeftEndOfHead() {
if (this.top == null)
return null;
int xLE = this.top.x - (int) (Math.cos(this.angle - this.headAngle) * this.headLength);
int yLE = this.top.y - (int) (Math.sin(this.angle - this.headAngle) * this.headLength);
return new Point(xLE, yLE);
}
private Point getRightEndOfHead() {
if (this.top == null)
return null;
int xRE = this.top.x - (int) (Math.cos(this.angle + this.headAngle) * this.headLength);
int yRE = this.top.y - (int) (Math.sin(this.angle + this.headAngle) * this.headLength);
return new Point(xRE, yRE);
}
private Polygon getHeadPolygon() {
if ((this.x2 > this.x1) && (this.y2 == this.y1)) // left
{
// System.out.println("left");
this.angle = .0;
this.top = new Point(this.x2 - this.tarW / 2, this.y2);
} else if ((this.x2 < this.x1) && (this.y2 == this.y1)) // right
{
// System.out.println("right");
this.angle = Math.PI;
this.top = new Point(this.x2 + this.tarW / 2, this.y2);
} else if ((this.x2 == this.x1) && (this.y2 > this.y1)) // top
{
// System.out.println("top");
this.angle = Math.PI / 2;
this.top = new Point(this.x2, this.y2 - this.tarH / 2);
} else if ((this.x2 == this.x1) && (this.y2 < this.y1)) // bottom
{
// System.out.println("bottom");
this.angle = Math.PI / 2 + Math.PI;
this.top = new Point(this.x2, this.y2 + this.tarH / 2);
} else if ((this.x2 > this.x1) && (this.y2 > this.y1)) // top left
{
// System.out.println("top left");
this.top = getTopOfHead(-1, -1);
} else if ((this.x2 < this.x1) && (this.y2 < this.y1)) // bottom right
{
// System.out.println("bottom right");
this.top = getTopOfHead(+1, +1);
this.angle = Math.PI + this.angle;
} else if ((this.x2 < this.x1) && (this.y2 > this.y1)) // this.top right
{
// System.out.println("top right");
this.top = getTopOfHead(+1, -1);
this.angle = Math.PI - this.angle;
} else if ((this.x2 > this.x1) && (this.y2 < this.y1)) // bottom left
{
// System.out.println("bootom left");
this.top = getTopOfHead(-1, +1);
this.angle = 2 * Math.PI - this.angle;
} else if ((this.x2 == this.x1) && (this.y2 == this.y1))
{
this.angle = .0;
this.top = new Point(0, 0);
}
// calc left end of head
this.leftEnd = getLeftEndOfHead();
// calc right end of head
this.rightEnd = getRightEndOfHead();
// System.out.println("this.top.x : "+this.top.x);
// System.out.println("xLE : "+this.leftEnd.x+" xRE : "+this.rightEnd.x);
if (this.top == null || this.leftEnd == null || this.rightEnd == null)
return null;
// do polygon
int xArray[] = new int[3];
xArray[0] = this.top.x;
xArray[1] = this.leftEnd.x;
xArray[2] = this.rightEnd.x;
int yArray[] = new int[3];
yArray[0] = this.top.y;
yArray[1] = this.leftEnd.y;
yArray[2] = this.rightEnd.y;
Polygon polygon = new Polygon(xArray, yArray, 3);
return polygon;
}
}