Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # много отрезков из метода make_plan_view
- # при y = 200 должен быть 1
- import sys
- import math
- import numpy
- import random
- from PyQt5.QtCore import Qt, QPoint, QRectF
- from PyQt5.QtGui import QPainter, QPen, QBrush
- from PyQt5.QtWidgets import QMainWindow, QWidget, QApplication
- class MyMainWindow(QMainWindow):
- def __init__(self):
- super().__init__()
- self.setWindowTitle("Построение выпуклых многоугольников")
- self.setGeometry(180, 100, 600, 600) # начало в экр., ширина, высота
- palette = self.palette()
- palette.setColor(self.backgroundRole(), Qt.white)
- self.setPalette(palette)
- self.form_widget = MyFormWidget()
- self.setCentralWidget(self.form_widget)
- class MyFormWidget(QWidget):
- def __init__(self):
- super().__init__()
- self.poly_1_true = {'bottom1': [(200, 200, 0), (250, 150, 50), (100, 200, 0)], # bottom
- 'back1': [(250, 150, 50), (150, 100, 0), (100, 200, 0)], # back
- 'right1': [(200, 200, 0), (250, 150, 50), (150, 100, 0)], # right
- 'front1': [(100, 200, 0), (200, 200, 0), (150, 100, 0)]} # front
- self.poly_2_true = {'left2': [(200, 150, 0), (200, 50, 0), (250, 20, 100), (250, 120, 100)], # left
- 'bottom2': [(200, 150, 0), (300, 150, 0), (350, 120, 100), (250, 120, 100)], # bottom
- 'back2': [(350, 120, 100), (350, 20, 100), (250, 20, 100), (250, 120, 100)], # back
- 'top2': [(200, 50, 0), (300, 50, 0), (350, 20, 100), (250, 20, 100)], # top
- 'right2': [(300, 50, 0), (300, 150, 0), (350, 120, 100), (350, 20, 100)], # right
- 'front2': [(200, 150, 0), (200, 50, 0), (300, 50, 0), (300, 150, 0)]} # front
- self.polys_sides_with_coef = {} # (A, B, C, D) : poly_true[side] for BOTH polygons
- self.polys_sides_with_coef_1 = {} # (A, B, C, D) : poly_true[side] for FIRST polygons
- self.polys_sides_with_coef_2 = {} # (A, B, C, D) : poly_true[side] for SECOND polygons
- self.side_color = {} # side: color
- self.bones_on_side = {} # bones: (A, B, C, D)
- def paintEvent(self, QPaintEvent):
- self.qp = QPainter()
- self.qp.begin(self)
- self.find_side_coef(self.poly_1_true, self.polys_sides_with_coef_1)
- self.find_side_coef(self.poly_2_true, self.polys_sides_with_coef_2)
- self.compare_polys_side()
- self.set_color()
- # self.bones_founder_once() # каждое ребро один раз (первый)
- self.bones_founder_all_sides() # ребро с каждой гранью, которой оно принадлежит
- self.y_min, self.y_max = self.get_min_max_y()
- # print(self.y_min, self.y_max)
- stra_with_ends, stra_on_side, straights = self.make_plane_view(200)
- print('stra w ends: ' + str(stra_with_ends))
- # ends = self.find_straights_ends((0, -5000, -5000, 1000000), 200, self.polys_sides_with_coef_1)
- # print('MAIN ENDS: ' + str(ends))
- # print('STRA W ENDS: ' + str(stra_with_ends))
- # print('STRA ON SIDE' + str(stra_on_side))
- # print('STRA' + str(straights))
- # for stra in stra_on_side.keys():
- # print(str(stra) + ': ' + str(self.polys_sides_with_coef[stra_on_side[stra]]) + ' -- ' + str(stra_with_ends[stra]))
- #----------------------
- # self.worker_2_1()
- # self.segm_painter()
- # print(self.polys_sides_with_coef)
- self.true_painter()
- self.qp.end()
- def find_side_coef(self, polygon, into_polys_side_w_coef):
- # Ax + By + Cz + D = 0
- for side in polygon.keys():
- u, v, w = polygon[side][0], polygon[side][1], polygon[side][2]
- A = v[1] * w[2] - v[1] * u[2] - u[1] * w[2] + u[1] * v[2] - w[1] * v[2] + w[1] * u[2]
- B = -(v[0] * w[2] - v[0] * u[2] - u[0] * w[2] + u[0] * v[2] - w[0] * v[2] + w[0] * u[2])
- C = v[0] * w[1] - v[0] * u[1] - u[0] * w[1] + u[0] * v[1] - w[0] * v[1] + w[0] * u[1]
- D = -u[0] * A - u[1] * B - u[2] * C
- into_polys_side_w_coef[(A, B, C, D)] = polygon[side]
- def compare_polys_side(self):
- for side_coef_1 in self.polys_sides_with_coef_1.keys():
- self.polys_sides_with_coef[side_coef_1] = self.polys_sides_with_coef_1[side_coef_1]
- for side_coef_2 in self.polys_sides_with_coef_2.keys():
- self.polys_sides_with_coef[side_coef_2] = self.polys_sides_with_coef_2[side_coef_2]
- def set_color(self):
- d_color = {1: Qt.darkYellow, 2: Qt.darkRed, 3: Qt.darkCyan, 4: Qt.darkGreen,
- 5: Qt.darkBlue, 6: Qt.darkGray, 7: Qt.darkMagenta, 8: Qt.black, 9: Qt.blue,
- 10: Qt.red, 11: Qt.green}
- for side_coef in self.polys_sides_with_coef:
- n_color = random.randrange(1, 11)
- self.side_color[side_coef] = d_color[n_color]
- def bones_founder_once(self):
- for side_coef in self.polys_sides_with_coef.keys():
- tmp_b = self.find_sides(self.polys_sides_with_coef[side_coef])
- for bone in tmp_b:
- if (bone[1], bone[0]) in self.bones_on_side.keys() or bone in self.bones_on_side.keys():
- continue
- else:
- self.bones_on_side[bone] = side_coef
- def bones_founder_all_sides(self):
- for side_coef in self.polys_sides_with_coef.keys():
- tmp_b = self.find_sides(self.polys_sides_with_coef[side_coef])
- for bone in tmp_b:
- self.bones_on_side[bone] = side_coef
- def find_sides(self, vertex):
- return [(vertex[i], vertex[i - 1]) for i in range(len(vertex))]
- def planes_intersection(self, y, side_coef):
- # return tuple of coeff of plane equation and of straight equation
- # Ax + By + Cz + D = 0 --> A'x + C'z + D = 0
- D_shift = side_coef[3] + y * side_coef[1]
- return (side_coef[0], side_coef[2], D_shift)
- def get_vertex(self, poly):
- vertex = set()
- for side in poly.keys():
- for x in poly[side]:
- vertex.add(x)
- return [*vertex]
- def local_min_max_y(self, vertex):
- return min(v[1] for v in vertex), max(v[1] for v in vertex)
- def get_min_max_y(self):
- poly_vert_1 = self.get_vertex(self.poly_1_true)
- poly_vert_2 = self.get_vertex(self.poly_2_true)
- y_min_1, y_max_1 = self.local_min_max_y(poly_vert_1)
- y_min_2, y_max_2 = self.local_min_max_y(poly_vert_2)
- return min(y_min_1, y_min_2), max(y_max_1, y_max_2)
- def have_intersection(self, y, side):
- bones = self.find_sides(side)
- for bone in bones:
- if (bone[0][1] <= y <= bone[1][1]) or (bone[1][1] <= y <= bone[0][1]):
- return bones
- return []
- def find_straights_ends(self, side_coef, y, polygon):
- ends = []
- for side_coef_2 in polygon.keys():
- main_coef_det = round(numpy.linalg.det([[0, 1, 0], [side_coef[0], side_coef[1], side_coef[2]],
- [side_coef_2[0], side_coef_2[1], side_coef_2[2]]]))
- # print('side_coef_2: ' + str(side_coef_2))
- # print('main_dev: ' + str(main_coef_det))
- if main_coef_det:
- x_det = round(numpy.linalg.det([[y, 1, 0], [-side_coef[3], side_coef[1], side_coef[2]],
- [-side_coef_2[3], side_coef_2[1], side_coef_2[2]]]))
- z_det = round(numpy.linalg.det([[0, 1, y], [side_coef[0], side_coef[1], -side_coef[3]],
- [side_coef_2[0], side_coef_2[1], -side_coef_2[3]]]))
- # print('x_det: ' + str(x_det))
- # print('z_det: ' + str(z_det))
- # x_det = round(numpy.linalg.det([[y, 0, 1], [-side_coef[3], side_coef[1], side_coef[2]],
- # [-side_coef_2[3], side_coef_2[1], side_coef_2[2]]]))
- # z_det = round(numpy.linalg.det([[0, 1, y], [side_coef[0], side_coef[1], -side_coef[3]],
- # [side_coef_2[0], side_coef_2[1], -side_coef_2[3]]]))
- # print('x_det ff: ' + str(x_det))
- # print('z_det ff: ' + str(z_det))
- x_coord_intersection = int(round(x_det / main_coef_det))
- z_coord_intersection = int(round(z_det / main_coef_det))
- x_c_i = 0 if x_coord_intersection == -0 else x_coord_intersection
- z_c_i = 0 if z_coord_intersection == -0 else z_coord_intersection
- print(x_c_i, z_c_i)
- ends.append((x_c_i, z_c_i))
- return ends
- def make_plane_view(self, y):
- straights_on_side = {}
- straights_with_ends = {}
- straights = []
- for side_coef in self.polys_sides_with_coef.keys():
- # polygon = {}
- flag_found = False
- for side_coef_t in self.polys_sides_with_coef_1.keys():
- if side_coef_t == side_coef:
- print('here1')
- print(side_coef)
- polygon = self.polys_sides_with_coef_1
- flag_found = True
- if flag_found:
- break
- if not flag_found:
- for side_coef_2t in self.polys_sides_with_coef_2.keys():
- if side_coef_2t == side_coef:
- polygon = self.polys_sides_with_coef_2
- flag_found = True
- if flag_found:
- break
- bones = self.have_intersection(y, self.polys_sides_with_coef[side_coef])
- if bones:
- print('side: ' + str(self.polys_sides_with_coef[side_coef]))
- print('side coef: ' + str(side_coef))
- print('bones: ' + str(bones))
- straight_coef = self.planes_intersection(y, side_coef)
- print('stra: ' + str(straight_coef))
- straights.append(straight_coef) # shouldnt be here !!!!!!! надо добавлять, когда точно будет 2 конца отрезка
- straights_on_side[straight_coef] = side_coef # аналогично
- print('polygon: ' + str(polygon))
- end_list = self.find_straights_ends(side_coef, y, polygon)
- print('ends: ' + str(end_list))
- straights_with_ends[straight_coef] = end_list
- return straights_with_ends, straights_on_side, straights
- def find_2_straights_inters(self, stra1, stra2):
- # point of intersection of 2 straight (use in next)
- main_det = round(numpy.linalg.det([[stra1[0], stra1[1]], [stra2[0], stra2[1]]]))
- if main_det:
- x_det = round(numpy.linalg.det([[-stra1[2], stra1[1]], [-stra2[2], stra2[1]]]))
- z_det = round(numpy.linalg.det([[stra1[0], -stra1[2]], [stra2[0], -stra2[2]]]))
- x_c = int(round(x_det / main_det))
- z_c = int(round(z_det / main_det))
- x_c_i = 0 if x_c == -0 else x_c
- z_c_i = 0 if z_c == -0 else z_c
- return x_c_i, z_c_i
- return None
- def is_between(self, end_p_1, end_p_2, point):
- return (end_p_1[0] <= point[0] <= end_p_2[0] or end_p_2[0] <= point[0] <= end_p_1[0]) and \
- (end_p_1[1] <= point[1] <= end_p_2[1] or end_p_2[1] <= point[1] <= end_p_1[1])
- def find_all_plane_points(self, straights, stra_w_ends):
- intersections = set()
- for i in range(len(straights)):
- for j in range(len(straights)):
- inter_v = self.find_2_straights_inters(straights[i], straights[j])
- if inter_v:
- a, b = stra_w_ends[straights[i]]
- if self.is_between(a, b, inter_v):
- c, d = stra_w_ends[straights[j]]
- if self.is_between(c, d, inter_v):
- intersections.add(inter_v)
- return intersections
- def collect_z_for_x(self, x, stra_w_ends):
- z_set = set()
- stra_dict_for_z = {}
- for stra in stra_w_ends.keys():
- if stra_w_ends[stra][0][0] <= x <= stra_w_ends[stra][1][0] or \
- stra_w_ends[stra][1][0] <= x <= stra_w_ends[stra][0][0]:
- try:
- z_for_x = -round((stra[0] * x + stra[2]) / stra[1])
- z_set.add(z_for_x)
- if not z_for_x in stra_dict_for_z.keys():
- stra_dict_for_z[z_for_x] = [stra]
- else:
- stra_dict_for_z[z_for_x].append(stra)
- except ZeroDivisionError:
- continue
- return z_set, stra_dict_for_z
- def get_segm_for_paint(self, y, points, stra_w_ends, str_on_side):
- for i in range(len(points) - 1):
- x_1 = points[i][0]
- x_2 = points[i + 1][0]
- z_1_set, stra_dict_for_x1 = self.collect_z_for_x(x_1, stra_w_ends)
- z_2_set, stra_dict_for_x2 = self.collect_z_for_x(x_2, stra_w_ends)
- z_1_list = [z for z in z_1_set]
- z_2_list = [z for z in z_2_set]
- z_1_list.sort()
- z_2_list.sort()
- z_p_1 = -1
- z_p_2 = -1
- flag_end = False
- for tz_1 in z_1_list:
- for tz_2 in z_2_list:
- common_stra = list(set(stra_dict_for_x1[tz_1]) & set(stra_dict_for_x2[tz_2]))
- if common_stra:
- color = self.side_color[str_on_side[common_stra]]
- flag_end = True
- break
- if flag_end:
- break
- if z_p_1 > -1 and z_p_2 > -1:
- self.segments_for_paint[((x_1, y), (x_2, y))] = color
- def worker_2_1(self):
- self.segments_for_paint = {} # segment: color
- for y in range(self.y_min, self.y_max):
- straights_with_ends, str_on_side, straights = self.make_plane_view(y)
- all_viewier_points = self.find_all_plane_points(straights, straights_with_ends)
- all_points_sorted = sorted(all_viewier_points, key=lambda p: (p[1], p[0]))
- self.get_segm_for_paint(y, all_points_sorted, straights_with_ends, str_on_side)
- def segm_painter(self):
- for p1, p2 in self.segments_for_paint.keys():
- self.qp.setPen(QPen(self.segments_for_paint[(p1, p2)], 2))
- self.qp.drawLine(p1[0], p1[1], p2[0], p2[1])
- def true_painter(self):
- poly_1_true = {Qt.darkMagenta: [(200, 200, 0), (250, 150, 50), (100, 200, 0)], # bottom
- Qt.darkYellow: [(250, 150, 50), (150, 100, 0), (100, 200, 0)], # back
- Qt.darkBlue: [(200, 200, 0), (250, 150, 50), (150, 100, 0)], # right
- Qt.darkGray: [(100, 200, 0), (200, 200, 0), (150, 100, 0)]} # front
- poly_2_true = {Qt.darkMagenta: [(200, 150, 0), (200, 50, 0), (250, 20, 100), (250, 120, 100)], # left
- Qt.darkBlue: [(200, 150, 0), (300, 150, 0), (350, 120, 100), (250, 120, 100)], # bottom
- Qt.blue: [(350, 120, 100), (350, 20, 100), (250, 20, 100), (250, 120, 100)], # back
- Qt.darkYellow: [(200, 50, 0), (300, 50, 0), (350, 20, 100), (250, 20, 100)], # top
- Qt.darkRed: [(300, 50, 0), (300, 150, 0), (350, 120, 100), (350, 20, 100)], # right
- Qt.darkGreen: [(200, 150, 0), (200, 50, 0), (300, 50, 0), (300, 150, 0)]} # front
- for side in poly_1_true.keys():
- self.qp.setPen(QPen(side, 2))
- self.qp.setBrush(QBrush(side))
- self.qp.drawPolygon(QPoint(poly_1_true[side][0][0], poly_1_true[side][0][1]),
- QPoint(poly_1_true[side][1][0], poly_1_true[side][1][1]),
- QPoint(poly_1_true[side][2][0], poly_1_true[side][2][1]))
- for side in poly_2_true.keys():
- self.qp.setPen(QPen(side, 2))
- self.qp.setBrush(QBrush(side))
- self.qp.drawPolygon(QPoint(poly_2_true[side][0][0], poly_2_true[side][0][1]),
- QPoint(poly_2_true[side][1][0], poly_2_true[side][1][1]),
- QPoint(poly_2_true[side][2][0], poly_2_true[side][2][1]),
- QPoint(poly_2_true[side][3][0], poly_2_true[side][3][1]))
- if __name__ == '__main__':
- app = QApplication(sys.argv)
- window = MyMainWindow()
- window.show()
- sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement