在Python中提取完全覆盖矩形空间的随机大小的三角形列表[关闭]

Posted

技术标签:

【中文标题】在Python中提取完全覆盖矩形空间的随机大小的三角形列表[关闭]【英文标题】:Extract list of randomly sized triangles fully covering a rectangular space in Python [closed] 【发布时间】:2022-01-19 21:41:04 【问题描述】:

我正在做一个 python 项目,它需要我将一个矩形空间分成三角形。

    三角形之间不能有重叠或空隙。 必须填充所有矩形区域。 理想情况下三角形的角度和大小应该不同于 以随机的方式彼此。 算法应该返回一个包含所有三角形的列表作为 他们的三个角坐标。

我正在请求一种算法来解决上述问题。

我尝试过的事情。

我一直在寻找可能对我有帮助但没有找到的包和算法。

到目前为止,我曾考虑在顶部边框之后一次创建一个随机三角形,但当我到达相反的垂直边框时会卡住。我不知道如何从那里继续,同时确保没有空间没有三角形。

我也想过只是从边界到边界绘制随机线,但我不知道如何找到由它们的交点创建的所有三角形以及保证所有子区域都是三角形。

任何帮助将不胜感激!


【问题讨论】:

打包,推荐sympy 一种实用的方法是在矩形内添加一些随机定位的点,然后对所有点进行 Delaunay 三角剖分,包括矩形角:en.wikipedia.org/wiki/Delaunay_triangulation 我发现这个问题充分要求一种算法将矩形划分为不相等的三角形。为什么关门了?? 嗨@Jesper,我编辑了你的问题,希望能重新打开它。希望你不介意。 谢谢@paddy3118,我一点也不介意!我将尝试使用我目前收到的反馈来解决它,但如果它被重新打开,将始终欢迎更多反馈/讨论! 【参考方案1】:

如果你想在矩形上画一条对角线,你已经实现了 2 个三角形的目标,每个三角形都是矩形面积的一半。

对于多个三角形,从任意一个角开始,从它画一条线到另一侧(不相邻)的随机点。使用该点在原边上绘制另一条线(不断增加 X 位置)。

最后绘制的线必须与原边的对角相交。

将每个三角形的坐标保存为 3 个元组。例如,第一个三角形的第一个元组可能是 0,0,具体取决于屏幕的点编号命名法。

【讨论】:

【参考方案2】:

算法

想象一个没有旋转的矩形躺在一个平面上。让我们这样命名角 A、B、C 和 D:

A        B

D        C

加一点,p between-but-not-equal-to A and B give

A p      B

D        C

创建两条额外的线 D-p 和 p-C,创建 3 个三角形 A-p-D、D-p-C 和 p-B-C。现在,如果距离 A-p、p-B 和 B-C 都不同,那么三角形也会不同。

如果我们改为在 A-B、p0 和 p1 之间插入 两个 点,我们可以沿 D-C 插入 一个 点 q0

  0  1
A p  p   B
  
D   q    C
    0

我们认为从左到右排序的顶点是 A p0 p1 然后 B;并且有序的 l 到 R 底部点为 D q0 然后 C。

使用第 i 个、第 (i+1) 个顶点和第 i 个底部点创建三角形;与第 (i)' 个第 (i+1)' 个底点和第 (i+1) 个顶点交替出现。 确保连续顶点 B-C 和连续底部点之间的距离都不同,以获得不同的三角形。 如果你插入ntop points p,那么你需要n-1 bottom points q。

我会随机划分A-B n次,D-C n-1次;如果所有距离都与您所需的精度没有差异,则重做此操作。

您没有要求提供代码,但 A B C 和 D 点有助于解释上面的内容,但如果我编写此代码,我将使用两个数组 P 和 Q,其中

P[0] = A; P[max_p] = B; Q[0] = D; Q[max_p] = C;
P[i+1] = p[i]; Q[i+1] = q[i]

这将简化三角形的创建。

