def __init__(self, obj_id, name, x, y): # Object constructor Object.__init__(self, obj_id, name, "Point") # Constructor of Point Point2D.__init__(self, x, y) self.nx = x self.ny = y
def clipCenter(start_point: Point2D, end_point: Point2D): x1 = start_point.x y1 = start_point.y TL, TR, BR, BL, M = getAngularCoeficients(start_point, end_point) if end_point.x > start_point.x: # P2 is at the right of P1 if M >= TR: # TOP BORDER y2 = 1 x2 = (y2 - y1) / M + x1 elif BR <= M and M < TR: # RIGHT BORDER x2 = 1 y2 = (x2 - x1) * M + y1 elif M < BR: # BOTTOM BORDER y2 = -1 x2 = (y2 - y1) / M + x1 else: if M < TL: # TOP BORDER y2 = 1 x2 = (y2 - y1) / M + x1 elif TL <= M and M < BL: # LEFT BORDER x2 = -1 y2 = M * (x2 - x1) + y1 elif M >= BL: # BOTTOM BORDER y2 = -1 x2 = (y2 - y1) / M + x1 return Line(Point2D(x1, y1), Point2D(x2, y2))
def calculateCSInterception(p: Point2D, regionCode, m, xe, xd, yf, yt): new_y = None new_x = None if regionCode & 1: # LEFT new_x = xe new_y = m * (xe - p.x) + p.y if new_y <= yt and new_y >= yf: return Point2D(new_x, new_y) if regionCode & 2: # RIGHT new_x = xd new_y = m * (xd - p.x) + p.y if new_y <= yt and new_y >= yf: return Point2D(new_x, new_y) if regionCode & 4: # BOTTOM new_x = p.x + 1 / m * (yf - p.y) new_y = yf if new_x <= xd and new_x >= xe: return Point2D(new_x, new_y) if regionCode & 8: # TOP new_x = p.x + 1 / m * (yt - p.y) new_y = yt return Point2D(new_x, new_y)
def on_mouse_move(self, widget, event): # translate window if self.mouse_pressed: current_pos = Point2D(event.x, event.y) # self.main_window.print_log(f'event-x:{event.x} eventy:{event.y}') delta_viewport = Point2D( current_pos.x - self.mouse_start_pos.x, current_pos.y - self.mouse_start_pos.y, ) # self.main_window.print_log( # f'd_vp_x:{delta_viewport.x} d_vp_y:{delta_viewport.y}') delta_scn = self.viewport.viewport_to_scn(delta_viewport) # self.main_window.print_log( # f'd_scn_x:{delta_scn.x} d_scn_y:{delta_scn.y}') delta_world = self.window.scn_to_world(delta_scn) def f_win(val): self.window.translate(Point2D(-val.x, -val.y), 2) def f_obj(obj_id, val): self.main_window.display_file[obj_id].translate(val) self.apply_to_selected_objects(delta_world, f_win, f_obj) self.mouse_start_pos = current_pos widget.queue_draw()
def clipEdge(start_point: Point2D, end_point: Point2D): y2 = end_point.y x2 = end_point.x TL, TR, BR, BL, M = getAngularCoeficients(start_point, end_point) # calculate LEFT border interception (general case) x1 = -1 y1 = end_point.y - M * (end_point.x - x1) if M >= TL or M < BL: return None if M > TR: # LEFT or TOP-LEFT if end_point.y >= 1: # intercepts the TOP border too y2 = 1 x2 = (y2 - y1) / M + x1 elif M <= BR: # LEFT or BOTTOM-LEFT if end_point.y <= -1: # intercepts the BOTTOM border too y2 = -1 x2 = (y2 - y1) / M + x1 else: # LEFT or LEFT-RIGHT if end_point.x >= 1: # intercepts the RIGHT border too x2 = 1 y2 = (x2 - x1) * M + y1 return Line(Point2D(x1, y1), Point2D(x2, y2))
def draw(self, transform: np.array, cairo): resolution = 50 points = [] array_x = np.array( [pt.x for pt in self.scn], dtype=float) array_y = np.array( [pt.y for pt in self.scn], dtype=float) if self.curve_type == CurveType.bezier: for section in range(0, len(self.scn) - 1, 3): for delta in np.linspace(0, 1, resolution): T = np.array( [delta**3, delta**2, delta, 1], dtype=float) TM = T @ self.bezier_matrix x = TM @ array_x[section:section + 4] y = TM @ array_y[section:section + 4] points.append(Point2D(x, y)) elif self.curve_type == CurveType.b_spline: for i in range(0, len(self.scn) - 3): Gx = array_x[i:i + 4] Gy = array_y[i:i + 4] Cx = self.bspline_matrix @ Gx Cy = self.bspline_matrix @ Gy E = self.calc_bspline_foward(1.0 / resolution) Dx = E @ Cx Dy = E @ Cy for _ in range(resolution + 1): x = Dx[0] y = Dy[0] Dx = Dx + np.append(Dx[1:], 0) Dy = Dy + np.append(Dy[1:], 0) points.append(Point2D(x, y)) cairo.save() [vx, vy, _] = np.array( ([points[0].x, points[0].y, 1]), dtype=float).dot(transform) cairo.move_to(vx, vy) for i in range(1, len(points) - 1): x = points[i].x y = points[i].y [vx, vy, _] = np.array( ([x, y, 1]), dtype=float).dot(transform) if -1 < x and x < 1 and -1 < y and y < 1: cairo.line_to(vx, vy) cairo.stroke() cairo.move_to(vx, vy)
def clipCorner(start_point: Point2D, end_point: Point2D): x2 = end_point.x y2 = end_point.y TL, TR, BR, BL, M = getAngularCoeficients(start_point, end_point) if M >= TR or M <= BL: return None if TL < BR: # case 1 (predominantly bottom) if M < TL: # LEFT or LEFT-BOTTOM x1 = -1 y1 = end_point.y - M * (end_point.x - x1) if end_point.y <= -1: # intercepts BOTTOM border too y2 = -1 x2 = (y2 - y1) / M + x1 else: y1 = 1 x1 = end_point.x - (end_point.y - y1) / M if M >= BR: # TOP or TOP-RIGHT if end_point.x >= 1: x2 = 1 y2 = (x2 - x1) * M + y1 else: # TOP or TOP-BOTTOM if end_point.y <= -1: y2 = -1 x2 = (y2 - y1) / M + x1 else: # case 2 (predominantly right) if M >= TL: # TOP or TOP-RIGHT y1 = 1 x1 = end_point.x - (end_point.y - y1) / M if end_point.x >= 1: x2 = 1 y2 = (x2 - x1) * M + y1 else: x1 = -1 y1 = end_point.y - M * (end_point.x - x1) if M <= BR: # LEFT or LEFT-BOTTOM if end_point.y <= -1: # intercepts BOTTOM border too y2 = -1 x2 = (y2 - y1) / M + x1 else: # LEFT or LEFT-RIGHT if end_point.x >= 1: # intercepts the RIGHT border too x2 = 1 y2 = (x2 - x1) * M + y1 return Line(Point2D(x1, y1), Point2D(x2, y2))
def get_center(self, center): cx = (self.start.x + self.end.x) / 2 cy = (self.start.y + self.end.y) / 2 if center == 1: return Point2D(0, 0) elif center == 2: return Point2D(cx, cy) else: return self.start
def get_center(self, center): cx = 0 cy = 0 for point in self.points: cx += point.x cy += point.y cx /= len(self.points) cy /= len(self.points) if center == 1: return Point2D(0, 0) elif center == 2: return Point2D(cx, cy) else: return self.points[0]
def update_scn(self, transform): self.scn = [] for index, point in enumerate(self.points): [vx, vy, _] = np.array( ([self.points[index].x, self.points[index].y, 1]), dtype=float).dot(transform) self.scn.append(Point2D(vx, vy))
def cb_menu_file_new(self, *args): self.main_window.display_file.clear() self.store.clear() self.window = Window(Point2D(0, 0), 0, 200, 200) # re-draw objects on drawing_area self.main_window.drawing_area.queue_draw()
def cohenSutherlandClip(line: Line): p0 = line.start p1 = line.end codeP0 = computeOutCode(p0, -1, -1, 1, 1) codeP1 = computeOutCode(p1, -1, -1, 1, 1) if not (codeP0 | codeP1): # TOTALMENTE CONTIDA return line elif (codeP0 & codeP1): # TOTALMENTE FORA DA JANELA return None else: # PARCIALMENTE CONTIDA (CALCULAR CLIP PARA OS DOIS PONTOS) if p1.x == p0.x: y0 = p0.y y1 = p1.y if p1.y > 1: y1 = 1 elif p1.y < -1: y1 = -1 if p0.y < -1: y0 = -1 elif p0.y > 1: y0 = 1 return Line(Point2D(p0.x, y0), Point2D(p1.x, y1)) m = (p1.y - p0.y) / (p1.x - p0.x) if codeP0: p0 = calculateCSInterception(p0, codeP0, m, -1, 1, -1, 1) if p0 and codeP1: p1 = calculateCSInterception(p1, codeP1, m, -1, 1, -1, 1) if not (p0) or not (p1): return None else: return Line(p0, p1)
def __init__(self, main_window): self.main_window = main_window self.builder = main_window.builder self.main_window.filepath = "obj_files/persistance.obj" self.store = self.builder.get_object("liststore_obj") self.scrolled_window = self.builder.get_object("scrolled_window_log") self.lb_window_pos = self.builder.get_object("lb_window_pos") self.entry_step = self.builder.get_object("entry_step") self.entry_angle = self.builder.get_object("entry_angle") self.da_width = 0 self.da_height = 0 self.mouse_start_pos = None self.mouse_pressed = False self.window = Window(Point2D(0, 0), 0, 200, 200) self.viewport = Viewport(0, 0, 100, 100, 100, 100)
def f_win(val): self.window.translate(Point2D(-val.x, -val.y), 2)
def on_mouse_press(self, widget, event): # self.main_window.print_log("MOUSE PRESS") if event.button == MouseButtons.left: self.mouse_start_pos = Point2D(event.x, event.y) self.mouse_pressed = True
def cb_menu_edit_reset_window(self, *args): self.window = Window(Point2D(0, 0), 0, 200, 200) # re-draw objects on drawing_area self.main_window.drawing_area.queue_draw()
def bt_create_object_clicked_cb(self, button): page = self.builder.get_object("add_obj_notebook").get_current_page() try: name = self.builder.get_object("entry_obj_name").get_text() new_id = 0 if self.main_window.display_file: new_id = max(self.main_window.display_file) new_id += 1 # new point insertion if page == 0: x = float(self.builder.get_object("entry_point_x").get_text()) y = float(self.builder.get_object("entry_point_y").get_text()) if name == "": name = f"Point {new_id}" obj = DrawablePoint2D(new_id, name, x, y) # new line insertion elif page == 1: x1 = float(self.builder.get_object("entry_line_x1").get_text()) y1 = float(self.builder.get_object("entry_line_y1").get_text()) x2 = float(self.builder.get_object("entry_line_x2").get_text()) y2 = float(self.builder.get_object("entry_line_y2").get_text()) if name == "": name = f"Line {new_id}" obj = DrawableLine(new_id, name, Point2D(x1, y1), Point2D(x2, y2)) # new wireframe insertion elif page == 2: buffer = self.builder.get_object( "wireframe_points_view").get_buffer() start_iter = buffer.get_start_iter() end_iter = buffer.get_end_iter() entrada = buffer.get_text(start_iter, end_iter, False) entrada = entrada.split("\n") filled = self.builder.get_object("filled_check").get_active() pontos = [] for i in range(len(entrada)): x, y = entrada[i].split() pontos.append(Point2D(float(x), float(y))) if name == "": name = f"Wireframe {new_id}" obj = DrawablePolygon(new_id, name, pontos, filled) # add curve elif page == 3: curve_type = None if self.builder.get_object("rdb_bezier").get_active(): if name == "": name = f"Bezier {new_id}" curve_type = CurveType.bezier else: if name == "": name = f"B-spline {new_id}" curve_type = CurveType.b_spline buffer = self.builder.get_object( "curve_points_view").get_buffer() start_iter = buffer.get_start_iter() end_iter = buffer.get_end_iter() entrada = buffer.get_text(start_iter, end_iter, False) entrada = entrada.split("\n") pontos = [] for i in range(len(entrada)): x, y = entrada[i].split() pontos.append(Point2D(float(x), float(y))) obj = DrawableCurve(new_id, name, pontos, curve_type) # end if if name == "": raise ValueError() self.main_window.display_file[obj.id] = obj store = self.builder.get_object("liststore_obj") store.append([obj.id, obj.name, obj.type]) da = self.builder.get_object("gtk_drawing_area") da.draw(da.get_window().cairo_create()) self.dialog_add_object.destroy() except ValueError: self.main_window.print_log( "Error: Invalid Value / All fields need to be defined\n")
def __init__(self, obj_id, name, start, end): # constructor of Object Object.__init__(self, obj_id, name, "Line") # constructor of Line Line.__init__(self, start, end) self.scn = Line(Point2D(0, 0), Point2D(0, 0))
def nichollLeeNichollClip(line: Line): p1 = line.start p2 = line.end codeP1 = computeOutCode(p1, -1, -1, 1, 1) codeP2 = computeOutCode(p2, -1, -1, 1, 1) if (codeP1 | codeP2) == 0: # trivially accepted return line elif (codeP1 & codeP2) > 0: # trivially rejected return None if p1.x == p2.x: # to prevent division by zero error x1 = p1.x x2 = p2.x y1 = p1.y y2 = p2.y if p1.y > 1: y1 = 1 elif p1.y < -1: y1 = -1 if p2.y > 1: y2 = 1 elif p2.y < -1: y2 = -1 return Line(Point2D(x1, y1), Point2D(x2, y2)) if codeP1 == 0: # CENTER clipped = clipCenter(p1, p2) elif codeP1 == 1: # LEFT clipped = clipEdge(p1, p2) elif codeP1 == 2: # RIGHT (-x, y) p1_aux = Point2D(-p1.x, p1.y) p2_aux = Point2D(-p2.x, p2.y) clipped = clipEdge(p1_aux, p2_aux) if clipped: clipped.start.x *= -1 clipped.end.x *= -1 elif codeP1 == 4: # BOTTOM (y, x) p1_aux = Point2D(p1.y, p1.x) p2_aux = Point2D(p2.y, p2.x) clipped = clipEdge(p1_aux, p2_aux) if clipped: temp = clipped.start.x clipped.start.x = clipped.start.y clipped.start.y = temp temp = clipped.end.x clipped.end.x = clipped.end.y clipped.end.y = temp elif codeP1 == 8: # TOP (-y, x) p1_aux = Point2D(-p1.y, p1.x) p2_aux = Point2D(-p2.y, p2.x) clipped = clipEdge(p1_aux, p2_aux) if clipped: temp = clipped.start.x clipped.start.x = clipped.start.y clipped.start.y = -temp temp = clipped.end.x clipped.end.x = clipped.end.y clipped.end.y = -temp elif codeP1 == 5: # LEFT-BOTTOM (x, -y) p1_aux = Point2D(p1.x, -p1.y) p2_aux = Point2D(p2.x, -p2.y) clipped = clipCorner(p1_aux, p2_aux) if clipped: clipped.start.y *= -1 clipped.end.y *= -1 elif codeP1 == 6: # RIGHT-BOTTOM (-x, -y) p1_aux = Point2D(-p1.x, -p1.y) p2_aux = Point2D(-p2.x, -p2.y) clipped = clipCorner(p1_aux, p2_aux) if clipped: clipped.start.x *= -1 clipped.end.x *= -1 clipped.start.y *= -1 clipped.end.y *= -1 elif codeP1 == 9: # TOP-LEFT clipped = clipCorner(p1, p2) else: # TOP-RIGHT (-x, y) p1_aux = Point2D(-p1.x, p1.y) p2_aux = Point2D(-p2.x, p2.y) clipped = clipCorner(p1_aux, p2_aux) if clipped: clipped.start.x *= -1 clipped.end.x *= -1 return clipped
def f_win(amount): self.window.translate(Point2D(-x * amount, -y * amount), 1)
def weilerAthertonPolygonClip(polygon: Polygon): points = getOrderedPoints(polygon) # lista todas interseções i = 0 while i < len(points): p1 = points[i] p2 = points[(i + 1) % len(points)] line = cohenSutherlandClip(Line(p1, p2)) if line: t1 = pointClip(p1) t2 = pointClip(p2) if t1: if not t2: np = line.end np.pType = 2 insertPoint(points, np, i + 1) else: if t2: np = line.start np.pType = 1 insertPoint(points, np, i + 1) else: np1 = line.start np2 = line.end np1.pType = 1 np2.pType = 2 insertPoint(points, np1, i + 1) insertPoint(points, np2, i + 2) i += 1 i += 1 # END FOR # nova lista dos pontos clip (varre as bordas externas) control = len(points) # borda superior sup = [Point2D(-1, 1)] for i in range(control): if points[i].y == 1 and points[i] not in sup: sup.append(points[i]) sup.sort(key=lambda a: a.x) # borda direita right = [Point2D(1, 1)] for i in range(control): if points[i].x == 1 and points[i] not in right: right.append(points[i]) right.sort(key=lambda a: a.y, reverse=True) # borda inferior inf = [Point2D(1, -1)] for i in range(control): if points[i].y == -1 and points[i] not in inf: inf.append(points[i]) inf.sort(key=lambda a: a.x, reverse=True) # borda esquerda left = [Point2D(-1, -1)] for i in range(control): if points[i].x == -1 and points[i] not in left: left.append(points[i]) left.sort(key=lambda a: a.y) clipping = sup + right + inf + left markUnvisited(points) # fluxo principal visible = [] for i in range( len(points )): # FLUXO PARA PERCORRER TODOS OS PONTOS DO OBJETO CLIPPADO if points[i].visited: continue if pointClip(points[i]): # DEFINE UM NOVO ESPACO PARA POLIGONO visible.append([]) point = points[i] l = 1 index = i while True: if point.visited: break else: # INSERE O PONTO NO POLIGONO A SER DESENHADO point.visited = True visible[-1].append(point) # DEFINING NEXT LIST if point.pType == 1: # INCOMING l = 1 index = (points.index(point) + 1) elif point.pType == 2: # OUTGOING l = 2 index = (clipping.index(point) + 1) else: index = index + 1 # DEFINING NEXT if l == 1: point = points[index % len(points)] else: point = clipping[index % len(clipping)] # end of visits # END FOR if len(visible): return visible else: return None
def f_obj(obj_id, amount): self.main_window.display_file[obj_id].translate( Point2D(x * amount, y * amount))
def clip(self, algorithm=None): if clip.pointClip(Point2D(self.nx, self.ny)): self.visible = True else: self.visible = False