2
$\begingroup$

Im manage to make a simple script to generate a stair in python. Now I would like to add it as a new mesh, and being able to have a menu where I can modify the value instead of changing the code. I start from the template addon_addObject

I can recreate my stairs but stuck with creating the parameters. Here is the code. Thank you for any help

import bpy
from bpy.types import Operator
from bpy.props import (FloatVectorProperty, FloatProperty, IntProperty)
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector


def add_object(self, context):

    #step variable
    cubsize = 2
    posx = 0
    posy = 5
    posz = 2

    scalx = 10
    scaly = 5
    scalz = 0.5

    #step numbers
    step = 20

    #step generators
    for i in range (step):
        bpy.ops.mesh.primitive_cube_add(size=cubsize, location=(posx, cubsize*i+posy*i,cubsize*i+posz*i))
        bpy.ops.transform.resize(value=(scalx, scaly, scalz))

    bpy.ops.object.select_pattern(pattern="Cube*")
    bpy.ops.object.join()
    bpy.context.object.name = "G_stair"



class OBJECT_OT_add_object(Operator, AddObjectHelper):
    """Create a new Mesh Object"""
    bl_idname = "mesh.add_object"
    bl_label = "parameter stair"
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}

    step: IntProperty(
        name="step",
        default=10,
        subtype='TRANSLATION',
        description="scaling",
    )

    def execute(self, context):
        add_object(self, context)

        return {'FINISHED'}



# Registration

def add_object_button(self, context):
    self.layout.operator(
        OBJECT_OT_add_object.bl_idname,
        text="stair",
        icon='PLUGIN')




def register():
    bpy.utils.register_class(OBJECT_OT_add_object)
    bpy.types.VIEW3D_MT_mesh_add.append(add_object_button)


def unregister():
    bpy.utils.unregister_class(OBJECT_OT_add_object)
    bpy.types.VIEW3D_MT_mesh_add.remove(add_object_button)


if __name__ == "__main__":
    register()
'''
$\endgroup$

1 Answer 1

3
$\begingroup$

TRANSLATION is Not a subtype of an int property

when the code is run you will be getting messages to the system console that

TypeError: IntProperty(subtype='TRANSLATION'): subtype not found in ('PIXEL', 'UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE')
ValueError: bpy_struct "MESH_OT_add_object" registration error: step could not register

recommend subtype = 'DISTANCE'

No error now, but.. it will have no dimension unit

enter image description here

If instead we change to a floatproperty

step: FloattProperty(
    name="step",
    default=10,
    subtype='DISTANCE',
    description="scaling",
)

enter image description here

Why??

If we look at the FloatProperty will see that it has a unit setting which Intproperty does not.

:arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', 'VELOCITY', 'ACCELERATION', 'MASS', 'CAMERA', 'POWER'].
:type unit: string

Hence the same result is achieved using

step: FloatProperty(
    name="step",
    default=10,
    unit='LENGTH',
    description="scaling",
)

Note in this case, step is a unit-less int with minimum 0. ie make sure your translation props are floats.

To get step in your method it will be

self.step

For example

#step generators
for i in range (self.step):
    ...

The AddObjectHelper class writes its gear first see How to link the adjust last operation menu to object? Blender 2.80 - 2.81

Python performance with Blender operators

Will find if you try and create a huge staircase calling 2 * (step + 1) operators may slow this down considerably.

Another way to do this would be to add an array modifier with both x and z offset, and the choice to apply or not

Copying an object with python without actually creating a new object

enter image description here

Putting it together

enter image description here

import bpy
from bpy.types import Operator
from bpy.props import (FloatVectorProperty, 
                       FloatProperty,
                       BoolProperty, 
                       IntProperty)
from bpy_extras.object_utils import AddObjectHelper
from mathutils import Matrix

def steps(context, count, size, scale, offset, align, location, rotation, apply_modifier):
    bpy.ops.mesh.primitive_cube_add(
            size=size,
            align=align, 
            location=location, 
            rotation=rotation
            )
    obj = context.active_object
    obj.data.transform(Matrix.Diagonal(scale).to_4x4())
    # add two array modifiers

    arrays = {"x": offset,}

    for axis, displace in arrays.items():          
        mod = obj.modifiers.new(axis, 'ARRAY')
        mod.use_relative_offset = False
        mod.use_constant_offset = True
        mod.count = count
        mod.constant_offset_displace = displace
        if apply_modifier:
            bpy.ops.object.modifier_apply(modifier=mod.name)


class OBJECT_OT_add_object(Operator, AddObjectHelper):
    """Create a new Mesh Object"""
    bl_idname = "mesh.add_object"
    bl_label = "parameter stair"
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}


    size : FloatProperty(
        name="Size",
        default=2,
        unit='LENGTH',
        )

    count: IntProperty(
        name="Steps",
        default=10,
        description="Number of Steps",
        min=0,
    )

    scale : FloatVectorProperty(
        name="Scale",
        default=(1, 1, 1),
        )

    offset : FloatVectorProperty(
        name="Offset",
        subtype='TRANSLATION',
        default=(0, 1, 1),
        )

    apply_modifier : BoolProperty(
        name="Apply Array Modifier",
        default=True,
        )

    def execute(self, context):
        steps(
            context,
            self.count,
            self.size,
            self.scale,
            self.offset,
            self.align,
            self.location,
            self.rotation,
            self.apply_modifier,
            )

        return {'FINISHED'}



# Registration

def add_object_button(self, context):
    self.layout.operator(
        OBJECT_OT_add_object.bl_idname,
        text="stair",
        icon='PLUGIN')




def register():
    bpy.utils.register_class(OBJECT_OT_add_object)
    bpy.types.VIEW3D_MT_mesh_add.append(add_object_button)


def unregister():
    bpy.utils.unregister_class(OBJECT_OT_add_object)
    bpy.types.VIEW3D_MT_mesh_add.remove(add_object_button)


if __name__ == "__main__":
    register()
$\endgroup$
1
  • $\begingroup$ Thank you @batFINGER Using Array was the solution I think about. But if I would like to use a panel where I can manage all variables of the stairs, for this exemple is the number of steps, so I should make the loop with self.step after step: FloaProperty $\endgroup$
    – ekka
    Commented Mar 27, 2020 at 7:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .