【问题标题】:How to get the 4 coordinates of a rectangle from 3 coordinates?如何从 3 个坐标中获取矩形的 4 个坐标?
【发布时间】:2019-06-04 08:49:28
【问题描述】:

我想创建一个允许用户从 3 个点(蓝点)绘制矩形的函数:

  • 前两点将形成一条边(宽度)。
  • 第三个点将决定高度。

我需要在传单中使用此自定义绘图功能,但是传单的默认矩形是用 2 个对角点创建的:https://leafletjs.com/reference-1.5.0.html#rectangle

我需要计算其中一个绿点,但我的小脑袋似乎无法弄清楚:P

PS/EDIT:矩形可能是有角度的,这就是它具有挑战性的原因

【问题讨论】:

    标签: geometry leaflet qgis


    【解决方案1】:

    Leaflet 的默认矩形是用 2 个对角点创建的

    [...]

    矩形可能是有角度的,这就是它具有挑战性的原因

    请注意,Leaflet 的 L.Rectangle 是从 L.LatLngBounds 创建的,这是一个其中的边缘隐式与坐标网格对齐的边界框。不要使用边界框,而是依靠L.Polygon,提供所有四个点。


    设 A 和 B 为矩形底边的点,C 为顶边的点。假设所有点都是 {x: Number, y: Number} 形式的 Javascript 结构,并假设您在欧几里得平面上工作(即不在大地水准面的表面上),

    首先,calculate the distance from a point to a line defined by the other two points,即从 C 到 AB 定义的直线的距离。让它成为distance(注意它等于图中的“高度”):

    var distance = Math.abs( 
        (A.y - B.y) * C.x  -  (A.x - B-x) * C.y  +  B.x * A.y  -  B.y * A.x ) 
      ) / Math.sqrt(
        Math.pow(B.y - A.y, 2) + Math.pow(B.x - A.x, 2)
      );
    

    那么,设 AB 为从 A 到 B 的向量

    var AB = {  x: B.x - A.x,   y: B.y - A.y };
    

    (注意 AB 的长度等于图中的“宽度”)

    计算一个垂直于 AB 的unit vector

    var perpendicular = {x: -AB.y, y: AB.x}
    var perpendicularSize = Math.sqrt(AB.x * AB.x + AB.y * AB.y);
    var unit = {x: perpendicular.x / perpendicularSize, y: perpendicular.y / perpendicularSize};
    

    将该单位向量乘以从 C 到 AB 的距离,得到矩形“边”的向量:

    var sideVector = { x: unit.x * distance, y: unit.y * distance };
    

    ...并通过将矩形边的向量偏移 A 和 B 来创建新点 D 和 E:

    var D = { x: A.x + sideVector.x, y: A.y + sideVector.y };
    var E = { x: B.x + sideVector.x, y: B.y + sideVector.y };
    

    ...您的矩形现在由点 ABDE 定义。请注意,C 在点 DE 定义的直线上。

    【讨论】:

    • 太棒了!非常感谢,现在我看了你的回答,我依稀记得很久以前在学校做这个哈哈哈。如果你不介意,我还有一个问题。由于我最终想在传单地图上绘制矩形,投影会影响形状吗?我需要最终的形状是一个有 4 个直角的矩形。我的用例是绘制一个有角度的矩形;最初我采用 2 步方法,绘制矩形然后旋转,但是我可以找到的旋转插件由于投影而扭曲了矩形。这就是我想使用边界的原因,你有什么建议?
    • 是的,预测会搞砸你的计算。这就是为什么我添加了“假设您在欧几里得平面上工作”位。大地水准面表面(或球体表面,就此而言)的几何与欧几里得几何非常不同,例如三角形的角加起来可以超过 180°(想想顶点在北极,赤道在本初子午线,赤道在 90° 子午线的三角形),所以你永远不可能有一个有四个 90° 角的矩形。
    • 实际上,您应该根据测地线几何重新定义您的问题,或者将数据投影到已知的CRS (最好是基于conformal projection 的数据足以满足您的数据)并工作在那个 CRS 上,就好像它是一个欧几里得平面一样。
    • 我明白了。我现在知道了。非常感谢您的解释!这很有趣,很有启发性。
    【解决方案2】:

    假设提供了这 3 个点的坐标, - 2、5(第一点) - 5、5(第二点) - x, 8(第三点)

    第一个绿色将从前两个点中的一个取 x 假设从第一个 => 2,从第三个点取 y => 8 所以第一个绿点在 2,8

    第二个将从第二个点取 x => 5,从第三个点取 y => 8 所以第二个绿点在 5,8

    我不确定我是否正确理解了答案。

    【讨论】:

    • 您好,感谢您的回答。是的,这是基本情况,但它仅在矩形不成角度时才有效(点 1 和点 2 形成的边缘平行于 x 轴)。但是,矩形可能是有角度的。所以会稍微复杂一点。
    • 啊,我明白了,这要复杂得多。现在我也想知道答案。
    【解决方案3】:

    假设 edge1 = [x1,y1] , edge2 = [x2,y2]

    def calculate_edges (edge1,edge2,height)
        edge3 [0] = edge1[0]          //x3
        edge3 [1] = edge1[1] + height //y3
        edge4 [0] = edge2[0]          //x4
        edge4 [1] = edge2[1] + height //y4
    return edge3,edge4
    

    【讨论】:

    • 您好,感谢您的回答。是的,这是基本情况,但它仅在矩形不成角度时才有效(点 1 和点 2 形成的边缘平行于 x 轴)。但是,矩形可能是有角度的。所以会稍微复杂一点
    • 在这里您必须进行地标转换(1-假设 edge1 是您的新地标,2-使用我实现的算法计算其他边缘的坐标,3-计算转换矩阵(从新地标到原始地标)和'-最终找到原始地标中不同边缘的坐标)[imgur.com/a/WNwIMJB]
    【解决方案4】:

    对于 Python:

    #Given three points fit a rectangle
    
    import math 
    a,b,c=[1,4],[3,4],[3,10] #Sample numbers
    
    #Distance from dot C to line AB (https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points)
    distance= abs((b[1]-a[1])*c[0] - (b[0]-a[0])*c[1] + b[0]*a[1] - b[1]*a[0] ) / math.sqrt((b[1]-a[1])**2 + (b[0]-a[0])**2)
    print(distance)
    #let AB be the vector from A to B
    ab=[b[0]-a[0],b[1]-a[1]]
    
    #unit vector perpendicular to AB (https://en.wikipedia.org/wiki/Unit_vector)
    perpendicularSize = math.sqrt(ab[0]**2+ab[1]**2)
    unit = [-ab[1]/perpendicularSize ,ab[0]/perpendicularSize]
    
    #Multiply that unit vector by the distance from C to AB to get the vectors for the "sides" of your rectangle
    sideVector = [unit[0]*distance,unit[1]*distance]
    
    #create new points D and E by offsetting A and B by the vector for the sides of the rectangle
    d=[a[0]+sideVector[0],a[1]+sideVector[1]]
    e=[b[0]+sideVector[0],b[1]+sideVector[1]]
    
    print(e,d)  #[3.0, 10.0] [1.0, 10.0]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-10
      • 2018-06-21
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      • 2018-04-01
      • 2021-02-09
      • 1970-01-01
      相关资源
      最近更新 更多