package open.dolphin.impl.scheam.schemastate;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.util.ArrayList;
import open.dolphin.impl.scheam.SchemaEditorImpl;
/**
*
* @author pns
*/
public class DotsState extends AbstractState {
// 塗りの texture
public static final int DOTS_SPARSE = 1;
public static final int DOTS_MEDIUM = 2;
public static final int DOTS_DENSE = 3;
public static final int NET_SPARSE = 4;
public static final int NET_MEDIUM = 5;
public static final int NET_DENSE = 6;
private int density; // 選択範囲にいくつ点を打つか
private int interval; // 領域の辺長当たり何本線を引くか
public DotsState(SchemaEditorImpl context) {
super(context);
}
public void setDots(int dots) {
if (dots == DOTS_SPARSE) density = 10;
else if (dots == DOTS_MEDIUM) density = 20;
else if (dots == DOTS_DENSE) density = 50;
else density = 0;
if (dots == NET_SPARSE) interval = 3;
else if (dots == NET_MEDIUM) interval = 6;
else if (dots == NET_DENSE) interval = 12;
else interval = 0;
properties.setIsFill(false);
}
@Override
public void mouseDown(Point p) {
start = p;
end = null;
first = true;
shape = new GeneralPath();
}
@Override
public void mouseDragged(Point p) {
end = p;
if (first) {
((GeneralPath)shape).moveTo(start.x, start.y);
((GeneralPath)shape).lineTo(end.x, end.y);
first = false;
} else {
((GeneralPath)shape).lineTo(end.x, end.y);
}
canvas.repaint();
start = end;
}
@Override
public void mouseUp(Point p) {
if (shape.getBounds().width !=0 && shape.getBounds().height != 0) {
undoMgr.storeDraw();
((GeneralPath)shape).closePath();
if (density != 0) addPathShape(getRandomDotsPath());
else addPathShape(getReticularPath());
}
// null にしておかないと undo の時などに描画されてしまう
shape = null;
canvas.repaint();
}
/**
* 網状に線を引いた GeneralPath を作る
* @return
*/
private GeneralPath getReticularPath() {
GeneralPath netShape = new GeneralPath();
Rectangle r = shape.getBounds();
int dx = ((r.width+r.height)/2) / interval;
if (dx == 0) return null;
int gap = 0;
for(int y=r.y; y<r.y+r.height; y++) {
for(int x=r.x; x<r.x+r.width+dx; x+=dx) {
int px = x + (gap%dx);
if (shape.contains(px,y)) {
netShape.moveTo(px, y);
netShape.lineTo(px, y);
}
px = x - (gap%dx);
if (shape.contains(px,y)) {
netShape.moveTo(px, y);
netShape.lineTo(px, y);
}
}
gap++;
}
return netShape;
}
/**
* ランダムにドットをうった GeneralPath を作る
* @return
*/
private GeneralPath getRandomDotsPath() {
GeneralPath dotsShape = new GeneralPath();
// shape の外側を覆う Rectangle の中でランダムドットを作成
Rectangle r = shape.getBounds();
java.util.Random rnd = new java.util.Random();
// 作った点の座標を保持する
ArrayList<Point> point = new ArrayList<>();
int maxDistance = Math.min(r.width, r.height);
// int dotsNumber = r.width * r.height * density/10000;
int dotsNumber = density;
// ランダムな点を,できるだけ既存の点から遠くなるように打つ
while(point.size() < dotsNumber) {
boolean done = false;
int d;
for(d = maxDistance ; d > 0; d--){
// 10回ためして見つからなかったら d を下げる
for (int i=0; i < 10; i++) {
double x = r.x + r.width * rnd.nextFloat();
double y = r.y + r.height * rnd.nextFloat();
if (shape.contains(x,y) && getMinimumDistance(point, x, y) >= d) {
point.add(new Point((int)x, (int)y));
maxDistance = d;
done = true;
break;
}
}
if (done) break;
}
// d <= 0 ならもう点を打つ場所はない
if (d <= 0) break;
}
// dot をうつ
for (Point pt : point) {
dotsShape.moveTo(pt.x, pt.y);
dotsShape.lineTo(pt.x, pt.y);
}
return dotsShape;
}
/**
* list の各点と (x,y) との距離を調べて,最小の距離を返す
* @param list
* @param x
* @param y
* @return
*/
private int getMinimumDistance(ArrayList<Point> list, double x, double y) {
double min2 = Double.MAX_VALUE;
double dist2 = 0;
double dx = 0;
double dy = 0;
for(Point p : list) {
dx = p.x - x;
dy = p.y - y;
dist2 = dx*dx + dy*dy;
min2 = (int) Math.min(min2, dist2);
}
return (int) Math.sqrt(min2);
}
@Override
public void draw(Graphics2D g2d) {
if (shape == null) return;
g2d.setStroke(properties.getOutlineStroke());
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2d.setPaint(Color.gray);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.draw(shape);
}
}