def __init__(self, da): self.display_file = DisplayFile() self.draw_counter = 0 self.da = da da_width = da.get_allocation().width da_height = da.get_allocation().height # Window and viewport start with the same size as the drawing area, # but compensating for the clipping border size (otherwise you # wouldn't see by default a point drawn at 0,0). self.window = Window(-cbz, -cbz, da_width - cbz, da_height - cbz) self.viewport = Viewport(-cbz, -cbz, da_width - cbz, da_height - cbz) self.transform = Transform() # Pass reference to window for Transform and Viewport self.transform.setWindow(self.window) self.viewport.setWindow(self.window) # To verify that both normalize() and denormalize() work # print(self.transform.normalize(0,0)) # print(self.transform.normalize(self.window.getWidth(),self.window.getHeight())) # print(self.transform.denormalize(-1,-1)) # print(self.transform.denormalize(1,1)) self.projection = 'parallel'
def __init__(self, x_min, y_min, x_max, y_max): #print("({},{}) ({},{})".format(x_min, y_min, x_max, y_max)) Window.x_min = x_min Window.y_min = y_min Window.x_max = x_max Window.y_max = y_max Window.transform = Transform() Window.display_file = DisplayFile()
def __init__(self, builder, drawing_manager): self.builder = builder self.dm = drawing_manager self.transform = Transform() self.obj_handler = ObjHandler() self.clipping = Clipping() # References to GTK objects self.add_object_window = self.builder.get_object("AddObjectWindow") self.text_view = self.builder.get_object("Log") self.tree_view = self.builder.get_object("TreeView") self.obj_file_chooser = self.builder.get_object("ObjFileChooser") self.object_radio_button = self.builder.get_object("ObjectRadioButton") self.world_radio_button = self.builder.get_object("WorldRadioButton") self.point_radio_button = self.builder.get_object("PointRadioButton") self.rotate_x = self.builder.get_object("RotateX") self.rotate_y = self.builder.get_object("RotateY") self.object_rotation_angle = self.builder.get_object( "objectRotationAngle") self.object_units_for_moving = self.builder.get_object( "objectUnitsForMoving") self.line_clipping_cs = self.builder.get_object("LineClippingCS") self.line_clipping_lb = self.builder.get_object("LineClippingLB") self.window_selected = self.builder.get_object("WindowSelected") self.object_selected = self.builder.get_object("ObjectSelected") self.parallel_projection = self.builder.get_object( "ParallelProjectionRadioButton") self.perspective_projection = self.builder.get_object( "PerspectiveProjectionRadioButton") self.text_buffer = self.text_view.get_buffer() self.display_file = DisplayFile() self.display_file.setBuilder(builder) # Used to keep state of polygons and curves when points are added self.temp_polygon = [] self.temp_curve = []
class ObjHandler: def __init__(self): self.display_file = DisplayFile() def importFile(self, path): self.display_file.wipeOut() #print("{}".format(path)) vertices = dict() vertice_counter = 0 name = "" self.file = open(path, "r+") # read and write for line in self.file: if (line[0] == "v"): # store vertices in a dictionary vertice_counter += 1 vertices[vertice_counter] = line elif (line[0] == "o" ): # store temporarily the name of the object to come match = re.findall(r"\S+", line) name = match[1] elif (line[0] == "p"): # TODO: FINISH THIS match = re.findall(r"\S+", line) vertice_for_point = vertices[float(match[1])] match = re.findall(r"\S+", vertice_for_point) coord = {"x": float(match[1]), "y": float(match[2])} p1 = Point(name) p1.addCoords(coord["x"], coord["y"]) self.display_file.addObject(p1) elif (line[0] == "l"): match = re.findall(r"\S+", line) if (len(match) == 3): # line l = Line(name) else: # polygon l = None if (match[1] == match[-1]): l = Polygon(name) else: l = Curve(name) for item in match: if ( item != "l" ): # ignore the first character, only compute coordinates vertice_for_point = vertices[float(item)] match_vertice = re.findall(r"\S+", vertice_for_point) coord = { "x": float(match_vertice[1]), "y": float(match_vertice[2]) } l.addCoords(coord["x"], coord["y"]) if (match[1] == match[-1] ): # if polygon (last coords == first coords) l.popCoords() # remove repeated coords self.display_file.addObject(l) def exportFile(self, path): output_file = open(path, "w+") # write, overwrite and create if needed temp = "" # this variable holds the objects related to the vertices vertice_counter = 0 # Valid objects are: # - vertice (v) (these are always in the beginning of the file) # - point (p) # - line (l) # - object name (o) for obj in DisplayFile.objects: obj_type = obj.__class__.__name__ w_coords = obj.getWorldCoords() if (obj_type == "Point"): vertice_counter += 1 output_file.write("v {} {} 0\n".format(w_coords[0]["x"], w_coords[0]["y"])) temp += "o {}\n".format(obj.getName()) temp += "p {}\n".format(vertice_counter) elif (obj_type == "Line"): vertice_counter += 1 output_file.write("v {} {} 0\n".format(w_coords[0]["x"], w_coords[0]["y"])) vertice_counter += 1 output_file.write("v {} {} 0\n".format(w_coords[1]["x"], w_coords[1]["y"])) temp += "o {}\n".format(obj.getName()) temp += "l {} {}\n".format(vertice_counter - 1, vertice_counter) elif (obj_type == "Polygon"): temp += "o {}\n".format(obj.getName()) temp += "l" initial = vertice_counter + 1 for coord in w_coords: vertice_counter += 1 output_file.write("v {} {} 0\n".format( coord["x"], coord["y"])) temp += " {}".format(vertice_counter) temp += " {}\n".format(initial) elif (obj_type == "Curve"): temp += "o {}\n".format(obj.getName()) temp += "l" for coord in w_coords: vertice_counter += 1 output_file.write("v {} {} 0\n".format( coord["x"], coord["y"])) temp += " {}".format(vertice_counter) temp += "\n" output_file.write("{}\n".format(temp)) output_file.close()
def __init__(self): self.display_file = DisplayFile()
import numpy as np from display_file import DisplayFile from matrices import Matrices from variables import clipping_border_size as cbz from numpy.matlib import identity from math import sin, cos, pi display_file = DisplayFile() class Transform: a, b = -1, 1 def __init__(self): self.m = Matrices() def setWindow(self, window): Transform.window = window def normalize(self, x, y): # x' = (b-a) * ((x - min) / (max - min)) + a window = Transform.window a, b = self.a, self.b wmin_x, wmax_x = window.getMin()["x"] + cbz, window.getMax()["x"] - cbz wmin_y, wmax_y = window.getMin()["y"] + cbz, window.getMax()["y"] - cbz # print("(Transform) Window at ({},{}) ({},{})".format(wmin_x, wmin_y, wmax_x, wmax_y)) new_x = (b - a) * ((x - wmin_x) / (wmax_x - wmin_x)) + a new_y = (b - a) * ((y - wmin_y) / (wmax_y - wmin_y)) + a
class DrawingManager: def __init__(self, da): self.display_file = DisplayFile() self.draw_counter = 0 self.da = da da_width = da.get_allocation().width da_height = da.get_allocation().height # Window and viewport start with the same size as the drawing area, # but compensating for the clipping border size (otherwise you # wouldn't see by default a point drawn at 0,0). self.window = Window(-cbz, -cbz, da_width - cbz, da_height - cbz) self.viewport = Viewport(-cbz, -cbz, da_width - cbz, da_height - cbz) self.transform = Transform() # Pass reference to window for Transform and Viewport self.transform.setWindow(self.window) self.viewport.setWindow(self.window) # To verify that both normalize() and denormalize() work # print(self.transform.normalize(0,0)) # print(self.transform.normalize(self.window.getWidth(),self.window.getHeight())) # print(self.transform.denormalize(-1,-1)) # print(self.transform.denormalize(1,1)) self.projection = 'parallel' def setProjection(self, name): self.projection = name def getWindow(self): return self.window def redraw(self): self.da.queue_draw() def drawBackground(self, da, ctx): ctx.set_source_rgb(255, 255, 255) # color white ctx.paint() def drawClippingBorder(self, da, ctx): ctx.set_line_width(1) ctx.set_source_rgb(255, 0, 0) # color red ctx.move_to(cbz, cbz) ctx.line_to(self.window.getWidth() - cbz, cbz) ctx.line_to(self.window.getWidth() - cbz, self.window.getHeight() - cbz) ctx.line_to(cbz, self.window.getHeight() - cbz) ctx.close_path() ctx.stroke() def draw(self, da, ctx): self.drawBackground(da, ctx) ctx.set_line_width(2) ctx.set_source_rgb(0, 0, 0) # color black for i in self.display_file.getObjects(): # print('Drawing object "{}"'.format(i.getName())) i.drawToViewport(ctx, self.viewport) self.draw_counter += 1 # print("draw() #{0}".format(self.draw_counter)) if (self.projection == 'perspective'): for i in self.display_file.getObjects3d(): obj_perspectiva = copy.deepcopy(i) lista_pontos_3d = [] for segmento in obj_perspectiva.segments: lista_pontos_3d.append(segmento[0]) lista_pontos_3d.append(segmento[1]) self.transform.perspectiva(lista_pontos_3d, 100) for s in obj_perspectiva.segments: #print(s[0].x, s[0].y) #print(s[1].x, s[1].y) coords0 = self.viewport.transformadaViewPortCoordenada( s[0].x, s[0].y) coords1 = self.viewport.transformadaViewPortCoordenada( s[1].x, s[1].y) ctx.move_to(coords0['x'], coords0['y']) ctx.line_to(coords1['x'], coords1['y']) else: for i in self.display_file.getObjects3d(): for s in i.segments: reta = [{ "x": s[0].x, "y": s[0].y }, { "x": s[1].x, "y": s[1].y }] clipping = Clipping() coords = clipping.cohenSutherland(reta, self.window) if (coords): coords0 = self.viewport.transformadaViewPortCoordenada( coords[0]['x'], coords[0]['y']) coords1 = self.viewport.transformadaViewPortCoordenada( coords[1]['x'], coords[1]['y']) ctx.move_to(coords0['x'], coords0['y']) ctx.line_to(coords1['x'], coords1['y']) ctx.stroke() self.drawClippingBorder(da, ctx)
class Handler: def __init__(self, builder, drawing_manager): self.builder = builder self.dm = drawing_manager self.transform = Transform() self.obj_handler = ObjHandler() self.clipping = Clipping() # References to GTK objects self.add_object_window = self.builder.get_object("AddObjectWindow") self.text_view = self.builder.get_object("Log") self.tree_view = self.builder.get_object("TreeView") self.obj_file_chooser = self.builder.get_object("ObjFileChooser") self.object_radio_button = self.builder.get_object("ObjectRadioButton") self.world_radio_button = self.builder.get_object("WorldRadioButton") self.point_radio_button = self.builder.get_object("PointRadioButton") self.rotate_x = self.builder.get_object("RotateX") self.rotate_y = self.builder.get_object("RotateY") self.object_rotation_angle = self.builder.get_object( "objectRotationAngle") self.object_units_for_moving = self.builder.get_object( "objectUnitsForMoving") self.line_clipping_cs = self.builder.get_object("LineClippingCS") self.line_clipping_lb = self.builder.get_object("LineClippingLB") self.window_selected = self.builder.get_object("WindowSelected") self.object_selected = self.builder.get_object("ObjectSelected") self.parallel_projection = self.builder.get_object( "ParallelProjectionRadioButton") self.perspective_projection = self.builder.get_object( "PerspectiveProjectionRadioButton") self.text_buffer = self.text_view.get_buffer() self.display_file = DisplayFile() self.display_file.setBuilder(builder) # Used to keep state of polygons and curves when points are added self.temp_polygon = [] self.temp_curve = [] def onDestroy(self, *args): Gtk.main_quit() def onImportObj(self, button): self.printToLog("onImportObj") self.obj_file_chooser.show_all() def onCancelFileImport(self, button): self.printToLog("onCancelFileImport") self.obj_file_chooser.hide() def onFileClicked(self, button): file_path = self.obj_file_chooser.get_filename() self.printToLog("onFileClicked ({})".format(file_path)) self.obj_handler.importFile(file_path) self.obj_file_chooser.hide() def onExportObj(self, button): self.printToLog("onExportObj") self.obj_handler.exportFile("./file.obj") def onRotateWindowLeft(self, button): self.printToLog("onRotateWindowLeft") angle = int(self.object_rotation_angle.get_text()) self.dm.getWindow().rotate(angle) self.dm.redraw() def onRotateWindowRight(self, button): self.printToLog("onRotateWindowRight") angle = float(self.object_rotation_angle.get_text()) self.dm.getWindow().rotate(-angle) self.dm.redraw() def onAddObjectClicked(self, button): self.printToLog("onAddObjectClicked") add_object_window = self.builder.get_object("AddObjectWindow") add_object_window.show_all() def onAddCurvePoint(self, button): x_entry = self.builder.get_object("EntryXCurve").get_text() y_entry = self.builder.get_object("EntryYCurve").get_text() self.temp_curve.append({"x": x_entry, "y": y_entry}) self.printToLog("onAddCurvePoint ({},{})".format(x_entry, y_entry)) def onAddPolygonPoint(self, button): x_entry = self.builder.get_object("EntryXPolygon").get_text() y_entry = self.builder.get_object("EntryYPolygon").get_text() self.temp_polygon.append({"x": x_entry, "y": y_entry}) self.printToLog("onAddPolygonPoint ({},{})".format(x_entry, y_entry)) def onRemoveCurvePoint(self, button): if (len(self.temp_curve) > 0): self.temp_curve.pop() else: self.printToLog("No point to remove") self.printToLog("onRemoveCurvePoint") def onRemovePolygonPoint(self, button): if (len(self.temp_polygon) > 0): self.temp_polygon.pop() else: self.printToLog("No point to remove") self.printToLog("onRemovePolygonPoint") def onAddCurve(self, button): self.printToLog("onAddCurve") name = self.builder.get_object("CurveName").get_text() curve = Curve(name) for point in self.temp_curve: curve.addCoords(float(point["x"]), float(point["y"])) self.display_file.addObject(curve) self.temp_curve = [] self.add_object_window.hide() def onAddPolygon(self, button): self.printToLog("onAddPolygon") name = self.builder.get_object("PolygonName").get_text() polygon = Polygon(name) for point in self.temp_polygon: polygon.addCoords(float(point["x"]), float(point["y"])) self.display_file.addObject(polygon) self.temp_polygon = [] self.add_object_window.hide() def onAddCube(self, button): name = self.builder.get_object("3DName").get_text() segments = [[Point3D(50, 50, 0), Point3D(50, 100, 0)], [Point3D(50, 100, 0), Point3D(150, 100, 0)], [Point3D(150, 100, 0), Point3D(150, 50, 0)], [Point3D(150, 50, 0), Point3D(50, 50, 0)], [Point3D(50, 50, 50), Point3D(50, 100, 50)], [Point3D(50, 100, 50), Point3D(150, 100, 50)], [Point3D(150, 100, 50), Point3D(150, 50, 50)], [Point3D(150, 50, 50), Point3D(50, 50, 50)], [Point3D(50, 50, 0), Point3D(50, 50, 50)], [Point3D(50, 100, 0), Point3D(50, 100, 50)], [Point3D(150, 100, 0), Point3D(150, 100, 50)], [Point3D(150, 50, 0), Point3D(150, 50, 50)]] obj3d = Object3D(segments, name) self.display_file.addObject3d(obj3d) self.add_object_window.hide() def onAddPoint(self, button): self.printToLog("onAddPoint") name_entry = self.builder.get_object("PointNameEntry") x_entry = self.builder.get_object("PointXEntry") y_entry = self.builder.get_object("PointYEntry") p1 = Point(name_entry.get_text()) p1.addCoords(float(x_entry.get_text()), float(y_entry.get_text())) self.display_file.addObject(p1) self.add_object_window.hide() def onAddLine(self, button): self.printToLog("onAddLine") name_entry = self.builder.get_object("EntryNameNewLine") x1_entry = self.builder.get_object("EntryX1Line") y1_entry = self.builder.get_object("EntryY1Line") x2_entry = self.builder.get_object("EntryX2Line") y2_entry = self.builder.get_object("EntryY2Line") l1 = Line(name_entry.get_text()) l1.addCoords(float(x1_entry.get_text()), float(y1_entry.get_text())) l1.addCoords(float(x2_entry.get_text()), float(y2_entry.get_text())) self.display_file.addObject(l1) self.add_object_window.hide() def onRemoveObjectClicked(self, button): self.printToLog("onRemoveObjectClicked") obj_list, index = self.tree_view.get_selection().get_selected() if index != None: self.display_file.removeObject(obj_list[index][2]) obj_list.remove(index) self.dm.redraw() else: self.printToLog("No object selected") def onZoomOut(self, button): self.printToLog("onZoomOut") self.dm.getWindow().zoom(0.9) self.dm.redraw() def onZoomIn(self, button): self.printToLog("onZoomIn") self.dm.getWindow().zoom(1.1) self.dm.redraw() def onMoveObjectUp(self, button): if self.window_selected.get_active(): return self.onMoveWindowUp(button) units = float(self.object_units_for_moving.get_text()) self.printToLog("onMoveObjectUp") self.transform.move(self.tree_view, 0, units) self.dm.redraw() def onMoveObjectDown(self, button): if self.window_selected.get_active(): return self.onMoveWindowDown(button) units = float(self.object_units_for_moving.get_text()) self.printToLog("onMoveObjectDown") self.transform.move(self.tree_view, 0, -units) self.dm.redraw() def onMoveObjectLeft(self, button): if self.window_selected.get_active(): return self.onMoveWindowLeft(button) units = float(self.object_units_for_moving.get_text()) self.printToLog("onMoveObjectLeft") self.transform.move(self.tree_view, -units, 0) self.dm.redraw() def onMoveObjectRight(self, button): if self.window_selected.get_active(): return self.onMoveWindowRight(button) units = float(self.object_units_for_moving.get_text()) self.printToLog("onMoveObjectRight") self.transform.move(self.tree_view, units, 0) self.dm.redraw() def onLineClippingChanged(self, button): if self.line_clipping_cs.get_active(): self.printToLog("Line clipping algorithm set to Cohen-Sutherland.") self.clipping.setlineClippingAlgorithm("cs") elif self.line_clipping_lb.get_active(): self.printToLog("Line clipping algorithm set to Liang-Barsky.") self.clipping.setlineClippingAlgorithm("lb") def onProjectionChanged(self, button): if self.parallel_projection.get_active(): self.printToLog("Parallel.") self.dm.setProjection('parallel') elif self.perspective_projection.get_active(): self.printToLog("Perspective.") self.dm.setProjection('perspective') def onRotateObjectLeft(self, button): if self.window_selected.get_active(): return self.onRotateWindowLeft(button) self.printToLog("onRotateObjectLeft") angle = int(self.object_rotation_angle.get_text()) if self.object_radio_button.get_active(): self.transform.rotate(self.tree_view, -angle, 'center', 0, 0) elif self.world_radio_button.get_active(): self.transform.rotate(self.tree_view, -angle, 'world', 0, 0) elif self.point_radio_button.get_active(): x = float(self.rotate_x.get_text()) y = float(self.rotate_y.get_text()) self.transform.rotate(self.tree_view, -angle, 'point', x, y) self.dm.redraw() def onRotateObjectRight(self, button): if self.window_selected.get_active(): return self.onRotateWindowRight(button) self.printToLog("onRotateObjectRight") angle = int(self.object_rotation_angle.get_text()) if self.object_radio_button.get_active(): self.transform.rotate(self.tree_view, angle, 'center', 0, 0) elif self.world_radio_button.get_active(): self.transform.rotate(self.tree_view, angle, 'world', 0, 0) elif self.point_radio_button.get_active(): x = float(self.rotate_x.get_text()) y = float(self.rotate_y.get_text()) self.transform.rotate(self.tree_view, angle, 'point', x, y) self.dm.redraw() def OnRotateObjectUp(self, button): self.printToLog("OnRotateObjectUp") angle = int(self.object_rotation_angle.get_text()) if self.object_radio_button.get_active(): self.transform.rotate3d(self.tree_view, angle, 'center', 0, 0) elif self.world_radio_button.get_active(): self.transform.rotate3d(self.tree_view, angle, 'world', 0, 0) elif self.point_radio_button.get_active(): x = float(self.rotate_x.get_text()) y = float(self.rotate_y.get_text()) self.transform.rotate3d(self.tree_view, angle, 'point', x, y) self.dm.redraw() def OnRotateObjectDown(self, button): self.printToLog("OnRotateObjectDown") angle = int(self.object_rotation_angle.get_text()) if self.object_radio_button.get_active(): self.transform.rotate3d(self.tree_view, -angle, 'center', 0, 0) elif self.world_radio_button.get_active(): self.transform.rotate3d(self.tree_view, -angle, 'world', 0, 0) elif self.point_radio_button.get_active(): x = float(self.rotate_x.get_text()) y = float(self.rotate_y.get_text()) self.transform.rotate3d(self.tree_view, -angle, 'point', x, y) self.dm.redraw() def onScaleObjectUp(self, button): if self.window_selected.get_active(): return self.onZoomIn(button) self.printToLog("onScaleObjectUp") self.transform.zoom(self.tree_view, 2, 2) self.dm.redraw() def onScaleObjectDown(self, button): if self.window_selected.get_active(): return self.onZoomOut(button) self.printToLog("onScaleObjectDown") self.transform.zoom(self.tree_view, 0.5, 0.5) self.dm.redraw() def onMoveWindowUp(self, button): self.printToLog("onMoveWindowUp") units = float(self.object_units_for_moving.get_text()) self.dm.getWindow().move(0, units) self.dm.redraw() def onMoveWindowDown(self, button): self.printToLog("onMoveWindowDown") units = float(self.object_units_for_moving.get_text()) self.dm.getWindow().move(0, -units) self.dm.redraw() def onMoveWindowLeft(self, button): self.printToLog("onMoveWindowLeft") units = float(self.object_units_for_moving.get_text()) self.dm.getWindow().move(-units, 0) self.dm.redraw() def onMoveWindowRight(self, button): self.printToLog("onMoveWindowRight") units = float(self.object_units_for_moving.get_text()) self.dm.getWindow().move(units, 0) self.dm.redraw() def printToLog(self, text, end="\n"): buffer, view = self.text_buffer, self.text_view buffer.insert_at_cursor(text + end) view.scroll_to_mark(buffer.get_insert(), 0, 0, 0, 0)