1
$\begingroup$

So in this script for Csharpen I am getting an error after the first if for the bpy.ops.object.convert(target='MESH'). I am not sure why that is since it was working fine before adding conditionals. Is there a reason why that is happening?

class sharpenOperator(bpy.types.Operator):
    '''Sharpen With Modifiers and Bevelling'''
    bl_idname = "csharpen.objects"
    bl_label = "CSharpen"
    bl_options = {'REGISTER', 'UNDO'} 

    ssharpangle = FloatProperty(name="SSharpening Angle", description="Set SSharp Angle", default= 30.0, min = 0.0, max = 180.0)

    angle = FloatProperty(name="AutoSmooth Angle", description="Set AutoSmooth angle", default= 60.0, min = 0.0, max = 180.0)

    bevelwidth = FloatProperty(name="Bevel Width Amount", description="Set Bevel Width", default= 0.0071, min = 0.002, max = .25)

    applyall = BoolProperty(default = True)

    originalbevel = FloatProperty()

    # ADD A DRAW FUNCTION TO DISPLAY PROPERTIES ON THE F6 MENU
    def draw(self, context):
        layout = self.layout

        box = layout.box()
        # DRAW YOUR PROPERTIES IN A BOX
        box.prop( self, 'ssharpangle', text = "SsharpAngle" )
        box.prop( self, 'angle', text = "SmoothingAngle" )
        box.prop( self, 'bevelwidth', text = "BevelWidth")
        box.prop( self, 'applyall', text = "ApplyAll")

    def execute(self, context):
        #convert angle
        ob = bpy.context.selected_objects
        angle = self.angle
        originalbevel = self.originalbevel
        ssharpangle = self.ssharpangle
        angle = angle * (3.14159265359/180)
        ssharpangle = ssharpangle * (3.14159265359/180)
        bevelwidth = self.bevelwidth

        #Sets the Bevel Width To The Orig Bevel Width
        originalbevel = bpy.context.object.modifiers["Bevel"].width

        if self.applyall:
            #remove modifiers no one would want applied in this instance
            bpy.ops.object.modifier_remove(modifier="Bevel")
            bpy.ops.object.modifier_remove(modifier="Solidify")
            #convert to mesh for sanity
            bpy.ops.object.convert(target='MESH')

            #apply the scale to keep me sane
            bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

            #Start In Edit Mode
            bpy.ops.object.mode_set(mode='EDIT')

            #Unhide all The Geo!
            bpy.ops.mesh.reveal()

            #Clear SSharps Then Redo It
            #bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
            #bpy.ops.mesh.select_all(action='DESELECT')
            #bpy.ops.mesh.select_all(action='TOGGLE')

            #AR suggested using -1s instead of Zeroes
            #bpy.ops.transform.edge_bevelweight(value=-1)
            #bpy.ops.mesh.mark_sharp(clear=True)
            #bpy.ops.transform.edge_crease(value=-1)

            #then do the csharp operator stuff.
            bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
            bpy.ops.mesh.select_all(action='DESELECT')

            #Sharpening now using the ssharpangle parameter.
            bpy.ops.mesh.edges_select_sharp(sharpness=ssharpangle)

            bpy.ops.transform.edge_bevelweight(value=1)
            bpy.ops.transform.edge_crease(value=1)
            bpy.ops.mesh.mark_sharp()
            bpy.ops.object.editmode_toggle()     

        else:
            #Start In Edit Mode
            bpy.ops.object.mode_set(mode='EDIT')

            #Unhide all The Geo!
            bpy.ops.mesh.reveal()

            #Clear SSharps Then Redo It
            #bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
            #bpy.ops.mesh.select_all(action='DESELECT')
            #bpy.ops.mesh.select_all(action='TOGGLE')

            #AR suggested using -1s instead of Zeroes
            #bpy.ops.transform.edge_bevelweight(value=-1)
            #bpy.ops.mesh.mark_sharp(clear=True)
            #bpy.ops.transform.edge_crease(value=-1)

            #then do the csharp operator stuff.
            bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
            bpy.ops.mesh.select_all(action='DESELECT')

            #Sharpening now using the ssharpangle parameter.
            bpy.ops.mesh.edges_select_sharp(sharpness=ssharpangle)

            bpy.ops.transform.edge_bevelweight(value=1)
            bpy.ops.transform.edge_crease(value=1)
            bpy.ops.mesh.mark_sharp()
            bpy.ops.object.editmode_toggle()     

        #keep the old here for now
        bpy.ops.object.modifier_add(type='BEVEL')
        bpy.context.object.modifiers["Bevel"].use_clamp_overlap = False
        bpy.context.object.modifiers["Bevel"].show_in_editmode = False
        bpy.context.object.modifiers["Bevel"].width = 0.0071
        bpy.context.object.modifiers["Bevel"].segments = 3
        bpy.context.object.modifiers["Bevel"].profile = 0.70
        bpy.context.object.modifiers["Bevel"].limit_method = 'WEIGHT'

        #Sets Bevel To Bevel Width needs IF
        bpy.context.object.modifiers["Bevel"].width = bevelwidth

        bpy.context.object.data.use_auto_smooth = True

        #now sets angle to Var angle.
        bpy.context.object.data.auto_smooth_angle = angle


        bpy.ops.object.shade_smooth()

        return {'FINISHED'}    
$\endgroup$
5
$\begingroup$

My suggestion is don't use operators when you can use low level API instead. Possibly a little difficult at first, but can save a lot of context hassles associated with calling operators, as well as giving (IMO) more control.

Object.to_mesh can be used to create a mesh with modifiers applied etc, details in link.

