Swing/TextOnPath のバックアップ(No.2)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/TextOnPath へ行く。
- 1 (2024-09-23 (月) 07:33:42)
- 2 (2024-10-31 (木) 14:01:34)
- category: swing folder: TextOnPath title: Shape上に文字列を配置する tags: [Font, GlyphVector, Shape, Path2D, FlatteningPathIterator] author: aterai pubdate: 2024-09-23T07:31:47+09:00 description: Path2Dなどの曲線上に添うよう文字列を移動・回転して配置します。 image: https://drive.google.com/uc?id=1kBK9anV1EnAjXes9rjN3o57Cyk_Qinnw
概要
Path2D
などの曲線上に添うよう文字列を移動・回転して配置します。
Screenshot
Advertisement
サンプルコード
public static Shape createTextOnPath(Shape shape, GlyphVector gv) {
double[] points = new double[6];
Point2D prevPt = new Point2D.Double();
double nextAdvance = 0d;
double next = 0d;
Path2D result = new Path2D.Double();
int length = gv.getNumGlyphs();
int idx = 0;
PathIterator pi = new FlatteningPathIterator(
shape.getPathIterator(null), 1d);
while (idx < length && !pi.isDone()) {
switch (pi.currentSegment(points)) {
case PathIterator.SEG_MOVETO:
result.moveTo(points[0], points[1]);
prevPt.setLocation(points[0], points[1]);
nextAdvance = gv.getGlyphMetrics(idx).getAdvance() * .5;
next = nextAdvance;
break;
case PathIterator.SEG_LINETO:
double dx = points[0] - prevPt.getX();
double dy = points[1] - prevPt.getY();
double distance = Math.hypot(dx, dy);
if (distance >= next) {
double r = 1d / distance;
double angle = Math.atan2(dy, dx);
while (idx < length && distance >= next) {
double x = prevPt.getX() + next * dx * r;
double y = prevPt.getY() + next * dy * r;
double advance = nextAdvance;
nextAdvance = getNextAdvance(gv, idx, length);
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.rotate(angle);
Point2D pt = gv.getGlyphPosition(idx);
at.translate(-pt.getX() - advance, -pt.getY());
Shape s = gv.getGlyphOutline(idx);
result.append(at.createTransformedShape(s), false);
next += advance + nextAdvance;
idx++;
}
}
next -= distance;
prevPt.setLocation(points[0], points[1]);
break;
default:
}
pi.next();
}
return result;
}
View in GitHub: Java, Kotlin解説
Arc2D
で作成した曲線をFlatteningPathIteratorで平坦化(パスを直線に変更)したPathIterator
に変換- 文字列を
Font#createGlyphVector(...)
でGlyphVector
に変換 GlyphVector#getGlyphOutline(...)
で文字のアウトライン図形を取得Math.hypot(dx, dy)
で移動距離、Math.atan2(dy, dx)
で回転角度を取得してAffineTransform
で文字のアウトライン図形を変換- Fun with Java2D - StrokesのShapeStroke.javaから繰り返しなし、文字間拡張なしを参考
Path2D#append(...)
で変換した文字アウトラインを追加して、Shape
上に文字列を配置したPath2D
を生成