1
0

board.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. import time
  2. import os
  3. import pygame
  4. from pygame.locals import *
  5. from draftboard.toolbox import tool_box
  6. # 定义一些变量
  7. pen_color = [0, 0, 0] # 画笔颜色
  8. increasing_color = [0, 0, 255]
  9. subtraction_color = [255, 0, 0]
  10. pen_weight = 2 # 圆形的粗细(线条*2)=中笔
  11. previous_x = None
  12. previous_y = None # 为画图所准备的
  13. continuous_draw = False # 设置免按
  14. coordinate_system_drawing_method = 0
  15. coordinate_click_point = [0, 0, 0] # 根据点击中键记录坐标系的点,没有记录则为数字0,记录则为数组
  16. record_origin_x = 0
  17. record_origin_y = 0 # 原点坐标
  18. horizontal_pixels = [] # X点
  19. ordinate_pixels = [] # Y点
  20. horizontal_scale = [] # X个数
  21. ordinate_scale = [] # Y个数
  22. anchor_x = []
  23. anchor_y = []
  24. span = 60 # 坐标系跨度调节
  25. middle_key = 0 # 中键模式
  26. line = [] # 画线列表
  27. rect = [] # 画矩阵和圆列表
  28. poly = [] # 画多边形列表
  29. tips = '' # 设置备注
  30. save_dir = '' # 保存路径
  31. bottom_tip = [0, 0, 0, 0, 0] # 底部显示信息[x,y,左键,中间,右键]
  32. mode = {1: '绘制坐标系', 2: '绘制直线(g)', 3: '填充矩形(f)', 4: '线条矩形(s)',
  33. 5: '绘制横线(k)', 6: '绘制竖线(l)', 7: '绘制多段线(j)',
  34. 8: '绘制横打点多段线(i)', 9: '绘制竖打点多段线(u)', 10: '坐标测绘(h)',
  35. 11: '绘制虚线(q)', 12: '填充圆形(c)', 13: '线条圆形(v)', 14: '多边形(n-填充,m-线条)',
  36. 15: '填充椭圆形(e)', 16: '线条椭圆形(r)', 0: 'None'} # 快捷键名字
  37. SCREEN_X = 900
  38. SCREEN_Y = 700
  39. init_done = pygame.init() # 初始化所有模块
  40. FONT = pygame.font.Font(r'Font\ZKST.ttf', 16) # 设置字体(Linux下应该用\而不是/)
  41. SCREEN = pygame.display.set_mode((SCREEN_X, SCREEN_Y), 0) # 创建屏幕
  42. SCREEN_CAPTION = pygame.display.set_caption('CoTan草稿板') # 定义标题(后期加上定义Logo)
  43. SCREEN.fill([255, 255, 255]) # 默认用白色填充窗口
  44. def func_draw(func_list, pixel_accuracy=1000):
  45. global horizontal_pixels, horizontal_scale, ordinate_pixels, ordinate_scale, anchor_y, anchor_x, pen_color
  46. global increasing_color, subtraction_color
  47. c = [0, 0, 0] # 增函数颜色
  48. def x_convert_pixels(x_coordinate):
  49. return ((x_coordinate - horizontal_scale[0]) / (horizontal_scale[1] - horizontal_scale[0]) *
  50. (horizontal_pixels[1] - horizontal_pixels[0]) + horizontal_pixels[0])
  51. def y_convert_pixels(y_coordinate):
  52. return ((y_coordinate - ordinate_scale[0]) / (ordinate_scale[1] - ordinate_scale[0]) *
  53. (ordinate_pixels[1] - ordinate_pixels[0]) + ordinate_pixels[0])
  54. for i in func_list:
  55. last_x = None # 上一组X和Y
  56. last_y = None
  57. if func_list is None:
  58. continue
  59. func = func_list[i]
  60. try:
  61. for x in range((horizontal_scale[0] - 1) * pixel_accuracy, (horizontal_scale[1] + 1) * pixel_accuracy, 1):
  62. x /= pixel_accuracy
  63. try:
  64. y = func(x)
  65. except BaseException:
  66. last_x = None
  67. last_y = None
  68. continue
  69. try:
  70. now_x = x_convert_pixels(x)
  71. now_y = y_convert_pixels(y)
  72. if now_y > anchor_y[0] or now_y < anchor_y[1] or now_x < anchor_x[0] or now_x > anchor_x[1]:
  73. last_x = None
  74. last_y = None
  75. continue
  76. except TypeError: # 预防复数
  77. continue
  78. if last_x is not None:
  79. if last_y > now_y:
  80. c = increasing_color # 增函数
  81. elif last_y < now_y:
  82. c = subtraction_color # 减函数#改为检查Y数值而不是坐标
  83. pygame.draw.line(
  84. SCREEN, c, (int(last_x), int(last_y)), (int(now_x), int(now_y)), pen_weight)
  85. last_x = now_x
  86. last_y = now_y
  87. except IndexError:
  88. break
  89. def draw_line(xy_coordinates: (list, tuple), with_point=False):
  90. global previous_x, previous_y
  91. if with_point:
  92. pygame.draw.circle(SCREEN, pen_color, xy_coordinates, pen_weight, 0)
  93. if previous_x is not None:
  94. pygame.draw.line(SCREEN, pen_color, (previous_x, previous_y), xy_coordinates, pen_weight)
  95. previous_x = xy_coordinates[0]
  96. previous_y = xy_coordinates[1]
  97. def coordinate_draw(origin_x, origin_y, x_interval=(-100, 100), # 三个点中,两边的两个点距离原点距离的一个list
  98. y_interval=(-200, 100), scale_span=10, width=3, arrow=3, origin=3):
  99. scale_span = abs(scale_span) # kd大于0
  100. global pen_weight, record_origin_x, record_origin_y, horizontal_scale, horizontal_pixels, ordinate_scale
  101. global ordinate_pixels, anchor_x, anchor_y
  102. record_origin_x = origin_x
  103. record_origin_y = origin_y # 存储原点坐标
  104. anchor_x = [origin_x + x_interval[0], origin_x + x_interval[1]] # 定位点
  105. anchor_y = [origin_y + y_interval[1], origin_y + y_interval[0]]
  106. pygame.draw.circle(SCREEN, pen_color, (origin_x, origin_y), origin, 0) # 绘制原点
  107. pygame.draw.line(
  108. SCREEN, pen_color, (origin_x + x_interval[0], origin_y), (origin_x + x_interval[1], origin_y), pen_weight)
  109. pygame.draw.line(
  110. SCREEN, pen_color, (origin_x, origin_y + y_interval[0]), (origin_x, origin_y + y_interval[1]), pen_weight)
  111. negative_scale = 0 # 刻度统计
  112. negative_pixels = 0
  113. for i in range(origin_x, origin_x + x_interval[0], -scale_span): # 右
  114. negative_scale -= 1
  115. pygame.draw.line(SCREEN, pen_color, (i, origin_y + width), (i, origin_y), pen_weight)
  116. negative_pixels = i
  117. positive_scale = 0
  118. positive_pixels = 0
  119. for i in range(origin_x, origin_x + x_interval[1], scale_span): # 刻度#左
  120. positive_scale += 1
  121. pygame.draw.line(SCREEN, pen_color, (i, origin_y + width), (i, origin_y), pen_weight)
  122. positive_pixels = i
  123. horizontal_scale = [negative_scale + 1, positive_scale - 1]
  124. horizontal_pixels = [negative_pixels, positive_pixels]
  125. negative_scale = 0
  126. negative_pixels = 0
  127. for i in range(origin_y, origin_y + y_interval[0], -scale_span): # 上
  128. negative_scale += 1
  129. pygame.draw.line(SCREEN, pen_color, (origin_x + width, i), (origin_x, i), pen_weight)
  130. negative_pixels = i
  131. positive_scale = 0
  132. positive_pixels = 0
  133. for i in range(origin_y, origin_y + y_interval[1], scale_span): # 下
  134. positive_scale -= 1
  135. pygame.draw.line(SCREEN, pen_color, (origin_x + width, i), (origin_x, i), pen_weight)
  136. positive_pixels = i
  137. ordinate_scale = [positive_scale + 1, negative_scale - 1]
  138. ordinate_pixels = [positive_pixels, negative_pixels]
  139. # 箭头
  140. pygame.draw.line(
  141. SCREEN,
  142. pen_color,
  143. (origin_x + x_interval[1],
  144. origin_y),
  145. (origin_x + x_interval[1] - arrow,
  146. origin_y + arrow),
  147. pen_weight) # X上
  148. pygame.draw.line(
  149. SCREEN,
  150. pen_color,
  151. (origin_x + x_interval[1],
  152. origin_y),
  153. (origin_x + x_interval[1] - arrow,
  154. origin_y - arrow),
  155. pen_weight) # X下
  156. pygame.draw.line(
  157. SCREEN,
  158. pen_color,
  159. (origin_x,
  160. origin_y + y_interval[0]),
  161. (origin_x - arrow,
  162. origin_y + y_interval[0] + arrow),
  163. pen_weight) # y左
  164. pygame.draw.line(
  165. SCREEN,
  166. pen_color,
  167. (origin_x,
  168. origin_y + y_interval[0]),
  169. (origin_x + arrow,
  170. origin_y + y_interval[0] + arrow),
  171. pen_weight) # X下
  172. def top_draw():
  173. # 绘制顶部
  174. global pen_weight, FONT, bottom_tip, SCREEN_X, SCREEN_Y, middle_key, save_dir, mode, continuous_draw, tips, line
  175. global record_origin_x, record_origin_y, rect, poly, pen_color, increasing_color, subtraction_color
  176. global coordinate_click_point, span
  177. if continuous_draw:
  178. key_d = '启动无点击画线(点击d关闭)'
  179. else:
  180. key_d = '关闭无点击画线'
  181. pygame.draw.rect(SCREEN, [255, 255, 255], [0, 0, SCREEN_X, 16], 0)
  182. pygame.draw.rect(
  183. SCREEN, [
  184. 255, 255, 255], [
  185. 0, SCREEN_Y - 16, SCREEN_X, SCREEN_Y], 0)
  186. point = ''
  187. if middle_key == 0:
  188. tips = ''
  189. if coordinate_click_point != [0, 0, 0]:
  190. a = []
  191. for i in coordinate_click_point:
  192. if i != 0:
  193. a.append(i)
  194. point += f'坐标端点:{str(a)} '
  195. if line:
  196. point += f'端点:{str(line)} '
  197. if rect:
  198. point += f'顶点(圆心):{str(rect)} '
  199. if poly:
  200. point += f'多顶点:{str(poly)} '
  201. if continuous_draw or middle_key != 0:
  202. model_tip = FONT.render(
  203. f'模式:{key_d} , {mode[middle_key]} {tips}', True, (0, 0, 0))
  204. else:
  205. s = ''
  206. if save_dir:
  207. s = f'保存路径(w):{save_dir}'
  208. model_tip = FONT.render(
  209. f'{time.strftime("%Y/%m/%d %I:%M")} {s}', True, (0, 0, 0))
  210. point = ''
  211. if point == '':
  212. point = f'主色调:{pen_color} 增函数颜色:{increasing_color} 减函数颜色:{subtraction_color}'
  213. mouse_tip = FONT.render(f'鼠标:{bottom_tip[0]},{bottom_tip[1]}', True, (0, 0, 0))
  214. status_tip = FONT.render(
  215. f'{bottom_tip[2]},{bottom_tip[3]},{bottom_tip[4]} ; 大小:{pen_weight} ; '
  216. f'原点:{record_origin_x},{record_origin_y}'
  217. f' ; 跨度:{span} ; {point}',
  218. True,
  219. (0,
  220. 0,
  221. 0))
  222. SCREEN.blit(mouse_tip, (0, 0))
  223. SCREEN.blit(status_tip, (100, 0))
  224. SCREEN.blit(model_tip, (0, SCREEN_Y - 16))
  225. def draw_main():
  226. global previous_x, previous_y, pen_color, pen_weight, coordinate_system_drawing_method
  227. global coordinate_click_point, record_origin_x
  228. global record_origin_y, span, line
  229. global continuous_draw, middle_key, rect, poly, SCREEN, SCREEN_CAPTION, init_done, previous_x, previous_y, save_dir
  230. global increasing_color, subtraction_color, bottom_tip, FONT, SCREEN_X, SCREEN_Y, tips
  231. flat = True # 循环条件(不是全局)
  232. while flat:
  233. top_draw()
  234. pygame.display.update() # 屏幕刷新
  235. for event in pygame.event.get(): # 事件检查
  236. if event.type == QUIT: # 退出事件
  237. pygame.quit()
  238. flat = False
  239. break
  240. elif event.type == MOUSEMOTION: # 鼠标移动事件
  241. bottom_tip[0], bottom_tip[1] = event.pos
  242. bottom_tip[2], bottom_tip[3], bottom_tip[4] = event.buttons
  243. if event.buttons == (1, 0, 0): # 左键点击
  244. draw_line(event.pos)
  245. elif event.buttons == (0, 0, 0): # 无点击绘图(启动快捷键d)
  246. if continuous_draw:
  247. draw_line(event.pos)
  248. else: # m_x和m_y是指上一点的xy,用于画线系统
  249. previous_x = None
  250. previous_y = None
  251. elif event.type == MOUSEBUTTONDOWN: # 鼠标按下
  252. event.pos = list(event.pos)
  253. if event.button == 3: # 右键点击
  254. bottom_tip[4] = 1
  255. pygame.image.save(SCREEN, '$CoTanCC.png') # 保存当前环境
  256. SCREEN = pygame.display.set_mode(
  257. (SCREEN_X, SCREEN_Y), pygame.NOFRAME) # 隐藏关闭按钮
  258. background_image = pygame.image.load('$CoTanCC.png').convert() # 加载位图
  259. SCREEN.blit(background_image, (0, 0)) # 绘制位图
  260. pygame.display.update() # 更新屏幕
  261. tool_set = tool_box() # 启动工具箱
  262. SCREEN = pygame.display.set_mode((SCREEN_X, SCREEN_Y), 0) # 显示关闭按钮
  263. background_image = pygame.image.load('$CoTanCC.png').convert() # 加载位图
  264. SCREEN.blit(background_image, (0, 0)) # 绘制位图
  265. pygame.display.update() # 更新屏幕
  266. os.remove('$CoTanCC.png')
  267. if tool_set[0] is not None:
  268. pen_color = tool_set[0] # 设置颜色
  269. if tool_set[1] is not None:
  270. pen_weight = tool_set[1] # 设置笔的粗细
  271. if tool_set[2] is not None:
  272. SCREEN.fill(tool_set[2]) # 设置背景填充
  273. if tool_set[3] == 1: # 绘制坐标系
  274. tips = '选择坐标三个端点'
  275. middle_key = 1
  276. coordinate_system_drawing_method = 3
  277. span = 60
  278. elif tool_set[3] == 2: # 绘制坐标系2(小跨度)
  279. tips = '选择坐标三个端点'
  280. middle_key = 1
  281. coordinate_system_drawing_method = 3
  282. span = 20
  283. elif tool_set[3] == 3: # 绘制坐标系3(大跨度)
  284. tips = '选择坐标三个端点'
  285. middle_key = 1
  286. coordinate_system_drawing_method = 3
  287. span = 120 # 坐标系跨度(字定义跨度再下面)
  288. else:
  289. middle_key = 0
  290. coordinate_system_drawing_method = 0 # 恢复选项
  291. if tool_set[6] is not None:
  292. increasing_color = tool_set[6] # 增函数颜色(要在函数绘制之前设置好)
  293. if tool_set[7] is not None:
  294. subtraction_color = tool_set[7] # 减函数颜色
  295. if tool_set[4] != {}:
  296. func_draw(tool_set[4]) # 函数绘制
  297. if tool_set[5] is not None:
  298. pygame.image.save(SCREEN, tool_set[5]) # 保存当前环境
  299. save_dir = tool_set[5]
  300. if tool_set[8] is not None:
  301. span = tool_set[8] # 自定义跨度
  302. if tool_set[9] is not None:
  303. try:
  304. bg_im = pygame.image.load(tool_set[9]).convert() # 加载位图
  305. SCREEN.blit(bg_im, (0, 0)) # 绘制位图
  306. except BaseException:
  307. pass
  308. # 恢复参数
  309. previous_x = None
  310. previous_y = None
  311. continuous_draw = False
  312. pygame.event.clear()
  313. elif event.button == 2: # 中键点击,ZJ是指中键的模式,来自快捷键和工具箱
  314. bottom_tip[3] = 1
  315. if middle_key == 1: # 坐标系模式
  316. tips = '选择下一个端点(共3个)'
  317. coordinate_click_point[coordinate_system_drawing_method - 1] = event.pos # 存储
  318. coordinate_system_drawing_method -= 1
  319. if coordinate_system_drawing_method == 0:
  320. x = []
  321. y = []
  322. for i in coordinate_click_point:
  323. x.append(i[0])
  324. y.append(i[1])
  325. x.sort()
  326. y.sort() # 排序
  327. s_x = x[1]
  328. s_y = y[1]
  329. p = (-abs(x[0] - x[1]), abs(x[1] - x[2]))
  330. c = (-abs(y[0] - y[1]), abs(y[1] - y[2]))
  331. b = 2 * pen_weight
  332. r = 2 * pen_weight
  333. jt = 3 * pen_weight
  334. coordinate_draw(s_x, s_y, p, c, span, b, jt, r)
  335. coordinate_click_point = [0, 0, 0]
  336. middle_key = 0
  337. elif middle_key == 2: # 画线模式
  338. line.append(event.pos)
  339. # pygame.draw.circle(root, pen_C, event.pos, d, 0)
  340. if len(line) == 2:
  341. pygame.draw.line(
  342. SCREEN, pen_color, line[0], line[1], pen_weight)
  343. middle_key = 0
  344. elif middle_key == 3 or middle_key == 4: # 画矩形模式
  345. rect.append(event.pos)
  346. if len(rect) == 2:
  347. x = [rect[0][0], rect[1][0]]
  348. y = [rect[0][1], rect[1][1]]
  349. x.sort()
  350. y.sort()
  351. if middle_key == 3:
  352. dx = 0
  353. else:
  354. dx = pen_weight
  355. pygame.draw.rect(
  356. SCREEN, pen_color, [
  357. x[0], y[0], x[1] - x[0], y[1] - y[0]], dx)
  358. middle_key = 0
  359. elif middle_key == 5: # 画横线模式
  360. line.append(event.pos)
  361. if len(line) == 2:
  362. pygame.draw.line(
  363. SCREEN, pen_color, line[0], (line[1][0], line[0][1]), pen_weight)
  364. middle_key = 0
  365. elif middle_key == 6: # 画竖线模式
  366. line.append(event.pos)
  367. if len(line) == 2:
  368. pygame.draw.line(
  369. SCREEN, pen_color, line[0], (line[0][0], line[1][1]), pen_weight)
  370. middle_key = 0
  371. elif middle_key == 7: # 画线多段线
  372. line.append(event.pos)
  373. if len(line) == 2:
  374. pygame.draw.line(
  375. SCREEN, pen_color, line[0], line[1], pen_weight)
  376. del line[0]
  377. elif middle_key == 8: # 画横线多段线
  378. line.append(event.pos)
  379. if len(line) == 2:
  380. pygame.draw.line(
  381. SCREEN, pen_color, line[0], (line[1][0], line[0][1]), pen_weight)
  382. pygame.draw.circle(
  383. SCREEN, pen_color, (line[1][0], line[0][1]), pen_weight * 2, 0)
  384. del line[1]
  385. else:
  386. pygame.draw.circle(
  387. SCREEN, pen_color, event.pos, pen_weight, 0)
  388. elif middle_key == 9: # 画竖线多段线
  389. line.append(event.pos)
  390. if len(line) == 2:
  391. pygame.draw.line(
  392. SCREEN, pen_color, line[0], (line[0][0], line[1][1]), pen_weight)
  393. pygame.draw.circle(
  394. SCREEN, pen_color, (line[0][0], line[1][1]), pen_weight * 2, 0)
  395. del line[1]
  396. else:
  397. pygame.draw.circle(
  398. SCREEN, pen_color, event.pos, pen_weight, 0)
  399. elif middle_key == 10: # 画竖线和横线多段线
  400. line.append(event.pos)
  401. if len(line) == 2:
  402. pygame.draw.line(
  403. SCREEN, pen_color, line[0], (line[1][0], line[0][1]), pen_weight) # 横线
  404. pygame.draw.circle(
  405. SCREEN, pen_color, (line[1][0], line[0][1]), pen_weight * 2, 0)
  406. pygame.draw.circle(
  407. SCREEN, pen_color, (line[1][0], line[1][1]), pen_weight * 2, 0)
  408. pygame.draw.line(
  409. SCREEN, pen_color, line[0], (line[0][0], line[1][1]), pen_weight) # 竖线
  410. pygame.draw.circle(
  411. SCREEN, pen_color, (line[0][0], line[1][1]), pen_weight * 2, 0)
  412. # 垂直于横线的虚线
  413. p = sorted([line[1][1], line[0][1]])
  414. y1 = p[0]
  415. y2 = p[1]
  416. a = list(range(y1, y2, 10))
  417. for i in range(
  418. int(len(a) / 2)): # 向下取整,可用math.ceil代替
  419. i += 1
  420. i = 2 * i - 1
  421. y1 = a[i - 1] # 计算两点的y坐标
  422. y2 = a[i]
  423. pygame.draw.line(
  424. SCREEN, pen_color, (line[1][0], y1), (line[1][0], y2), pen_weight) # 横线
  425. # 垂直于竖线的虚线
  426. p = [line[1][0], line[0][0]]
  427. p.sort()
  428. x1 = p[0]
  429. x2 = p[1]
  430. a = list(range(x1, x2, 10))
  431. for i in range(
  432. int(len(a) / 2)): # 向下取整,可用math.ceil代替
  433. i += 1
  434. i = 2 * i - 1
  435. x1 = a[i - 1] # 计算两点的x坐标
  436. x2 = a[i]
  437. pygame.draw.line(
  438. SCREEN, pen_color, (x1, line[1][1]), (x2, line[1][1]), pen_weight) # 横线
  439. del line[1]
  440. else:
  441. pygame.draw.circle(
  442. SCREEN, pen_color, event.pos, pen_weight, 0)
  443. elif middle_key == 11: # 画虚线线模式
  444. line.append(event.pos)
  445. pygame.draw.circle(
  446. SCREEN, pen_color, event.pos, pen_weight, 0)
  447. if len(line) == 2:
  448. if abs(line[0][0] - line[1][0]) >= 100:
  449. p1 = [line[0][0], line[1][0]]
  450. p2 = {
  451. line[0][0]: line[0][1],
  452. line[1][0]: line[1][1]}
  453. p1.sort()
  454. x1 = p1[0]
  455. y1 = p2[x1]
  456. x2 = p1[1]
  457. y2 = p2[x2]
  458. a = list(range(x1, x2, 10))
  459. for i in range(
  460. int(len(a) / 2)): # 向下取整,可用math.ceil代替
  461. i += 1
  462. i = 2 * i - 1
  463. x1 = a[i - 1] # 计算两点的x坐标
  464. x2 = a[i]
  465. y1 = (x1 - x1) / (x2 - x1) * (y2 - y1) + y1
  466. y2 = (x2 - x1) / (x2 - x1) * (y2 - y1) + y1
  467. pygame.draw.line(
  468. SCREEN, pen_color, (x1, y1), (x2, y2), pen_weight) # 横线
  469. elif abs(line[0][1] - line[1][1]) >= 100:
  470. p1 = [line[0][1], line[1][1]]
  471. p2 = {
  472. line[0][1]: line[0][0],
  473. line[1][1]: line[1][0]}
  474. p1.sort()
  475. y1 = p1[0]
  476. x1 = p2[y1]
  477. y2 = p1[1]
  478. x2 = p2[y2]
  479. a = list(range(y1, y2, 10))
  480. for i in range(
  481. int(len(a) / 2)): # 向下取整,可用math.ceil代替
  482. i += 1
  483. i = 2 * i - 1
  484. y1 = a[i - 1] # 计算两点的x坐标
  485. y2 = a[i]
  486. x1 = (y1 - y1) / (y2 - y1) * (x2 - x1) + x1
  487. x2 = (y2 - y1) / (y2 - y1) * (x2 - x1) + x1
  488. pygame.draw.line(
  489. SCREEN, pen_color, (x1, y1), (x2, y2), pen_weight) # 横线
  490. else:
  491. pygame.draw.line(
  492. SCREEN, pen_color, line[1], line[0], pen_weight)
  493. middle_key = 0
  494. elif middle_key == 12: # 画圆模式
  495. rect.append(event.pos)
  496. if len(rect) == 2:
  497. # 两点间求距离
  498. r = int(
  499. ((rect[0][0] - rect[1][0]) ** 2 + (rect[0][1] - rect[1][1]) ** 2) ** (1 / 2))
  500. pygame.draw.circle(SCREEN, pen_color, rect[0], r, 0)
  501. middle_key = 0
  502. else:
  503. pygame.draw.circle(
  504. SCREEN, pen_color, rect[0], pen_weight * 2, 0)
  505. elif middle_key == 13: # 画圆线框模式
  506. rect.append(event.pos)
  507. if len(rect) == 2:
  508. # 两点间求距离
  509. r = int(
  510. ((rect[0][0] - rect[1][0]) ** 2 + (rect[0][1] - rect[1][1]) ** 2) ** (1 / 2))
  511. pygame.draw.circle(
  512. SCREEN, pen_color, rect[0], r, pen_weight)
  513. middle_key = 0
  514. else:
  515. pygame.draw.circle(
  516. SCREEN, pen_color, rect[0], pen_weight, 0)
  517. elif middle_key == 14: # 画多边形模式
  518. line.append(event.pos)
  519. if len(line) == 2:
  520. pygame.draw.line(
  521. SCREEN, pen_color, line[0], line[1], pen_weight)
  522. del line[0]
  523. poly.append(event.pos)
  524. elif middle_key == 15: # 画椭圆模式
  525. rect.append(event.pos)
  526. if len(rect) == 2:
  527. x = [rect[0][0], rect[1][0]]
  528. y = [rect[0][1], rect[1][1]]
  529. x.sort()
  530. y.sort()
  531. pygame.draw.ellipse(
  532. SCREEN, pen_color, [
  533. x[0], y[0], x[1] - x[0], y[1] - y[0]], 0)
  534. middle_key = 0
  535. elif middle_key == 16: # 画椭圆边框模式
  536. rect.append(event.pos)
  537. if len(rect) == 2:
  538. x = [rect[0][0], rect[1][0]]
  539. y = [rect[0][1], rect[1][1]]
  540. x.sort()
  541. y.sort()
  542. pygame.draw.ellipse(
  543. SCREEN, pen_color, [
  544. x[0], y[0], x[1] - x[0], y[1] - y[0]], pen_weight)
  545. middle_key = 0
  546. elif event.button == 1:
  547. bottom_tip[2] = 1
  548. pygame.draw.circle(
  549. SCREEN, pen_color, event.pos, pen_weight, 0)
  550. previous_x = event.pos[0]
  551. previous_y = event.pos[1]
  552. elif event.type == KEYDOWN: # 键盘按下(长按不算)快捷键
  553. if event.key == K_d: # 不用点击左键画线
  554. if continuous_draw:
  555. continuous_draw = False
  556. else:
  557. continuous_draw = True
  558. previous_x = None
  559. previous_y = None
  560. elif event.key == K_g: # 画直线
  561. tips = '根据两个端点画直线'
  562. middle_key = 2
  563. line = []
  564. rect = []
  565. poly = []
  566. elif event.key == K_f: # 画矩阵
  567. middle_key = 3
  568. tips = '根据两个相对的顶点绘制矩形'
  569. line = []
  570. rect = []
  571. poly = []
  572. elif event.key == K_s: # 画矩阵边框
  573. middle_key = 4
  574. tips = '根据两个相对的顶点绘制矩形'
  575. line = []
  576. rect = []
  577. poly = []
  578. elif event.key == K_k: # 画横线
  579. middle_key = 5
  580. tips = '选择起点和与终点y坐标相同的点'
  581. line = []
  582. rect = []
  583. poly = []
  584. elif event.key == K_l: # 画竖线
  585. middle_key = 6
  586. tips = '选择起点和与终点x坐标相同的点'
  587. line = []
  588. rect = []
  589. poly = []
  590. elif event.key == K_j: # 多段线
  591. if middle_key == 7:
  592. middle_key = 0
  593. else:
  594. middle_key = 7
  595. tips = '依次选择多段线的顶点'
  596. line = []
  597. rect = []
  598. poly = []
  599. elif event.key == K_i: # 多段线横线打点
  600. if middle_key == 8:
  601. middle_key = 0
  602. else:
  603. middle_key = 8
  604. tips = '选择终点,依次选择与其他端点y坐标相同的点(点击i结束)'
  605. line = []
  606. rect = []
  607. poly = []
  608. elif event.key == K_u: # 多段线竖线打点
  609. if middle_key == 9:
  610. middle_key = 0
  611. else:
  612. middle_key = 9
  613. tips = '选择终点,依次选择与其他端点x坐标相同的点(点击u结束)'
  614. line = []
  615. rect = []
  616. poly = []
  617. elif event.key == K_h: # 多段横竖线打点
  618. if middle_key == 10:
  619. middle_key = 0
  620. else:
  621. middle_key = 10
  622. tips = '选择参考点,再选择研究对象(点击h结束)'
  623. line = []
  624. rect = []
  625. poly = []
  626. elif event.key == K_q: # 绘制虚线
  627. middle_key = 11
  628. tips = '选择虚线的两个端点'
  629. line = []
  630. rect = []
  631. poly = []
  632. elif event.key == K_c: # 绘制圆形
  633. middle_key = 12
  634. tips = '选择圆形和圆上任意一点(确定半径)'
  635. line = []
  636. rect = []
  637. poly = []
  638. elif event.key == K_v: # 绘制圆形线框
  639. middle_key = 13
  640. tips = '选择圆形和圆上任意一点(确定半径)'
  641. line = []
  642. rect = []
  643. poly = []
  644. elif event.key == K_o: # 捕捉
  645. tips = '起点已经捕捉到坐标系原点了'
  646. line = [[record_origin_x, record_origin_y]]
  647. rect = [[record_origin_x, record_origin_y]]
  648. poly = [[record_origin_x, record_origin_y]]
  649. elif event.key == K_y: # 捕捉上y轴
  650. if len(line) >= 1:
  651. tips = '起点已经移动到坐标系y轴上了'
  652. line[0][0] = record_origin_x
  653. if len(rect) >= 1:
  654. tips = '起点已经移动到坐标系y轴上了'
  655. rect[0][0] = record_origin_x
  656. if len(poly) >= 1:
  657. tips = '起点已经移动到坐标系y轴上了'
  658. rect[0][0] = record_origin_x
  659. elif event.key == K_x: # 捕捉上x轴
  660. if len(line) >= 1:
  661. tips = '起点已经移动到坐标系x轴上了'
  662. line[0][1] = record_origin_y
  663. if len(rect) >= 1:
  664. tips = '起点已经移动到坐标系x轴上了'
  665. rect[0][1] = record_origin_y
  666. if len(poly) >= 1:
  667. tips = '起点已经移动到坐标系x轴上了'
  668. rect[0][1] = record_origin_y
  669. elif event.key == K_n: # 画多边形
  670. if middle_key == 14:
  671. middle_key = 0
  672. pygame.draw.polygon(SCREEN, pen_color, poly, 0)
  673. else:
  674. tips = '依次选择多边形的各个端点(点击n闭合并填充)'
  675. middle_key = 14
  676. elif event.key == K_m: # 画多边形边框
  677. if middle_key == 14:
  678. middle_key = 0
  679. pygame.draw.polygon(SCREEN, pen_color, poly, pen_weight)
  680. else:
  681. tips = '依次选择多边形的各个端点(点击m闭合)'
  682. middle_key = 14
  683. line = []
  684. rect = []
  685. poly = []
  686. elif event.key == K_e: # 绘制填充椭圆
  687. middle_key = 15
  688. tips = '选择椭圆外界矩形的两个相对的顶点'
  689. line = []
  690. rect = []
  691. poly = []
  692. elif event.key == K_r: # 绘制椭圆边框
  693. middle_key = 16
  694. tips = '选择椭圆外界矩形的两个相对的顶点'
  695. line = []
  696. rect = []
  697. poly = []
  698. elif event.key == K_w: # 保存
  699. if save_dir != '':
  700. pygame.image.save(SCREEN, save_dir) # 保存当前环境
  701. elif event.key == K_b: # 清空当前操作
  702. middle_key = 0
  703. line = []
  704. rect = []
  705. poly = []
  706. # 快捷键操作指南
  707. # d-不用点击左键画线(再次点击关闭)
  708. # g-画直线
  709. # f-画填充矩阵
  710. # s-画矩阵边框
  711. # k-画横线
  712. # l-画竖线
  713. # j-画多段线
  714. # i-横线多段线打点(再次点击结束绘制)
  715. # u-竖线多段线打点(再次点击结束绘制)
  716. # h-横线和竖线多段线打点并由虚线标注(再次点击结束绘制)
  717. # q-绘制虚线
  718. # c-绘制填充圆形
  719. # v-绘制圆形边框
  720. # n和m-绘制多边形
  721. # n-再次点击完成填充多边形绘制
  722. # m-再次点击完成多边形边框绘制
  723. # o-捕捉坐标原点(请先点击功能快捷键)
  724. # x-捕捉坐标x轴(请先点击功能快捷键并选择起点)
  725. # y-捕捉坐标y轴(同上)
  726. # b-关闭当前所有快捷键操作
  727. # e-绘制填充椭圆
  728. # r-绘制椭圆边框