• category: swing folder: TextOnPath title: Shape上に文字列を配置する tags: [Font, 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などの曲線上に添うよう文字列を回転して配置します。

サンプルコード

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());
            result.append(at.createTransformedShape(gv.getGlyphOutline(idx)), 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(dx, dy)で回転角度を取得してAffineTransformで文字のアウトライン図形を変換
  • Path2D#append(...)で変換した文字アウトラインを追加して、Shape上に文字列を配置したPath2Dを生成

参考リンク

コメント