代码

这是我写的一些 Python:

# -*- coding: utf-8 -*-
"""
For: https://***.com/questions/70385109/extract-list-of-randomly-sized-triangles-fully-covering-a-rectangular-space-in-p/70390360#70390360


Created on Fri Dec 17 08:47:03 2021

@author: paddy
"""
import random
from typing import List, Union, Tuple


# Types
Num = Union[int, float]
Point = Tuple[Num, Num]


def rect_into_tri(
        top_right: Tuple[Num, Num] = (2, 1), # assuming bottom_left is at 0,0
        triangles: int             = 5,      # Odd number > 2
        _rand_tol: Num             = 1e6,    # Sets max random divisions of rectange width
        ) -> List[Tuple[Point, Point, Point]]:
    """
    Divide Rectangle into triangles number of non-similar triangles that 
    exactly cover the rectangles area.

    Parameters
    ----------
    top_right : Tuple[Num, Num], optional
        Rectangle bottom-left is (0, ). The default is (2, 1).
    triangles : int, optional
        Number of triangles created. An odd number > 2. The default is 5.
    _rand_tol : Num, optional
        Sets max random divisions of rectange width. The default is 1e6.

    Returns
    -------
    List[Tuple[Point, Point, Point]]
        A list of triangles; each of three points - of two numbers.

    """

    width, height = top_right
    assert triangles > 2 and triangles % 2 == 1, "Needs Odd number greater than 2"
    #assert triangles * 100 < _rand_tol, "Might not have enough tolerance to ensure disimilar triangles"
    
    _rand_tol = int(_rand_tol)
    
    #%% Point insertion
    insert_top = triangles // 2
    p = q = None
    while not p or not different_distances(p, q, height):
        p = [0] + rand_points(insert_top,     width, int(_rand_tol)) + [width]  # top points 
        q = [0] + rand_points(insert_top - 1, width, int(_rand_tol)) + [width]  # bottom points
    
    #%% Triangle extraction
    top_tri = [((t0, height), (t1, height), (b0, 0))
               for t0, t1, b0 in zip(p, p[1:], q)]
    bottom_tri = [((b0, 0), (b1, 0), (t1, height))
                  for b0, b1, t1 in zip(q, q[1:], p[1:])]
    
    return top_tri + bottom_tri

#%% Helpers
def rand_points(n: int, width: Num=1, _rand_tol: int=1_000_000) -> List[float]:
    "return n sorted, random points where 0 < point < width"
    return sorted(p * width / _rand_tol 
                  for p in random.sample(range(1, _rand_tol), n))
        
def different_distances(p: List[Num], q: List[Num], height: Num) -> bool:
    "Are all point-to-next-point distances in p and q; and height all different?"
    diffs =  [p1 - p0 for p0, p1 in zip(p, p[1:])]
    diffs += [q1 - q0 for q0, q1 in zip(q, q[1:])]
    diffs += [height]
    return len(diffs) == len(set(diffs))


if __name__ == "__main__":
    from pprint import pprint as pp
    
    pp(rect_into_tri((2, 1), 5, 10))

样本输出

[((0, 1), (0.2, 1), (0, 0)),
 ((0.2, 1), (0.8, 1), (0.4, 0)),
 ((0.8, 1), (2, 1), (2, 0)),
 ((0, 0), (0.4, 0), (0.2, 1)),
 ((0.4, 0), (2, 0), (0.8, 1))]

【讨论】:

以上是关于在Python中提取完全覆盖矩形空间的随机大小的三角形列表[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

查找覆盖原始矩形的旋转矩形的大小

在 Python 中覆盖命名空间

随机将N个圆放置在矩形中而没有重叠

OpenGL随机大小矩形代码更改绘制的矩形

JS_生成随机矩形位置/矩形大小_面向对象_原型+构造函数模式

即使在 SwiftUI 中调整矩形大小,如何将点转换为 Rectangle 的点?