Code
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;
}
References