import math import random import sys import numpy as np # hex 转rgb def hex_to_rgb(hex_color): # 确保输入以 '#' 开头并且长度为 7 if hex_color.startswith('#') and len(hex_color) == 7: # 去掉 '#' 并将字符串拆分为 RGB 部分 hex_rgb = hex_color[1:] # 每两个字符一组转换为十进制数 r = int(hex_rgb[0:2], 16) g = int(hex_rgb[2:4], 16) b = int(hex_rgb[4:6], 16) return r, g, b else: raise ValueError("Invalid hex color code") # 计算旋转角度 def calculate_route(point_1, point_2): a, b = point_1 c, d = point_2 if a == c: return 1 else: return math.atan((d - b) / (c - a)) # 计算旋转坐标 def calculate_route_coordinate(point, route): x = point[0] y = point[1] x1 = x * math.cos(route) + y * math.sin(route) y1 = -x * math.sin(route) + y * math.cos(route) return (x1, y1) def find_point_on_line(A, B, fraction): """ 计算线段AB上距离A点fraction长度处的点C的坐标。 参数: A -- 点A的坐标,形式为(x1, y1) B -- 点B的坐标,形式为(x2, y2) fraction -- 线段AB上距离A点的比例(0到1之间) 返回: 点C的坐标,形式为(x, y) """ x1, y1 = A x2, y2 = B # 使用线性插值计算C点的坐标 x = x1 + (x2 - x1) * fraction y = y1 + (y2 - y1) * fraction return (x, y) def scale_point(x, y, k): """ 缩放二维点坐标。 参数: x, y: 原点的x和y坐标。 k: 缩放因子。 返回: 新的x'和y'坐标。 """ x_prime = k * x y_prime = k * y return x_prime, y_prime # 计算 a点到b点之间1/x处(距离a点)的c点坐标 def calculate_point_c(point_a, point_b, x): x_a, y_a = point_a x_b, y_b = point_b # 计算方向向量 dx = x_b - x_a dy = y_b - y_a # 计算方向向量的模长 distance_ab = math.sqrt(dx ** 2 + dy ** 2) # 计算单位方向向量 unit_vector_x = dx / distance_ab unit_vector_y = dy / distance_ab # 计算点C的坐标 x_c = x_a + (1 / x) * unit_vector_x y_c = y_a + (1 / x) * unit_vector_y return x_c, y_c # 找线段之间某点的坐标 def rotate_point_around_another(point_a, point_b, a): x_a, y_a = point_a x_b, y_b = point_b """ 旋转点A(x_a, y_a)围绕点B(x_b, y_b) a 弧度后的新坐标。 """ # 将A点的坐标转换到以B点为原点的坐标系中 dx = x_a - x_b dy = y_a - y_b # 旋转坐标 x_prime = dx * math.cos(a) - dy * math.sin(a) y_prime = dx * math.sin(a) + dy * math.cos(a) # 将旋转后的坐标转换回原来的坐标系 x_rotated = x_prime + x_b y_rotated = y_prime + y_b return x_rotated, y_rotated def calculate_angle_with_x_axis(point1, point2): x1, y1 = point1 x2, y2 = point2 """ 计算线段(x1, y1)到(x2, y2)与x轴的夹角(以弧度为单位)。 结果角度是从x轴正方向逆时针旋转到线段方向所经过的角度。 """ # 首先计算线段的斜率 if x1 == x2: # 避免除以零 if y2 > y1: return math.pi / 2 # 垂直于x轴且向上 elif y2 < y1: return -math.pi / 2 # 垂直于x轴且向下 else: return 0 # 与x轴重合 else: slope = (y2 - y1) / (x2 - x1) # 使用atan2计算角度,它返回从x轴正方向到点(y, x)的向量与x轴之间的夹角 # 注意:atan2的参数顺序是(y的差, x的差),即(y2-y1, x2-x1) angle_radians = math.atan2(y2 - y1, x2 - x1) return angle_radians def get_color_by_layer(layer_id): return { '1': 53, '2': 83, '3': 133, '4': 173, '5': 162, '6': 77 }.get(layer_id) def min_distance_between_segments(seg1, seg2): """ 计算两条线段之间的最小距离(基于端点之间的最小距离) seg1, seg2: 线段的端点坐标,例如 [(x1, y1), (x2, y2)] """ # 提取端点 p1, p2 = seg1 p3, p4 = seg2 # 计算所有端点之间的距离 dist1 = distance(p1, p3) dist2 = distance(p1, p4) dist3 = distance(p2, p3) dist4 = distance(p2, p4) # 返回最小距离 return min(dist1, dist2, dist3, dist4) def distance(p1, p2): """计算两点之间的距离""" return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) def symmetric_point(A, B): """ 计算点A相对于点B的对称点C的坐标 参数: A -- 点A的坐标,形式为(x_a, y_a) B -- 点B的坐标,形式为(x_b, y_b) 返回: 点C的坐标,形式为(x_c, y_c) """ x_a, y_a = A x_b, y_b = B x_c = 2 * x_b - x_a y_c = 2 * y_b - y_a return x_c, y_c def divide_segment(A, B, x): # A 和 B 是元组,表示线段的两个端点 (x, y) # x 是分割段数 # 计算线段 AB 的长度 length_AB = ((B[0] - A[0]) ** 2 + (B[1] - A[1]) ** 2) ** 0.5 # 计算每段的长度 segment_length = length_AB / (x + 1) # 加1是因为包括端点在内有x+1个点 # 初始化点的列表,包括起点 A points = [A] # 使用线性插值法计算每个分割点的坐标 for i in range(1, x + 1): t = i / (x + 1) # 插值参数,从0到1 Cx = A[0] + t * (B[0] - A[0]) Cy = A[1] + t * (B[1] - A[1]) points.append((Cx, Cy)) # 包括终点 B points.append(B) return points def get_random_id(): return random.randint(0, 99999999) def parallel_line(start, end, distance): """ 计算与给定线段平行且距离为distance的线段(只返回上方的一条)。 参数: start -- 原始线段的起点坐标,形式为(x, y) end -- 原始线段的终点坐标,形式为(x, y) distance -- 平行线段与原始线段的距离 返回: tuple -- 平行线段的起点和终点坐标,形式为((new_start_x, new_start_y), (new_end_x, new_end_y)) """ # 计算原始线段的斜率 if start[0] == end[0]: # 斜率不存在(垂直线) # 对于垂直线,我们只需在x坐标上保持不变,y坐标增减distance new_start = (start[0], start[1] + distance) new_end = (end[0], end[1] + distance) else: # 计算斜率 slope = (end[1] - start[1]) / (end[0] - start[0]) # 计算法线的斜率(负倒数) if slope == 0: slope = 1 normal_slope = -1 / slope # 计算法线方向上从起点到距离distance的点的偏移量 # 注意:这里我们使用勾股定理的简化形式,因为距离是垂直于线段的 # 实际上,我们只需要y方向的偏移量,因为x方向的偏移量由斜率决定 dx = distance / math.sqrt(1 + slope ** 2) dy = slope * dx # 计算新线段的起点和终点 # 注意:这里我们假设距离是正值,只计算上方的平行线 # 如果需要下方的平行线,可以将dy的符号取反 new_start = (start[0] - dy / slope, start[1] + dx) new_end = (end[0] - dy / slope, end[1] + dx) # 注意:上面的计算方式在斜率为负时可能不正确,因为它没有考虑线段的方向 # 一种更健壮的方法是分别计算与start和end距离为distance的点,然后取这两个点作为新线段的端点 # 但为了简单起见,这里我们假设斜率不是负数或垂直线的情况已经处理 # 注意:上面的计算方式在斜率为负或接近0时可能不准确,下面是一个更准确的版本 # 它直接计算与start和end等距的点 # 考虑到斜率可能接近无穷(即几乎垂直),我们使用向量叉积的概念来避免除以0 vector = (end[0] - start[0], end[1] - start[1]) norm = (-vector[1], vector[0]) # 法线向量 norm_length = math.sqrt(norm[0] ** 2 + norm[1] ** 2) unit_norm = (norm[0] / norm_length, norm[1] / norm_length) # 单位法线向量 offset_point_start = (start[0] + unit_norm[0] * distance, start[1] + unit_norm[1] * distance) offset_point_end = (end[0] + unit_norm[0] * distance, end[1] + unit_norm[1] * distance) return (offset_point_start, offset_point_end) def shrink_line(start, end, scale_factor): """ 将线段缩小指定的倍数。 参数: start -- 原始线段的起点坐标,形式为(x, y) end -- 原始线段的终点坐标,形式为(x, y) scale_factor -- 缩小倍数,例如0.5表示缩小到原来的一半 返回: tuple -- 缩小后的线段的起点和终点坐标,形式为((new_start_x, new_start_y), (new_end_x, new_end_y)) """ # 计算原始线段的长度和方向向量 length = ((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2) ** 0.5 direction = ((end[0] - start[0]) / length, (end[1] - start[1]) / length) # 计算缩小后的线段的长度 new_length = length * scale_factor # 计算缩小后的线段的起点和终点 new_start = start new_end = (start[0] + direction[0] * new_length, start[1] + direction[1] * new_length) return (new_start, new_end) # 计算两点之间的欧几里得距离 def euclidean_distance(p1, p2) -> float: return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) # 寻找距离最远的两个点 def farthest_points(points): if len(points) < 2: raise ValueError("至少需要两个点") max_distance = -1 # 初始化为一个较小的值 farthest_pair = (None, None) # 遍历所有点对 for i in range(len(points)): for j in range(i + 1, len(points)): distance_ = euclidean_distance(points[i], points[j]) if distance_ > max_distance: max_distance = distance_ farthest_pair = (points[i], points[j]) return farthest_pair def find_vector_on_d(A,d,route): x1 = A[0]+d*math.sin(math.pi-route) y1 = A[1]+d*math.cos(math.pi-route) x2 = A[0]-d*math.sin(math.pi-route) y2 = A[1]-d*math.cos(math.pi-route) return (x1,y1),(x2,y2) def find_point_on_segment(A, B, d): # 将 A 和 B 转换为 numpy 数组 A = np.array(A) B = np.array(B) # 计算向量 AB AB = B - A # 计算 AB 的长度 AB_length = np.linalg.norm(AB) # 检查 d 是否在 AB 的长度范围内 if d < 0 or d > AB_length: raise ValueError("d is out of range of the segment AB") # 计算单位向量 AB_hat AB_hat = AB / AB_length # 计算向量 AP AP = d * AB_hat # 计算点 P 的坐标 P = A + AP return P