def plotlist_xyz(self, face: Face): """Return a list of lists with the xyz coordinates of each vertex.""" # If object has no parent, return plot list in terms of global frame: plotlist_xyz = [] for vertex in face.vertices(): plotlist_xyz.append(list(self.vertex_xyz_global(vertex))) return plotlist_xyz
def face_centroid(self, face: Face): """Find the vertex centroid of the face.""" xc = 0 yc = 0 zc = 0 for vertex in face.vertices(): (dx, dy, dz) = self.vertex_xyz_global(vertex) xc += 0.25*dx yc += 0.25*dy zc += 0.25*dz return np.array([xc, yc, zc])
def plot_face(axes, face: Face, fill=0, alpha=0.2, linecolour='black', linealpha=1, illumination=False, ill_value=0): """ Plots an individual Face object. Check source code for kwargs. """ (xlist, ylist, zlist) = face.plotlist() # Plot individual vertices: axes.scatter(xlist, ylist, zlist, c=linecolour, s=10) # Plot edges that connect vertices: for i in range(-1, len(xlist) - 1): axes.plot3D([xlist[i], xlist[i + 1]], [ylist[i], ylist[i + 1]], [zlist[i], zlist[i + 1]], linecolour, alpha=linealpha, lw=2) # Plot the face surface: if fill == 1: fs = mp3d.art3d.Poly3DCollection([face.plotlist2()], linewidth=0) # If illumination functionality is turned on, face is coloured # based on its illumination value. if illumination == True: # No illumination: rgb = [0.1, 0.1, 0.1] (dark gray) # Total illumination: [1, 1, 1] (white) value = round(0.1 + 0.9 / 1.6 * ill_value, 2) fs.set_facecolor((value, value, value, alpha)) else: fs.set_facecolor((0.1, 0.1, 0.1, alpha)) axes.add_collection3d(fs)
def plotlist(self, face: Face): """Return three lists with the x, y, and z-components of all four vertices in the face.""" xlist = [] ylist = [] zlist = [] for vertex in face.vertices(): xg, yg, zg = self.vertex_xyz_global(vertex) xlist.append(xg) ylist.append(yg) zlist.append(zg) return xlist, ylist, zlist
def project_face(self, face: Face, plane='xy', new_frame=None): """Project a copy of the face onto a plane that is spanned by two axes. The projection is orthographic. Coordinates will be in terms of the GLOBAL frame. TODO: A "new_frame" can be specified, which will make the projection elements children of this frame. Otherwise, the elements will be children of the global coordinate frame. TODO: Generalize this function for arbitrary projection plane. """ # Eliminate minus sign in front of the plane: if plane[0] == '-': plane = plane[1:] pj_xyz = [] for vertex in [face.p1, face.p2, face.p3, face.p4]: global_coords = self.vertex_xyz_global(vertex) if plane == 'xy': pj_x = global_coords[0] pj_y = global_coords[1] pj_z = 0 elif plane == 'xz': pj_x = global_coords[0] pj_y = 0 pj_z = global_coords[2] elif plane == 'yz': pj_x = 0 pj_y = global_coords[1] pj_z = global_coords[2] else: raise ValueError("No valid projection plane given to " "projection method! " "Valid options: 'xy', 'xz', 'yz'") pj_xyz.append(Vertex([pj_x, pj_y, pj_z], parenttype="face")) # Create the projected face using the projected vertices. if not new_frame: pj = Face(pj_xyz[0], pj_xyz[1], pj_xyz[2], pj_xyz[3], parenttype="global") else: raise TypeError("new_frame functionality is not yet implemented.") return pj
def remove_face(self, face: Face): self.faces.remove(face) face.set_parenttype="global"
def add_face(self, face: Face): self.faces.append(face) face.set_parenttype="frame"
angle_step = d2r(360 / steps) frame1 = Frame() frame1.translate(0.5, 0.5, 0.5) frame1.rotate(0, 0, d2r(1 * 360 / 12)) p1 = Vertex(-0.05, -0.05, -0.1, frame1) p2 = Vertex(-0.05, -0.05, 0.1, frame1) p3 = Vertex(0.05, -0.05, 0.1, frame1) p4 = Vertex(0.05, -0.05, -0.1, frame1) p5 = Vertex(-0.05, 0.05, -0.1, frame1) p6 = Vertex(-0.05, 0.05, 0.1, frame1) p7 = Vertex(0.05, 0.05, 0.1, frame1) p8 = Vertex(0.05, 0.05, -0.1, frame1) fA = Face(p4, p3, p2, p1, frame1) fB = Face(p2, p3, p7, p6, frame1) fC = Face(p3, p4, p8, p7, frame1) fD = Face(p4, p1, p5, p8, frame1) fE = Face(p1, p2, p6, p5, frame1) fF = Face(p5, p6, p7, p8, frame1) cubesat = Geometry(frame1) cubesat.add_faces([fA, fB, fC, fD, fE, fF]) def update(i): # Transforming frame1 cubesat.rotate(angle_step, 0, 0, cor=cubesat.make_cuboid_centroid()) projection_frame = Frame()
ax.view_init(elev=20, azim=-60) steps = 24 angle_step = d2r(360 / steps) p0 = Vertex([0.5, 0.5, 0.5]) p1 = Vertex([-0.05, -0.05, -0.1]) p2 = Vertex([-0.05, -0.05, 0.1]) p3 = Vertex([0.05, -0.05, 0.1]) p4 = Vertex([0.05, -0.05, -0.1]) p5 = Vertex([-0.05, 0.05, -0.1]) p6 = Vertex([-0.05, 0.05, 0.1]) p7 = Vertex([0.05, 0.05, 0.1]) p8 = Vertex([0.05, 0.05, -0.1]) fA = Face(p4, p3, p2, p1) fB = Face(p2, p3, p7, p6) fC = Face(p3, p4, p8, p7) fD = Face(p4, p1, p5, p8) fE = Face(p1, p2, p6, p5) fF = Face(p5, p6, p7, p8) cubesat = Geometry([fA, fB, fC, fD, fE, fF]) frame1 = Frame() frame1.add_geometry(cubesat) frame1.translate(0.5, 0.5, 0.5) frame1.rotate(0, 0, d2r(1 * 360 / 12)) # cubesat.rotate(d2r(-45),0,0,cor=list(cubesat.find_cuboid_centroid()))
from cp_frame import Frame from cp_utilities import d2r #, r2d from cp_plotting import plot_global_tripod, plot_frame, \ plot_vertex, plot_face, plot_geometry_perpendiculars, plot_illumination p0 = Vertex([0.5, 0.5, 0.5]) p1 = Vertex([-0.05, -0.05, -0.1]) p2 = Vertex([-0.05, -0.05, 0.1]) p3 = Vertex([0.05, -0.05, 0.1]) p4 = Vertex([0.05, -0.05, -0.1]) p5 = Vertex([-0.05, 0.05, -0.1]) p6 = Vertex([-0.05, 0.05, 0.1]) p7 = Vertex([0.05, 0.05, 0.1]) p8 = Vertex([0.05, 0.05, -0.1]) fA = Face(p4, p3, p2, p1) fB = Face(p2, p3, p7, p6) fC = Face(p3, p4, p8, p7) fD = Face(p4, p1, p5, p8) fE = Face(p1, p2, p6, p5) fF = Face(p5, p6, p7, p8) cubesat = Geometry([fA, fB, fC, fD, fE, fF]) frame1 = Frame() frame1.add_geometry(cubesat) frame1.translate(0.5, 0.5, 0.5) frame1.rotate(0, 0, d2r(1 * 360 / 12)) cubesat.rotate(d2r(-45), 0, 0, cor=list(cubesat.find_cuboid_centroid()))
def add_face(self, face: Face): """Add a singular face to the geometry.""" self.faces.append(face) face.set_parenttype("geometry")
# | p1 = Vertex([-0.05, -0.05, -0.1]) # 2 ___ 6 p2 = Vertex([-0.05, -0.05, 0.1]) # |\3__\7 p3 = Vertex([ 0.05, -0.05, 0.1]) # | | | Y p4 = Vertex([ 0.05, -0.05, -0.1]) # 1| | 5| --------> p5 = Vertex([-0.05, 0.05, -0.1]) # \|__| p6 = Vertex([-0.05, 0.05, 0.1]) # 4 8 p7 = Vertex([ 0.05, 0.05, 0.1]) # \ p8 = Vertex([ 0.05, 0.05, -0.1]) # v X # Assembling the side panels of the Cubesat. Note that the order in which # the points is specified DOES matter! (see definition of Face class) # ^ Z # | fA = Face(p4, p3, p2, p1) # E ___ fB = Face(p2, p3, p7, p6) # |\ B_\ fC = Face(p3, p4, p8, p7) # A | | | F Y fD = Face(p4, p1, p5, p8) # | | C| --------> fE = Face(p1, p2, p6, p5) # \|__| fF = Face(p5, p6, p7, p8) # D # \ # v X # Assembling a Geometry instance named 'cubesat', and add all the faces # we just defined to the geometry. cubesat = Geometry([fA, fB, fC, fD, fE, fF]) # Define a reference frame which will be attached to the centre of gravity # of the CubeSat. If you move/rotate this frame, the 'cubesat' # Geometry will move/rotate along with it (if it is attached of course).
frame2 = Frame() # p1 = Vertex(0,0,0,frame1) # p2 = Vertex(1,0,0) # p3 = Vertex(1,1,0) # p4 = Vertex(0,1,0) # p5 = Vertex(0,1,1) # p6 = Vertex(0,0,1) # f1 = Face(p1, p2, p3, p4, frame1) # f2 = Face(p1, p4, p5, p6, frame1) frame1.readout() f1 = Face(Vertex(0, 0, 0), Vertex(1, 0, 0), Vertex(1, 1, 0), Vertex(0, 1, 0), frame1) frame1.readout() del (f1) frame1.readout() #%% ==== Plotting ==== # Toggle plotting functionality: if False: # Setting up the plot: fig = plt.figure(figsize=(8, 8)) ax = mp3d.Axes3D(fig)
ax.view_init(elev=20, azim=-50) steps = 64 angle_step = d2r(360 / steps) p0 = Vertex([0.5, 0.5, 0.5]) p1 = Vertex([-0.05, -0.05, -0.1]) p2 = Vertex([-0.05, -0.05, 0.1]) p3 = Vertex([0.05, -0.05, 0.1]) p4 = Vertex([0.05, -0.05, -0.1]) p5 = Vertex([-0.05, 0.05, -0.1]) p6 = Vertex([-0.05, 0.05, 0.1]) p7 = Vertex([0.05, 0.05, 0.1]) p8 = Vertex([0.05, 0.05, -0.1]) fA = Face(p4, p3, p2, p1) fB = Face(p2, p3, p7, p6) fC = Face(p3, p4, p8, p7) fD = Face(p4, p1, p5, p8) fE = Face(p1, p2, p6, p5) fF = Face(p5, p6, p7, p8) cubesat = Geometry([fA, fB, fC, fD, fE, fF]) frame1 = Frame() frame1.add_geometry(cubesat) frame1.translate(0.3, 0.3, 0.25) frame1.rotate(0, 0, d2r(1.5 * 360 / 12)) # DO A BARN DOOR!
def plot_face( axes: plt.matplotlib.axes, face: Face, plotlist: list = None, # Face plotting properties: linefill=True, # If False, does not plot face lines linecolour="#000", # Colour of face lines linewidth=2, # Thickness of face lines linealpha=1, # Opacity of face lines facefill=True, # If False, does not shade the face area facecolour="#555", # Colour of the face area shading facealpha=1, # Opacity of the face area shading # Vertex plotting properties: vertexfill=True, # If False, vertex will not be plotted vertexcolour="#000", # Specifies the vertex colour vertexsize=10, # Size of the plotted vertex vertexalpha=1, # Opacity of the plotted vertex # Illumination: illumination=False, # If True, plots illumination intensity ill_value=0 # Used to plot illumination intensity ): """ Plots an individual Face object. Check source code for kwargs. """ def plotlist2plotlist_xyz(plotlist: tuple): """Return a list of lists with the xyz coordinates of each vertex.""" # If object has no parent, return plot list in terms of global frame: p1_xyz = [] p2_xyz = [] p3_xyz = [] p4_xyz = [] for coordinate_row in plotlist: p1_xyz.append(coordinate_row[0]) p2_xyz.append(coordinate_row[1]) p3_xyz.append(coordinate_row[2]) p4_xyz.append(coordinate_row[3]) return [p1_xyz, p2_xyz, p3_xyz, p4_xyz] # Situations: # 1. Face is an orphan (parent == "global") and so it has to use # local coordinates only # 2. Face is part of a geometry, which we will assume has a frame underlying # it # print("[DEBUG] Plotting {}".format(face)) # Case 1: Face is an orphan: if face.parenttype == "global": (xlist, ylist, zlist) = face.plotlist_local() # Plot individual vertices: if vertexfill: for vertex in face.vertices(): plot_vertex(axes, vertex) # Plot edges that connect vertices: for i in range(-1, len(xlist) - 1): axes.plot3D([xlist[i], xlist[i + 1]], [ylist[i], ylist[i + 1]], [zlist[i], zlist[i + 1]], linecolour, alpha=linealpha, lw=linewidth) # Plot the face surface: if facefill: plotlist_xyz = plotlist2plotlist_xyz(face.plotlist_local()) fs = mp3d.art3d.Poly3DCollection([plotlist_xyz], linewidth=0) (nR, nG, nB) = hex2nRGB(facecolour) fs.set_facecolor((nR, nG, nB, facealpha)) axes.add_collection3d(fs) # Case 2: Face is in a frame else: (xlist, ylist, zlist) = plotlist # Plot individual vertices: # if vertexfill: # for vertex in face.vertices(): # plot_vertex(axes, vertex) # Plot edges that connect vertices: for i in range(-1, len(xlist) - 1): axes.plot3D([xlist[i], xlist[i + 1]], [ylist[i], ylist[i + 1]], [zlist[i], zlist[i + 1]], linecolour, alpha=linealpha, lw=linewidth) # Plot the face surface: if facefill: plotlist_xyz = plotlist2plotlist_xyz(plotlist) fs = mp3d.art3d.Poly3DCollection([plotlist_xyz], linewidth=0) if not illumination: (nR, nG, nB) = hex2nRGB(facecolour) fs.set_facecolor((nR, nG, nB, facealpha)) axes.add_collection3d(fs) else: value = round(0.1 + 0.9 / 1.6 * ill_value, 2) fs.set_facecolor((value, value, value, facealpha)) axes.add_collection3d(fs)