从点到圆角矩形或椭圆的最长距离

longest distance from point to rounded rectangle or ellipse

如何找到从形状内部的点到其边界的最长距离。

我特别想为这些情况寻找距离:

示例 3(没有圆角的右侧)将是右下角,但如何计算其他 2 个?

我正在寻找 JavaScript 解决方案,但我也对基本的逻辑解释感到满意。

这是我用来获得最远角的脚本:

Codepen example

// the bounding box
var bound = document.getElementById('bound')
var radius = parseInt(getComputedStyle(bound).borderRadius, 10);
// listen to events
bound.addEventListener('mousedown', getFarthest)

/**
 * get the fartest point from click to border
 **/
function getFarthest(event) {
  // get event coordinates
  var y = event.layerY;
  var x = event.layerX;
  // get event dimensions
  var w = event.target.offsetWidth;
  var h = event.target.offsetHeight;

  // get offset
  var offsetX = Math.abs(w / 2 - x);
  var offsetY = Math.abs(h / 2 - y);

  // get delta
  var deltaX = w / 2 + offsetX;
  var deltaY = h / 2 + offsetY;

  // calculate size
  var size = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2) - 2 * deltaX * deltaY * Math.cos(90 / 180 * Math.PI));

  event.target.innerText = Math.round(size);
}

基本逻辑解释:

您正在寻找形状上的点 X,X 处的切线垂直于红点 P。

矩形是一种特殊情况,因为角没有明确定义的切线。但是你已经处理过那个案子了。

至于椭圆和圆角,我假设你知道如何计算切线(如果不会,Google它)。找到给定点 X=(x,y) 处的切线表达式,以及从 P 到 X 的直线的表达式。当它们垂直时(它们方向的点积为零),你就有了一个候选。计算所有这些候选点,然后找出哪个离P最远。

在 html 中,radius 在角上创建了 4 个圆。我很确定无论你点击哪里,最远的点总是在一个角上,因为到最远点的线与边缘成 90 度角。最远的点也总是在相反的象限中。请注意,在html中,半径不能大于width/2height/2。因此不可能制作出真正的椭圆。

因为直线总是和边成90度角,我们知道直线应该穿过圆的中间。每隔一条线都不能与圆的边缘成 90 度角。要计算距离,我们只需要在我们点击的点和圆的中间之间做毕达哥拉斯。圆心到圆边的距离是已知的,因为那是半径。

密码

// listen to events
bound.addEventListener('mousedown', getFarthest)

/**
 * get the fartest point from click to border
 **/
function getFarthest(event) {
  //In IE the computed border radius is an empty string, causing parseInt to make it NaN.
  var radius = parseInt(window.getComputedStyle(event.target).borderRadius, 10);

  if( radius === NaN ) {
    event.target.innerText = "ERROR";
    console.error( "Computed radius is not a number in this browser." );
    return;
  }
  
  // get event coordinates
  var x = event.offsetX;
  var y = event.offsetY;
  
  //get the width and height of the element
  var rect = event.target.getBoundingClientRect();
  
  //We know that the furthest point is in the opposite quarter, on the rounded bit
  //The greatest distance is the point where the line to the edge has a 90 degrees corner
  //with the edge. This only happens if the line goes through the center of the circle
  //the distance between the center of a circle and it's edge is... the radius.
  //the distance between the center of a circle and a point is simple pythagoras.
  //Thus, we don't need to know where it intersects to find the distance.
  var circleX;
  var circleY;
  
  //Find the middle point of the circle
  if( x < (rect.width / 2) ) {
    circleX = rect.width - radius;
  } else {
    circleX = radius;
  }
  if( y < (rect.height / 2) ) {
    circleY = rect.height - radius;
  } else {
    circleY = radius;
  }
  
  var pythagoras = Math.sqrt( Math.pow( circleX - x, 2 ) + Math.pow( circleY - y, 2 ) );
  
  var distance = pythagoras + radius;

  //Put it in a suitable place
  event.target.innerText = Math.round( distance );
}
body {
  margin: 50px;
  font-family: sans-serif;
  background: #424242;
  overflow: hidden;
}

.wire {
  display: block;

  width: 10em;
  height: 20em;
  box-shadow: 0 0 0 2px;
  font-size: 20px;
  line-height: 20em;
  margin: -10em -5em;
  position: absolute;
  top: 50%;
  left: 50%;
  user-select: none;
  text-align: center;
  border: 0;
  border-radius: 0em;
  background: white;
}

.tracker {
  background: red;
  pointer-events:none;
}
<span id="bound" class="wire">Area</span>

有点证明

此图像显示角始终比形状的边更远。 r 是半径。 abc 是毕达哥拉斯中使用的术语。 c 将始终大于 ab,因此 c + r 将始终大于 a + rb + r

此图显示了为什么割线总是更短。 A线是最长的线。 B线是割线。蓝色条纹圆圈的中间点是 A 线和 B 线的起点,并经过 B 线与我们的圆相交的点。蓝色条纹圆圈上的所有点与直线 A 和 B 的起点的距离相同。正如您可以清楚地看到,线 A 更长,因为它穿过蓝色圆圈。如果要创建一个圆,中间点为 A 和 B 的起点,半径为 A 与圆的相交处,则除了 A 与圆相交的地方外,它不会与我们的形状相交。