def mobius(): """Makes a mobius strip using the Tube class""" θ = np.radians(np.arange(0, 360 + 40, 40)) r = 1.5 x1 = r * np.cos(θ) y1 = r * np.sin(θ) z1 = np.zeros_like(θ) spine = np.array( [np.array((tx, ty, tz)) for tx, ty, tz in zip(x1, y1, z1)]) normals = np.vstack( (spine[1, :] - spine[0, :], spine[2:, :] - spine[:-2, :], spine[-1, :] - spine[-2, :])) t = new.Tube('mobius', x=θ, y=np.zeros_like(θ), z=np.zeros_like(θ), n=8, th=0) t.shade('flat') #pylint: disable=no-member t.subsurf(3, 3) t.scale((1, 1, 0.3)) t.apply_matrix() X = t.xsec.all nX = len(X) for ix, x in enumerate(X): x.origin = trf.PointCloud((x1[ix], y1[ix], z1[ix]), np.eye(4)) x.normal = trf.PointCloud(normals[ix, :] + x.origin, np.eye(4)) x.twist(360 * ix / (nX - 1)) for ix in (0, -1): X[ix].normal = trf.PointCloud( np.array([0, 1, 0]) + X[ix].origin, np.eye(4)) ## make a merge_XS feature # bm = bmesh.new() # bm.from_mesh(t.bm) # bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001) # bm.to_mesh(t.bm) # t.bm.update() # bm.clear() # bm.free() X[0].origin = trf.PointCloud((2, 0, 0), np.eye(4)) X[-1].origin = trf.PointCloud((2, 0, 0), np.eye(4)) return t
def plot(self, x, y, **kwargs): """(x, y) plot""" def _norm_inp(d, d_lim=None): # scale the input between 0 and 1 d = np.array(d) if d_lim is None: do = np.min(d) dw = np.max(d) - do else: assert np.size(d_lim) == 2 do = d_lim[0] dw = d_lim[1] - d_lim[0] return (d - do) / dw x_plt = _norm_inp(x) * self._width y_plt = _norm_inp(y) * self._height pc = trf.PointCloud( np.vstack((x_plt, y_plt, np.zeros_like(x_plt))).T, self.frame) plot_defaults = { 'layer': 'plot', 'color': self.next_color, 'keyframe': 0, 'pressure': 1.0, 'strength': 1.0 } return super().stroke(pc, **{**plot_defaults, **kwargs})
def __init__(self): # create dancer body = new.cone(name='body',r1=0.2, r2=0.2, h=1.5) body.translate(z=0.75) body.scale((0.5, 1, 1)) body.apply_matrix() head = new.cone(name='head', r1=0.2, r2=0, h=0.3) head.rotate((0.,90.,0.)) head.translate(x=0.1) head.apply_matrix() head.translate(z=1.6) self.gp = [] self.gp.append(body.show_frame()) self.gp.append(head.show_frame()) # create markers m1 = new.sphere(name='m1', r=0.05) self.m1_pos = trf.PointCloud((-0.1, 0, 1)) # both body frame and world frame self.body = body self.head = head self.m1 = m1 self.screen = new.empty() self.screen.frame = self.head.frame self.screen.translate((1, 0, -0.3)) self.m1viz = new.sphere(name='m1viz', r=0.08) self._update_m1()
def normals(self, new_normal_dir): """ Directions are origin-agnostic. """ new_normal_dir = np.array(new_normal_dir) assert np.shape(new_normal_dir) == (self.n, 3) for i in range(np.shape(new_normal_dir)[0]): self.all[i].normal = trf.PointCloud(new_normal_dir[i, :]+self.all[i].origin, np.eye(4))
def frame(self, new_frame): # User can manually change the reference frame. Points follow frame. assert isinstance(new_frame, trf.CoordFrame) new_frame = trf.CoordFrame( new_frame.m) # to ensure new_frame matrix has unit vectors vectors # The relative positions of the points don't change because the points are following the frame self.pts = trf.PointCloud(self.pts.in_frame(self.frame).co, new_frame) self._frame = new_frame
def frame(self, new_frame): # user can manually change the reference frame. If the origin is different, then the points are going to move! assert isinstance(new_frame, trf.CoordFrame) # this line moves the points, and explicitly specifies that the new frame was specified in world coordinates. self.origin = trf.PointCloud(np.array([new_frame.origin]), trf.CoordFrame()) # the orientation of the frame is simply taken from new_frame (vectors will be normalized!) self._frame = trf.CoordFrame(i=new_frame.i, j=new_frame.j, k=new_frame.k, origin=self.origin)
def draw_axes(self, **kwargs): """Draw a rectangular box. Re-draws strokes every time!""" screen_points = trf.PointCloud( self.loc + np.vstack(([0, 0, 0], [self._width, 0, 0], [ self._width, self._height, 0 ], [0, self._height, 0], [0, 0, 0])), self.frame) ax_defaults = { 'layer': 'ax', 'color': 'black', 'keyframe': 0, 'pressure': 1.5, 'strength': 1.0 } return self.stroke(screen_points, **{**ax_defaults, **kwargs})
def _transform_bones(bones, articulation_center_rel, articulation_center_frames, articulation_angle): """ :param bones: (list of bpn.core.MeshObject) list of bones to be transformed :param articulation_center_rel: (3-element np array) location of the center of transformation. The position of the rotation center does not change in this frame. :param articulation_center_frames: (list of CoordFrames, same length as number of keyframes) The coordinate frame in which articulation center is specified (specifies the frame in world coordinates) :param articulation angle: (radians) how much to articulate that joint """ for tkf in range(1, n_keyframes): articulation_center = trf.PointCloud( articulation_center_rel, articulation_center_frames[tkf]).in_world().co[0, :] progress = (tkf / n_keyframes)**1 q = trf.Quat([1, 0, 0], articulation_angle * progress, trf.CoordFrame(origin=articulation_center)) for b in bones: all_frames[b.name][tkf] = q * all_frames[b.name][tkf]
def grease_pencil(): """Illustrate making animated 2d plots with grease pencil.""" # equivalent of MATLAB's figure() gp = new.pencil(gp_name='myGP', obj_name='myGPobj', coll_name='Pencil', layer_name='sl1') θ = np.radians(np.arange(0, 360 * 2 + 1, 1)) z1 = np.sin(θ) y1 = np.cos(θ) x1 = θ / 2 # equivalent of plot pc1 = trf.PointCloud(np.vstack((x1, y1, z1)).T, np.eye(4)) pc2 = copy.deepcopy(pc1) pc1.frame = trf.Quat([-1, 1, 0], np.pi / 4) * pc1.frame gp.stroke(pc1, color=2, layer='sl1', keyframe=0) # pressure controls thickness of individual points gp.stroke(pc2, color=1, layer='sl3', keyframe=10, pressure=np.linspace(0, 3, len(θ))) # strength seems to control transparencu of individual points gp.stroke(pc1, color=2, layer='sl1', keyframe=20, strength=np.linspace(0, 1, len(θ))) gp.keyframe = 30 # show the frame for point cloud 1 emp = new.empty('pc1_frame', coll_name='Pencil') emp.frame = pc1.frame emp.show_frame() return gp
n_keyframes_nutation = 20 n_keyframes_hold = 10 hip_articulation_center_world = (-0.10529670119285583, 0.007387260906398296, 0.9325617551803589) knee_articulation_center_world = (-0.10663662105798721, 0.03164456784725189, 0.5140388011932373) ankle_articulation_center_world = (-0.1197955459356308, 0.06532438099384308, 0.06592987477779388) hip_articulation_angle = -66 * np.pi / 180 knee_articulation_angle = 77 * np.pi / 180 ankle_articulation_angle = 1 * np.pi / 180 hip_articulation_center_rel_ilium = trf.PointCloud( hip_articulation_center_world, np.eye(4)).in_frame(utils.get('Ilium_R').frame).co[0, :] knee_articulation_center_rel_femur = trf.PointCloud( knee_articulation_center_world, np.eye(4)).in_frame(utils.get('Femur_R').frame).co[0, :] ankle_articulation_center_rel_tibia = trf.PointCloud( ankle_articulation_center_world, np.eye(4)).in_frame(utils.get('Tibia_R').frame).co[0, :] def _transform_bones(bones, articulation_center_rel, articulation_center_frames, articulation_angle): """ :param bones: (list of bpn.core.MeshObject) list of bones to be transformed :param articulation_center_rel: (3-element np array) location of the center of transformation. The position of the rotation center does not change in this frame. :param articulation_center_frames: (list of CoordFrames, same length as number of keyframes)
def centers(self, new_centers): new_centers = np.array(new_centers) assert np.shape(new_centers) == (self.n, 3) for i in range(self.n): self.all[i].origin = trf.PointCloud(new_centers[i, :], np.eye(4))
def __init__(self, parent, normal, **kwargs): super().__init__(parent, **kwargs) # initalization sets _frame, but it needs to be modified without bringing the points along if not isinstance(normal, trf.PointCloud): normal = trf.PointCloud(normal, self.parent.frame) self.change_normal(normal)
def pts(self): """Vertex positions in the parent mesh's frame of reference.""" return trf.PointCloud(self.parent.v[self.vi, :], frame=self.parent.frame)