不规则多边形等比例缩小及等间距缩小算法

不规则多边形等间距等比例缩小

等间距缩小算法

原理参考:https://blog.csdn.net/leon_zeng0/article/details/73500174

多边形的重心点为 G ( x , y ) G(x,y) G(x,y),重心的求解方法见我的另外一篇博客不规则多边形重心求解。设需要向内缩进的距离为 L L L,则
∣ v 1 ∣ = ∣ v 2 ∣ \left |\boldsymbol{v_1}\right |=\left |\boldsymbol{v_2} \right | v1=v2
A ′ A' A的坐标可以表示为
A ′ = A + ( v 1 + v 2 ) = A + L sin ⁡ θ ( v 1 ∣ v 1 ∣ + v 2 ∣ v 2 ∣ ) A'=A+(\boldsymbol{v_1}+\boldsymbol{v_2})=A+\frac{L}{\sin{\theta}}\left ( \frac{\boldsymbol{v_1}}{\left |\boldsymbol{v_1}\right |} + \frac{\boldsymbol{v_2}}{\left |\boldsymbol{v_2}\right |}\right ) A=A+(v1+v2)=A+sinθL(v1v1+v2v2)
其中,
sin ⁡ θ = ∣ v 1 × v 2 ∣ ∣ v 1 ∣ ∣ v 2 ∣ \sin{\theta}=\frac{\left |\boldsymbol{v_1} \times \boldsymbol{v_2}\right |}{\left |\boldsymbol{v_1}\right |\left |\boldsymbol{v_2}\right |} sinθ=v1v2v1×v2

  • 创建内部等间距点
def create_equal_dist_points(points, L, gravity_point):
    """
    @brief      创建等间距的边界内点
    @param      points         The points
    @param      L         间距
    @param      gravity_point  重心
    @return     创建等间距点
    """
    # 判断输入条件
    if len(points) <= 2 or not gravity_point:
        return list()

    length = len(points)
    # 获取边的单位向量
    normal_vector = list()
    for i in range(length):
        vector_x = points[(i + 1) % length][0] - points[i][0]
        vector_y = points[(i + 1) % length][1] - points[i][1]
        normal_vector_x = vector_x / math.sqrt(vector_x ** 2 + vector_y ** 2)
        normal_vector_y = vector_y / math.sqrt(vector_x ** 2 + vector_y ** 2)
        normal_vector.append([normal_vector_x, normal_vector_y])

    # 获取夹角
    theta = list()
    for i in range(length):
        x1 = normal_vector[i][0]
        y1 = normal_vector[i][1]
        x2 = normal_vector[(i - 1) % len(points)][0]
        y2 = normal_vector[(i - 1) % len(points)][1]
        sin_theta = abs(x1 * y2 - x2 * y1)
        theta.append(sin_theta)

    # 计算向内扩展的点坐标
    new_points = list()
    for i in range(length):
        point = points[i]
        x1 = -normal_vector[(i - 1) % len(points)][0]
        y1 = -normal_vector[(i - 1) % len(points)][1]
        x2 = normal_vector[i][0]
        y2 = normal_vector[i][1]
        add_x = L / theta[i] * (x1 + x2)
        add_y = L / theta[i] * (y1 + y2)
        new_point_x = point[0] + add_x
        new_point_y = point[1] + add_y
        new_point = [new_point_x, new_point_y]
        # 判断点是否在里面,如果不在减去2倍的矢量增量
        if get_distance(new_point, gravity_point) > get_distance(point, gravity_point):
            new_point[0] -= 2 * add_x
            new_point[1] -= 2 * add_y

        new_points.append(new_point)
    return new_points

其中的 get_distance 函数定义如下

def get_distance(point1, point2):
    """
    @brief      计算两点之间的距离
    @param      point1  The point 1
    @param      point2  The point 2
    @return     The distance.
    """
    diff = [(point1[x] - point2[x]) for x in range(2)]
    dist = math.sqrt(diff[0] ** 2 + diff[1] ** 2)
    return dist

等比例缩小算法

