Path2Dで指定した隅を丸めたランウド矩形図形を作成する
Total: 399
, Today: 1
, Yesterday: 0
Posted by aterai at
Last-modified:
概要
Path2D
を使用して指定した隅のみをベジェ曲線で丸めたランウド矩形図形を作成します。
Screenshot
Advertisement
サンプルコード
enum Corner { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }
public Shape makeRoundedRect2(
Rectangle2D r, double aw, double ah, Set<Corner> corners) {
double x = r.getX();
double y = r.getY();
double w = r.getWidth();
double h = r.getHeight();
double arh = ah * .5;
double arw = aw * .5;
double kappa = 4d * (Math.sqrt(2d) - 1d) / 3d; // = 0.55228...;
double akw = arw * kappa;
double akh = arh * kappa;
Path2D.Double p = new Path2D.Double();
if (corners.contains(Corner.TOP_LEFT)) {
p.moveTo(x, y + arh);
p.curveTo(
x, y + arh - akh,
x + arw - akw, y,
x + arw, y);
} else {
p.moveTo(x, y);
}
if (corners.contains(Corner.TOP_RIGHT)) {
p.lineTo(x + w - arw, y);
p.curveTo(
x + w - arw + akw,
y, x + w, y + arh - akh,
x + w, y + arh);
} else {
p.lineTo(x + w, y);
}
if (corners.contains(Corner.BOTTOM_RIGHT)) {
p.lineTo(x + w, y + h - arh);
p.curveTo(
x + w, y + h - arh + akh,
x + w - arw + akw,
y + h, x + w - arw, y + h);
} else {
p.lineTo(x + w, y + h);
}
if (corners.contains(Corner.BOTTOM_LEFT)) {
p.lineTo(x + arw, y + h);
p.curveTo(
x + arw - akw, y + h,
x, y + h - arh + akh,
x, y + h - arh);
} else {
p.lineTo(x, y + h);
}
p.closePath();
return p;
}
View in GitHub: Java, Kotlin解説
ROUND_RECTANGLE2D
new RoundRectangle2D.Double(x, y, w, h, aw, ah)
で生成した図形を黒線で描画
SUBTRACT
Rectangle2D
からEllipse2D
を除去して作成した図形で矩形の指定した隅を丸めてランウド矩形を作成し赤線で描画RoundRectangle2D
とEllipse2D
のランウド半径は同一なので指定して丸めた隅は上記の黒色で描画したRoundRectangle2D
と完全に一致する
public Shape makeRoundedRect0(
Rectangle2D rect, double aw, double ah, Set<Corner> corners) {
double x = rect.getX();
double y = rect.getY();
double w = rect.getWidth();
double h = rect.getHeight();
double arw = aw * .5;
double arh = ah * .5;
Area r = new Area(rect);
if (corners.contains(Corner.TOP_LEFT)) {
Area tl = new Area(new Rectangle2D.Double(x, y, arw, arh));
tl.subtract(new Area(new Ellipse2D.Double(x, y, aw, ah)));
r.subtract(tl);
}
if (corners.contains(Corner.TOP_RIGHT)) {
Area tr = new Area(new Rectangle2D.Double(x + w - arw, y, arw, arh));
tr.subtract(new Area(new Ellipse2D.Double(x + w - aw, y, aw, ah)));
r.subtract(tr);
}
if (corners.contains(Corner.BOTTOM_LEFT)) {
Area bl = new Area(new Rectangle2D.Double(x, y + h - arh, arw, arh));
bl.subtract(new Area(new Ellipse2D.Double(x, y + h - ah, aw, ah)));
r.subtract(bl);
}
if (corners.contains(Corner.BOTTOM_RIGHT)) {
Area br = new Area(new Rectangle2D.Double(x + w - arw, y + h - arh, arw, arh));
br.subtract(new Area(new Ellipse2D.Double(x + w - aw, y + h - ah, aw, ah)));
r.subtract(br);
}
return r;
}
PATH2D1
Path2D#curveTo(...)
を使用して指定した隅を丸めたランウド矩形を作成し緑線で描画- ベジェ制御点はラウンド半径を単純に
0.5
倍した点を使用しているので指定して丸めた隅は同じランウド半径を使用したRoundRectangle2D
などと少しずれる
public static Path2D makeRoundedRect1(
Rectangle2D r, double aw, double ah, Set<Corner> corners) {
double x = r.getX();
double y = r.getY();
double w = r.getWidth();
double h = r.getHeight();
double arw = aw * .5;
double arh = ah * .5;
Path2D.Double path = new Path2D.Double();
if (corners.contains(Corner.TOP_LEFT)) {
path.moveTo(x, y + arh);
path.curveTo(x, y + arh, x, y, x + arw, y);
} else {
path.moveTo(x, y);
}
if (corners.contains(Corner.TOP_RIGHT)) {
path.lineTo(x + w - arw, y);
path.curveTo(x + w - arw, y, x + w, y, x + w, y + arh);
} else {
path.lineTo(x + w, y);
}
if (corners.contains(Corner.BOTTOM_RIGHT)) {
path.lineTo(x + w, y + h - arh);
path.curveTo(x + w, y + h - arh, x + w, y + h, x + w - arw, y + h);
} else {
path.lineTo(x + w, y + h);
}
if (corners.contains(Corner.BOTTOM_LEFT)) {
path.lineTo(x + arw, y + h);
path.curveTo(x + arw, y + h, x, y + h, x, y + h - arh);
} else {
path.lineTo(x, y + h);
}
path.closePath();
// path.transform(AffineTransform.getTranslateInstance(x, y));
return path;
}
PATH2D2
Path2D#curveTo(...)
を使用して指定した隅を丸めたランウド矩形を作成し青線で描画RoundRectangle2D
などの円で使用するベジェ制御点と同じラウンド半径を4d * (Math.sqrt(2d) - 1d) / 3d
倍(約0.55228...
倍)した点を使用するため指定して丸めた隅は上記の黒色で描画したRoundRectangle2D
と完全に一致する
参考リンク
- Path2Dで額縁風の図形を作成しBorderとして使用する
- ベジェ曲線による円の描画の制御点の位置はなぜ0.55228…なのか?
- java - How to make half rounded border? - Stack Overflow