def get_clipped(self) -> Optional[Line]: '''Return the line clipped if is inside the setup''' if not self.is_inside: return None positives = [ d for d in self.pq_list if not close_to_zero(d['p']) and d['p'] > 0 ] negatives = [ d for d in self.pq_list if not close_to_zero(d['p']) and d['p'] < 0 ] positives = [d['q'] / d['p'] for d in positives] negatives = [d['q'] / d['p'] for d in negatives] u1 = max([0] + negatives) u2 = min([1] + positives) if u1 > u2: return None new_line = deepcopy(self.line) new_line.p1 = Point3D(name='_p1', x=self.line.p1.x + self.pq_list[1]['p'] * u1, y=self.line.p1.y + self.pq_list[3]['p'] * u1, z=0) new_line.p2 = Point3D(name='_p2', x=self.line.p1.x + self.pq_list[1]['p'] * u2, y=self.line.p1.y + self.pq_list[3]['p'] * u2, z=0) return new_line
def __init__(self, wireframe: Wireframe, setup: ClipperSetup): '''Initialize with internal properties''' self.setup = setup self.wireframe = wireframe self.top_left = Point3D('tl', x=setup.xmin, y=setup.ymax, z=0) self.top_right = Point3D('tr', x=setup.xmax, y=setup.xmax, z=0) self.bot_right = Point3D('br', x=setup.xmax, y=setup.ymin, z=0) self.bot_left = Point3D('bl', x=setup.xmin, y=setup.ymin, z=0)
def viewpoert_transform_point(self, point: Point3D): """ Apply viewport transformation to a point Parameters ---------- p: Point3D Return ---------- UnamedPoint3D(x, y) transformed to current viewport """ # xwmax = self.window_xmax # ywmax = self.window_ymax # xwmin = self.window_xmin # ywmin = self.window_ymin xwmax = 1 ywmax = 1 xwmin = -1 ywmin = -1 xvpmax = self.xvp_max yvpmax = self.yvp_max xvpmin = self.xvp_min yvpmin = self.yvp_min xvp = ((point.x - xwmin)/(xwmax - xwmin)) * \ (xvpmax - xvpmin) + xvpmin yvp = (1 - ((point.y - ywmin)/(ywmax - ywmin))) * \ (yvpmax - yvpmin) + yvpmin return Point3D(name=point.name, x=xvp, y=yvp, z=point.z)
def create_line(name: str, tab: LineTab) -> Line: """ Create Line object """ x1 = int(tab.start_x_coord_line_input.text()) y1 = int(tab.start_y_coord_line_input.text()) z1 = int(tab.start_z_coord_line_input.text()) x2 = int(tab.end_x_coord_line_input.text()) y2 = int(tab.end_y_coord_line_input.text()) z2 = int(tab.end_z_coord_line_input.text()) p1 = Point3D('_p1', x1, y1, z1) p2 = Point3D('_p2', x2, y2, z2) return Line(name, p1, p2)
def create_point3D(name: str, tab: PointTab) -> Point3D: """ Create Point3D object """ x = int(tab.x_coord_pt_input.text()) y = int(tab.y_coord_pt_input.text()) z = int(tab.z_coord_pt_input.text()) return Point3D(name, x, y, z)
def create_bspline(obj_name: str, tab: BSplineTab) -> BSplineCurve: '''Take BSpline tab and create the BSpline object''' points = [] for i, point in enumerate(tab.points_list): x, y, z = point point = Point3D('Po' + str(i).zfill(3), x, y, z) points.append(point) return BSplineCurve(name=obj_name, control_points=points)
def VPN(self) -> Tuple[Point3D, Point3D]: '''Return VRP and a Point3D''' vrp = self.VRP vpn = (vrp, Point3D('_vpn_end', x=self._vpn_dir.x + vrp.x, y=self._vpn_dir.y + vrp.y, z=self._vpn_dir.z + vrp.z)) return vpn
def create_wireframe(name: str, tab: WireframeTab) -> Wireframe: """ Create Wireframe object """ points = [] for i, point in enumerate(tab.points_list): x, y, z = point point = Point3D('Po' + str(i).zfill(3), x, y, z) points.append(point) return Wireframe(name, points)
def create_curve(name: str, tab: CurveTab) -> BezierCurve: """Create a bezier curve, compsoed by multipe P1 to P4 points""" points_groups = tab.curves_list setups: List[BezierCurveSetup] = [] for group in points_groups: p1 = group['P1'] p2 = group['P2'] p3 = group['P3'] p4 = group['P4'] setup = BezierCurveSetup( P1=Point3D('__', x=p1['x'], y=p1['y'], z=p1['z']), P2=Point3D('__', x=p2['x'], y=p2['y'], z=p2['z']), P3=Point3D('__', x=p3['x'], y=p3['y'], z=p3['z']), P4=Point3D('__', x=p4['x'], y=p4['y'], z=p4['z']), ) setups.append(setup) return BezierCurve(name=name, curve_setups=setups)
def create_3dobject(obj_name: str, tab: _3dObjectTab) -> Object3D: '''Take 3D object tab and create the 3d object''' points = [] faces = [] for i, point in enumerate(tab.points_list_3d): x, y, z = point point = Point3D('Po' + str(i).zfill(3), x, y, z) points.append(point) faces = tab.faces_list_3d return Object3D(name=obj_name, points=points, faces=faces)
def create_bicubicSurface(obj_name: str, tab: _BicubicTab) -> BicubicSurface: '''Take 3D object tab and create the 3d object''' points = [] for i, point in enumerate(tab.points_list): x, y, z = point point = Point3D('Po' + str(i).zfill(3), x, y, z) points.append(point) setup = BicubicSetup(points[0],points[1],points[2],points[3],points[4],points[5],points[6], points[7],points[8],points[9],points[10],points[11],points[12],points[13], points[14],points[15]) return BicubicSurface(name=obj_name, setup=setup)
def _rotate_internal_point_over_origin(self, angle: float) -> Point3D: '''Rotate when internal is a point and return copy of object''' if not isinstance(self._object, Point3D): error = 'Trying to operate as point over:' raise TypeError(error + str(type(self._object))) rotated = rotate_points_over_point_by_degrees( points=[self._object], point=Point3D('_', 0, 0, 0), angle=angle, rotation_axis=self._rotation_axis)[0] rotated.color = self._object.color return rotated
def transform_rotate(self, obj, tab): '''Apply rotate transformation''' transformator = Transformator(obj) angle = float(tab.degrees_input.text()) axis = tab.get_axis() if axis == 'arbitrary': p = Point3D(name='__p', x=int(tab.p_x_input.text()), y=int(tab.p_y_input.text()), z=int(tab.p_z_input.text())) a = Point3D(name='__a', x=int(tab.a_x_input.text()), y=int(tab.a_y_input.text()), z=int(tab.a_z_input.text())) new_obj = transformator.rotate_by_degrees_arbitrary_axis( p, a, angle) elif tab.over_obj_center_radio_btn.isChecked(): new_obj = transformator.rotate_by_degrees_geometric_center( angle, axis) elif tab.over_world_center_radio_btn.isChecked(): new_obj = transformator.rotate_by_degrees_origin(angle, axis) else: # tab.over_point_radio_btn.isChecked() x = float(tab.x_input.text()) y = float(tab.y_input.text()) z = 0 # float(tab.z_input.text()) new_obj = transformator.rotate_by_degrees_point( angle, Point3D('rotationPoint', x, y, z), axis) # inserting new obj in the same index as the transformed obj index = self.display_file.index(obj) self.display_file.pop(index) self.display_file.insert(index, new_obj)
def transform(points: List[Point3D], matrix: np.ndarray) -> List[Point3D]: '''Apply transformation''' new_points: List[Point3D] = [] for point in points: np_point = np.array([point.x, point.y, point.z, 1]) new_point = np_point.dot(matrix) w = new_point[-1] new_points.append( Point3D(name=point.name, x=new_point[0] / w, y=new_point[1] / w, z=new_point[2] / w)) return new_points
def get_object_geometric_center(self) -> Point3D: '''Get geometrix center of intern object''' if isinstance(self._object, Point3D): points = [self._object] elif isinstance(self._object, BezierCurve): points = [] for setup in self._object.curves: points.extend([setup.P1, setup.P2, setup.P3, setup.P4]) else: # Wireframe and BSpline points = self._object.points return Point3D(name='_geometric_center', x=mean(map(lambda p: p.x, points)), y=mean(map(lambda p: p.y, points)), z=mean(map(lambda p: p.z, points)))
def _rotate_internal_wireframe_over_origin(self, angle: float) -> Wireframe: '''Rotate when internal is a Wireframe and return copy of object''' if isinstance(self._object, Point3D): error = 'Trying to operate as line/wireframe over point' raise TypeError(error) new_points = rotate_points_over_point_by_degrees( points=self._object.points, point=Point3D('_', 0, 0, 0), angle=angle, rotation_axis=self._rotation_axis) new_obj = self._intern_copy() new_obj.points = new_points return new_obj
def _rotate_internal_bezier_curve_over_origin(self, angle: float) -> BezierCurve: '''Rotate when internal is a curve and return copy of object''' new_setups = [] for setup in self._object.curves: points = [setup.P1, setup.P2, setup.P3, setup.P4] new_points = rotate_points_over_point_by_degrees( points, Point3D('_', 0, 0, 0), angle, self._rotation_axis) new_setups.append( BezierCurveSetup(P1=new_points[0], P2=new_points[1], P3=new_points[2], P4=new_points[3])) new_curve = deepcopy(self._object) new_curve.curves = new_setups return new_curve
def _rotate_internal_line_over_origin(self, angle: float) -> Line: '''Rotate when internal is a Line and return copy of object''' if isinstance(self._object, Point3D): error = 'Trying to operate as line/wireframe over point' raise TypeError(error) new_points = rotate_points_over_point_by_degrees( points=self._object.points, point=Point3D('_', 0, 0, 0), angle=angle, rotation_axis=self._rotation_axis) line = Line( name=self._object.name, p1=new_points[0], p2=new_points[1], ) line.color = self._object.color return line
def _import_from_file(self, file: str): '''Call wavefront loaders''' geoms = read_wavefront(file) for name, props in geoms.items(): if not 'v' and not 'cstype' in props: logger.error( f'Failed to load: {name}, no vertexes and its not a curve!' ) continue points: List[Point3D] = [] if 'v' in props: # its a point, line or polygon for x, y, z in props['v']: points.append(Point3D(name='', x=x, y=y, z=z)) if 'curv2' in props: for x, y, z in props['curv2']: points.append(Point3D(name='', x=x, y=y, z=z)) color = QColor(0, 0, 0) if 'material' in props and 'Kd' in props['material']: r, g, b = props['material']['Kd'] color = QColor(255 * r, 255 * g, 255 * b) if not self._validate_new_name(name): i = 1 new_name = f'{name}({i})' while not self._validate_new_name(new_name): i += 1 new_name = f'{name}({i})' name = new_name if len(points) == 1: # Is a point point = points[0] point.name = name point.color = color self.add_object_to_list(point) elif len(points) == 2: # Is a line line = Line(name=name, p1=points[0], p2=points[1]) line.color = color self.add_object_to_list(line) elif len(points) > 2: if props['cstype'] == 'bezier': beziersetup = [] for i in range(0, len(points), 4): p1 = points[i] p2 = points[i + 1] p3 = points[i + 2] p4 = points[i + 3] beziersetup.append(BezierCurveSetup(p1, p2, p3, p4)) bezier = BezierCurve(name=name, curve_setups=beziersetup) bezier.color = color self.add_object_to_list(bezier) elif props['cstype'] == 'bspline': bspline = BSplineCurve(name=name, control_points=points) bspline.color = color self.add_object_to_list(bspline) elif props['number_faces'] > 1: # its a 3d object faces = props['faces'] object3d = Object3D(name=name, points=points, faces=faces) object3d.color = color self.add_object_to_list(object3d) else: # Is a wireframe wireframe = Wireframe(name=name, points=points) wireframe.color = color self.add_object_to_list(wireframe)
def __init__(self): # Init the models structure self.display_file = [] # Angle between the Vup vector and the world Y axis self._vup_angle_degrees = 0 self._proj_type = _ProjectionType.PARALEL # Init main interface self.app = QApplication(sys.argv) self.main_window = MainWindow() self.main_window.show() self._add_main_window_handlers() # Instantiate dialog for adding objects self.add_object_dialog = NewObjectDialog() self.add_object_dialog.show() self.add_object_dialog.setVisible(False) self._add_new_obj_dialog_handlers() # Instantiate dialog to input transformations self.transform_dialog = TransformationDialog() self.transform_dialog.show() self.transform_dialog.setVisible(False) self._add_transform_dialog_handlers() # Initial window settings self.window_xmin = -300 self.window_ymin = -300 self.window_xmax = 300 self.window_ymax = 300 self._vrp_z = 500 # Point to be the second extreme of the VPN self._vpn_dir = Point3D('_vpn_direction', x=0, y=0, z=-1) # Viewport values self.xvp_min = 10 # it was 0, changed for clipping proof self.yvp_min = 10 # it was 0, changed for clipping proof self.xvp_max = 590 # it was 600, changed for clipping proof self.yvp_max = 590 # it was 600, changed for clipping proof # self.add_object_to_list( # BSplineCurve('Spline', # points=[ # Point3D('_', x=0, y=0, z=0), # Point3D('_', x=-100, y=200, z=0), # Point3D('_', x=-200, y=0, z=0), # Point3D('_', x=-300, y=-200, z=0), # Point3D('_', x=-400, y=0, z=0), # Point3D('_', x=-500, y=500, z=0), # ]) # ) # self.add_object_to_list( # Object3D( # name='Objeto3D', # points=[ # Point3D('0', x=0, y=0, z=0), # Point3D('1', x=100, y=0, z=0), # Point3D('2', x=100, y=100, z=0), # Point3D('3', x=0, y=100, z=0), # Point3D('4', x=0, y=0, z=100), # Point3D('5', x=100, y=0, z=100), # Point3D('6', x=100, y=100, z=100), # Point3D('7', x=0, y=100, z=100), # ], # faces=[ # [0, 1, 2, 3], # [0, 1, 5, 4], # [0, 4, 7, 3], # [3, 2, 6, 7], # [1, 5, 6, 2], # [4, 5, 6, 7] # ] # ) # ) # self.add_object_to_list( # BSplineCurve('Spline', # control_points=[ # Point3D('_', x=0, y=0, z=0), # Point3D('_', x=-100, y=200, z=0), # Point3D('_', x=-200, y=0, z=0), # Point3D('_', x=-300, y=-200, z=0), # Point3D('_', x=-400, y=0, z=0), # Point3D('_', x=-500, y=500, z=0), # ]) # ) # self.add_object_to_list( # BicubicSurface('bicubic', # setup=BicubicSetup( # Point3D('_', x=0, y=0, z=0), # Point3D('_', x=-100, y=0, z=0), # Point3D('_', x=-200, y=0, z=0), # Point3D('_', x=-300, y=0, z=0), # Point3D('_', x=-400, y=0, z=0), # Point3D('_', x=-500, y=0, z=0), # Point3D('_', x=0, y=100, z=0), # Point3D('_', x=0, y=200, z=0), # Point3D('_', x=0, y=300, z=0), # Point3D('_', x=0, y=400, z=0), # Point3D('_', x=0, y=500, z=0), # Point3D('_', x=0, y=0, z=100), # Point3D('_', x=0, y=0, z=200), # Point3D('_', x=0, y=0, z=300), # Point3D('_', x=0, y=0, z=400), # Point3D('_', x=0, y=0, z=500), # )) # ) self._process_viewport()
def VRP(self) -> Point3D: '''Return window center''' wcx = (self.window_xmax + self.window_xmin) / 2 wcy = (self.window_ymax + self.window_ymin) / 2 return Point3D('VPN_start', x=wcx, y=wcy, z=self._vrp_z)