示例#1
0
 def viewport(self) -> Rect:
     widget = self.builder.get_object('drawing_area')
     return Rect(min=Vec2(0, 0),
                 max=Vec2(
                     widget.get_allocated_width(),
                     widget.get_allocated_height(),
                 )).with_margin(10)
示例#2
0
def liang_barsky_line_clip(line: Line) -> Optional[Line]:
    start, end = line.vertices_ndc

    p1 = start.x - end.x
    p2 = -p1
    p3 = start.y - end.y
    p4 = -p3

    q1 = start.x - (-1)
    q2 = 1 - start.x
    q3 = start.y - (-1)
    q4 = 1 - start.y

    posarr = [1.0 for _ in range(5)]
    negarr = [0.0 for _ in range(5)]

    if (p1 == 0 and q1 < 0 or p3 == 0 and q3 < 0):
        return None

    if p1 != 0:
        r1 = q1 / p1
        r2 = q2 / p2

        if p1 < 0:
            negarr.append(r1)
            posarr.append(r2)
        else:
            negarr.append(r2)
            posarr.append(r1)

    if p3 != 0:
        r3 = q3 / p3
        r4 = q4 / p4

        if p3 < 0:
            negarr.append(r3)
            posarr.append(r4)
        else:
            negarr.append(r4)
            posarr.append(r3)

    rn1 = max(negarr)
    rn2 = min(posarr)

    if rn1 > rn2:
        return None

    xn1 = start.x + p2 * rn1
    yn1 = start.y + p4 * rn1

    xn2 = start.x + p2 * rn2
    yn2 = start.y + p4 * rn2

    new_line = copy.deepcopy(line)
    new_line.vertices_ndc = [Vec2(xn1, yn1), Vec2(xn2, yn2)]
    return new_line
示例#3
0
    def on_resize(self, widget: Gtk.Widget, allocation: Gdk.Rectangle):
        if self.scene.window is None:
            w, h = allocation.width, allocation.height
            self.old_size = allocation
            self.scene.window = Window(Vec2(-w / 2, -h / 2),
                                       Vec2(w / 2, h / 2))

        w_proportion = allocation.width / self.old_size.width
        h_proportion = allocation.height / self.old_size.height

        self.scene.window.max = Vec2(self.scene.window.max.x * w_proportion,
                                     self.scene.window.max.y * h_proportion)
        self.scene.window.min = Vec2(self.scene.window.min.x * w_proportion,
                                     self.scene.window.min.y * h_proportion)
        self.old_size = allocation

        self.scene.update_ndc()
示例#4
0
    def on_ok(self, widget):
        window = self.builder.get_object('new_object_window')
        notebook = self.builder.get_object('notebook1')

        page_num = notebook.get_current_page()
        name = entry_text(self, 'entry_name')

        if NB_PAGES[page_num] == 'point':
            x = float(entry_text(self, 'entryX'))
            y = float(entry_text(self, 'entryY'))

            self.dialog.new_object = Point(Vec2(x, y), name=name)
        elif NB_PAGES[page_num] == 'line':
            y2 = float(entry_text(self, 'entryY2'))
            x1 = float(entry_text(self, 'entryX1'))
            y1 = float(entry_text(self, 'entryY1'))
            x2 = float(entry_text(self, 'entryX2'))

            self.dialog.new_object = Line(Vec2(x1, y1),
                                          Vec2(x2, y2),
                                          name=name)
        elif NB_PAGES[page_num] == 'polygon':
            if len(self.vertices) >= 3:
                filled = self.builder.get_object('switch_filled').get_active()

                self.dialog.new_object = Polygon(self.vertices,
                                                 name=name,
                                                 filled=filled)
        elif NB_PAGES[page_num] == 'curve':
            if self.builder.get_object('btn_bezier').get_active():
                type = 'bezier'
            elif self.builder.get_object('btn_b-spline').get_active():
                type = 'b-spline'

            if len(self.vertices) >= 4:
                self.dialog.new_object = Curve.from_control_points(
                    self.vertices,
                    type=type,
                    name=name,
                )
        else:
            raise ValueError('No page with given index.')

        window.destroy()
