def move_to_origin(self): size = self.original_size self.wmin = Coordinate((-size.width / 2) + CLIP_BOUNDARY, (-size.height / 2) + CLIP_BOUNDARY) self.wmax = Coordinate((size.width / 2) - CLIP_BOUNDARY, (size.height / 2) - CLIP_BOUNDARY) self.angle = 0 self._notify()
def on_press_drawing_area(self, drawing_area, event): click = Coordinate(event.x, event.y) if self.creating_wireframe is not None: untransformed_click = self.vp.untransform_coordinate(click) self.creating_wireframe.append(untransformed_click) self._refresh() return True
def untransform_coordinate(self, coordinate: Coordinate) -> Coordinate: coordinate = coordinate.rotate(self.vcenter, -self.angle) x = coordinate.x / (self.vmax.x - self.vmin.x) * ( self.wmax.x - self.wmin.x) + self.wmin.x y = coordinate.y / (self.vmax.y - self.vmin.y) * ( self.wmax.y - self.wmin.y) + self.wmin.y return Coordinate(x, y)
def transform_coordinate(self, coordinate: Coordinate) -> Coordinate: coordinate = coordinate.rotate(self.wcenter, self.angle) x = (coordinate.x - self.wmin.x) / (self.wmax.x - self.wmin.x) * ( self.vmax.x - self.vmin.x) y = (coordinate.y - self.wmin.y) / (self.wmax.y - self.wmin.y) * ( self.vmax.y - self.vmin.y) return Coordinate(x, y)
def cohen_sutherland(self, c0: Coordinate, c1: Coordinate): while True: code0 = self._code(c0) code1 = self._code(c1) if (code0 | code1) == 0: return True, c0, c1 elif (code0 & code1) != 0: return False, None, None else: out = code0 if code0 != 0 else code1 x = None y = None if (out & TOP) != 0: x = c0.x + (c1.x - c0.x) * (self.vmin.y - c0.y) / (c1.y - c0.y) y = self.vmin.y elif (out & BOTTOM) != 0: x = c0.x + (c1.x - c0.x) * (self.vmax.y - c0.y) / (c1.y - c0.y) y = self.vmax.y elif (out & RIGHT) != 0: x = self.vmax.x y = c0.y + (c1.y - c0.y) * (self.vmax.x - c0.x) / (c1.x - c0.x) elif (out & LEFT) != 0: x = self.vmin.x y = c0.y + (c1.y - c0.y) * (self.vmin.x - c0.x) / (c1.x - c0.x) assert x is not None and y is not None if out == code0: c0 = Coordinate(x, y) else: c1 = Coordinate(x, y)
def _refresh(self): self._refresh_list() self._clear_surface() pencil = Pencil(self.surface) clipper = Clipper(self.vp.cmin, self.vp.cmax) for wireframe in self.vp.get_grid(): clipped_wireframes = clipper.clip(wireframe) for w in clipped_wireframes: pencil.draw_wireframe(w) origin = self.vp.transform_coordinate(Coordinate(0, 0)) if clipper.inside(origin): pencil.line_width(10) pencil.color(Color(0, 0, 0, 0.5)) pencil.draw_point(origin) pencil.line_width(1.5) for wireframe in self.df.wireframes: transformed_wireframe = self.vp.transform_wireframe(wireframe) clipped_wireframe = clipper.clip(transformed_wireframe) for w in clipped_wireframe: pencil.draw_wireframe(w) if self.creating_wireframe is not None: new_wireframe = Wireframe( id='creating', coordinates=self.creating_wireframe, color=Color(1, 0, 0) ) transformed_wireframe = self.vp.transform_wireframe(new_wireframe) pencil.draw_wireframe(transformed_wireframe) clipping_square = Wireframe.square( 'clipping_square', self.vp.cmin, self.vp.cmax, color=Color(1, 0.5, 0), ) pencil.draw_wireframe(clipping_square) self.window.queue_draw()
def apply(self, df: DisplayFile, vp: Viewport): wireframe = df[self.oid] if wireframe is None: raise ValueError('invalid oid') new = None if self.type == 'translate': if self.x is None or self.y is None: raise ValueError('scale') new = wireframe.translate(Delta(self.x, self.y).rotate(-vp.angle)) if self.type == 'scale': if self.x is None or self.y is None: raise ValueError('scale') new = wireframe.scale(Delta(self.x, self.y)) if self.type == 'rotate_world': if self.theta is None: raise ValueError('rotate_world') new = wireframe.rotate_on_world(self.theta) if self.type == 'rotate_coordinate': if self.x is None or self.y is None or self.theta is None: raise ValueError('rotate_coordinate') new = wireframe.rotate_on_coordinate(Coordinate(self.x, self.y), self.theta) if self.type == 'rotate_self': if self.theta is None: raise ValueError('rotate_self') new = wireframe.rotate_on_center(self.theta) if new is not None: df.replace(self.oid, new)
def __init__(self, size: Size, on_changed: Callable[[], None]): self.original_size = size self.wmin = Coordinate((-size.width / 2) + CLIP_BOUNDARY, (-size.height / 2) + CLIP_BOUNDARY) self.wmax = Coordinate((size.width / 2) - CLIP_BOUNDARY, (size.height / 2) - CLIP_BOUNDARY) self.vmin = Coordinate(0, 0) self.vmax = Coordinate(size.width, size.height) self.cmin = Coordinate(CLIP_BOUNDARY, CLIP_BOUNDARY) self.cmax = Coordinate(size.width - CLIP_BOUNDARY, size.height - CLIP_BOUNDARY) self.angle = 0 self.on_changed = on_changed
def vcenter(self) -> Coordinate: return Coordinate( (self.vmin.x + self.vmax.x) / 2, (self.vmin.y + self.vmax.y) / 2, )