Znalazłem odpowiedź! :D
Interfejs java.awt.Shape posiada metody getPathIterator(AffineTransform at, double flatness) i getPathIterator(AffineTransform at). Te dwie metody odpowiedzialne są za punkty Shape'a.
Pokażę teraz jak stworzyć Shape'a, aby powstał kwadrat o boku size i współrzędnych (x, y):
1. Tworzymy obiekt QuadratPathIterator, który implementować będzie interfejs PathIterator.
Kopiuj
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
public class QuadratPathIterator implements PathIterator {
private double x, y, size;
private AffineTransform affine;
private int index = 0;
public QuadratPathIterator(AffineTransform affine, double x, double y, double size) {
this.affine = affine;
this.x = x;
this,y = y;
this.size = size;
}
@Override
public int getWindingRule() {
return PathIterator.WIND_NON_ZERO;
}
@Override
public boolean isDone() {
return index > 5;
}
@Override
public void next() {
this.index++;
}
@Override
public int currentSegment(float[] coords) {
if(index == 5) {
return PathIterator.SEG_CLOSE;
coords[0] = (float) this.x;
coords[1] = (float) this.y;
if(index == 1 || index == 2) {
coords[0] += (float) size;
} else if(index == 2 || index == 3) {
coords[1] += (float) size;
}
if(affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return (index == 0 ? PathIterator.SEG_MOVETO : PathIterator.SEG_LINETO);
}
@Override
public int currentSegment(double[] coords) {
if(index == 5) {
return PathIterator.SEG_CLOSE;
coords[0] = this.x;
coords[1] = this.y;
if(index == 1 || index == 2) {
coords[0] += size;
} else if(index == 2 || index == 3) {
coords[1] += size;
}
if(affine != null) {
affine.transform(coords, 0, coords, 0, 1);
}
return (index == 0 ? PathIterator.SEG_MOVETO : PathIterator.SEG_LINETO);
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
public double getSize() {
return this.size;
}
}
Przedstawię teraz po krótce co robią poszczególne metody:
- getWindingRule() - zwraca jedną z wartości: PathIterator.WIND_EVEN_ODD i PathIterator.WIND_NON_ZERO. Określają one jakimi regułami ma ją być "nawijane" segmenty (segment - tu: sposób rysowania linii, wyrażany w int i przyjmujący wartość: PathIterator.SEG_MOVETO, PathIterator.SEG_LINETO, PathIterator.SEG_QUADTO, PathIterator.SEG_CUBICTO lub PathIterator.SEG_CLOSE;
- isDone() - zwraca true jeśli iterator zakończył działanie a false, kiedy jeszcze zwraca elementy. Należy ją tak napisać, aby zwracała true, gdy w iteratorze nie ma już segmentów;
- next() - zwiększa index iteratora, co powoduje, że każde nastęne odwołanie do obiektu dotyczyć będzie innego segmentu;
- currentSegment(float[] coords) - funkcja zwraca używany teraz segment i jako argument podawana jest tablica float[6], która zawierać może maksymalnie trzy pary współrzędnych x i y (każda para to inny punkt). Dla segmentu PathIterator.SEG_MOVETO i PathIterator.SEG_LINETO tablica coords zawiera dwa punkty, dla PathIterator.SEG_QUADTO - trzy, a dla PathIterator.SEG_CUBICTO zawiera cztery. Gdy jest segment PathIterator.SEG_CLOSE, wówczas tablica coords powinna być pusta.
- currentSegment(double[] coords) - powinna wywoływać ten sam efekt co metoda currentSegment(float[] coords)
2. Tworzymy klasę implementującą piękny interfejs Shape:
Kopiuj
import java.awt.Shape;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.Rectangle2D;
public class Quadrat2D implements Shape {
private double x, y, size;
public Quadrat(double x, double y, double size) {
this.x = x;
this.y = y;
this.size = size;
}
@Override
public boolean contains(double x, double y) {
throw new UnsupportedOperationException("Nie chce mi się myśleć nad tą metodą. Napiszcie ją sobie sami :)");
}
@Override
public boolean contains(Point2D p) {
return contains(p.getX(), p.getY());
}
@Override
public boolean contains(Rectangle2D r) {
return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
@Override
public boolean contains(double x, double y, double w, double h) {
throw new UnsupportedOperationException("Nie chce mi się myśleć nad tą metodą. Napiszcie ją sobie sami :)");
}
@Override
public boolean intersects(double x, double y, double w, double h) {
throw new UnsupportedOperationException("Nie chce mi się myśleć nad tą metodą. Napiszcie ją sobie sami :)");
}
@Override
public boolean intersects(Rectangle2D r) {
return this.intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
@Override
public Rectangle getBounds() {
return this.getBounds2D().getBounds();
}
@Override
public Rectangle2D getBounds2D() {
return new Rectangle2D.Double(this.x, this.y, this.size, this.size);
}
@Override
public PathIterator getPathIterator(AffineTransform at) {
return new QuadratPathIterator(at, this.x, this.y, this.size);
}
@Override
public PathIterator getPathIterator(final AffineTransform at, double flatness) {
return new FlatteningPathIterator(getPathIterator(at), flatness);
}
}
- tego mi się zdaje już nie muszę tłumaczyć :)
Możemy teraz cieszyć się z nowego kształtu :D.