概要

Path2Dを使用して指定した隅のみをベジェ曲線で丸めたランウド矩形図形を作成します。

サンプルコード

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を除去して作成した図形で矩形の指定した隅を丸めてランウド矩形を作成し赤線で描画
    • RoundRectangle2DEllipse2Dのランウド半径は同一なので指定して丸めた隅は上記の黒色で描画した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と完全に一致する

参考リンク

コメント