// $Id: Loop.java,v 1.8 2010/09/23 08:15:51 olga Exp $
package agg.editor.impl;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import agg.gui.editor.EditorConstants;
/** A Loop specifies a loop representation of arc. */
public class Loop {
public int x, y; // upper left corner ( not center!)
public int w, h;
public Point anchor; // current anchor
public Point anch0; // CENTER
public Point anch1; // UPPER_LEFT
public Point anch2; // UPPER_RIGHT
public Point anch3; // BOTTOM_RIGHT
public Point anch4; // BOTTOM_LEFT
public int anchorID; // current anchor ID
public static final int CENTER = 0;
public static final int UPPER_LEFT = 1;
public static final int UPPER_RIGHT = 2;
public static final int BOTTOM_RIGHT = 3;
public static final int BOTTOM_LEFT = 4;
public static final int DEFAULT_SIZE = 20; //14;
private Color col = new Color(0, 0, 0);
private int min = 14;
/** Create a loop with upper left corner (x,y), width w and height h */
public Loop(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.anch1 = new Point(x, y);
this.anch2 = new Point(x + w, y);
this.anch3 = new Point(x + w, y + h);
this.anch4 = new Point(x, y + h);
this.anch0 = new Point(x + w / 2, y + h / 2);
this.anchorID = UPPER_LEFT;
this.anchor = this.anch1;
}
/**
* Sets the loop to a loop with upper left corner (x,y), width w and height
* h
*/
public void setLoop(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.anch1 = new Point(x, y);
this.anch2 = new Point(x + w, y);
this.anch3 = new Point(x + w, y + h);
this.anch4 = new Point(x, y + h);
this.anch0 = new Point(x + w / 2, y + h / 2);
this.anchorID = UPPER_LEFT;
this.anchor = this.anch1;
}
/** Gets the current anchor */
public Point getAnchor(int id) {
Point myAnchor = null;
switch (id) {
case CENTER:
myAnchor = this.anch0;
break;
case UPPER_LEFT:
myAnchor = this.anch1;
break;
case UPPER_RIGHT:
myAnchor = this.anch2;
break;
case BOTTOM_RIGHT:
myAnchor = this.anch3;
break;
case BOTTOM_LEFT:
myAnchor = this.anch4;
break;
default:
myAnchor = this.anch1;
break;
}
return myAnchor;
}
/** Checks whether the current anchor is on the upper left corner */
public boolean isUPPER_LEFT() {
if ((this.anchor.x == this.anch1.x) && (this.anchor.y == this.anch1.y))
return true;
return false;
}
/** Checks whether the current anchor is on the upper right corner */
public boolean isUPPER_RIGHT() {
if ((this.anchor.x == this.anch2.x) && (this.anchor.y == this.anch2.y))
return true;
return false;
}
/** Checks whether the current anchor is on the bottom right corner */
public boolean isBOTTOM_RIGHT() {
if ((this.anchor.x == this.anch3.x) && (this.anchor.y == this.anch3.y))
return true;
return false;
}
/** Checks whether the current anchor is on the bottom left corner */
public boolean isBOTTOM_LEFT() {
if ((this.anchor.x == this.anch4.x) && (this.anchor.y == this.anch4.y))
return true;
return false;
}
/** Sets a color of the loop */
public void setColor(Color aColor) {
this.col = aColor;
}
/** Draws a black solid loop */
private void drawLoop(Graphics g) {
g.setColor(Color.black);
g.drawLine(this.anch1.x, this.anch1.y, this.anch2.x, this.anch2.y);
g.drawLine(this.anch2.x, this.anch2.y, this.anch3.x, this.anch3.y);
g.drawLine(this.anch3.x, this.anch3.y, this.anch4.x, this.anch4.y);
g.drawLine(this.anch4.x, this.anch4.y, this.anch1.x, this.anch1.y);
}
/** Draws a black solid loop */
public void drawSolidLoop(Graphics g) {
drawLoop(g);
g.setColor(Color.black);
}
/** Draws a colored solid loop */
public void drawColorSolidLoop(Graphics g) {
g.setColor(this.col);
new DrawLine(g, this.anch1.x, this.anch1.y, this.anch2.x, this.anch2.y);
new DrawLine(g, this.anch2.x, this.anch2.y, this.anch3.x, this.anch3.y);
new DrawLine(g, this.anch3.x, this.anch3.y, this.anch4.x, this.anch4.y);
new DrawLine(g, this.anch4.x, this.anch4.y, this.anch1.x, this.anch1.y);
}
/** Draws a colored dotted loop */
public void drawColorDotLoop(Graphics g) {
g.setColor(this.col);
new DrawLine(g, DrawLine.DOTTED, this.anch1.x, this.anch1.y,
this.anch2.x, this.anch2.y);
new DrawLine(g, DrawLine.DOTTED, this.anch2.x, this.anch2.y, this.anch3.x,
this.anch3.y);
new DrawLine(g, DrawLine.DOTTED, this.anch3.x, this.anch3.y, this.anch4.x,
this.anch4.y);
new DrawLine(g, DrawLine.DOTTED, this.anch4.x, this.anch4.y, this.anch1.x,
this.anch1.y);
}
/** Draws a colored dashed loop */
public void drawColorDashLoop(Graphics g) {
g.setColor(this.col);
new DrawLine(g, DrawLine.DASHED, this.anch1.x, this.anch1.y,
this.anch2.x, this.anch2.y);
new DrawLine(g, DrawLine.DASHED, this.anch2.x, this.anch2.y, this.anch3.x,
this.anch3.y);
new DrawLine(g, DrawLine.DASHED, this.anch3.x, this.anch3.y, this.anch4.x,
this.anch4.y);
new DrawLine(g, DrawLine.DASHED, this.anch4.x, this.anch4.y, this.anch1.x,
this.anch1.y);
}
public void drawWeakselectedLoop(Graphics g) {
g.setColor(EditorConstants.weakselectColor); //this.col);
// -1
new DrawLine(g, this.anch1.x-1, this.anch1.y-1, this.anch2.x+1, this.anch2.y-1);
new DrawLine(g, this.anch2.x+1, this.anch2.y-1, this.anch3.x+1, this.anch3.y+1);
new DrawLine(g, this.anch3.x+1, this.anch3.y+1, this.anch4.x-1, this.anch4.y+1);
new DrawLine(g, this.anch4.x-1, this.anch4.y+1, this.anch1.x-1, this.anch1.y-1);
// -2
new DrawLine(g, this.anch1.x-2, this.anch1.y-2, this.anch2.x+2, this.anch2.y-2);
new DrawLine(g, this.anch2.x+2, this.anch2.y-2, this.anch3.x+2, this.anch3.y+2);
new DrawLine(g, this.anch3.x+2, this.anch3.y+2, this.anch4.x-2, this.anch4.y+2);
new DrawLine(g, this.anch4.x-2, this.anch4.y+2, this.anch1.x-2, this.anch1.y-2);
// +1
// new DrawLine(g, this.anch1.x+1, this.anch1.y+1, this.anch2.x-1, this.anch2.y+1);
// new DrawLine(g, this.anch2.x-1, this.anch2.y+1, this.anch3.x-1, this.anch3.y-1);
// new DrawLine(g, this.anch3.x-1, this.anch3.y-1, this.anch4.x+1, this.anch4.y-1);
// new DrawLine(g, this.anch4.x+1, this.anch4.y-1, this.anch1.x+1, this.anch1.y+1);
// +2
// new DrawLine(g, this.anch1.x+2, this.anch1.y+2, this.anch2.x-2, this.anch2.y+2);
// new DrawLine(g, this.anch2.x-2, this.anch2.y+2, this.anch3.x-2, this.anch3.y-2);
// new DrawLine(g, this.anch3.x-2, this.anch3.y-2, this.anch4.x+2, this.anch4.y-2);
// new DrawLine(g, this.anch4.x+2, this.anch4.y-2, this.anch1.x+2, this.anch1.y+2);
}
/**
* Draws a move anchor of this loop.
*
* @param anchorKey
* can be: Loop.UPPER_LEFT / Loop.UPPER_RIGHT / Loop.BOTTOM_RIGHT /
* Loop.BOTTOM_LEFT / Loop.CENTER. Only Loop.UPPER_LEFT is
* implemented.
*/
public void drawMoveAnchor(Graphics grs, int anchorKey) {
Graphics2D g = (Graphics2D) grs;
Color lastColor = g.getColor();
g.setPaint(Line.MOVE_ANCHOR_COLOR);
if (anchorKey == Loop.UPPER_LEFT)
g.fill(new Rectangle(this.anch1.x - Line.MOVE_ANCHOR_OFFSET,
this.anch1.y - Line.MOVE_ANCHOR_OFFSET,
Line.MOVE_ANCHOR_SIZE,
Line.MOVE_ANCHOR_SIZE));
/*
* else if (anchorKey == Loop.UPPER_RIGHT) g.fill(new Rectangle(this.anch2.x -
* 4, this.anch2.y - 4, MOVE_ANCHOR_SIZE, MOVE_ANCHOR_SIZE)); else if
* (anchorKey == Loop.BOTTOM_RIGHT) g.fill(new Rectangle(this.anch3.x - 4,
* this.anch3.y - 4, MOVE_ANCHOR_SIZE, MOVE_ANCHOR_SIZE)); else if (anchorKey ==
* Loop.BOTTOM_LEFT) g.fill(new Rectangle(this.anch4.x - 4, this.anch4.y - 4,
* MOVE_ANCHOR_SIZE, MOVE_ANCHOR_SIZE));
*/
g.setPaint(lastColor);
}
/**
* Moves the loop with source and target specified by the argument Rectangle
* r around x, y specified by the arguments int dx, int dy
*/
public void move(Rectangle r, int anchor_id, int dx, int dy) {
// System.out.println("Loop.move : "+dx+","+dy);
this.anchorID = anchor_id;
if (anchor_id == CENTER)
this.anchor = this.anch0;
else if (anchor_id == UPPER_LEFT)
this.anchor = this.anch1;
else if (anchor_id == UPPER_RIGHT)
this.anchor = this.anch2;
else if (anchor_id == BOTTOM_RIGHT)
this.anchor = this.anch3;
else if (anchor_id == BOTTOM_LEFT)
this.anchor = this.anch4;
if (anchor_id == CENTER)
moveMe(r, dx, dy);
else
resizeMe(r, dx, dy);
}
private void moveMe(Rectangle r, int dx, int dy) {
if (testAnchors(r, dx, dy)) {
// System.out.println(">>> Loop.moveMe CENTER");
this.x = this.x + dx;
this.y = this.y + dy;
}
}
// private void moveMe(int dx, int dy) {
// this.x = this.x + dx;
// this.y = this.y + dy;
// }
private void resizeMe(Rectangle r, int dx, int dy) {
// System.out.println(">>> Loop.resizeMe : "+this.anchorID+" :
// ("+dx+","+dy+")" );
if (this.anchorID == UPPER_LEFT) {
if (testActiveAnchor(r, dx, dy)) {
if (dx < 0 && dy < 0) {
this.x = this.x + dx;
this.y = this.y + dy;
this.w = this.w + Math.abs(dx);
this.h = this.h + Math.abs(dy);
} else if (dx >= 0 && dy >= 0) {
this.x = this.x + dx;
this.y = this.y + dy;
this.w = this.w - dx;
this.h = this.h - dy;
}
}
} else if (this.anchorID == UPPER_RIGHT) {
if (testActiveAnchor(r, dx, dy)) {
if (dx > 0 && dy < 0) {
this.y = this.y + dy;
this.w = this.w + dx;
this.h = this.h + Math.abs(dy);
} else if (dx < 0 && dy > 0) {
this.y = this.y + dy;
this.w = this.w + dx;
this.h = this.h - dy;
}
}
} else if (this.anchorID == BOTTOM_RIGHT) {
if (testActiveAnchor(r, dx, dy)) {
if ((dx > 0 && dy > 0) || (dx < 0 && dy < 0)) {
this.w = this.w + dx;
this.h = this.h + dy;
}
}
} else if (this.anchorID == BOTTOM_LEFT) {
if (testActiveAnchor(r, dx, dy)) {
if (dx < 0 && dy > 0) {
this.x = this.x + dx;
this.w = this.w + Math.abs(dx);
this.h = this.h + dy;
} else if (dx > 0 && dy < 0) {
this.x = this.x + dx;
this.w = this.w - dx;
this.h = this.h + dy;
}
}
}
if ((this.x + this.w) >= (r.x + r.width))
this.w = this.w - ((this.x + this.w) - (r.x + r.width)) * 2;
if ((this.y + this.h) >= (r.y + r.height))
this.h = this.h - ((this.y + this.h) - (r.y + r.height)) * 2;
}
/** Checks whether the Point p is contained within the loop */
public boolean contains(Point p) {
Rectangle r = new Rectangle(this.anch1.x - 5, this.anch1.y - 5,
Line.MOVE_ANCHOR_SIZE + 2, Line.MOVE_ANCHOR_SIZE + 2);
// Rectangle r = new Rectangle(this.x-2, y-2, this.w+4, this.h+4);
if (r.contains(p.x, p.y)) {
return true;
}
return false;
}
private boolean testActiveAnchor(Rectangle r, int dx, int dy) {
Point a1 = new Point(this.anch1.x, this.anch1.y);
Point a2 = new Point(this.anch2.x, this.anch2.y);
Point a3 = new Point(this.anch3.x, this.anch3.y);
Point a4 = new Point(this.anch4.x, this.anch4.y);
int wl = 0, hl = 0;
if (this.anchorID == UPPER_LEFT) {
a1.x = a1.x + dx;
a1.y = a1.y + dy;
a4.x = a4.x + dx;
a2.y = a2.y + dy;
if (dx < 0 && dy < 0) {
wl = this.w + Math.abs(dx);
hl = this.h + Math.abs(dy);
if (inside(r, a1, a2, a3, a4) && outside(r, a1, a2, a3, a4)
&& minWidth(wl) && minHeight(hl))
return true;
return false;
}
wl = this.w - dx;
hl = this.h - dy;
r.setSize((int) (r.getWidth() + 1), (int) (r.getHeight() + 1));
if (inside(r, a1, a2, a3, a4) && outside(r, a1, a2, a3, a4)
&& minWidth(wl) && minHeight(hl))
return true;
return false;
} else if (this.anchorID == UPPER_RIGHT) {
a2.x = a2.x + dx;
a2.y = a2.y + dy;
a1.y = a1.y + dy;
a3.x = a3.x + dx;
if (dx > 0 && dy < 0) {
wl = this.w + dx;
hl = this.h + Math.abs(dy);
if (inside(r, a1, a2, a3, a4) && outside(r, a1, a2, a3, a4)
&& minWidth(wl) && minHeight(hl))
return true;
return false;
}
wl = this.w + dx;
hl = this.h - dy;
r.setSize((int) (r.getWidth() + 1), (int) (r.getHeight() + 1));
if (inside(r, a1, a2, a3, a4) && outside(r, a1, a2, a3, a4)
&& minWidth(wl) && minHeight(hl))
return true;
return false;
} else if (this.anchorID == BOTTOM_RIGHT) {
a3.x = a3.x + dx;
a3.y = a3.y + dy;
a4.x = a4.x + dx;
a2.y = a2.y + dy;
if ((dx > 0 && dy > 0) || (dx < 0 && dy < 0)) {
wl = this.w + dx;
hl = this.h + dy;
}
if (inside(r, a1, a2, a3, a4) && outside(r, a1, a2, a3, a4)
&& minWidth(wl) && minHeight(hl))
return true;
return false;
} else if (this.anchorID == BOTTOM_LEFT) {
a4.x = a4.x + dx;
a4.y = a4.y + dy;
a3.y = a3.y + dy;
a1.x = a1.x + dx;
if (dx < 0 && dy > 0) {
wl = this.w + Math.abs(dx);
hl = this.h + dy;
if (inside(r, a1, a2, a3, a4) && outside(r, a1, a2, a3, a4)
&& minWidth(wl) && minHeight(hl))
return true;
return false;
}
wl = this.w - dx;
hl = this.h + dy;
r.setSize((int) (r.getWidth() + 1), (int) (r.getHeight() + 1));
if (inside(r, a1, a2, a3, a4) && outside(r, a1, a2, a3, a4)
&& minWidth(wl) && minHeight(hl))
return true;
return false;
} else
return false;
}
private boolean inside(Rectangle r, Point a1, Point a2, Point a3, Point a4) {
if (r.contains(a1.x, a1.y) || r.contains(a2.x, a2.y)
|| r.contains(a3.x, a3.y) || r.contains(a4.x, a4.y)) {
return true;
}
return false;
}
/**
* Checks whether the loop ( as a rectangle) specified by the arguments
* Point a1, Point a2, Point a3, Point a4 is outside of the source specified
* by the argument Rectangle r
*/
public boolean outside(Rectangle r, Point a1, Point a2, Point a3, Point a4) {
if (!r.contains(a1.x, a1.y) || !r.contains(a2.x, a2.y)
|| !r.contains(a3.x, a3.y) || !r.contains(a4.x, a4.y))
return true;
return false;
}
private boolean testAnchors(Rectangle r, int dx, int dy) {
Point a1 = new Point(this.anch1.x, this.anch1.y);
Point a2 = new Point(this.anch2.x, this.anch2.y);
Point a3 = new Point(this.anch3.x, this.anch3.y);
Point a4 = new Point(this.anch4.x, this.anch4.y);
a1.x = a1.x + dx;
a1.y = a1.y + dy;
a2.x = a2.x + dx;
a2.y = a2.y + dy;
a3.x = a3.x + dx;
a3.y = a3.y + dy;
a4.x = a4.x + dx;
a4.y = a4.y + dy;
if (inside(r, a1, a2, a3, a4) && outside(r, a1, a2, a3, a4))
return true;
return false;
}
/*
private void setActiveAnchor(Point p) {
Rectangle r1 = new Rectangle(this.anch1.x - 4, this.anch1.y - 4, 8, 8);
Rectangle r2 = new Rectangle(this.anch2.x - 4, this.anch2.y - 4, 8, 8);
Rectangle r3 = new Rectangle(this.anch3.x - 4, this.anch3.y - 4, 8, 8);
Rectangle r4 = new Rectangle(this.anch4.x - 4, this.anch4.y - 4, 8, 8);
Rectangle r0 = new Rectangle(x, y, this.w, this.h);
if (r1.contains(p.x, p.y)) {
this.anchor = this.anch1;
this.anchorID = UPPER_LEFT;
} else if (r2.contains(p.x, p.y)) {
this.anchor = this.anch2;
this.anchorID = UPPER_RIGHT;
} else if (r3.contains(p.x, p.y)) {
this.anchor = this.anch3;
this.anchorID = BOTTOM_RIGHT;
} else if (r4.contains(p.x, p.y)) {
this.anchor = this.anch4;
this.anchorID = BOTTOM_LEFT;
} else if (r0.contains(p.x, p.y)) {
this.anchor = this.anch0;
this.anchorID = CENTER;
// System.out.println(">>> Loop.setActiveAnchor on CENTER");
} else {
this.anchor = null;
this.anchorID = -1;
}
}
*/
private boolean minWidth(int wl) {
if (wl >= this.min)
return true;
return false;
}
private boolean minHeight(int hl) {
if (hl >= this.min)
return true;
return false;
}
}