示例#5
0
    def on_key_press(self, widget, event):
        '''
        Returns: False if event can propagate, True otherwise.
        '''
        DIRECTIONS = {
            Gdk.KEY_Up: Vec2(0, -10),
            Gdk.KEY_Down: Vec2(0, 10),
            Gdk.KEY_Left: Vec2(10, 0),
            Gdk.KEY_Right: Vec2(-10, 0),
        }

        self.pressed_keys |= {event.keyval}

        for key in self.pressed_keys:
            if key in DIRECTIONS:
                self.world_window.offset(DIRECTIONS[key])

        self.window.queue_draw()

        return True
示例#6
0
def cohen_sutherland_line_clip(line: Line) -> Optional[Line]:
    new_line = copy.deepcopy(line)
    start, end = new_line.vertices_ndc
    regions = [CohenRegion.region_of(v) for v in (start, end)]

    while True:
        # Both inside
        if all([r == CohenRegion.INSIDE for r in regions]):
            return new_line
        # Both outside (and in the same side)
        elif regions[0] & regions[1] != 0:
            return None

        clip_index = 0 if regions[0] != CohenRegion.INSIDE else 1

        dx, dy, _ = end - start
        m = dx / dy

        if regions[clip_index] & CohenRegion.TOP != 0:
            x = start.x + m * (1 - start.y)
            y = 1
        elif regions[clip_index] & CohenRegion.BOTTOM != 0:
            x = start.x + m * (-1 - start.y)
            y = -1
        elif regions[clip_index] & CohenRegion.RIGHT != 0:
            x = 1
            y = start.y + (1 - start.x) / m
        elif regions[clip_index] & CohenRegion.LEFT != 0:
            x = -1
            y = start.y + (-1 - start.x) / m

        if clip_index == 0:
            start = Vec2(x, y)
            new_line.vertices_ndc[0] = start
            regions[0] = CohenRegion.region_of(start)
        else:
            end = Vec2(x, y)
            new_line.vertices_ndc[1] = end
            regions[1] = CohenRegion.region_of(end)
示例#7
0
    def clip_region(vertices, clipping_region):
        clipped = []
        for i in range(len(vertices) - 1):
            v1 = vertices[i]
            v2 = vertices[i + 1]

            regions = [
                CohenRegion.region_of(v) & clipping_region for v in [v1, v2]
            ]

            if all([region != clipping_region for region in regions]):
                clipped.extend([v1, v2])
            elif all([region == clipping_region for region in regions]):
                continue
            elif any([region == clipping_region for region in regions]):
                clip_index = 0 if regions[0] == clipping_region else 1

                dx, dy, _ = v2 - v1
                m = dx / dy

                if clipping_region == CohenRegion.TOP:
                    x = v1.x + m * (1 - v1.y)
                    y = 1
                elif clipping_region == CohenRegion.BOTTOM:
                    x = v1.x + m * (-1 - v1.y)
                    y = -1
                elif clipping_region == CohenRegion.RIGHT:
                    x = 1
                    y = v1.y + (1 - v1.x) / m
                elif clipping_region == CohenRegion.LEFT:
                    x = -1
                    y = v1.y + (-1 - v1.x) / m

                if clip_index == 0:
                    v1 = Vec2(x, y)
                else:
                    v2 = Vec2(x, y)
                clipped.extend([v1, v2])
        return clipped
示例#8
0
    def on_add_point(self, widget):
        notebook = self.builder.get_object('notebook1')
        page_num = notebook.get_current_page()
        vertice_store = self.builder.get_object('vertice_store')

        if NB_PAGES[page_num] == 'polygon':
            x = float(entry_text(self, 'entryX3'))
            y = float(entry_text(self, 'entryY3'))
        elif NB_PAGES[page_num] == 'curve':
            x = float(entry_text(self, 'entryX4'))
            y = float(entry_text(self, 'entryY4'))

        vertice_store.append([x, y, 1])
        self.vertices.append(Vec2(x, y))
