Пример #1
0
def pencil(name=None, **kwargs):
    """
    Create a new grease pencil object.
    """
    names, kwargs = utils.clean_names(name, kwargs, {'layer_name':'main', 'priority_gp': 'current', 'priority_obj': 'current'}, mode='gp')
    gp_name = names['gp_name']
    obj_name = names['obj_name']
    coll_name = names['coll_name']
    layer_name = names['layer_name']

    # Create palette in the blender file
    kwargs, _ = pn.clean_kwargs(kwargs, {
        'palette_list': ['MATLAB', 'blender_ax'], 
        'palette_prefix': ['MATLAB_', ''], 
        'palette_alpha': [1, 0.8],
        })
    this_palette = {}
    for pal_name, pal_pre, pal_alpha in zip(kwargs['palette_list'], kwargs['palette_prefix'], kwargs['palette_alpha']):
        this_palette = {**this_palette, **utils.color_palette(pal_name, pal_pre, pal_alpha)} # material library for this grease pencil
    for mtrl_name, rgba in this_palette.items(): # create material library
        utils.new_gp_color(mtrl_name, rgba) # will only create if it doesn't exist

    s = core.GreasePencilObject(obj_name, core.GreasePencil(gp_name))
    s.layer = layer_name
    # assign colors to this pencil's material slots
    for color in this_palette:
        s.color = color

    s.color = 0
    s.to_coll(coll_name)
    return s
Пример #2
0
def torus(name=None, **kwargs):
    """
    Make a torus in the x-y plane
    torus('mytorus', u=6, v=32, r=1, t=0.3)
        u = number of subdivisions in a saggital section (small circle)
        v = number of subdivisions in the horizontal section (big circle)
        r = radius of the doughnut
        t = thickness (radius)
        th = degrees to rotate the small circle
    """
    names, kwargs = utils.clean_names(name, kwargs, {'msh_name':'torus', 'obj_name':'torus', 'priority_msh':'current', 'priority_obj':'new'})

    kwargs_def = {'n_u':16, 'r_u':0.3, 'n_v':32, 'r_v':1, 'theta_offset_deg':'auto'}
    kwargs_alias = {'n_u':['n_u', 'u'], 'r_u':['r_u', 't', 'thickness'], 'n_v':['n_v', 'v'], 'r_v':['r_v', 'r'], 'theta_offset_deg':['theta_offset_deg', 'th', 'offset', 'th_off_deg', 'th_u']}
    kwargs, _ = pn.clean_kwargs(kwargs, kwargs_def, kwargs_alias)
    
    a = turtle.Draw(**names)
    start = a.ngon(n=kwargs['n_u'], r=kwargs['r_u'], th_off_deg=kwargs['theta_offset_deg'])
    bmesh.ops.rotate(a.bm, verts=start.v, cent=(0, 0, 0), matrix=mathutils.Matrix.Rotation(np.radians(90.0), 3, 'Y'))
    for vert in start.v:
        vert.co += mathutils.Vector((0., -kwargs['r_v'], 0.))
    end = a.spin(angle=2*np.pi-2*np.pi/kwargs['n_v'], steps=kwargs['n_v']-1, axis='z', cent=(0., 0., 0.))
    a.join(start.e + end.e)
    tor = +a
    return tor
Пример #3
0
 def __init__(self, name=None, **kwargs):
     self.names, _ = utils.clean_names(
         name, kwargs, {
             'msh_name': 'draw_msh',
             'obj_name': 'draw_obj',
             'priority_obj': 'new',
             'priority_msh': 'new'
         })
     self.bm = bmesh.new()
     self.all_geom = ()
Пример #4
0
    def __init__(self, name=None, x=0, y=0, z=0, **kwargs):
        names, kwargs = utils.clean_names(name, kwargs, {'msh_name':'tube_msh', 'obj_name':'tube_obj', 'priority_obj':'new', 'priority_msh':'new'})
        kwargs_ngon, _ = pn.clean_kwargs(kwargs, {'n':6, 'r':0.3, 'theta_offset_deg':-1}, {'n':['segments', 'seg', 'u', 'n'], 'r':['radius', 'r'], 'theta_offset_deg':['theta_offset_deg', 'th', 'offset', 'th_off_deg']})
        
        spine = np.array([np.array((tx, ty, tz)) for tx, ty, tz in zip(x, y, z)])
        normals = np.vstack((spine[1, :] - spine[0, :], spine[2:, :] - spine[:-2, :], spine[-1, :] - spine[-2, :]))

        a = turtle.Draw(**names)
        a.skin(spine, **kwargs_ngon)
        a_exp = a.export()
        this_obj = +a
        super().__init__(this_obj.name, this_obj.data)

        self.xsec = self.XSec(self, normals, a_exp)
