ポリライン(折れ線)やポリゴン(多角形の図形)の情報を持つ PathIterator オブジェクトを Point2D オブジェクトの配列へ変換するサンプル。
2次パラメトリック曲線(SEG_QUADTO)や3次パラメトリック曲線(SEG_CUBICTO)のようなベジェスプライン曲線を含む PathIterator は事前に FlatteningPathIterator 等で平坦化しておくこと。
サンプルソースコード(Path2Points.java)
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
public class Path2Points {
// PathIterator を Point2D へ変換するサンプル
public static void main(String[] args) {
Shape polyline = createPolyline();
Shape polygon1 = createPolygon1();
Shape polygon2 = createPolygon2();
Shape polygon3 = createPolygon3();
// 点列情報を出力
System.out.println("--- polyline ---");
printPoints(path2points(polyline.getPathIterator(null)));
System.out.println("--- polygon1 ---");
printPoints(path2points(polygon1.getPathIterator(null)));
System.out.println("--- polygon2 ---");
printPoints(path2points(polygon2.getPathIterator(null)));
System.out.println("--- polygon3 ---");
printPoints(path2points(polygon3.getPathIterator(null)));
}
private static void printPoints(Point2D[][] p){
for(int i=0; i<p.length; i++){
for(int j=0; j<p[i].length; j++){
System.out.print("(" + p[i][j].getX() + "," + p[i][j].getY() + ")");
}
System.out.println();
}
}
private static Shape createPolyline() {
// 9の字
GeneralPath p = new GeneralPath();
p.moveTo(40, 30);
p.lineTo(10, 30);
p.lineTo(10, 10);
p.lineTo(50, 10);
p.lineTo(50, 50);
p.lineTo(10, 50);
return p;
}
private static Shape createPolygon1() {
// 9の字
Polygon p = new Polygon();
// 外側
p.addPoint(10, 10);
p.addPoint(50, 10);
p.addPoint(50, 60);
p.addPoint(10, 60);
p.addPoint(10, 50);
p.addPoint(40, 50);
p.addPoint(40, 40);
p.addPoint(10, 40);
p.addPoint(10, 10);
// 内側
p.addPoint(20, 20);
p.addPoint(40, 20);
p.addPoint(40, 30);
p.addPoint(20, 30);
p.addPoint(20, 20);
return p;
}
private static Shape createPolygon2() {
// 9の字
//パスの内部を決める偶奇屈曲規則
GeneralPath p = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
// 外側
p.moveTo(10, 10);
p.lineTo(50, 10);
p.lineTo(50, 60);
p.lineTo(10, 60);
p.lineTo(10, 50);
p.lineTo(40, 50);
p.lineTo(40, 40);
p.lineTo(10, 40);
p.lineTo(10, 10);
p.closePath();
// 内側
p.moveTo(20, 20);
p.lineTo(40, 20);
p.lineTo(40, 30);
p.lineTo(20, 30);
p.lineTo(20, 20);
p.closePath();
return p;
}
private static Shape createPolygon3() {
// 9の字
//パスの内部を決める非ゼロ屈曲規則
GeneralPath p = new GeneralPath(GeneralPath.WIND_NON_ZERO);
// 外側
p.moveTo(10, 10);
p.lineTo(50, 10);
p.lineTo(50, 60);
p.lineTo(10, 60);
p.lineTo(10, 50);
p.lineTo(40, 50);
p.lineTo(40, 40);
p.lineTo(10, 40);
p.lineTo(10, 10);
p.closePath();
// 内側
p.moveTo(20, 20);
p.lineTo(40, 20);
p.lineTo(40, 30);
p.lineTo(20, 30);
p.lineTo(20, 20);
p.closePath();
return p;
}
/**
* パスを Point2D の配列へ変換します。
* @param pi 1つまたは複数のパスである PathIterator オブジェクト
* @return Point2D の配列の配列
*/
private static Point2D[][] path2points(PathIterator pi) {
// Point2D の配列の配列
ArrayList pointsList = new ArrayList();
// Point2D の配列
ArrayList currentPoints = new ArrayList();
while (!pi.isDone()) {
double coords[] = new double[6];
int type = pi.currentSegment(coords);
switch (type) {
// 折れ線の場合は moveto で新しい点列の開始
// 多角形の場合は close & moveto で新しい点列の開始
// close の直後に lineto が出現しても問題なくなる
// close 連続は在り得るのか?
case PathIterator.SEG_MOVETO:
if (currentPoints.size() > 0) {
pointsList.add(currentPoints.toArray(new Point2D[currentPoints.size()]));
currentPoints = new ArrayList();
}
// 点を追加
currentPoints.add(new Point2D.Double(coords[0], coords[1]));
break;
case PathIterator.SEG_CLOSE:
if (currentPoints.size() > 0) {
pointsList.add(currentPoints.toArray(new Point2D[currentPoints.size()]));
currentPoints = new ArrayList();
}
break;
case PathIterator.SEG_LINETO:
// 点を追加
currentPoints.add(new Point2D.Double(coords[0], coords[1]));
break;
case PathIterator.SEG_CUBICTO:
// サポート外
throw new IllegalArgumentException("This method don't support PathIterator.SEG_CUBICTO.");
case PathIterator.SEG_QUADTO:
// サポート外
throw new IllegalArgumentException("This method don't support PathIterator.SEG_QUADTO.");
}
pi.next();
}
// close されていない PathIterator の残りを処理
if (currentPoints.size() > 0) {
pointsList.add(currentPoints.toArray(new Point2D[currentPoints.size()]));
}
return (Point2D[][]) pointsList.toArray(new Point2D[pointsList.size()][]);
}
}
出力結果
--- polyline ---
(40.0,30.0)(10.0,30.0)(10.0,10.0)(50.0,10.0)(50.0,50.0)(10.0,50.0)
--- polygon1 ---
(10.0,10.0)(50.0,10.0)(50.0,60.0)(10.0,60.0)(10.0,50.0)(40.0,50.0)(40.0,40.0)(10.0,40.0)(10.0,10.0)(20.0,20.0)(40.0,20.0)(40.0,30.0)(20.0,30.0)(20.0,20.0)
--- polygon2 ---
(10.0,10.0)(50.0,10.0)(50.0,60.0)(10.0,60.0)(10.0,50.0)(40.0,50.0)(40.0,40.0)(10.0,40.0)(10.0,10.0)
(20.0,20.0)(40.0,20.0)(40.0,30.0)(20.0,30.0)(20.0,20.0)
--- polygon3 ---
(10.0,10.0)(50.0,10.0)(50.0,60.0)(10.0,60.0)(10.0,50.0)(40.0,50.0)(40.0,40.0)(10.0,40.0)(10.0,10.0)
(20.0,20.0)(40.0,20.0)(40.0,30.0)(20.0,30.0)(20.0,20.0)
追記: 2007-07-01
多角形の場合は、close時に先頭と末尾が一致していなかったら、末尾に先頭と同じ値を追加する必要がありそう。
先頭と末尾の値が一致していないと、java.awt.* が多角形と認識してくれないから。
PathIterator.SEG_CLOSE のときに
if(!currentPoints.get(0).equals(currentPoints.get(currentPoints.size()-1))){
currentPoints.add(currentPoints.get(0));
}
のような処理を入れておく必要あり。
追記: 2011-02-25
あと、わざわざ記事にしたのは
[Java]PathIterator を Point2D 配列へ変換する
というNI-Lab’.sさんの古い記事が検索トップであったのですが、これが微妙に間違ってるので訂正もかねて。
マウスをShape(PathIterator)の形にドラッグ(移動)させよう - プログラムdeタマゴ
おぉっと。
で、自分で見てみたけど
ってTwitterでつぶやいたら、ありがたいことに解説エントリを書いてもらえたので メモメモ φ(..)
createPolygon2 について、
p.lineTo(10,10);とp.closePath();およびp.lineTo(20,20);とp.closePath();
のどちらかが不要です。
実際にlineToの方を外してGrahpics2Dのdraw(Shape)で描画してみます
きちんと閉じた図が得られました。
ですが、この外した状態ではNI-Lab.さんのコードでは最後の閉じるための点を取得できません。
GeneralPathとPathIteratorの諸注意 - プログラムdeタマゴ
ふむふむ φ( ̄ー ̄ )ノ
というわけで、NI-Lab.さんのPathIterator解読部分のソースコードを修正すると以下の様な感じになります。
case PathIterator.SEG_CLOSE: if (currentPoints.size() > 0) { Point2D.Double d = currentPoints.get(0); currentPoints.add(new Point2D.Double(d.x,d.y)); //ここまでで最後にmoveToされた点の追加が終了 pointsList.add(currentPoints.toArray(new Point2D[currentPoints.size()])); currentPoints = new ArrayList(); //次にlineToが来るときの為に現在の点を追加しておきます currentPoints.add(new Point2D.Double(d.x,d.y)); } break;
GeneralPathとPathIteratorの諸注意 - プログラムdeタマゴ
なるほ。
「次にlineToが来るときの為に現在の点を追加」というのがミソですね。
参考になりました。ありがとうございますm(_ _)m
tags: zlashdot Java Java
Posted by NI-Lab. (@nilab)