class Bezier: default_points = [ v2((10, 10)), v2((20, 200)), v2((500, 10)), v2((500, 300)) ] def __init__(self, points: List[v3] = default_points): self.points: List[v2] = points # print(points) self.n = len(points) - 1 self.point = v2((0, 0)) self.current_point = self.points[0] self.current_index = 0 self.spline_points: List[v2] = [] self.calculate() def calculate(self): x = [point.x for point in self.points] y = [point.y for point in self.points] n = self.n self.spline_points.clear() for t in linspace(0, 1, 50): tmp_x = sum([self.N(i, n, t) * x[i] for i in range(0, n + 1)]) tmp_y = sum([self.N(i, n, t) * y[i] for i in range(0, n + 1)]) self.spline_points.append(v2((tmp_x, tmp_y))) def N(self, i: int, n: int, t: float): res = ( factorial(n) )/( factorial(i)*factorial(n-i) ) \ * t**(i) * (1-t)**(n-i) return res def set_current_index(self, index): self.current_index = index
def move_point(self, x, y): self.curve.current_point = v2((x, y)) ci = self.curve.current_index if ci == -1: return self.curve.points[ci] = v2((x, y)) self.curve.calculate() self.repaint()
def temp_highlight(self, painter: QtGui.QPainter): for i, line in enumerate(self.lines): if i < self.limit: Line(line.A, v2([self.poly.x_r_max, line.A.y])).draw(painter, self.center) Line(line.B, v2([self.poly.x_r_max, line.B.y])).draw(painter, self.center) for key, point in self.poly.cache.items(): painter.drawEllipse( point.to_QPoint() + self.center, 2,2 )
def add_point(self): last = self.curve.points[-1] points = self.curve.points[:-1] points.extend([v2((500, 500)), last]) self.curve = Bezier(points) self.curve.calculate() self.repaint()
def generate_new_lines(self): self.lines.clear() self.active_lines.clear() max_l = 50 t = 1 for i in range(100): x, y = [ randint(-self.w//2 + t*max_l, self.w // 2 - t*max_l), randint(-self.h//2 + t*max_l, self.h // 2 - t*max_l) ] offset = v2([x, y]) a = v2([0, 0]) + offset b = v3([randint(10, self.max_l), 0, 0]).rotate(0, 0, randint(0, 360)).to_v2() + offset self.lines.append( Line(a, b) ) self.repaint()
def calculate(self): x = [point.x for point in self.points] y = [point.y for point in self.points] n = self.n self.spline_points.clear() for t in linspace(0, 1, 50): tmp_x = sum([self.N(i, n, t) * x[i] for i in range(0, n + 1)]) tmp_y = sum([self.N(i, n, t) * y[i] for i in range(0, n + 1)]) self.spline_points.append(v2((tmp_x, tmp_y)))
def __init__(self, points: List[v3] = default_points): self.points: List[v2] = points # print(points) self.n = len(points) - 1 self.point = v2((0, 0)) self.current_point = self.points[0] self.current_index = 0 self.spline_points: List[v2] = [] self.calculate()
def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None: if self.mouse_grabbed: x, y = event.x(), event.y() self.poly.move_point( v2([ x - self.w//2, y - self.h//2 ]) ) self.repaint()
def contains(self, point: v2, offset: QPoint): temp_line = Line(point, v2([self.x_r_max + 2, point.y])) cnt = 0 for line in self.lines: intersection = line.intersection(temp_line, self.cache) if line.contains(intersection) and temp_line.contains( intersection): cnt += 1 if cnt % 2 == 0: return False else: return True
def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None: if self.mouse_grabbed: x, y = event.x(), event.y() self.figures[self.cf].move_point( v2([ x - self.w//2, y - self.h//2 ]) ) if self.update_on_mouse_move: self.update_cache() self.repaint()
def generate_figures(self) -> Dict[Tuple[int, str], Figure]: ret = {} ret[(0, 'Треугольник')] = Polygon([ v2([ 0, 0]), v2([100, 0]), v2([ 0,200]), ]) ret[(1, 'Четырёхугольник')] = Polygon([ v2([ 0, 0]), v2([100, 0]), v2([100,200]), v2([ 0,200]), ]) return ret
def __init__(self, parent: QtWidgets.QWidget): super().__init__(parent) self.setMouseTracking(True) self.mouse_grabbed = False self.setGeometry(parent.geometry()) self.setMinimumSize(550, 550) # self.setSizePolicy(parent.sizePolicy()) parent.resize(parent.minimumSize()) self.handle_resize() self.line = Line(v2([20, 20]), v2([50, 60])) self.lines: List[Line] = [] self.limit = 0 self.poly = Polygon( [ v2([ 0, 0]), v2([ 0, 200]), v2([200, 200]), v2([200, 0]), ], ) self.max_l = 50 self.active_lines = set() self.generate_new_lines() self.partially_visible_lines: List[Line] = []
# QtCore.Qt.OddEvenFill ) def move_point(self, pos: v2): self.points[self.ci] = pos # if self.x_r_max < pos.x: # self.x_r_max = pos.x #TODO: хранить индекс самой правой точки self.x_r_max = max([point.x for point in self.points]) self.regenerate_lines() def get_points(self) -> List[Point]: return self.points def get_all_intersections(self, other_line: Line) -> List[Point]: ret = [] for line in self.lines: intersection = line.intersection(other_line, self.cache) if line.contains(intersection) and other_line.contains( intersection): ret.append(intersection) # return intersection return ret if __name__ == "__main__": a = Line(v2([0, 1]), v2([6, 4])) b = Line(v2([8, 8]), v2([8, 0])) C = a.intersection(b) p = v2([0, 1])
def set_point(self, x, y): self.point = v2((x, y)) self.repaint()
def update_cache(self): self.cache.clear() h, w = [self.geometry().height(), self.geometry().width()] # lines = [Line(v2([0,y]), v2([w,y])) for y in range(0,h,3)] c = self.center cache = [] new_cache= {} for y in range(0, h, self.line_period): line = Line( v2([ 0 - c.x(), y - c.y() ]), v2([ w - c.x(), y - c.y() ]), ) line_cache = [] cl = -1 current_color = [QtGui.QColor(0xFF0000),] tmp: List[Tuple[Point, str, QtGui.QColor]] = [] intersection = [] for i, figure in enumerate(self.figures): intersection = figure.get_all_intersections(line) if len(intersection) == 2: # intersection.sort(key=lambda point: point.x) A, B = intersection if A.x > B.x: A, B = B, A tmp.append((A, 'start', i, self.colors[i])) tmp.append((B, 'stop', i, self.colors[i])) # print(len(intersection)) if len(tmp) > 0: tmp.sort(key=lambda item: item[0].x) for a,b in zip(tmp[::1], tmp[1::1]): a_point, a_state, a_layer, a_color = a b_point, b_state, b_layer, b_color = b if a_state == 'start': if a_layer > cl: cl = a_layer current_color.append(a_color) line_cache.append( ( Line( # a_point, v2([a_point.x + 2, b_point.y]), b_point # v2([b_point.x-1, b_point.y]) ), a_color ) ) else: line_cache.append( ( Line( # a_point, v2([a_point.x + 2, b_point.y]), b_point # v2([b_point.x-1, b_point.y]) ), current_color[-1] ) ) if b_state == 'stop': if b_layer == cl: cl = -1 current_color.pop() else: # a - stop if a_layer == cl: cl = -1 current_color.pop() if b_state == 'start': if cl > -1: line_cache.append( ( Line( # a_point, v2([a_point.x + 2, b_point.y]), b_point # v2([b_point.x-1, b_point.y]) ), current_color[-1] ) ) pass else: # no layer pass pass else: # b - stop if cl > -1: line_cache.append( ( Line( # a_point, v2([a_point.x + 2, b_point.y]), b_point # v2([b_point.x-1, b_point.y]) ), current_color[-1] ) ) else: # cl == -1 line_cache.append( ( Line( # a_point, v2([a_point.x + 2, b_point.y]), b_point # v2([b_point.x-1, b_point.y]) ), b_color ) ) pass pass cache.append(line_cache) new_cache[y] = line_cache self.cache = cache