多边形的重心点位置为 G ( x , y ) G(x,y) G(x,y),设缩小比例为 λ \lambda λ,那么根据向量的比例关系可以得到
λ G A ⃗ = G A ′ ⃗ \lambda \vec{GA}= \vec{G{A}'} λGA =GA

A A A的坐标为 A ( x 1 , y 1 ) A(x_1,y_1) A(x1,y1) A ’ A’ A的坐标为 A ′ ( x ′ , y ′ ) A'(x',y') A(x,y),那么根据上述公式即可求得

{ x ′ = λ ( x 1 − x ) + x y ′ = λ ( y 1 − y ) + y \left\{\begin{matrix} x' =\lambda(x_1-x)+x\\ y' =\lambda(y_1-y)+y \end{matrix}\right. {x=λ(x1x)+xy=λ(y1y)+y

  • 创建内部等比例点
def create_equal_ratio_points(points, ratio, gravity_point):
    """
    @brief      创建等比例的点
    @param      points         The points
    @param      ratio          The ratio
    @param      gravity_point  The gravity point
    @return     { description_of_the_return_value }
    """
    # 判断输入条件
    if len(points) <= 2 or not gravity_point:
        return list()

    new_points = list()
    length = len(points)

    for i in range(length):
        vector_x = points[i][0] - gravity_point[0]
        vector_y = points[i][1] - gravity_point[1]
        new_point_x = ratio * vector_x + gravity_point[0]
        new_point_y = ratio * vector_y + gravity_point[1]
        new_point = [new_point_x, new_point_y]
        new_points.append(new_point)
    return new_points

判断点是否位于多边形内部

参考W. Randolph Franklin 提出的PNPoly算法https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html ,总体来说就是使用射线法,代码很简单。

enter image description here

假设条件

  1. 射线经过的点属于射线以上的一侧
  2. 点与多边形顶点重合直接算内部点

判断准则:

如果以测试点为起点发出一条射线,经过多边形的边数为奇数,那么该点就位于多边形内,否则位于多边形外面。

在上图中,点X经过了两条边,属于外部点,点Y经过了BC这条边,所以属于内部点,点Z没有经过任何边(边数为0),所以属于外部点。

对于不规则的多边形,判断算法步骤为

  1. 如果测试点是顶点,则返回True
  2. 如果测试点位于多边形的AABB最小包围盒之外,则直接返回False
  3. 开始依次遍历所有的顶点
  4. 如果被测试点位于本次循环的两个相邻点纵坐标范围之内并且位于两个相邻点拟合直线的下方,则对返回的布尔量取反
  5. 返回布尔量
  • 射线法判断点是否位于多边形内部
def is_inner_point(points, test_point):
    """
    @brief      判断一个点是否在多边形的内部
    @param      points      多边形外围点,按顺序存储
    @param      test_point  测试点
    @return     True if inner point, False otherwise.
    """
    # 输入是否合理
    if not test_point or not points or len(points) <= 2:
        return False

    # 是否为边界顶点
    if test_point in points:
        return True

    x = test_point[0]
    y = test_point[1]
    # 判断是否在多边形的AABB包围盒之内,如果不在,则不需要进行后续的判断
    xmin = np.min([index[0] for index in points])
    xmax = np.max([index[0] for index in points])
    ymin = np.min([index[1] for index in points])
    ymax = np.max([index[1] for index in points])
    if (x < xmin) or (x > xmax) or (y < ymin) or (y > ymax):
        return False

    # 根据射线法判断
    res = False
    length = len(points)
    for i in range(length):
        x1 = points[i][0]
        y1 = points[i][1]
        x2 = points[(i - 1) % len(points)][0]
        y2 = points[(i - 1) % len(points)][1]
        # 判断纵坐标y是否在本次循环所测试的两个相邻点纵坐标范围之内
        if (y2 > y) != (y1 > y):
            # 判断点是否在两点直线下方
            if x < ((x2 - x1) * (y - y1) / (y2 - y1) + x1):
                res = not res
    return res
  • 4
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值