Пример #5
0
    def __init__(self, name, **kwargs):
        names, kwargs00 = utils.clean_names(name,
                                            kwargs, {
                                                'layer_name': 'main',
                                                'priority_gp': 'current',
                                                'priority_obj': 'current'
                                            },
                                            mode='gp')
        gp_name = names['gp_name']
        obj_name = names['obj_name']
        coll_name = names['coll_name']
        layer_name = names['layer_name']

        # Create palette in the blender file
        kwargs01, kwargs02 = pn.clean_kwargs(
            kwargs00, {
                'palette_list': ['MATLAB', 'blender_ax'],
                'palette_prefix': ['MATLAB_', ''],
                'palette_alpha': [1, 0.8],
            })
        this_palette = {}
        for pal_name, pal_pre, pal_alpha in zip(kwargs01['palette_list'],
                                                kwargs01['palette_prefix'],
                                                kwargs01['palette_alpha']):
            this_palette = {
                **this_palette,
                **utils.color_palette(pal_name, pal_pre, pal_alpha)
            }  # material library for this grease pencil
        for mtrl_name, rgba in this_palette.items():  # create material library
            utils.new_gp_color(mtrl_name,
                               rgba)  # will only create if it doesn't exist

        super().__init__(obj_name, core.GreasePencil(gp_name))
        self.data.layer = layer_name
        # assign colors to this pencil's material slots
        for color in this_palette:
            self.color = color

        custom, _ = pn.clean_kwargs(kwargs02, {
            'color': 'white',
            'keyframe': 1
        })
        color = custom['color']
        if isinstance(color, int):
            # NOTE: This is confusing, because the color behavior is core.greasepencilobject is different!
            color = 'MATLAB_{:02d}'.format(color)
        self.color = color
        self.keyframe = custom['keyframe']
        self.to_coll(coll_name)
Пример #6
0
def easycreate(mshfunc, name=None, **kwargs):
    """
    **kwargs : u=16, v=8, r=0.5 for uv sphere
    **kwargs : size=0.5 for uv cube

    Warning: Avoid empty creates such as new.sphere()!
    """
    names, kwargs = utils.clean_names(name, kwargs, {'priority_obj':'new', 'priority_msh':'current'})
    if int(bpy.app.version_string.split('.')[0]) == 2:
        size_param_name = 'diameter'
    else:
        size_param_name = 'radius' # API change in version 3

    # input control
    if str(mshfunc) == str(bmesh.ops.create_uvsphere):
        kwargs_def = {'u_segments':16, 'v_segments':8, size_param_name:0.5}
        kwargs_alias = {'u_segments': ['u', 'u_segments'], 'v_segments': ['v', 'v_segments'], size_param_name: ['r', 'radius', 'diameter']}
        kwargs, _ = pn.clean_kwargs(kwargs, kwargs_def, kwargs_alias)

    if str(mshfunc) == str(bmesh.ops.create_cube):
        kwargs_def = {'size':1}
        kwargs_alias = {'size': ['size', 'sz', 's', 'r']}
        kwargs, _ = pn.clean_kwargs(kwargs, kwargs_def, kwargs_alias)
    
    if str(mshfunc) == str(bmesh.ops.create_cone):
        kwargs_def = {'segments':12, f'{size_param_name}1':2, f'{size_param_name}2':0, 'depth':3, 'cap_ends':True, 'cap_tris':False}
        kwargs_alias = {'segments':['segments', 'seg', 'u', 'n'], f'{size_param_name}1':['diameter1', 'radius1', 'r1', 'r'], f'{size_param_name}2':['diameter2', 'radius2', 'r2'], 'depth':['depth', 'd', 'h'], 'cap_ends':['cap_ends', 'fill'], 'cap_tris':['cap_tris', 'fill_tri']}
        kwargs, _ = pn.clean_kwargs(kwargs, kwargs_def, kwargs_alias)

    if str(mshfunc) == str(bmesh.ops.create_monkey):
        kwargs = {}

    if names['msh_name'] in [m.name for m in bpy.data.meshes]:
        msh = bpy.data.meshes[names['msh_name']]
    else:
        msh = bpy.data.meshes.new(names['msh_name'])
        bm = bmesh.new()
        mshfunc(bm, **kwargs)
        bm.to_mesh(msh)
        bm.free()
        msh.update()
    return mesh(msh_name=msh.name, obj_name=names['obj_name'], coll_name=names['coll_name'], pargs=kwargs)
