【问题标题】:Draw non-overlapping arc between two rectangles在两个矩形之间绘制不重叠的弧线
【发布时间】:2016-10-28 00:01:04
【问题描述】:

我正在尝试绘制连接两个矩形的 (svg) 弧。问题是,弧线应该从矩形的边界开始,而不是从中心开始。

举例说明:

我有矩形C1 w1 h1 C2 w2 h2 的中心点、宽度和高度以及圆弧D rx ry 的中心和x 和y 半径。所以基本上,为了绘制紫色弧线,我缺少P1P2

所有值都是动态的并且可以改变,所以算法需要不知道rxry、矩形的宽度和高度、矩形之间的相对位置等等。

考虑到圆角将是顶部的樱桃。但这不是真的必要..

【问题讨论】:

  • 你总是想画较短的弧线吗?你如何决定你画的两条弧线?
  • 此外,C1 和 C2 始终位于圆弧上,还是只是巧合?
  • @WillemVanOnsem 我从第三点P3 推导出弧线,图中未绘制。 P3 用于编辑圆弧,as described here。是的,弧总是通过中心点C1C2
  • 您是否有理由不采用简单的方法并在从 C1 到 C2 的圆弧顶部绘制不透明矩形?
  • @PaulLeBeau 是的,我在弧的开始/结束处附加箭头(和其他附加信息)。

标签: algorithm math svg


【解决方案1】:

让我们以椭圆的中心为坐标原点(如果不是,只需将矩形坐标移动 -D.X 和 -D.Y)。

在这个系统中,椭圆方程是

 x^2/rx^2 + y^2/ry^2 = 1

在这个方程中替换矩形边缘坐标并检查结果是否真的属于矩形。 例如,顶部矩形的右边缘是X = C1'.X + w1。从椭圆方程中找到 Y 并检查它是否在C1'Y - h1 .. C1'Y + h1 范围内。如果是,P1 = (C1'.X + w1, CalculatedY)

【讨论】:

  • 谢谢!这个想法实际上比我预期的要简单得多。我会检查一下,看看我想出了什么。如果一切顺利,我会将您的答案标记为已接受。
【解决方案2】:

好吧,只为将来可能会偶然发现此问题的人准备..

这是我在 javascript (ES6) 中提出的。但是将其移植到其他语言应该很容易..

/**
 * Calculate the intersection of the border of the given rectangle
 * and a circular arc.
 * @param  {Object} rectangle    Rectangle object with dimensions and position properties.
 * @param  {Object} arc          Arc object with center and radius properties.
 * @return {Object}              Resulting intersection point, with x- and y-coordinates.
 */
calculateBorderPoint(rectangle, arc) {
  // Clone the rectangle, because we don't want to mutate the original.
  const a = Object.assign({}, rectangle.position);

  // Treat center of circle as coordinate origin.
  a.x -= arc.center.x;
  a.y -= arc.center.y;

  let points = [];

  // Check east & west with possible x values
  const possibleX = [
    a.x - rectangle.dimensions.width / 2,
    a.x + rectangle.dimensions.width / 2,
  ];
  possibleX.forEach((x) => {
    const ySquared = [
      Math.sqrt(Math.pow(arc.radius, 2) - Math.pow(x, 2)),
      -Math.sqrt(Math.pow(arc.radius, 2) - Math.pow(x, 2)),
    ];
    // Check if the derived y value is in range of rectangle
    ySquared.forEach((y) => {
      if (y >= a.y - rectangle.dimensions.height / 2 &&
          y <= a.y + rectangle.dimensions.height / 2) {
        points.push({x, y});
      }
    });
  });

  // Check north & south with possible y values
  const possibleY = [
    a.y - rectangle.dimensions.height / 2,
    a.y + rectangle.dimensions.height / 2,
  ];
  possibleY.forEach((y) => {
    const xSquared = [
      Math.sqrt(Math.pow(arc.radius, 2) - Math.pow(y, 2)),
      -Math.sqrt(Math.pow(arc.radius, 2) - Math.pow(y, 2)),
    ];
    // Check if the derived x value is in range of rectangle
    xSquared.forEach((x) => {
      if (x >= a.x - rectangle.dimensions.width / 2 &&
          x <= a.x + rectangle.dimensions.width / 2) {
        points.push({x, y});
      }
    });
  });

  // At this point you will propably have multiple possible solutions,
  // because the circle might intersect the rectangle at multiple points.
  // You need to select the point, that makes most sense in your case.
  // One solution would be to select the one closest to the other rectangle.

  // Translate it back.
  points[0].x += arc.center.x;
  points[0].y += arc.center.y;

  return points[0];
}

它不漂亮,但它有效。我很高兴听到任何建议..

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 2016-12-29
    • 1970-01-01
    • 2015-01-25
    • 2019-08-15
    • 2022-06-10
    • 1970-01-01
    相关资源
    最近更新 更多