core.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. import math
  2. import sys
  3. import numpy as np
  4. # hex 转rgb
  5. def hex_to_rgb(hex_color):
  6. # 确保输入以 '#' 开头并且长度为 7
  7. if hex_color.startswith('#') and len(hex_color) == 7:
  8. # 去掉 '#' 并将字符串拆分为 RGB 部分
  9. hex_rgb = hex_color[1:]
  10. # 每两个字符一组转换为十进制数
  11. r = int(hex_rgb[0:2], 16)
  12. g = int(hex_rgb[2:4], 16)
  13. b = int(hex_rgb[4:6], 16)
  14. return r, g, b
  15. else:
  16. raise ValueError("Invalid hex color code")
  17. # 计算某线段1/4点处的法线上距离该线段5个长度的坐标
  18. def point_on_line(A, B, t):
  19. # 根据参数 t 计算线段 AB 上的点
  20. x = A[0] + t * (B[0] - A[0])
  21. y = A[1] + t * (B[1] - A[1])
  22. return (x, y)
  23. def normal_vector(A, B):
  24. # 计算线段 AB 的方向向量,并返回其法向量
  25. dx = B[0] - A[0]
  26. dy = B[1] - A[1]
  27. # 法向量可以选择 (-dy, dx) 或 (dy, -dx),这里选择 (-dy, dx)
  28. return (-dy, dx)
  29. def find_vector_on_d(A,d,route):
  30. x1 = A[0]+d*math.sin(math.pi-route)
  31. y1 = A[1]+d*math.cos(math.pi-route)
  32. x2 = A[0]-d*math.sin(math.pi-route)
  33. y2 = A[1]-d*math.cos(math.pi-route)
  34. return (x1,y1),(x2,y2)
  35. def offset_point(point, normal, distance):
  36. # 在点 point 处的法线 normal 上距离 distance 的点
  37. nx, ny = normal
  38. px, py = point
  39. offset_x = distance * nx
  40. offset_y = distance * ny
  41. return (px + offset_x, py + offset_y), (px - offset_x, py - offset_y)
  42. def line_point_normal_distance(A, B, t, distance):
  43. # 计算线段 AB 上参数为 t 的点处的法线上距离线段 distance 的两个点
  44. point = point_on_line(A, B, t)
  45. normal = normal_vector(A, B)
  46. return offset_point(point, normal, distance)
  47. def find_point_on_segment(A, B, d):
  48. # 将 A 和 B 转换为 numpy 数组
  49. A = np.array(A)
  50. B = np.array(B)
  51. # 计算向量 AB
  52. AB = B - A
  53. # 计算 AB 的长度
  54. AB_length = np.linalg.norm(AB)
  55. # 检查 d 是否在 AB 的长度范围内
  56. if d < 0 or d > AB_length:
  57. raise ValueError("d is out of range of the segment AB")
  58. # 计算单位向量 AB_hat
  59. AB_hat = AB / AB_length
  60. # 计算向量 AP
  61. AP = d * AB_hat
  62. # 计算点 P 的坐标
  63. P = A + AP
  64. return P
  65. # 计算旋转角度
  66. def calculate_route(point_1, point_2):
  67. a, b = point_1
  68. c, d = point_2
  69. if a == c:
  70. return 1
  71. else:
  72. return math.atan((d - b) / (c - a))
  73. # 计算旋转坐标
  74. def calculate_route_coordinate(point, route):
  75. x = point[0]
  76. y = point[1]
  77. x1 = x * math.cos(route) + y * math.sin(route)
  78. y1 = -x * math.sin(route) + y * math.cos(route)
  79. return (x1, y1)
  80. def find_point_on_line(A: object, B: object, fraction: object) -> object:
  81. """
  82. 计算线段AB上距离A点fraction长度处的点C的坐标。
  83. 参数:
  84. A -- 点A的坐标,形式为(x1, y1)
  85. B -- 点B的坐标,形式为(x2, y2)
  86. fraction -- 线段AB上距离A点的比例(0到1之间)
  87. 返回:
  88. 点C的坐标,形式为(x, y)
  89. """
  90. x1, y1 = A
  91. x2, y2 = B
  92. # 使用线性插值计算C点的坐标
  93. x = x1 + (x2 - x1) * fraction
  94. y = y1 + (y2 - y1) * fraction
  95. return (x, y)
  96. def scale_point(x, y, k):
  97. """
  98. 缩放二维点坐标。
  99. 参数:
  100. x, y: 原点的x和y坐标。
  101. k: 缩放因子。
  102. 返回:
  103. 新的x'和y'坐标。
  104. """
  105. x_prime = k * x
  106. y_prime = k * y
  107. return x_prime, y_prime
  108. # 计算 a点到b点之间1/x处(距离a点)的c点坐标
  109. def calculate_point_c(point_a, point_b, x):
  110. x_a, y_a = point_a
  111. x_b, y_b = point_b
  112. # 计算方向向量
  113. dx = x_b - x_a
  114. dy = y_b - y_a
  115. # 计算方向向量的模长
  116. distance_ab = math.sqrt(dx ** 2 + dy ** 2)
  117. # 计算单位方向向量
  118. unit_vector_x = dx / distance_ab
  119. unit_vector_y = dy / distance_ab
  120. # 计算点C的坐标
  121. x_c = x_a + (1 / x) * unit_vector_x
  122. y_c = y_a + (1 / x) * unit_vector_y
  123. return x_c, y_c
  124. # 找线段之间某点的坐标
  125. def rotate_point_around_another(point_a, point_b, a):
  126. x_a, y_a = point_a
  127. x_b, y_b = point_b
  128. """
  129. 旋转点A(x_a, y_a)围绕点B(x_b, y_b) a 弧度后的新坐标。
  130. """
  131. # 将A点的坐标转换到以B点为原点的坐标系中
  132. dx = x_a - x_b
  133. dy = y_a - y_b
  134. # 旋转坐标
  135. x_prime = dx * math.cos(a) - dy * math.sin(a)
  136. y_prime = dx * math.sin(a) + dy * math.cos(a)
  137. # 将旋转后的坐标转换回原来的坐标系
  138. x_rotated = x_prime + x_b
  139. y_rotated = y_prime + y_b
  140. return x_rotated, y_rotated
  141. def calculate_angle_with_x_axis(point1, point2):
  142. x1, y1 = point1
  143. x2, y2 = point2
  144. """
  145. 计算线段(x1, y1)到(x2, y2)与x轴的夹角(以弧度为单位)。
  146. 结果角度是从x轴正方向逆时针旋转到线段方向所经过的角度。
  147. """
  148. # 首先计算线段的斜率
  149. if x1 == x2: # 避免除以零
  150. if y2 > y1:
  151. return math.pi / 2 # 垂直于x轴且向上
  152. elif y2 < y1:
  153. return -math.pi / 2 # 垂直于x轴且向下
  154. else:
  155. return 0 # 与x轴重合
  156. else:
  157. slope = (y2 - y1) / (x2 - x1)
  158. # 使用atan2计算角度,它返回从x轴正方向到点(y, x)的向量与x轴之间的夹角
  159. # 注意:atan2的参数顺序是(y的差, x的差),即(y2-y1, x2-x1)
  160. angle_radians = math.atan2(y2 - y1, x2 - x1)
  161. return angle_radians
  162. def get_color_by_layer(layer_id):
  163. return {
  164. '1': 53,
  165. '2': 83,
  166. '3': 133,
  167. '4': 173,
  168. '5': 162,
  169. '6': 77
  170. }.get(layer_id)
  171. # 计算两点之间的欧几里得距离
  172. def euclidean_distance(p1, p2) -> float:
  173. return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2)
  174. # 寻找距离最远的两个点
  175. def farthest_points(points):
  176. if len(points) < 2:
  177. raise ValueError("至少需要两个点")
  178. max_distance = -1 # 初始化为一个较小的值
  179. farthest_pair = (None, None)
  180. # 遍历所有点对
  181. for i in range(len(points)):
  182. for j in range(i + 1, len(points)):
  183. distance_ = euclidean_distance(points[i], points[j])
  184. if distance_ > max_distance:
  185. max_distance = distance_
  186. farthest_pair = (points[i], points[j])
  187. return farthest_pair
  188. def min_distance_between_segments(seg1, seg2):
  189. print(seg1)
  190. """
  191. 计算两条线段之间的最小距离(基于端点之间的最小距离)
  192. seg1, seg2: 线段的端点坐标,例如 [(x1, y1), (x2, y2)]
  193. """
  194. # 提取端点
  195. p1, p2 = seg1
  196. p3, p4 = seg2
  197. # 计算所有端点之间的距离
  198. dist1 = distance(p1, p3)
  199. dist2 = distance(p1, p4)
  200. dist3 = distance(p2, p3)
  201. dist4 = distance(p2, p4)
  202. # 返回最小距离
  203. return min(dist1, dist2, dist3, dist4)
  204. def distance(p1, p2):
  205. """计算两点之间的距离"""
  206. return math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2)
  207. def symmetric_point(A, B):
  208. """
  209. 计算点A相对于点B的对称点C的坐标
  210. 参数:
  211. A -- 点A的坐标,形式为(x_a, y_a)
  212. B -- 点B的坐标,形式为(x_b, y_b)
  213. 返回:
  214. 点C的坐标,形式为(x_c, y_c)
  215. """
  216. x_a, y_a = A
  217. x_b, y_b = B
  218. x_c = 2 * x_b - x_a
  219. y_c = 2 * y_b - y_a
  220. return x_c, y_c
  221. def divide_segment(A, B, x):
  222. # A 和 B 是元组,表示线段的两个端点 (x, y)
  223. # x 是分割段数
  224. # 计算线段 AB 的长度
  225. length_AB = ((B[0] - A[0]) ** 2 + (B[1] - A[1]) ** 2) ** 0.5
  226. # 计算每段的长度
  227. segment_length = length_AB / (x + 1) # 加1是因为包括端点在内有x+1个点
  228. # 初始化点的列表,包括起点 A
  229. points = [A]
  230. # 使用线性插值法计算每个分割点的坐标
  231. for i in range(1, x + 1):
  232. t = i / (x + 1) # 插值参数,从0到1
  233. Cx = A[0] + t * (B[0] - A[0])
  234. Cy = A[1] + t * (B[1] - A[1])
  235. points.append((Cx, Cy))
  236. # 包括终点 B
  237. points.append(B)
  238. return points
  239. def parallel_line(start, end, distance):
  240. """
  241. 计算与给定线段平行且距离为distance的线段(只返回上方的一条)。
  242. 参数:
  243. start -- 原始线段的起点坐标,形式为(x, y)
  244. end -- 原始线段的终点坐标,形式为(x, y)
  245. distance -- 平行线段与原始线段的距离
  246. 返回:
  247. tuple -- 平行线段的起点和终点坐标,形式为((new_start_x, new_start_y), (new_end_x, new_end_y))
  248. """
  249. # 计算原始线段的斜率
  250. if start[0] == end[0]: # 斜率不存在(垂直线)
  251. # 对于垂直线,我们只需在x坐标上保持不变,y坐标增减distance
  252. new_start = (start[0], start[1] + distance)
  253. new_end = (end[0], end[1] + distance)
  254. else:
  255. # 计算斜率
  256. slope = (end[1] - start[1]) / (end[0] - start[0])
  257. # 计算法线的斜率(负倒数)
  258. if slope == 0:
  259. slope = 1
  260. normal_slope = -1 / slope
  261. # 计算法线方向上从起点到距离distance的点的偏移量
  262. # 注意:这里我们使用勾股定理的简化形式,因为距离是垂直于线段的
  263. # 实际上,我们只需要y方向的偏移量,因为x方向的偏移量由斜率决定
  264. dx = distance / math.sqrt(1 + slope ** 2)
  265. dy = slope * dx
  266. # 计算新线段的起点和终点
  267. # 注意:这里我们假设距离是正值,只计算上方的平行线
  268. # 如果需要下方的平行线,可以将dy的符号取反
  269. new_start = (start[0] - dy / slope, start[1] + dx)
  270. new_end = (end[0] - dy / slope, end[1] + dx)
  271. # 注意:上面的计算方式在斜率为负时可能不正确,因为它没有考虑线段的方向
  272. # 一种更健壮的方法是分别计算与start和end距离为distance的点,然后取这两个点作为新线段的端点
  273. # 但为了简单起见,这里我们假设斜率不是负数或垂直线的情况已经处理
  274. # 注意:上面的计算方式在斜率为负或接近0时可能不准确,下面是一个更准确的版本
  275. # 它直接计算与start和end等距的点
  276. # 考虑到斜率可能接近无穷(即几乎垂直),我们使用向量叉积的概念来避免除以0
  277. vector = (end[0] - start[0], end[1] - start[1])
  278. norm = (-vector[1], vector[0]) # 法线向量
  279. norm_length = math.sqrt(norm[0] ** 2 + norm[1] ** 2)
  280. unit_norm = (norm[0] / norm_length, norm[1] / norm_length) # 单位法线向量
  281. offset_point_start = (start[0] + unit_norm[0] * distance, start[1] + unit_norm[1] * distance)
  282. offset_point_end = (end[0] + unit_norm[0] * distance, end[1] + unit_norm[1] * distance)
  283. return (offset_point_start, offset_point_end)
  284. def shrink_line(start, end, scale_factor):
  285. """
  286. 将线段缩小指定的倍数。
  287. 参数:
  288. start -- 原始线段的起点坐标,形式为(x, y)
  289. end -- 原始线段的终点坐标,形式为(x, y)
  290. scale_factor -- 缩小倍数,例如0.5表示缩小到原来的一半
  291. 返回:
  292. tuple -- 缩小后的线段的起点和终点坐标,形式为((new_start_x, new_start_y), (new_end_x, new_end_y))
  293. """
  294. # 计算原始线段的长度和方向向量
  295. length = ((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2) ** 0.5
  296. direction = ((end[0] - start[0]) / length, (end[1] - start[1]) / length)
  297. # 计算缩小后的线段的长度
  298. new_length = length * scale_factor
  299. # 计算缩小后的线段的起点和终点
  300. new_start = start
  301. new_end = (start[0] + direction[0] * new_length, start[1] + direction[1] * new_length)
  302. return (new_start, new_end)