Пример #7
0
def bezier_circle(name=None, **kwargs):
    """
    Bezier circle of radius r.
    Returns core.Object
    """
    names, kwargs = utils.clean_names(name, kwargs, {'curve_name':'Bezier', 'obj_name':'bezier', 'priority_curve':'current', 'priority_obj':'new'}, 'curve')
    kwargs, _ = pn.clean_kwargs(kwargs, {'r':1, 'h':None})
    r = kwargs['r']
    h = kwargs['h']
    if h is None:
        h = r*(np.sqrt(2)/2 - 4*(0.5**3))/(3*(0.5**3)) # handle length for cubic bezier approx. of a circle

    path_obj = core.CurveObject(names['obj_name'], core.Curve(names['curve_name']))
    path_obj.to_coll(names['coll_name'])

    spl = path_obj().data.splines.new(type='BEZIER')
    spl.bezier_points.add(3)
    spl.bezier_points[0].co = (-r, 0, 0)
    spl.bezier_points[1].co = (0, r, 0)
    spl.bezier_points[2].co = (r, 0, 0)
    spl.bezier_points[3].co = (0, -r, 0)

    spl.bezier_points[0].handle_right = (-r, h, 0)
    spl.bezier_points[0].handle_left = (-r, -h, 0)

    spl.bezier_points[1].handle_right = (h, r, 0)
    spl.bezier_points[1].handle_left = (-h, r, 0)

    spl.bezier_points[2].handle_right = (r, -h, 0)
    spl.bezier_points[2].handle_left = (r, h, 0)

    spl.bezier_points[3].handle_right = (-h, -r, 0)
    spl.bezier_points[3].handle_left = (h, -r, 0)

    spl.use_cyclic_u = True
    spl.order_u = 4
    spl.order_v = 4
    spl.resolution_u = 12
    spl.resolution_v = 12
    spl.tilt_interpolation = 'LINEAR' #('LINEAR', 'CARDINAL', 'BSPLINE', 'EASE')

    return path_obj
Пример #8
0
    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)
Пример #9
0
def loadSVG(svgfile, name=None, **kwargs):
    """
    import an svg file into the blender scene.
    Originally created to import latex text into blender.
    Create text using the commands:
        pdflatex testdoc.tex
        pdftocairo -svg testdoc.pdf testdoc.svg
    
    Example:
        io.loadSVG(os.path.join(utils.PATH['cache'], 'testdoc.svg'), color=utils.color_palette('blender_ax')['crd_k'])
    """
    if name is None:
        name = os.path.splitext(os.path.basename(svgfile))[0]
    kwargs_names, kwargs = utils.clean_names(name,
                                             kwargs, {'priority_curve': 'new'},
                                             mode='curve')
    kwargs_def = {
        'remove_default_coll': True,
        'scale': (100, 100, 100),  # svg imports are really small
        'color': (1.0, 1.0, 1.0, 1.0),
        'combine_curves': True,  # this may not work!!
        'halign': 'center',  # 'center', 'left', 'right', None
        'valign': 'middle',  # 'top', 'middle', 'bottom', None
    }
    kwargs, _ = pn.clean_kwargs(kwargs, kwargs_def)

    @env.ReportDelta
    def _loadSVG(files):
        """
        Import an SVG file into the blender scene.
        Hidden. Use loadSVG.
        """
        if isinstance(files, str):
            files = [files]
        for f in files:
            if not os.path.exists(f):
                raise FileNotFoundError(errno.ENOENT,
                                        os.strerror(errno.ENOENT), f)
            bpy.ops.import_curve.svg(filepath=f)

    s = _loadSVG(svgfile)
    col_def = s['collections'][0]
    col = core.Collection(kwargs_names['coll_name'])()

    if kwargs['combine_curves']:
        utils.combine_curves(s['objects'], s['materials'])
        base_obj = s['objects'][0]
        base_curve = base_obj.data

        base_obj.name = kwargs_names['obj_name']
        base_curve.name = kwargs_names['curve_name']
        col.objects.link(base_obj)
        col_def.objects.unlink(base_obj)
        base_obj.scale = kwargs['scale']
        for mtrl in base_curve.materials:
            mtrl.diffuse_color = kwargs['color']

        # curve alignment
        utils.align_curve(base_obj.data,
                          halign=kwargs['halign'],
                          valign=kwargs['valign'])
    else:
        for obj in s['objects']:
            col.objects.link(obj)
            col_def.objects.unlink(obj)
            obj.scale = kwargs['scale']
            # utils.align_curve(obj.data, halign=kwargs['halign'], valign=kwargs['valign'])

        for mtrl in s['materials']:
            mtrl.diffuse_color = kwargs['color']

    if kwargs['remove_default_coll']:
        bpy.data.collections.remove(col_def)

    bpy.context.view_layer.update()
