Swing/TextOnPath の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/TextOnPath へ行く。
- Swing/TextOnPath の差分を削除
--- 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 --- * 概要 [#summary] `Path2D`などの曲線上に添うよう文字列を移動・回転して配置します。 #download(https://drive.google.com/uc?id=1kBK9anV1EnAjXes9rjN3o57Cyk_Qinnw) * サンプルコード [#sourcecode] #code(link){{ 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; } }} * 解説 [#explanation] - `Arc2D`で作成した曲線を[https://docs.oracle.com/javase/jp/8/docs/api//java/awt/geom/FlatteningPathIterator.html FlatteningPathIterator]で平坦化(パスを直線に変更)した`PathIterator`に変換 -- [[FlatteningPathIteratorでShape上の点を取得する>Swing/FlatteningPathIterator]] - 文字列を`Font#createGlyphVector(...)`で`GlyphVector`に変換 - `GlyphVector#getGlyphOutline(...)`で文字のアウトライン図形を取得 - `Math.hypot(dx, dy)`で移動距離、`Math.atan2(dx, dy)`で回転角度を取得して`AffineTransform`で文字のアウトライン図形を変換 - `Math.hypot(dx, dy)`で移動距離、`Math.atan2(dy, dx)`で回転角度を取得して`AffineTransform`で文字のアウトライン図形を変換 -- [http://www.jhlabs.com/java/java2d/strokes/ Fun with Java2D - Strokes]の[http://www.jhlabs.com/java/java2d/strokes/ShapeStroke.java ShapeStroke.java]から繰り返しなし、文字間拡張なしを参考 - `Path2D#append(...)`で変換した文字アウトラインを追加して、`Shape`上に文字列を配置した`Path2D`を生成 * 参考リンク [#reference] - [http://www.jhlabs.com/java/java2d/strokes/ Fun with Java2D - Strokes] - [[FlatteningPathIteratorでShape上の点を取得する>Swing/FlatteningPathIterator]] * コメント [#comment] #comment #comment