示例#9
0
    def decode(cls, obj_file: str) -> 'Scene':
        from scene import Scene
        # Returns a Scene with the window and objects found
        vertices = []
        objs: List[GraphicObject] = []
        window = None

        current_name = ''
        filled = False

        for line in obj_file.splitlines():
            cmd, *args = line.split(' ')

            if cmd == 'v':
                vertices.append(Vec2(float(args[0]), float(args[1])))
            elif cmd == 'o':
                current_name = ' '.join(args)
            elif cmd == 'usemtl':
                if args[0] == 'filled':
                    filled = True
            elif cmd == 'p':
                objs.append(
                    Point(pos=vertices[int(args[0]) - 1], name=current_name))
            elif cmd == 'l':
                if len(args) == 2:
                    objs.append(
                        Line(start=vertices[int(args[0]) - 1],
                             end=vertices[int(args[1]) - 1],
                             name=current_name))
                elif args[0] == args[-1]:
                    objs.append(
                        Polygon(
                            vertices=[vertices[int(i) - 1] for i in args[:-1]],
                            name=current_name,
                            filled=filled))
                    filled = False
                else:
                    objs.append(
                        Curve(
                            vertices=[vertices[int(i) - 1] for i in args],
                            name=current_name,
                        ))
            elif cmd == 'w':
                window = Window(min=vertices[int(args[0]) - 1],
                                max=vertices[int(args[1]) - 1])

        return Scene(objs=objs, window=window)
示例#10
0
    def on_press_navigation_button(self, widget):
        TRANSFORMATIONS = {
            'nav-move-up': ('translate', Vec2(0, 10)),
            'nav-move-down': ('translate', Vec2(0, -10)),
            'nav-move-left': ('translate', Vec2(-10, 0)),
            'nav-move-right': ('translate', Vec2(10, 0)),
            'nav-rotate-left': ('rotate', -5),
            'nav-rotate-right': ('rotate', 5),
            'nav-zoom-in': ('scale', Vec2(1.1, 1.1)),
            'nav-zoom-out': ('scale', Vec2(0.9, 0.9)),
        }

        op, *args = TRANSFORMATIONS[widget.get_name()]
        if op == 'translate':
            args[0] = (args[0] @ rotation_matrix(self.scene.window.angle))

        for obj in self.selected_objs():
            if op == 'translate':
                obj.translate(*args)
            elif op == 'scale':
                obj.scale(*args)
            elif op == 'rotate':
                try:
                    abs_x = int(entry_text(self, 'rotation-ref-x'))
                    abs_y = int(entry_text(self, 'rotation-ref-y'))
                except ValueError:
                    abs_x = 0
                    abs_y = 0

                ref = {
                    RotationRef.CENTER: obj.centroid,
                    RotationRef.ORIGIN: Vec2(0, 0),
                    RotationRef.ABSOLUTE: Vec2(float(abs_x), float(abs_y)),
                }[self.rotation_ref]

                if isinstance(obj, GraphicObject3D):
                    obj.rotate(args[0], 0, 0, ref)
                else:
                    obj.rotate(*args, ref)
            obj.update_ndc(self.scene.window)

        self.window.queue_draw()
示例#11
0
    def on_motion(self, widget, event):
        def viewport_to_window(v: Vec2):
            viewport = self.viewport()

            return Vec2((v.x / viewport.width) * self.scene.window.width,
                        (v.y / viewport.height) * self.scene.window.height)

        # register x, y
        # translate window
        if self.dragging:
            current = Vec2(-event.x, event.y)
            delta = viewport_to_window(current - self.press_start)

            window = self.scene.window

            m = rotation_matrix(window.angle)

            delta = delta @ m

            self.scene.translate_window(delta)
            self.press_start = current
            widget.queue_draw()
示例#12
0
        def viewport_to_window(v: Vec2):
            viewport = self.viewport()

            return Vec2((v.x / viewport.width) * self.scene.window.width,
                        (v.y / viewport.height) * self.scene.window.height)
示例#13
0
 def on_button_press(self, widget, event):
     if BUTTON_EVENTS[event.button] == 'left':
         # register x, y
         self.press_start = Vec2(-event.x, event.y)
         self.dragging = True