Modifiers can be added / removed from the objects modifier collection, using obj.modifiers.new(...), modifiers.remove(mod) respectively. I've used a dictionary to store the original settings of the Bevel modifier(s), removed them, created a new mesh with other modifiers applied, then re-added bevel mod to the modifiers collection.

To add a bevel modifier and set properties.

mod = ob.modifiers.new("Bevel", 'BEVEL')
mod.width = self.bevelwidth

Another thing, blender natively uses radians as an angle unit, set the subtype to 'ANGLE' of a FloatProperty and the "conversions" are done for you via the UI. The math.radians(degrees) method can be used to set the props.

import bpy
from bpy.props import *
from math import pi, radians

class sharpenOperator(bpy.types.Operator):
    '''Sharpen With Modifiers and Bevelling'''
    bl_idname = "csharpen.objects"
    bl_label = "CSharpen"
    bl_options = {'REGISTER', 'UNDO'} 
    items = [(x.identifier, x.name, x.description, x.icon) 
             for x in bpy.types.Modifier.bl_rna.properties['type'].enum_items]

    modtypes = EnumProperty(name="Modifier Types",
                           items=[(id, name, desc, icon, 2**i) for i, (id, name, desc, icon) in enumerate(items)
                                   if id in ['BEVEL', 'BOOLEAN', 'SOLIDIFY', 'EDGE_SPLIT']],
                           description="Don't apply these",
                           default={'BEVEL'},
                           options={'ENUM_FLAG'})

    angle = FloatProperty(name="AutoSmooth Angle",
                          description="Set AutoSmooth angle",
                          default= radians(60.0),
                          min = 0.0,
                          max = radians(180.0),
                          subtype='ANGLE')

    bevelwidth = FloatProperty(name="Bevel Width Amount",
                               description="Set Bevel Width",
                               default=0.0071,
                               min =
                               0.002,
                               max =0.25)

    apply_all = BoolProperty(default = True)

    original_bevel = FloatProperty()

    @classmethod
    def poll(cls, context):
        ob = context.object
        if ob is None:
            return False
        return (ob.type == 'MESH')

        # ADD A DRAW FUNCTION TO DISPLAY PROPERTIES ON THE F6 MENU
    def draw(self, context):
        layout = self.layout

        box = layout.box()
        # DRAW YOUR PROPERTIES IN A BOX
        #box.prop( self, 'ssharpangle', text = "SsharpAngle")
        col = box.column()
        col.prop(self, "modtypes", expand=True)
        box.prop( self, 'angle', text = "SmoothingAngle" )
        box.prop( self, 'bevelwidth', text = "BevelWidth")
        box.prop( self, 'apply_all', text = "ApplyAll")

    def execute(self, context):
        scene = context.scene
        ob = context.object  # soapbox call don't use bpy.context as context is passed
        obs = context.selected_objects
        angle = self.angle
        original_bevel = self.original_bevel
        bevelwidth = self.bevelwidth

        #Sets the Bevel Width To The Orig Bevel Width

        mod_dic = {}
        if self.apply_all:
            #remove modifiers no one would want applied in this instance

            #bpy.ops.object.modifier_remove(modifier="Bevel")
            #bpy.ops.object.modifier_remove(modifier="Solidify")
            # replace with       
            mods = [m for m in ob.modifiers if m.type in self.modtypes]
            for mod in mods:

                mod_dic[mod.name] = {k:getattr(mod, k) for k in mod.bl_rna.properties.keys()
                                     if k not in ["rna_type"]}
                print(mod_dic)
                ob.modifiers.remove(mod)

            #convert to mesh for sanity
            #bpy.ops.object.convert(target='MESH')            
            #Object.to_mesh(scene, apply_modifiers, settings, calc_tessface=True, calc_undeformed=False)

            mesh_name = ob.data.name
            ob.data.name = 'XXXX'
            # remove the old mesh
            if not ob.data.users:
                bpy.data.meshes.remove(ob.data)               
            mesh = ob.to_mesh(scene, True, 'PREVIEW') # or 'RENDER'
            ob.modifiers.clear()
            mesh.name = mesh_name
            ob.data = mesh

            for name, settings in mod_dic.items():
                m = ob.modifiers.new(name, settings["type"])
                for s, v in settings.items():
                    if s == "type":
                        continue
                    setattr(m, s, v)

        return {'FINISHED'}

def register():
    bpy.utils.register_module(__name__)

register()
bpy.ops.csharpen.objects()

EDIT Added an EnumProperty as an example of how to choose which mods to "keep" (remove then re-add)

$\endgroup$
  • $\begingroup$ your syntax is so different than what i was used to. I figured i was writing code pretty badly. So in its current state it removes the bevel. What if I wanted to apply basically all boolean modifiers but keep the values and settings of the bevel? $\endgroup$ – masterxeon1001 Oct 24 '15 at 8:59
  • $\begingroup$ Basically Csharpen's goal is to add a bevel modifier with specific attributes but also alternatively collapse modifiers(mainly booleans) while keeping the bevels in action. $\endgroup$ – masterxeon1001 Oct 24 '15 at 9:06
  • $\begingroup$ Edited post to i) re-add all modifier types removed, added a tip on how select what mods to remove and how to add a new modifier. Added a multi enum prop to decide which mods to keep. $\endgroup$ – batFINGER Oct 24 '15 at 10:17
  • $\begingroup$ now what about having it do bevelling normally and then on reapplication goes through the other process? On the normal run I would expect it to ask for bevel / sharpening information and then on subsequent runs go through the other process. Would i be able to add a property to the mesh connected to the bevel parameter and then use it as the bevel parameter default on the operator. $\endgroup$ – masterxeon1001 Oct 24 '15 at 10:36
  • $\begingroup$ As in if there is no bevel modifier add one? $\endgroup$ – batFINGER Oct 24 '15 at 11:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.