/**
* Circle.java
* Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
*
* 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 3 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, see .
*/
package org.expeditee.items;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.LinkedList;
/**
* @author root
*
*/
public class Circle extends XRayable {
private Item _center;
private Line _line;
/**
* Construct a circle
*
* @param _source
*/
public Circle(Text source) {
super(source);
// Collection- connected = source.getAllConnected();
// assert (connected.size() == 4);
_line = source.getLines().get(0);
_center = _line.getOppositeEnd(_source);
_center.addEnclosure(this);
_line.setHidden(true);
updatePolygon();
}
public Collection
- getItemsToSave() {
Collection
- toSave = super.getItemsToSave();
toSave.add(_center);
return toSave;
}
@Override
public Collection
- getConnected() {
Collection
- conn = super.getConnected();
conn.add(_center);
conn.add(_line);
return conn;
}
@Override
public void addAllConnected(Collection
- connected) {
super.addAllConnected(connected);
if (!connected.contains(_center)) {
connected.add(_center);
connected.add(_line);
}
}
@Override
public boolean isFloating() {
return _center.isFloating() || super.isFloating();
}
@Override
public boolean isEnclosed() {
return true;
}
@Override
public Polygon getEnclosedShape() {
// assert(_poly != null);
// Ensure that vector items will gradient fill are painted OK!!
if (_poly == null) {
updatePolygon();
}
return _poly;
}
@Override
public double getEnclosedArea() {
double radius = getRadius();
return Math.PI * radius * radius;
}
@Override
public Collection
- getEnclosingDots() {
Collection
- enclosed = new LinkedList
- ();
enclosed.add(this);
enclosed.add(_center);
return enclosed;
}
/*
* (non-Javadoc)
*
* @see org.expeditee.items.Item#copy()
*/
@Override
public Item copy() {
Collection
- toCopy = new LinkedList
- ();
toCopy.add(_source);
toCopy.add(_line);
toCopy.add(_center);
Collection
- newItems = ItemUtils.CopyItems(toCopy);
assert (newItems.size() == 3);
// find the Source item from the three items
Text newSource = null;
for (Item i : newItems) {
if (i instanceof Text) {
newSource = (Text) i;
if (ItemUtils.startsWithTag(i, "@c"))
break;
}
}
assert (newSource != null);
Circle newCircle = new Circle(newSource);
Item.DuplicateItem(this, newCircle);
newCircle._line.setVisible(_line.isVisible());
newCircle._source.setVisible(_source.isVisible());
newCircle.updatePolygon();
return newCircle;
}
/**
* Gets the radius of this circle.
*
* @return the radius of the cicle
*/
public double getRadius() {
return _line.getLength();
}
@Override
public boolean contains(int x, int y) {
double radius = getRadius();
double distance = Math.sqrt(Math.pow(Math.abs(_center.getX() - x), 2)
+ Math.pow(Math.abs(_center.getY() - y), 2));
return Math.abs(distance - radius) < getGravity() * 2;
}
/*
* (non-Javadoc)
*
* @see org.expeditee.items.Item#paint(java.awt.Graphics2D)
*/
@Override
public void paint(Graphics2D g) {
int radius = (int) Math.round(getRadius());
int diameter = radius * 2;
Color fillColor = getFillColor();
if (fillColor != null) {
setFillPaint(g);
g.fillOval(_center.getX() - radius, _center.getY() - radius,
diameter, diameter);
}
if (getThickness() > 0 || fillColor == null) {
Color lineColor = getPaintColor();
g.setColor(lineColor);
g.setStroke(_line.getStroke());
g.drawOval(_center.getX() - radius, _center.getY() - radius,
diameter, diameter);
}
// Arc version, same result but allows for portions of the circle to be
// drawn
// g.drawArc(end.getX() - (distance / 2), end.getY() - (distance / 2),
// distance, distance, 0, 360);
if (isHighlighted()) {
// Flag the background color of the circle so that the item will be
// drawn with alternate color if the background is the same as
// the highlight}
_center.paint(g);
Color highlightColor = getHighlightColor();
g.setColor(highlightColor);
g.setStroke(HIGHLIGHT_STROKE);
g.drawOval(_center.getX() - radius, _center.getY() - radius,
diameter, diameter);
}
}
@Override
public void setHighlightMode(HighlightMode mode, Color color) {
_center.setHighlightMode(mode, color);
super.setHighlightMode(mode, color);
}
@Override
public int setHighlightColor(Color c) {
_center.setHighlightColor(c);
return super.setHighlightColor(c);
}
@Override
public void setFillColor(Color c) {
super.setFillColor(c);
_center.setColor(c);
invalidateCommonTrait(ItemAppearence.FillColor);
}
@Override
public void setGradientColor(Color c) {
super.setGradientColor(c);
invalidateCommonTrait(ItemAppearence.GradientColor);
}
// @Override
// public void setPosition(float x, float y) {
// // float deltaX = x - _source._x;
// // float deltaY = y - _source._y;
// // _center.setPosition(_center._x + deltaX, _center._y + deltaY);
// _source.setPosition(x, y);
//
// updatePolygon();
// }
// TODO use an algorithm to get more precicely for contains and intersects
/*
* (non-Javadoc)
*
* @see org.expeditee.items.Item#setAnnotation(boolean)
*/
@Override
public void setAnnotation(boolean val) {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see org.expeditee.items.Item#updatePolygon()
*/
@Override
public void updatePolygon() {
double radius = getRadius();
// Approximation of circle for mouse interaction
int points = 20;
double radians = 0.0;
int xPoints[] = new int[points];
int yPoints[] = new int[xPoints.length];
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] = (int) Math.round(radius * Math.cos(radians));
yPoints[i] = (int) Math.round(radius * Math.sin(radians));
radians += (2.0 * Math.PI) / xPoints.length;
}
_poly = new Polygon(xPoints, yPoints, xPoints.length);
_poly.translate(_center.getX(), _center.getY());
return;
}
@Override
public float getSize() {
return (float) getRadius();
}
/**
* Resizes the circle from the center.
*/
@Override
public void setSize(float size) {
double ratio = size / getRadius();
// Extend the line along the same plane as the underlying line
_source.translate(_center.getPosition(), ratio);
updatePolygon();
}
@Override
public void setLinePattern(int[] pattern) {
_line.setLinePattern(pattern);
}
@Override
public int[] getLinePattern() {
return _line.getLinePattern();
}
@Override
public void translate(Point2D origin, double ratio) {
updatePolygon();
// _center.translate(origin, ratio);
// super.translate(origin, ratio);
}
@Override
public Rectangle[] getDrawingArea() {
float thickness = getThickness();
double radius = getRadius();
int size = (int) ((2 * radius) + 3.0 + thickness);
return new Rectangle[] { new Rectangle((int) (_center.getX() - radius
- 0.5 - (thickness / 2.0)), (int) (_center.getY() - radius
- 0.5 - (thickness / 2.0)), size, size) };
}
// @Override
// public void setPosition(float x, float y){
// float deltaX = x - _source._x;
// float deltaY = y = _source._y;
// _center.setPosition(deltaX, deltaY);
// super.setPosition(x,y);
// }
public Item getCenter() {
return _center;
}
@Override
public void setPermission(PermissionPair permissionPair) {
super.setPermission(permissionPair);
_center.setPermission(permissionPair);
_line.setPermission(permissionPair);
}
@Override
public void scale(Float scale, int originX, int originY) {
getCenter().scale(scale, originX, originY);
super.scale(scale, originX, originY);
}
@Override
public void setThickness(float thick, boolean setConnected) {
super.setThickness(thick, setConnected);
_line.refreshStroke(thick);
}
@Override
public boolean isConnectedToAnnotation() {
return false;
}
}