Пример #10
0
def mesh(name=None, **kwargs): # formerly bpn.Msh
    """
    Create a mesh object from various types of input
    Returns core.MeshObject

    :param name: name='thing' (str) both the mesh and the object will receive this name
            name will get overwritten by msh_name or obj_name if present
    :param kwargs: (create mesh from vertices and faces, 2d array, or function)
        msh_name='new_mesh'  
            (str) name of the mesh loaded in blender
            (str) name of an object loaded in blender (get the associated mesh)
            (bpy.types.Mesh) the bpy mesh object
        obj_name='new_obj' (str) name of the object to assign the mesh
        coll_name='new_coll' (str) name of the collection to locate the object / to place the created object        
        stl=stlfilename (str) name of stl file to import

        Create a mesh from a function:
            xyfun (function with two float inputs and one float output)
                xyfun = lambda x, y: x*x+y*y
                A 2d matrix, z, gets created if a function is supplied

        Create a mesh from 2d list or numpy array (xyz):
            z (2d list or matrix to render in blender)
            x (list) list or numpy array
                x = np.arange(-2, 2, 0.02)
            y (list)
                y = np.arange(-2, 3, 0.2)
        
        Create a mesh from vertices and faces (vef):
            v (numpy array of size nVx3, or a 2d list of size nV with 3 element lists of locations)
                Vertices
            f (numpy array of face indices nFx4 is most common, but also a 2d list of size nF typically with 4-element faces)
                Faces

        Create a 3d plot (xyz):
            z (list) with n elements
            x (list) with n elements
            y (list) with n elements
            
        Create a 'line' from vertices and edges (vef):
            v (numpy array of size nVx3, or a 2d list of size nV with 3 element lists of locations)
                Vertices
            e (numpy array of size nEx2, or a 2d list of size nE with 2 element lists of vertex index)
                Edges connecting vertices
        
        More generally, supply v=myVertices, e=myEdges, f=myFaces to create a mesh
    
    Broadly, using this function, core.MeshObjects can be created from:
    - (type=stl) an STL file import
    - (type=blend) the blender environment
    - (type=vfedata) creating vertex, faces, and edges from data
        - (type=fun) a 2d function that takes two floats as input and produces one output
            xyfun -> x (list), y (list), z (2D list) -> v, f (e=automatically calculated) -> mesh
            xyfun (function with two float inputs and one float output)
                xyfun = lambda x, y: x*x+y*y
        - (type=mat) a 2d matrix or list
            - x (list), y(list), z (2D list) -> v, f (e=automatically created) -> mesh
        - (type=plot) a 3d plot
            - x (list), y(list), z (list) -> v, e (no faces) -> mesh
    Examples:
        # make a mesh from python data
        new.mesh(name=name, v=vertices, f=faces)
        new.mesh(v=v1, f=f1)
        new.mesh(v=v1, e=e1)
        new.mesh(v=v1, e=e1, f=f1)

        # make a mesh from an STL file
        new.mesh(stl=stlfile)
        new.mesh(stl=stlfile, name='awesome') # mesh and object get the same name
        new.mesh(stl=stlfile, coll_name='myColl') # put msh in a collection coll_name
        new.mesh(stlfile, name='awesome', msh_name='awesomeMesh', coll_name='myColl')
        new.mesh(stlfile, msh_name='awesomeMesh', obj_name='awesomeObj', coll_name='myColl')

        # get a mesh from the blender environment
        new.mesh(name=blender mesh name)
        new.mesh(name=blender obj name)
        new.mesh(name=blender mesh object) # works, but not recommended

        # make a mesh from a 2d function
        new.mesh(xyfun=lambda x, y: x*x+y*y, name='parabola')
    """
    def _make_mesh(msh_name, kwargs):
        """
        This mesh creation function is invoked only if mesh specified by msh_name does not exist.
        """
        if 'z' in kwargs or 'xyfun' in kwargs:
            if 'x' not in kwargs:
                if 'z' in kwargs and len(np.shape(kwargs['z'])) == 2:
                    x = np.arange(0, np.shape(kwargs['z'])[0])
                elif 'xyfun' in kwargs:
                    x = np.arange(-2, 2, 0.1)
            else:
                x = kwargs['x']
            if 'y' not in kwargs:
                if 'z' in kwargs and len(np.shape(kwargs['z'])) == 2:
                    y = np.arange(0, np.shape(kwargs['z'])[1])
                elif 'xyfun' in kwargs:
                    y = np.arange(-2, 2, 0.1)
            else:
                y = kwargs['y']

        if 'xyfun' in kwargs:
            xyfun = kwargs['xyfun']
            assert isinstance(xyfun, types.FunctionType)
            assert xyfun.__code__.co_argcount == 2 # function has two input arguments
            kwargs['z'] = np.array([[xyfun(xv, yv) for yv in y] for xv in x])

        if 'z' in kwargs:
            z = np.array(kwargs['z'])
            if len(np.shape(z)) == 2: # 2D array, surface plot
                nX = len(x)
                nY = len(y)
                assert nX == np.shape(z)[0]
                assert nY == np.shape(z)[1]
                # matrix to vertices and faces
                kwargs['v'] = [(xv, yv, z[ix][iy]) for iy, yv in enumerate(y) for ix, xv in enumerate(x)]
                kwargs['f'] = [(iy*nX+ix, iy*nX+ix+1, (iy+1)*nX+(ix+1), (iy+1)*nX+ix) for iy in np.arange(0, nY-1) for ix in np.arange(0, nX-1)]
            if len(np.shape(z)) == 1: # 3D plot!
                kwargs['v'], kwargs['e'], _ = vef.xyz2vef(x, y, z)

        if 'v' in kwargs and ('f' in kwargs or 'e' in kwargs):
            if 'e' not in kwargs:
                kwargs['e'] = []
            if 'f' not in kwargs:
                kwargs['f'] = []
            msh = bpy.data.meshes.new(msh_name)
            msh.from_pydata(kwargs['v'], kwargs['e'], kwargs['f'])
            if not kwargs['e']:
                msh.update(calc_edges=True)
            else:
                msh.update()
        return msh # blender mesh

    names, kwargs = utils.clean_names(name, kwargs, {'priority_msh': 'current', 'priority_obj': 'current'}, mode='msh')
    msh_name = names['msh_name']
    obj_name = names['obj_name']
    coll_name = names['coll_name']
    if 'stl' in kwargs:
        stlfile = kwargs['stl']
        assert os.path.isfile(stlfile)
        s = core.MeshObject(io.loadSTL([stlfile])['objects'][0])
        s.name = obj_name
        s.data.name = msh_name
        s.to_coll(coll_name)
        return s

    # if obj_name exists, use object and corresponding mesh
    if obj_name in [o.name for o in bpy.data.objects]:
        s = core.MeshObject(obj_name)
        s.to_coll(coll_name)
        return s

    # if mesh exists, assign it to the object, and put it in collection
    if msh_name in [m.name for m in bpy.data.meshes]:
        s = core.MeshObject(obj_name, bpy.data.meshes[msh_name])
        s.to_coll(coll_name)
        return s

    # if mesh doesn't exist, make it, make object, and put it in the collection
    s = core.MeshObject(obj_name, _make_mesh(msh_name, kwargs))
    s.to_coll(coll_name)
    return s