def draw_point(self, event, x, y, flags, param): #global point, drawing, pointContainer, radius, plot if event == cv2.EVENT_LBUTTONDOWN: # set drawing mode self.drawing = True # create point and point container to append them to history for memento design pattern self.point = Point(x, y, self.radius) self.pointContainer.points.append(self.point) self.plot.history.append(copy.deepcopy(self.pointContainer)) elif event == cv2.EVENT_MOUSEMOVE: if self.drawing == True: self.point = Point(x, y, self.radius) self.pointContainer.points.append(self.point) self.plot.history.append(copy.deepcopy(self.pointContainer)) self.draw_circle(self.point.x, self.point.y) elif event == cv2.EVENT_MOUSEWHEEL: if flags > 0: self.radius += 2 else: # prevent issues with < 0 if self.radius > 5: self.radius -= 2 elif event == cv2.EVENT_LBUTTONUP: self.drawing = False
def test_moving(self): project = CADProject() # Add figures point1 = Point((1, 1)) point1_name = project.add_figure(point1) point2 = Point((5, 6)) point2_name = project.add_figure(point2) segment1 = Segment((0, 0), 0, 10) segment1_name = project.add_figure(segment1) # Move point to (3, 4) bb = choose_best_bindings(project.bindings, 1.1, 1)[0] project.move_figure(bb, 3, 4) correct_figures = { point1_name: (3, 4), point2_name: (5, 6), segment1_name: (0, 0, 10, 0), } assert self._is_figures_correct(project.figures, correct_figures) project.commit() # Move segment end to (7, 7) bb = choose_best_bindings(project.bindings, 10, 0)[0] project.move_figure(bb, 7, 7) correct_figures = { point1_name: (3, 4), point2_name: (5, 6), segment1_name: (0, 0, 7, 7), } assert self._is_figures_correct(project.figures, correct_figures) project.commit()
def controller_add_point(self, cmd): self._logger.debug(f'controller_add_point start with status {cmd}') if cmd == ControllerCmd.SUBMIT: figure_coo = self._created_figure.get_base_representation() self._project.add_figure(Point.from_coordinates(*figure_coo)) self.reset() self.controller_add_point(ControllerCmd.SHOW) elif cmd == ControllerCmd.SHOW: if self.action_st == ActionSt.NOTHING: self._reset_behind_statuses() self.controller_st = ControllerSt.ADD_POINT self.creation_st = CreationSt.POINT_SET self._created_figure = Point.from_coordinates( self.field_x_add_point.value(), self.field_y_add_point.value(), ) self.button_add_point.setChecked(True) self.widget_add_point.show() self.field_x_add_point.setFocus() self.field_x_add_point.selectAll() elif cmd == ControllerCmd.HIDE: self.reset() self.update()
def test_save_and_load(self): project1 = CADProject() # Add figures point1 = Point((1, 2)) point1_name = project1.add_figure(point1, 'p1') assert point1_name in project1.figures # Save filename = 'test_save_and_load.scad' project1.save(filename) # Load 1 project2 = CADProject() project2.load(filename) assert point1_name in project2.figures # One more project project3 = CADProject() point2 = Point((0, 0)) point2_name = project3.add_figure(point2, 'p2') assert point2_name in project3.figures assert point1_name not in project3.figures project3.load(filename) assert point2_name not in project3.figures assert point1_name in project3.figures os.remove(filename)
def test_choosing_best_bindings(self): figures = { 'point1': Point((1, 1)), 'point2': Point((2, 3)), 'segment1': Segment((0, 0), 0, 7), 'segment2': Segment.from_coordinates(3, 8, 7, 4), 'segment3': Segment((5, 5), np.pi / 2, 5), } bindings = create_bindings( figures, circle_bindings_radius=0.5, segment_bindings_margin=0.2 ) def get_binding(figure_names, binding_type, spot_type=None): for binding in bindings: objects_names = binding.get_object_names() if is_sequences_equal( figure_names, objects_names ) and isinstance(binding, binding_type): if ( binding_type != SegmentSpotBinding or binding.spot_type == spot_type ): return binding figures['point2'].set_param('x', 3).set_param('y', 8) # No bindings bb = choose_best_bindings(bindings, 10, 10) assert is_sequences_equal(bb, []) # Just point bb = choose_best_bindings(bindings, 1.1, 1.1) point1_b = get_binding(['point1'], PointBinding) assert is_sequences_equal(bb, [point1_b], use='is') # Full segment bb = choose_best_bindings(bindings, 3, 0.15) segment1_full_b = get_binding(['segment1'], FullSegmentBinding) assert is_sequences_equal(bb, [segment1_full_b], use='is') # Segment center beat full segment bb = choose_best_bindings(bindings, 3.5, 0.15) segment1_center_b = get_binding( ['segment1'], SegmentSpotBinding, 'center' ) # No full binding! assert is_sequences_equal(bb, [segment1_center_b], use='is') # To points with same coordinates bb = choose_best_bindings(bindings, 2.9, 7.9) s2_start_b = get_binding(['segment2'], SegmentSpotBinding, 'start') point2_b = get_binding(['point2'], PointBinding) answer_v1 = [s2_start_b, point2_b] answer_v2 = [point2_b, s2_start_b] assert is_sequences_equal( bb, answer_v1, use='is', sort=False ) or is_sequences_equal(bb, answer_v2, use='is', sort=False)
def test_diffrent_color_place(self): p = Point.parse({ 'x': 10, 'y': 2, 'color': 'cos' }, {'cos': "#123456"}, Color("#990011")) self.assertEqual(p.color, Color("#123456")) p = Point.parse({'x': 10, 'y': 2}, {'cos': "123456"}, Color("#123456")) self.assertEqual(p.color, Color("#123456"))
def test_undo_redo_commit_rollback(self): project = CADProject() with pytest.raises(ActionImpossible): project.undo() # Add figures point1 = Point((1, 2)) _ = project.add_figure(point1) point2 = Point((5, 6)) point2_name = project.add_figure(point2) # Undo, redo, _commit inside with pytest.raises(ActionImpossible): project.redo() project.undo() assert point2_name not in project.figures project.redo() assert point2_name in project.figures project.undo() assert point2_name not in project.figures segment1 = Segment((0, 0), 0, 10) segment1_name = project.add_figure(segment1) with pytest.raises(ActionImpossible): project.redo() project.undo() assert segment1_name not in project.figures project.undo() assert not project.figures assert not project.bindings with pytest.raises(ActionImpossible): project.undo() # Commit & rollback point3 = Point((1, 1)) point3_name = project.add_figure(point3) bb = choose_best_bindings(project.bindings, 1, 1)[0] project.move_figure(bb, 5, 5) assert project.figures[point3_name].get_params()['x'] == 5 project.commit() assert project.figures[point3_name].get_params()['x'] == 5 bb = choose_best_bindings(project.bindings, 5, 5)[0] project.move_figure(bb, 7, 7) assert project.figures[point3_name].get_params()['x'] == 7 project.rollback() assert project.figures[point3_name].get_params()['x'] == 5 project.rollback() assert project.figures[point3_name].get_params()['x'] == 5
def test_complex(self): project = CADProject() # Add figures point1 = Point((1, 2)) point1_name = project.add_figure(point1) point2 = Point((5, 6)) point2_name = project.add_figure(point2) segment1 = Segment.from_coordinates(0, 0, 10, 1) segment1_name = project.add_figure(segment1) # Fix point1 r = PointFixed(1, 2) _ = project.add_restriction(r, (point1_name,)) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (0, 0, 10, 1), } assert self._is_figures_correct(project.figures, correct_figures) # Join point1 and start of segment1 r = PointAndSegmentSpotJoint(spot_type='start') _ = project.add_restriction(r, (point1_name, segment1_name)) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (1, 2, 10, 1), } assert self._is_figures_correct(project.figures, correct_figures) # Move segment end bb = choose_best_bindings(project.bindings, 10, 0)[0] project.move_figure(bb, 12, 2) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (1, 2, 12, 2), # Segment set. save length and angle } assert self._is_figures_correct(project.figures, correct_figures) project.commit() # Change length project.change_figure(segment1_name, 'length', 11) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (1, 2, 12, 2), } assert self._is_figures_correct(project.figures, correct_figures)
def __init__(self): self.point = Point(0, 0, 0) self.drawing = False self.pointContainer = PointContainerMemento() self.radius = 10 self.plot = PlotHistory() self.img = np.zeros((384, 384, 3), np.uint8)
def test_parse(self): p = Point.parse({ 'x': 10, 'y': 2, 'color': '(255, 0, 255)' }, {}, Color("#990011")) self.assertEqual(p.x, 10) self.assertEqual(p.y, 2) self.assertEqual(p.color, Color("#ff00ff"))
def test_changing_parameters(self): project = CADProject() # Add figures point1 = Point((1, 1)) point1_name = project.add_figure(point1) point2 = Point((5, 6)) point2_name = project.add_figure(point2) segment1 = Segment((0, 0), 0, 10) segment1_name = project.add_figure(segment1) project.change_figure(point1_name, 'y', 2) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (0, 0, 10, 0), } assert self._is_figures_correct(project.figures, correct_figures) new_len = 7 project.change_figure(segment1_name, 'length', new_len) answer_1 = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: ((10 - new_len) / 2, 0, 10 - (10 - new_len) / 2, 0), } answer_2 = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (0, 0, new_len, 0), } answer_3 = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (10 - new_len, 0, 10, 0), } assert ( self._is_figures_correct(project.figures, answer_1) or self._is_figures_correct(project.figures, answer_2) or self._is_figures_correct(project.figures, answer_3) )
def test_addition_and_deletion_figures(self): project = CADProject() # Add figures point1 = Point((1, 2)) point1_name = project.add_figure(point1) correct_types = {point1_name: Point} assert check_objects_types(project.figures, correct_types) point2 = Point((5, 6)) point2_name = project.add_figure(point2) correct_types = {point1_name: Point, point2_name: Point} assert check_objects_types(project.figures, correct_types) segment1 = Segment((0, 0), 0, 10) segment1_name = project.add_figure(segment1) correct_types = { point1_name: Point, point2_name: Point, segment1_name: Segment, } assert check_objects_types(project.figures, correct_types) # Remove figures project.remove_figure(point2_name) correct_types = {point1_name: Point, segment1_name: Segment} assert check_objects_types(project.figures, correct_types) with pytest.raises(IncorrectParamValue): project.remove_figure(point2_name) project.remove_figure(segment1_name) correct_types = {point1_name: Point} assert check_objects_types(project.figures, correct_types) project.remove_figure(point1_name) correct_types = {} assert check_objects_types(project.figures, correct_types)
def load_figures(json_figures): figs = [] for fig in json_figures: t = fig['type'] if t == "point": figs.append(Point(int(fig['x']), int(fig['y']))) elif t == "polygon": figs.append(Polygon(fig['points'])) elif t == "rectangle": figs.append( Rectangle(int(fig['x']), int(fig['y']), int(fig['width']), int(fig['height']))) elif t == "square": figs.append(Square(int(fig['x']), int(fig['y']), int(fig['size']))) elif t == "circle": figs.append( Circle(int(fig['x']), int(fig['y']), int(fig['radius']))) if "color" in fig: figs[-1].color = fig['color'] return figs
def handle_all(self, event): """ En mode point on s'interesse aux clics gauches de souris et on dessine un point """ handled = self.handle(event) # commun a tous les handler qui verifie si on change de mode ou on quitte if handled: return if event.type == pygame.MOUSEBUTTONDOWN: if event.dict["button"] != 1: return coord = event.dict["pos"] to_draw = Point(coord, self.whiteboard.get_config(["active_color"]), self.whiteboard.get_config(["font_size"]), self.whiteboard.get_config(["toolbar_y"])) now = datetime.now() timestamp = datetime.timestamp(now) self.whiteboard.draw(to_draw, timestamp)
def test_errors(self): with self.assertRaises(ValueError): Point.parse({ 'x': 10, 'color': '(255, 0, 255)' }, {}, Color("#990011")) Point.parse({ 'y': 2, 'color': '(255, 0, 255)' }, {}, Color("#990011")) with self.assertRaises(TypeError): Point.parse({ 'x': 10, 'y': "", 'color': '(255, 0, 255)' }, {}, Color("#990011")) Point.parse({ 'x': {}, 'y': 2, 'color': '(255, 0, 255)' }, {}, Color("#990011"))
def scanline_fill(paint_area, polygon, painter=None, color=Qt.black, to_matrix=False): if not polygon.is_valid(): raise Exception('多边形不合法,无法使用扫描线填充') area_width = paint_area.width() area_height = paint_area.height() area_xmin = 0 area_ymin = 0 area_xmax = area_width - 1 area_ymax = area_height - 1 if to_matrix: matrix = zeros((area_height, area_width), dtype=int) else: painter.setPen(color) for ynow in range(area_ymin, area_ymax + 1): xline = QLineF(area_xmin, ynow, area_xmax, ynow) # 求交点 points = [] sides = [] similar_sides = [] for index, side in enumerate(polygon.sides): if isclose(side.y1(), ynow) and isclose(side.y2(), ynow): # 平行线段 prev_index = index - 1 next_index = index + 1 - len(polygon.sides) similar_sides.append((side, polygon.sides[prev_index], polygon.sides[next_index])) continue point = Point() intersect_type = side.intersect(xline, point) if intersect_type == QLineF.BoundedIntersection: # 有交点 points.append(point) sides.append(side) # 平行线段处理 for side, prev_side, next_side in similar_sides: y0 = prev_side.y1() y3 = next_side.y2() # 异侧:丢弃一个交点 if PLGFloat((y0 - ynow) * (y3 - ynow)) < PLGFloat(0): index = points.index(side.p2()) points.pop(index) sides.pop(index) # 重复交点处理 for point, count in count_list(points): if count == 1: continue elif count == 2: index1 = points.index(point) index2 = points.index(point, index1 + 1) side1 = sides[index1] side2 = sides[index2] if point in side1.points() and point in side2.points(): # 顶点 another_y1 = side1.get_another_vertice(point).y() another_y2 = side2.get_another_vertice(point).y() # 异侧:只留一个顶点 if PLGFloat((another_y1 - ynow) * (another_y2 - ynow)) < PLGFloat(0): points.pop(index2) sides.pop(index2) else: # 非顶点 pass else: raise Exception('交点个数不合法') # 交点排序、配对,线段涂色 points = sorted(points, key=lambda p: p.x()) for i in range(0, len(points), 2): try: x1 = round(points[i].x()) x2 = round(points[i + 1].x()) if to_matrix: matrix[ynow][x1:x2 + 1].fill(1) else: painter.drawLine(x1, ynow, x2, ynow) except: pass # 再单独画一次边框 for side in polygon.sides: x1 = round(side.x1()) y1 = round(side.y1()) x2 = round(side.x2()) y2 = round(side.y2()) if to_matrix: if y1 == y2: matrix[y1][x1:x2 + 1].fill(1) else: painter.drawLine(x1, y1, x2, y2) if to_matrix: return matrix else: return
def test_bindings_and_bindings_creation(self): figures = { 'point1': Point((1, 1)), 'point2': Point((2, 3)), 'segment1': Segment((0, 0), 0, 7), 'segment2': Segment.from_coordinates(3, 8, 7, 4), 'segment3': Segment((5, 5), np.pi / 2, 5), } bindings = create_bindings( figures, circle_bindings_radius=0.5, segment_bindings_margin=0.2 ) correct_bindings_types = ( [PointBinding] * 2 + ([SegmentSpotBinding] * 3 + [FullSegmentBinding]) * 3 + [SegmentsIntersectionBinding] * 3 ) assert is_sequences_equal( list(map(type, bindings)), correct_bindings_types, sort=False ) def get_binding(figure_names, binding_type, spot_type=None): for binding in bindings: objects_names = binding.get_object_names() if is_sequences_equal( figure_names, objects_names ) and isinstance(binding, binding_type): if ( binding_type != SegmentSpotBinding or binding.spot_type == spot_type ): return binding # Point1 point1_b = get_binding(['point1'], PointBinding) assert point1_b.check(10, 10) is None assert isclose(point1_b.check(1.2, 1.2), 0.2 * 2 ** 0.5) assert all(isclose(point1_b.bind(), (1, 1))) figures['point1'].move(dy=2) assert point1_b.check(1.4, 3.4) is None assert all(isclose(point1_b.bind(), (1, 3))) # Segment1 segment1_center_b = get_binding( ['segment1'], SegmentSpotBinding, 'center' ) assert isclose(segment1_center_b.check(3.5, 0.1), 0.1) assert all(isclose(segment1_center_b.bind(), (3.5, 0))) segment1_full_b = get_binding(['segment1'], FullSegmentBinding) assert isclose(segment1_full_b.check(3, 0.15), 0.15) assert isclose(segment1_full_b.check(7.15, 0), 0.15) assert segment1_full_b.check(7.15, 0.15) is None assert all(isclose(segment1_full_b.bind(2.3, -0.7), (2.3, 0))) # Intersections s1_s2_b = get_binding( ['segment1', 'segment2'], SegmentsIntersectionBinding ) assert all(isclose(s1_s2_b.bind(), (11, 0))) s1_s3_b = get_binding( ['segment1', 'segment3'], SegmentsIntersectionBinding ) assert all(isclose(s1_s3_b.bind(), (5, 0))) s2_s3_b = get_binding( ['segment2', 'segment3'], SegmentsIntersectionBinding ) assert all(isclose(s2_s3_b.bind(), (5, 6)))
def test_addition_and_deletion_restrictions(self): project = CADProject() # Add figures point1 = Point((1, 2)) point1_name = project.add_figure(point1) point2 = Point((5, 6)) point2_name = project.add_figure(point2) segment1 = Segment((0, 0), 0, 10) segment1_name = project.add_figure(segment1) # Fix point1 r = PointFixed(1, 2) p1_fixed_name = project.add_restriction(r, (point1_name,)) correct_types = {p1_fixed_name: PointFixed} assert check_objects_types(project.restrictions, correct_types) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (0, 0, 10, 0), } assert self._is_figures_correct(project.figures, correct_figures) # Join point1 and start of segment1 r = PointAndSegmentSpotJoint(spot_type='start') p1_s1s_joint_name = project.add_restriction( r, (point1_name, segment1_name) ) correct_types = { p1_fixed_name: PointFixed, p1_s1s_joint_name: PointAndSegmentSpotJoint, } assert check_objects_types(project.restrictions, correct_types) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (1, 2, 10, 0), # Segment set. save length and angle } assert self._is_figures_correct(project.figures, correct_figures) # Fix end of segment1 r = SegmentSpotFixed(1, 7, spot_type='end') s1e_fixed_name = project.add_restriction(r, (segment1_name,)) correct_types = { p1_fixed_name: PointFixed, p1_s1s_joint_name: PointAndSegmentSpotJoint, s1e_fixed_name: SegmentSpotFixed, } assert check_objects_types(project.restrictions, correct_types) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (1, 2, 1, 7), } assert self._is_figures_correct(project.figures, correct_figures) # Remove fix end of segment1 project.remove_restriction(s1e_fixed_name) correct_types = { p1_fixed_name: PointFixed, p1_s1s_joint_name: PointAndSegmentSpotJoint, } assert check_objects_types(project.restrictions, correct_types) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (1, 2, 1, 7), } assert self._is_figures_correct(project.figures, correct_figures) # Fix length of segment1 r = SegmentLengthFixed(3) s1_fixed_length_name = project.add_restriction(r, (segment1_name,)) correct_types = { p1_fixed_name: PointFixed, p1_s1s_joint_name: PointAndSegmentSpotJoint, s1_fixed_length_name: SegmentLengthFixed, } assert check_objects_types(project.restrictions, correct_types) correct_figures = { point1_name: (1, 2), point2_name: (5, 6), segment1_name: (1, 2, 1, 5), } assert self._is_figures_correct(project.figures, correct_figures)