Adding curve primitives to the scene (2.69)

addClusteredCurves-20140302.zip (3.02 KB)

Hi all,

I’m trying to make an addon to generate a ‘cluster’ of bezier circles in my scene. See code in attachment. The UI looks like this:


I don’t want it to update the scene every time a parameter is changed, so I’ve included a Generate button that triggers the generation action. The actual work is done by a GeneratorCircles object, as defined in GeneratorCircles.py. This generator creates some Circle objects (in Circle.py), a representation of which should be automatically added to the scene. The constructor of the Circle object calls bpy.ops.curve.primitive_bezier_circle_add() to achieve this.

This is the way I’ve implemented this:

  1. Add a menu item for Add -> Curve -> Clustered -> Circles. This is bound to OperatorCircles.
  2. OperatorCircles include a Generate button, which is bound to OperatorCirclesGenerate.
  3. OperatorCirclesGenerate makes a GeneratorCircles object.
  4. GeneratorCircles makes some Circle objects, a representation of which should be automatically added to the scene.

Unfortunately, this doesn’t work. The circles seem to get created (see output in console), but they’re not visible in my scene. The only place where I can succesfully add a bezier circle to my scene is in the execute method of my (main) operator, ie OperatorCircles.

Is this by design? Is there anything I can do to avoid this problem?

Thanks in advance for any tips.
g

toolClusteredCurves-20140302.zip (2.85 KB)

As I should probably have known by now, everything works as expected when you add this functionalty as a tool (rather than as an add_curve_operator). Code in attachment. It looks like this:


Please note that it doesn’t really do anything yet as to the creation the ‘cluster of circles’. It just adds 2 initial circles to the scene – which are visible/real at last! – while still adding the primitives in the constructor of Circle, which is nice.

g

You shouldn’t add operators in an operator’s draw() method to place e.g. a generate button to the redo panel. It is really just for redoing with different parameters, and runs your operator code on every change by intention. If this is undesired, either add all your stuff to a panel or show a property dialog on invocation

Docs: http://www.blender.org/documentation/blender_python_api_2_69_10/bpy.types.WindowManager.html?highlight=invoke_props_dialog#bpy.types.WindowManager.invoke_props_dialog

Fancy example:

import bpy

class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"
    bl_options = {'REGISTER', 'UNDO'}
    
    prop = bpy.props.StringProperty(name="Material", maxlen=63)
    mats = bpy.props.CollectionProperty(type=bpy.types.PropertyGroup)

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH')    

    def execute(self, context):
        print(self.prop)
        return {'FINISHED'}
    
    def draw(self, context):
        layout = self.layout
        layout.prop_search(self, "prop", self, "mats", icon='MATERIAL')
        
    def invoke(self, context, event):
        self.mats.clear()
        for i in range(1, 7):
            self.mats.add().name = "Material %i" % i
        return context.window_manager.invoke_props_dialog(self)


def register():
    bpy.utils.register_class(SimpleOperator)


def unregister():
    bpy.utils.unregister_class(SimpleOperator)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.object.simple_operator('INVOKE_DEFAULT')