【问题标题】:longest distance from point to rounded rectangle or ellipse点到圆角矩形或椭圆的最长距离
【发布时间】:2015-08-21 16:28:16
【问题描述】:

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

我特别想找出这些情况的距离:

示例 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);
}

【问题讨论】:

  • @ne1410s 见第二行。它从元素中获取半径。还要检查我发布的 codepen 中的示例。
  • 您可以简化尺寸计算,只使用Pythagorean theorem 而不是law of cosines,因为cos(90/180*PI) 为零。
  • @GreenGiant thx 给小费..
  • 中间的数字永远不会出现,对吧?我相信border-radius 默认为width/2height/2 中的最小值,如果它大于其中之一或两者。
  • @Sumurai8 正确。我的错。

标签: javascript trigonometry


【解决方案1】:

基本逻辑解释:

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

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

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

【讨论】:

    【解决方案2】:

    在 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;
    }
    &lt;span id="bound" class="wire"&gt;Area&lt;/span&gt;

    有点证明

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

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

    【讨论】:

    • 存在一些逻辑错误。单击 4 个角中的每一个应始终返回相同的值。但在您的示例中,它从下到上有所不同。在拐角得到半径之前,拐角始终是最远的。然后该点在该圆上移动。这条线并不总是与产生半径的圆心相交,否则它会扩大直径。它是一个secant 的圈子。
    • 我已经修复了一个错误,我使用了rect.bottom 而不是rect.height。底角现在应该给出与顶角相同的数字 +/- 1 像素。至于另一点:见brainjam的回答。如果从我们的点到边缘的线不垂直(或与切线成 90 度角),则有一条较长的线垂直于切线。发生这种情况的唯一地方是我们点的上方、下方、左侧和右侧以及每个角落的直边。毕达哥拉斯告诉我,到拐角处的线总是比直边长。
    • 我添加了一些视觉证据,证明角圆始终是最远的点,并且割线总是比穿过中间的线短,因此垂直于切线.我认为穿过对角中点的线总是在圆上结束,因为中点不能超过height/2width/2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多