经典算法-分治法由散点得出凸包-python实现

import copy
import random
import matplotlib
import math


def distance_p2l(point, line_point1, line_point2):
    if (line_point2[0] - line_point1[0]) == 0:
        return abs(point[0] - line_point2[0])
    # 计算直线的斜率
    m = (line_point2[1] - line_point1[1]) / (line_point2[0] - line_point1[0])
    # 计算直线的截距
    b = line_point1[1] - m * line_point1[0]
    # 计算距离
    d = abs(m * point[0] - point[1] + b) / math.sqrt(m ** 2 + 1)
    return d


def node_above_line(node, line0, line1,upper_convex=True,left_convex=True):
    real_y = node[1]
    # y_on_line =(node[0]-line0[0])/(line1[0]-line0[0])*(line1[1]-line0[1])+line0[1]

    if (line1[0] - line0[0])!=0:
        print(node[1],
              node[0] - line0[0] / (line1[0] - line0[0]) * (line1[1] - line0[1]) + line0[
                  1])
        if node[1] > (node[0]-line0[0])/(line1[0]-line0[0])* (line1[1]-line0[1])+line0[1]:

            return True
        else:
            return False
    else:
        if node[0]<line0[0]:
            if upper_convex==True:
                if left_convex:
                    return True
                else:
                    return False
            if upper_convex==False:
                if left_convex:
                    return False
                else:
                    return True

        else:
            if upper_convex == True:
                if left_convex:
                    return False
                else:
                    return True
            if upper_convex==False:
                if left_convex:
                    return True
                else:
                    return False

def cal_convex_hull_point(min_x_node, max_x_node, upper_set,upper_convex=True):
    if len(upper_set) == 0:
        return [min_x_node, max_x_node]
    upper_set_distance2line = [distance_p2l(point, max_x_node, min_x_node) for point in upper_set]
    max_idx = upper_set_distance2line.index(max(upper_set_distance2line))
    farthest_p = upper_set[max_idx]
    upper_set_mins =  [node for node in upper_set if node != farthest_p]
    left_subset_of_upper, right_subset_of_upper = [], []
    for node in upper_set_mins:
        if node_above_line(node, farthest_p, min_x_node,upper_convex=upper_convex,left_convex=True)==upper_convex:
            left_subset_of_upper.append(node)
        if node_above_line(node, farthest_p, max_x_node,upper_convex=upper_convex,left_convex=False)==upper_convex:
            right_subset_of_upper.append(node)
    lu = cal_convex_hull_point(min_x_node,farthest_p,left_subset_of_upper,upper_convex)
    ru = cal_convex_hull_point(farthest_p,max_x_node,right_subset_of_upper,upper_convex)
    return lu+ru



def divide_conquer(nodes):
    sorted_nodes = sorted(nodes, key=lambda x: x[0])
    max_x_node = sorted_nodes[-1]
    min_x_node = sorted_nodes[0]
    upper_set = []
    lower_set = []
    lu,ru,ll,rl = [],[],[],[]
    for node in sorted_nodes[1:-1]:
        if node_above_line(node, max_x_node, min_x_node):
            upper_set.append(node)
        else:
            lower_set.append(node)
    if len(upper_set)!=0:
        upper_set_distance2line = [distance_p2l(point, max_x_node, min_x_node) for point in upper_set]
        max_idx = upper_set_distance2line.index(max(upper_set_distance2line))
        farthest_p = upper_set[max_idx]
        upper_set_mins = [node for node in upper_set if node != farthest_p]
        left_subset_of_upper, right_subset_of_upper = [], []
        for node in upper_set_mins:
            if node_above_line(node, farthest_p, min_x_node,left_convex=True):
                left_subset_of_upper.append(node)
            if node_above_line(node, farthest_p, max_x_node,left_convex=False):
                right_subset_of_upper.append(node)
        lu = cal_convex_hull_point(min_x_node, farthest_p, left_subset_of_upper)
        ru = cal_convex_hull_point(farthest_p, max_x_node, right_subset_of_upper)
    if len(lower_set) != 0:
        lower_set_distance2line = [distance_p2l(point, max_x_node, min_x_node) for point in lower_set]
        max_idx = lower_set_distance2line.index(max(lower_set_distance2line))
        farthest_p = lower_set[max_idx]
        lower_set_mins = [node for node in lower_set if node != farthest_p]
        left_subset_of_lower, right_subset_of_lower = [], []
        for node in lower_set_mins:
            if node_above_line(node, farthest_p, min_x_node,upper_convex=False,left_convex=True)==False:
                left_subset_of_lower.append(node)
            if node_above_line(node, farthest_p, max_x_node,upper_convex=False,left_convex=False)==False:
                right_subset_of_lower.append(node)
        ll = cal_convex_hull_point(min_x_node, farthest_p, left_subset_of_lower,upper_convex=False)
        rl = cal_convex_hull_point(farthest_p, max_x_node, right_subset_of_lower,upper_convex=False)

    point_set = list(set(ll + lu + rl + ru))
    print("set point",point_set)
    convex0 = lu + ru
    convex1 = ll + rl
    convex0 = [convex0[i] for i in range(len(convex0)) if i==0 or i>0 and convex0[i]!=convex0[(i-1)]]
    convex1 = [convex1[i] for i in range(len(convex1)) if i==0 or i>0 and convex1[i] != convex1[i - 1]]
    convex1 = [convex1[i] for i in range(len(convex1) - 1, -1, -1)]
    convex  = convex0 +convex1
    convex = convex + [convex[0]]
    print("lines are ", convex)
    return convex


def draw_points(points, convex_p=None):
    import matplotlib.pyplot as plt
    plt.ion()
    # 输入点的坐标
    # points = [(0, 55), (40, 93), (20, 70), (10, 60)]  # 示例坐标

    # 分离 x 和 y 坐标
    x_coords = [point[0] for point in points]
    y_coords = [point[1] for point in points]

    # 绘制点
    plt.scatter(x_coords, y_coords, color='blue')

    if convex_p != None:
        c_x = [p[0] for p in convex_p]
        c_y = [p[1] for p in convex_p]
        colors = ['red'] * len(c_y)
        plt.scatter(c_x, c_y, color=colors)
        plt.plot(c_x, c_y, color='red')
    # 添加标题和坐标轴标签
    plt.title('Scatter Plot of Points')
    plt.xlabel('X Coordinate')
    plt.ylabel('Y Coordinate')
    plt.pause(5)
    plt.ioff()
    plt.clf()

def pnpoly(vertices, testp):
    n = len(vertices)
    j = n - 1
    res = False
    for i in range(n):
        if (vertices[i][1] > testp[1]) != (vertices[j][1] > testp[1]) and \
                testp[0] < (vertices[j][0] - vertices[i][0]) * (testp[1] - vertices[i][1]) / (
                vertices[j][1] - vertices[i][1]) + vertices[i][0]:
            res = not res
        j = i
    return res


for i in range(38,100):
    print('seed',i)
    random.seed(i)
    nodes = [(random.randint(0, 100), random.randint(0, 100)) for i in range(10)]
    print(nodes)
    draw_points(nodes)
    convex_p = divide_conquer(nodes)

    draw_points(nodes, convex_p)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值