def box(name=None, **kwargs): """ Extend the functionality of a cube to create bounding boxes b = new.box(limits=pn.dotdict({'x': (-0.383, 0.165), 'y': (-0.143, 0.405), 'z': (0.069, 0.617)})) """ class Box(core.MeshObject): def __init__(self, name, **kwargs): limits = kwargs.pop('limits', None) this_obj = easycreate(bmesh.ops.create_cube, name, **kwargs) super().__init__(this_obj.name, this_obj.data) if limits is not None: # put the cube in the right place assert isinstance(limits, pn.dotdict) new_origin = [np.mean(limits[dim]) for dim in limits] new_span = [np.diff(limits[dim])[0] for dim in limits] curr_lim = self.lim() curr_span = [np.diff(curr_lim[dim])[0] for dim in curr_lim] self.loc = (0., 0., 0.) self.scale(np.array(new_span)/np.array(curr_span)) self.loc = new_origin def lim(self, round_dec=3): v = trf.apply_matrix(self().matrix_world, self.data.v) x, y, z = [(round(np.min(v[:, dim]), round_dec), round(np.max(v[:, dim]), round_dec)) for dim in (0, 1, 2)] return pn.dotdict(x=x, y=y, z=z) name = utils.new_name('new_box', [o.name for o in bpy.data.objects]) if name is None else name return Box(name, **kwargs)
def empty(name=None, typ='PLAIN_AXES', size=0.25, coll_name='Collection'): """ Create a new empty. Convenience wrapper for initalizing core.Object # typ ('PLAIN_AXES', 'ARROWS', 'SINGLE_ARROW', 'CIRCLE', 'CUBE', 'SPHERE', 'CONE', 'IMAGE') returns: core.Object """ if name is None: name = 'empty' name = utils.new_name(name, [o.name for o in bpy.data.objects]) s = core.ContainerObject(name, empty_display_type=typ, empty_display_size=size) s.to_coll(coll_name) return s
def __init__(self, this_thing, coll_name, path, size, targ=None): super().__init__(this_thing.name.lower(), this_thing) self.to_coll(coll_name) container_name = utils.new_name(self.name+'_container', [o.name for o in bpy.data.objects]) self.container = core.ContainerObject(container_name, empty_display_type='CUBE', empty_display_size=size) self.container.to_coll(coll_name) self.container.add(self) if isinstance(path, (int, float)): self.path = bezier_circle(r=path, curve_name=this_thing.name+'Path', obj_name=this_thing.name.lower()+'_path', coll_name=coll_name) if isinstance(path, core.Object): self.path = path self.container.follow_path(self.path) if targ is not None: self.track_to(targ)
def __init__(self, expr, name=None, **kwargs): if name is None: name = utils.new_name('new_text', [o.name for o in bpy.data.objects]) kwargs_names, _ = utils.clean_names(name, kwargs, {'priority_curve': 'new'}, mode='curve') def write_tex_file(fname): try: f = open(fname, 'w') f.write(r"\documentclass{standalone}" + "\n") f.write(r"\usepackage{amsthm, amssymb, amsfonts, amsmath}" + "\n") f.write(r"\begin{document}" + "\n") f.write(expr + "\n") f.write(r"\end{document}" + "\n") finally: f.close() tmp_name = name orig_dir = os.getcwd() os.chdir(utils.PATH['cache']) write_tex_file(tmp_name + '.tex') os.system("pdflatex " + tmp_name + '.tex -quiet') os.system("pdftocairo -svg " + tmp_name + '.pdf ' + tmp_name + '.svg') os.chdir(orig_dir) svgfile = os.path.join(utils.PATH['cache'], tmp_name + '.svg') delta = io.loadSVG(svgfile, name, **kwargs) self.delta = {key:val for key, val in delta.items() if key in delta['changedFields']} self.obj_names = [o.name for o in self.delta['objects']] self.obj_names.sort() if len(self.obj_names) == 1: self.base_obj_name = self.obj_names[0] else: # make an empty and parent everything emp = bpy.data.objects.new(kwargs_names['obj_name'], None) col = core.Collection(kwargs_names['coll_name'])() col.objects.link(emp) for o in [bpy.data.objects[obj_name] for obj_name in self.obj_names]: o.parent = emp self.base_obj_name = emp.name super().__init__(self.base_obj_name)
def __init__(self, path, **kwargs): """Load image from file onto a plane""" assert os.path.isfile(path) name = kwargs.get('name', os.path.splitext(os.path.split(path)[-1])[0]) p = plane(name) # vertex order matters for correct uv mapping p.v = np.array([[-1., -1., 0], [1., -1., 0.], [1., 1., 0.], [-1., 1., 0.]]) p().data.uv_layers.new(name='imUV') img = bpy.data.images.load(path) im_width, im_height = img.size[:] p.scale((1, im_height/im_width, 1)) p.apply_matrix() p.rotate((90, 0, 0)) # default plane is XZ mtrl_name = utils.new_name('immaterial', [m.name for m in bpy.data.materials]) mat = bpy.data.materials.new(name=mtrl_name) mat.use_nodes = True bsdf = mat.node_tree.nodes["Principled BSDF"] im_node = mat.node_tree.nodes.new('ShaderNodeTexImage') im_node.image = img mat.node_tree.links.new(bsdf.inputs['Base Color'], im_node.outputs['Color']) if p().data.materials: p().data.materials[0] = mat else: p().data.materials.append(mat) self.nodes = {} self.nodes['image'] = im_node self.nodes['bsdf'] = bsdf self.material = mat self.plane = p