在两个矩形之间绘制不重叠的弧

时间:2016-06-25 13:37:52

标签: algorithm math svg

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

举例说明:

Connect two rectangles via an arc

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

所有值都是动态的,可以更改,因此算法需要与rxry无关,矩形的宽度和高度,矩形相对于彼此的位置等等。 / p>

考虑到圆角将成为顶部的樱桃。但那不是必要的......

2 个答案:

答案 0 :(得分:1)

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

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

X = C1'.X + w1

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

答案 1 :(得分:0)

好的,仅适用于将来偶然发现这种情况的人。

这是我在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];
}

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