def euler_to_gp_trsf(euler_zxz=None, unit="deg"): """ returns a rotation-only gp_Trsf given Euler angles :param euler_zxz: a list of three intrinsic Euler angles in zxz-convention :param unit: If "deg", the euler angles are in degrees, otherwise radians :return: A rotation-only gp_Trsf """ if euler_zxz is None: euler_zxz = [0, 0, 0] if unit == "deg": # convert angle to radians euler_zxz = [radians(a) for a in euler_zxz] x = gp_Ax1(gp_Pnt(), gp_Dir(1, 0, 0)) z = gp_Ax1(gp_Pnt(), gp_Dir(0, 0, 1)) trns = gp_Trsf() trns.SetRotation(z, euler_zxz[2]) trns_next = gp_Trsf() trns_next.SetRotation(x, euler_zxz[1]) trns = trns *trns_next trns_next = gp_Trsf() trns_next.SetRotation(z, euler_zxz[0]) return trns *trns_next
def rotate(self, x=0.0, y=0.0, z=0.0): trsf = gp_Trsf() if (x != 0.0): axx = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(1., 0., 0.)) a_trsf1 = gp_Trsf() a_trsf1.SetRotation(axx, math.radians(x)) #trsf = trsf*a_trsf1 trsf = a_trsf1 * trsf if (y != 0.0): axy = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(0., 1., 0.)) a_trsf2 = gp_Trsf() a_trsf2.SetRotation(axy, math.radians(y)) #trsf = trsf*a_trsf2 trsf = a_trsf2 * trsf if (z != 0.0): axz = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(0., 0., 1.)) a_trsf3 = gp_Trsf() a_trsf3.SetRotation(axz, math.radians(z)) #trsf = trsf*a_trsf3 trsf = a_trsf3 * trsf for c in self.children: c.propagate_trsf(trsf)
def generate_tool_targets(self): ba = BRepAdaptor_Curve(self.helix_edge) u_min = ba.FirstParameter() u_max = ba.LastParameter() u_step = 0.1 u_now = u_min while u_now <= u_max: v_contact = gp_Vec(ba.Value(u_now).XYZ()) if self.inside: # cut inside v_contact_to_ball_center = -gp_Vec(v_contact.X(),v_contact.Y(),0).Normalized()*self.ball_radius else: # cut outside v_contact_to_ball_center = gp_Vec(v_contact.X(),v_contact.Y(),0).Normalized()*self.ball_radius trsf = gp_Trsf() trsf.SetRotation(gp_Ax1(gp_Pnt(0,0,0),gp_Dir(0,0,1)),pi/2) v_rotation_axis = v_contact_to_ball_center.Transformed(trsf) trsf.SetRotation(gp_Ax1(gp_Pnt(0,0,0),gp_Dir(v_rotation_axis.XYZ())),radians(self.cutting_angle)) v_ball_center_to_tool_tip = gp_Vec(0,0,-self.ball_radius) v_ball_center_to_tool_tip.Transform(trsf) v_tool_tip = v_contact+v_contact_to_ball_center+v_ball_center_to_tool_tip v_tool_orientation = - v_ball_center_to_tool_tip.Normalized() * (0.500+1e-8) if self.create_target_vis_edges: me = BRepBuilderAPI_MakeEdge(gp_Pnt(v_tool_tip.XYZ()),gp_Pnt((v_tool_tip+v_tool_orientation).XYZ())) self.target_edges.append(me.Edge()) I = v_tool_tip.X() / 1000 J = v_tool_tip.Y() / 1000 K = v_tool_tip.Z() / 1000 U = v_tool_orientation.X() V = v_tool_orientation.Y() W = v_tool_orientation.Z() x,y,z,a,b = self.ikSolver.solve((I,J,K,U,V,W),1e-6,False) x += self.output_offset[0] y += self.output_offset[1] z += self.output_offset[2] a += self.output_offset[3] b += self.output_offset[4] if self.v_previous_contact_point: cut_distance = (v_contact - self.v_previous_contact_point).Magnitude() f = self.feedrate / cut_distance self.gcode += "G01 X{:.6f} Y{:.6f} Z{:.6f} A{:.6f} B{:.6f} F{:.6f}\n".format(x,y,z,a,b,f) else: f = 0 self.gcode += "G0 X{:.6f} Y{:.6f} Z{:.6f} A{:.6f} B{:.6f}\n".format(x,y,z,a,b) self.v_previous_contact_point = v_contact print(x,y,z,a,b) if u_now == u_max: break u_next = u_now + u_step if u_next > u_max: u_next = u_max u_now = u_next
def rot_axs(axis=gp_Ax3(), pxyz=[0, 0, 0], rxyz=[0, 0, 0]): axs = gp_Ax3(gp_Pnt(*pxyz), gp_Dir(0, 0, 1)) ax1 = gp_Ax1(axis.Location(), axis.XDirection()) ax2 = gp_Ax1(axis.Location(), axis.YDirection()) ax3 = gp_Ax1(axis.Location(), axis.Direction()) axs.Rotate(ax1, np.deg2rad(rxyz[0])) axs.Rotate(ax2, np.deg2rad(rxyz[1])) axs.Rotate(ax3, np.deg2rad(rxyz[2])) trsf = set_trf(gp_Ax3(), axs) axis.Transform(trsf)
def rotate_xyz(axs=gp_Ax3(), deg=0.0, xyz="x"): if xyz == "x": ax1 = gp_Ax1(axs.Location(), axs.XDirection()) elif xyz == "y": ax1 = gp_Ax1(axs.Location(), axs.YDirection()) elif xyz == "z": ax1 = gp_Ax1(axs.Location(), axs.Direction()) else: ax1 = gp_Ax1(axs.Location(), axs.Direction()) axs.Rotate(ax1, np.deg2rad(deg))
def RotateAxis_Ax(self, ax=gp_Ax3(), deg=0.0, axs="z"): if axs == "x": ax1 = gp_Ax1(ax.Location(), ax.XDirection()) elif axs == "y": ax1 = gp_Ax1(ax.Location(), ax.YDirection()) elif axs == "z": ax1 = gp_Ax1(ax.Location(), ax.Direction()) else: ax1 = gp_Ax1(ax.Location(), ax.Direction()) rot = ax.Rotated(ax1, np.deg2rad(deg)) trf = gp_Trsf() trf.SetDisplacement(ax, rot) ax.Transform(trf)
def RotateAxis(self, deg=0.0, axs="z"): if axs == "x": ax1 = gp_Ax1(self.rot.Location(), self.rot.XDirection()) elif axs == "y": ax1 = gp_Ax1(self.rot.Location(), self.rot.YDirection()) elif axs == "z": ax1 = gp_Ax1(self.rot.Location(), self.rot.Direction()) else: ax1 = gp_Ax1(self.rot.Location(), self.rot.Direction()) rot = self.rot.Rotated(ax1, np.deg2rad(deg)) trf = gp_Trsf() trf.SetDisplacement(self.rot, rot) self.axs.Transform(trf)
def RotateSurf(self, deg=0.0, axs="z"): if axs == "x": ax1 = gp_Ax1(self.rot.Location(), self.rot.XDirection()) elif axs == "y": ax1 = gp_Ax1(self.rot.Location(), self.rot.YDirection()) elif axs == "z": ax1 = gp_Ax1(self.rot.Location(), self.rot.Direction()) else: ax1 = gp_Ax1(self.rot.Location(), self.rot.Direction()) trf = gp_Trsf() trf.SetRotation(ax1, np.deg2rad(deg)) self.rot.Transform(trf) self.axs.Transform(trf) self.surf.Move(TopLoc_Location(trf))
def face_rotate(self, face=TopoDS_Face(), axs=gp_Ax1()): plan = self.pln_on_face(face) plan_axs = plan.Position() pln_angle = self.tmp_axis.Angle(plan_axs) ref_angle = self.tmp_axis.Direction().AngleWithRef( plan_axs.Direction(), axs.Direction()) print(np.rad2deg(pln_angle), np.rad2deg(ref_angle)) trf = gp_Trsf() if np.abs(ref_angle) >= np.pi / 2: trf.SetRotation(axs, -ref_angle) elif 0 < ref_angle < np.pi / 2: trf.SetRotation(axs, np.pi - ref_angle) elif -np.pi / 2 < ref_angle < 0: trf.SetRotation(axs, -ref_angle - np.pi) else: trf.SetRotation(axs, -ref_angle) #trf.SetTransformation(axs3.Rotated(axs, angle), axs3) loc_face = TopLoc_Location(trf) new_face = face.Located(loc_face) # self.sol_builder.Add(new_face) self.face_lst.Append(new_face) # face.Location(loc_face) if self.show == True: self.display.DisplayShape(new_face) return new_face
def face_tranfer(self, face=TopoDS_Face(), axs=gp_Ax1()): axs_3 = gp_Ax3(axs.Location(), axs.Direction()) trf = gp_Trsf() trf.SetTransformation(axs_3, self.tmp_axs3) loc_face = TopLoc_Location(trf) face.Location(loc_face) return face
def RotAxs(self, deg, axs="y"): if axs == None: rot_axs = gp_Ax1(self.axs.Location(), self.axs.XDirection()) elif axs == "x": rot_axs = gp_Ax1(self.axs.Location(), self.axs.XDirection()) elif axs == "y": rot_axs = gp_Ax1(self.axs.Location(), self.axs.YDirection()) else: rot_axs = gp_Ax1(self.axs.Location(), self.axs.YDirection()) self.Move_Beam(gp_Ax3(), gp_Ax3().Rotated(rot_axs, np.deg2rad(deg))) self.axs.Rotate(rot_axs, np.deg2rad(deg)) self.srf = set_surface(self.dir + self.name + ".stp") self.trf = gp_Trsf() self.trf.SetTransformation(self.axs, gp_Ax3()) self.loc_face = TopLoc_Location(self.trf) self.srf.Location(self.loc_face)
def revolve(): """Revolve profile on active WP to create a new part.""" wp = win.activeWp if win.lineEditStack and len(win.ptStack) == 2: p2 = win.ptStack.pop() p1 = win.ptStack.pop() name = win.lineEditStack.pop() win.clearAllStacks() wireOK = wp.makeWire() if not wireOK: print("Unable to make wire.") return face = BRepBuilderAPI_MakeFace(wp.wire).Shape() revolve_axis = gp_Ax1(p1, gp_Dir(gp_Vec(p1, p2))) myBody = BRepPrimAPI_MakeRevol(face, revolve_axis).Shape() uid = doc.addComponent(myBody, name, DEFAULT_COLOR) win.build_tree() win.setActivePart(uid) win.draw_shape(uid) win.syncUncheckedToHideList() win.statusBar().showMessage("New part created.") win.clearCallback() else: win.registerCallback(revolveC) display.SetSelectionModeVertex() win.lineEdit.setFocus() statusText = "Pick two points on revolve axis." win.statusBar().showMessage(statusText)
def make_revolved_cylinder(pnt, height, revolve_angle, rotation, wall_thick): """ This method demonstrates how to create a revolved shape from a drawn closed edge. It currently creates a hollow cylinder adapted from algotopia.com's opencascade_basic tutorial: http://www.algotopia.com/contents/opencascade/opencascade_basic :param pnt: :param height: :param revolve_angle: :param rotation: :param wall_thick: :type pnt: dict :type height: float :type revolve_angle: float :type rotation: float :type wall_thick: float """ from OCC.Core.BRepBuilderAPI import ( BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeFace, BRepBuilderAPI_MakeWire, ) from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeRevol from OCC.Core.gp import gp_Ax1, gp_Dir, gp_Pnt face_inner_radius = pnt["X"] + (17.0 - wall_thick / 2) * 1000 face_outer_radius = pnt["X"] + (17.0 + wall_thick / 2) * 1000 # point to create an edge from edg_points = [ gp_Pnt(face_inner_radius, pnt["Y"], pnt["Z"]), gp_Pnt(face_inner_radius, pnt["Y"], pnt["Z"] + height), gp_Pnt(face_outer_radius, pnt["Y"], pnt["Z"] + height), gp_Pnt(face_outer_radius, pnt["Y"], pnt["Z"]), gp_Pnt(face_inner_radius, pnt["Y"], pnt["Z"]), ] # aggregate edges in wire hexwire = BRepBuilderAPI_MakeWire() for i in range(len(edg_points) - 1): hexedge = BRepBuilderAPI_MakeEdge(edg_points[i], edg_points[i + 1]).Edge() hexwire.Add(hexedge) hexwire_wire = hexwire.Wire() # face from wire hexface = BRepBuilderAPI_MakeFace(hexwire_wire).Face() revolve_axis = gp_Ax1(gp_Pnt(pnt["X"], pnt["Y"], pnt["Z"]), gp_Dir(0, 0, 1)) # create revolved shape revolved_shape_ = BRepPrimAPI_MakeRevol(hexface, revolve_axis, np.radians( float(revolve_angle))).Shape() revolved_shape_ = rotate_shp_3_axis(revolved_shape_, revolve_axis, rotation) return revolved_shape_
def rotateAP(): ax1 = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(1., 0., 0.)) aRotTrsf = gp_Trsf() angle = math.pi / 18 # 10 degrees aRotTrsf.SetRotation(ax1, angle) aTopLoc = TopLoc_Location(aRotTrsf) win.activePart.Move(aTopLoc) win.redraw()
def make_revolve_solid(face: TopoDS_Face, axis, angle, origin) -> TopoDS_Shape: from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeRevol revolve_axis = gp_Ax1(gp_Pnt(origin[0], origin[1], origin[2]), gp_Dir(axis[0], axis[1], axis[2])) revolved_shape = BRepPrimAPI_MakeRevol(face, revolve_axis, np.deg2rad(angle)).Shape() return revolved_shape
def __GetTransform(self, X: float, Y: float, Z: float, RX: float, RY: float, RZ: float) -> gp_Trsf: trsf_T = gp_Trsf() trsf_RX = gp_Trsf() trsf_RY = gp_Trsf() trsf_RZ = gp_Trsf() center = gp_Pnt(X, Y, Z) ax1_X = gp_Ax1(center, gp_Dir(1., 0., 0.)) ax1_Y = gp_Ax1(center, gp_Dir(0., 1., 0.)) ax1_Z = gp_Ax1(center, gp_Dir(0., 0., 1.)) trsf_T.SetTranslation(gp_Vec(X, Y, Z)) trsf_RX.SetRotation(ax1_X, RX * math.pi / 180) trsf_RY.SetRotation(ax1_Y, RY * math.pi / 180) trsf_RZ.SetRotation(ax1_Z, RZ * math.pi / 180) return trsf_RZ * trsf_RY * trsf_RX * trsf_T
def setRotate(self, pntAxFrom, pntAxTo, angle): trsf = gp_Trsf() ax1 = gp_Ax1(pntAxFrom, gp_Dir(gp_Vec(pntAxFrom, pntAxTo))) trsf.SetRotation(ax1, angle) self.aTrsf *= trsf return self
def rotate(axis, angle=None): if angle is None: angle = np.linalg.norm(axis) axis = axis / angle trsf = gp_Trsf() trsf.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir( gp_Vec(axis[0], axis[1], axis[2]))), angle) return Transformation(trsf)
def rotating_cube_2_axis(event=None): display.EraseAll() ais_boxshp = build_shape() ax1 = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(0., 0., 1.)) ax2 = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(0., 1., 0.)) a_cube_trsf = gp_Trsf() a_cube_trsf2 = gp_Trsf() angle = 0.0 tA = time.time() n_rotations = 200 for i in range(n_rotations): a_cube_trsf.SetRotation(ax1, angle) a_cube_trsf2.SetRotation(ax2, angle) aCubeToploc = TopLoc_Location(a_cube_trsf * a_cube_trsf2) display.Context.SetLocation(ais_boxshp, aCubeToploc) display.Context.UpdateCurrentViewer() angle += 2*pi / n_rotations print("%i rotations took %f" % (n_rotations, time.time() - tA))
def _revol(shp, r=None, yaw=0.0): if r is not None: shp = shp.rotX(deg(90)).movX(r) ax = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)) if yaw == 0: return Shape(BRepPrimAPI_MakeRevol(shp.Shape(), ax).Shape()) else: return Shape(BRepPrimAPI_MakeRevol(shp.Shape(), ax, yaw).Shape())
def add_feature(base): """Add a "feature" to a shape. In this case we drill a hole through it.""" feature_diameter = 0.8 feature_origin = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)) feature_maker = BRepFeat_MakeCylindricalHole() feature_maker.Init(base, feature_origin) feature_maker.Build() feature_maker.Perform(feature_diameter / 2.0) shape = feature_maker.Shape() return shape
def rotateAP(): """Experimental... useful methods to come""" ax1 = gp_Ax1(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0)) aRotTrsf = gp_Trsf() angle = math.pi / 18 # 10 degrees aRotTrsf.SetRotation(ax1, angle) aTopLoc = TopLoc_Location(aRotTrsf) uid = win.activePartUID win.erase_shape(uid) win.activePart.Move(aTopLoc) win.draw_shape(uid)
def mirror_pnt_dir(brep, pnt, direction, copy=False): ''' @param brep: @param line: ''' trns = gp_Trsf() trns.SetMirror(gp_Ax1(pnt, direction)) brep_trns = BRepBuilderAPI_Transform(brep, trns, copy) with assert_isdone(brep_trns, 'could not produce mirror'): brep_trns.Build() return brep_trns.Shape()
def rotate_shp(ais_shp): ax1 = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(0., 0., 1.)) aCubeTrsf = gp_Trsf() angle = 0.0 #tA = time.time() n_rotations = 200 for i in range(n_rotations): aCubeTrsf.SetRotation(ax1, angle) aCubeToploc = TopLoc_Location(aCubeTrsf) display.Context.SetLocation(ais_shp, aCubeToploc) display.Context.UpdateCurrentViewer() angle += 2*pi / n_rotations
def generate_TCP(): global tool_tcp_pnts, tool_tcp_vxs, tool_tcp_vys, tool_tcp_vzs tool_tcp_pnts = [] tool_tcp_vxs = [] tool_tcp_vys = [] tool_tcp_vzs = [] numperface = 1 num1 = round(abs(math.sqrt(numperface))) num2 = round(abs(math.sqrt(numperface))) numofrots = 8 for sur in surf: umin, umax, vmin, vmax = shapeanalysis_GetFaceUVBounds(sur) bsur = BRepAdaptor_Surface(sur, True) for i in range(0, num1 + 1): for j in range(0, num2 + 1): u = umin + i * (umax - umin) / num1 v = vmin + j * (vmax - vmin) / num2 point, Vx, Vy, Vz = get_point(bsur, u, v) flag = 0 for apoint in tool_tcp_pnts: if abs(point.Distance(apoint)) < 0.1: flag = 1 break if flag == 0: for k in range(0, numofrots): ang = 2 * math.pi / numofrots tool_tcp_pnts.append(point) Vx = Vx.Rotated(gp_Ax1(point, gp_Dir(Vz)), ang) tool_tcp_vxs.append(Vx) Vy = Vy.Rotated(gp_Ax1(point, gp_Dir(Vz)), ang) tool_tcp_vys.append(Vy) tool_tcp_vzs.append(Vz) display_coord(tool_tcp_pnts, tool_tcp_vxs, tool_tcp_vys, tool_tcp_vzs) display.DisplayMessage(gp_Pnt(100, 100, 100), 'TCP #:' + str(len(tool_tcp_pnts)), height=None, message_color=(1, 1, 1), update=True)
def mirrorInPlane(self, listOfShapes, axis="X"): local_coord_system = gp_Ax3(self.origin.toPnt(), self.zDir.toDir(), self.xDir.toDir()) T = gp_Trsf() if axis == "X": T.SetMirror( gp_Ax1(self.origin.toPnt(), local_coord_system.XDirection())) elif axis == "Y": T.SetMirror( gp_Ax1(self.origin.toPnt(), local_coord_system.YDirection())) else: raise NotImplementedError resultWires = [] for w in listOfShapes: mirrored = w.transformShape(Matrix(T)) # attemp stitching of the wires resultWires.append(mirrored) return resultWires
def occ_to_grasp_cor_ref(axs=gp_Ax1(), ref=gp_Ax3(), name="name", filename="pln.cor"): trf = gp_Trsf() trf.SetTransformation(ref, gp_Ax3()) axis = axs.Transformed(trf) pnt = axis.Location() v_x = axis.XDirection() v_y = axis.YDirection() fp = open(filename, "w") fp.write(' {:s}\n'.format(name)) fp.write(' {:s}\n'.format("mm")) fp.write(''.join([float_to_string(v) for v in pnt_to_xyz(pnt)]) + '\n') fp.write(''.join([float_to_string(v) for v in pnt_to_xyz(v_x)]) + '\n') fp.write(''.join([float_to_string(v) for v in pnt_to_xyz(v_y)]) + '\n') fp.close()
def edge(event=None): # The blud edge BlueEdge = BRepBuilderAPI_MakeEdge(gp_Pnt(-80, -50, -20), gp_Pnt(-30, -60, -60)) V1 = BRepBuilderAPI_MakeVertex(gp_Pnt(-20, 10, -30)) V2 = BRepBuilderAPI_MakeVertex(gp_Pnt(10, 7, -25)) YellowEdge = BRepBuilderAPI_MakeEdge(V1.Vertex(), V2.Vertex()) #The white edge line = gp_Lin(gp_Ax1(gp_Pnt(10, 10, 10), gp_Dir(1, 0, 0))) WhiteEdge = BRepBuilderAPI_MakeEdge(line, -20, 10) #The red edge Elips = gp_Elips(gp_Ax2(gp_Pnt(10, 0, 0), gp_Dir(1, 1, 1)), 60, 30) RedEdge = BRepBuilderAPI_MakeEdge(Elips, 0, math.pi/2) # The green edge and the both extreme vertex P1 = gp_Pnt(-15, 200, 10) P2 = gp_Pnt(5, 204, 0) P3 = gp_Pnt(15, 200, 0) P4 = gp_Pnt(-15, 20, 15) P5 = gp_Pnt(-5, 20, 0) P6 = gp_Pnt(15, 20, 0) P7 = gp_Pnt(24, 120, 0) P8 = gp_Pnt(-24, 120, 12.5) array = TColgp_Array1OfPnt(1, 8) array.SetValue(1, P1) array.SetValue(2, P2) array.SetValue(3, P3) array.SetValue(4, P4) array.SetValue(5, P5) array.SetValue(6, P6) array.SetValue(7, P7) array.SetValue(8, P8) curve = Geom_BezierCurve(array) ME = BRepBuilderAPI_MakeEdge(curve) GreenEdge = ME V3 = ME.Vertex1() V4 = ME.Vertex2() display.DisplayColoredShape(BlueEdge.Edge(), 'BLUE') display.DisplayShape(V1.Vertex()) display.DisplayShape(V2.Vertex()) display.DisplayColoredShape(WhiteEdge.Edge(), 'WHITE') display.DisplayColoredShape(YellowEdge.Edge(), 'YELLOW') display.DisplayColoredShape(RedEdge.Edge(), 'RED') display.DisplayColoredShape(GreenEdge.Edge(), 'GREEN') display.DisplayShape(V3) display.DisplayShape(V4, update=True)
def __init__(self, sectorParms) : from math import pi from OCC.Core.gp import gp_Ax1, gp_Pnt, gp_Dir self.TwoPi = 2*(pi) self.Pi = pi if sectorParms != None : self.Start = sectorParms[0] self.Delta = sectorParms[1] self.Aunit = sectorParms[2] else : self.Start = 0 self.Delta = self.TwoPi self.Aunit = 'rad' self.RevAxis = gp_Ax1(gp_Pnt(0,0,0), gp_Dir(0,0,1))
def rotated(self, rotate=(0, 0, 0)): """Returns a copy of this plane, rotated about the specified axes Since the z axis is always normal the plane, rotating around Z will always produce a plane that is parallel to this one. The origin of the workplane is unaffected by the rotation. Rotations are done in order x, y, z. If you need a different order, manually chain together multiple rotate() commands. :param rotate: Vector [xDegrees, yDegrees, zDegrees] :return: a copy of this plane rotated as requested. """ # NB: this is not a geometric Vector rotate = Vector(rotate) # Convert to radians. rotate = rotate.multiply(math.pi / 180.0) # Compute rotation matrix. T1 = gp_Trsf() T1.SetRotation( gp_Ax1(gp_Pnt(*(0, 0, 0)), gp_Dir(*self.xDir.toTuple())), rotate.x) T2 = gp_Trsf() T2.SetRotation( gp_Ax1(gp_Pnt(*(0, 0, 0)), gp_Dir(*self.yDir.toTuple())), rotate.y) T3 = gp_Trsf() T3.SetRotation( gp_Ax1(gp_Pnt(*(0, 0, 0)), gp_Dir(*self.zDir.toTuple())), rotate.z) T = Matrix(gp_GTrsf(T1 * T2 * T3)) # Compute the new plane. newXdir = self.xDir.transform(T) newZdir = self.zDir.transform(T) return Plane(self.origin, newXdir, newZdir)