Esempio n. 1
0
class arch_op0(bpy.types.Operator):

    bl_idname = 'arch.op0_id'
    bl_label = 'Arch'
    bl_options = {'REGISTER', 'UNDO'}

    d = FloatProperty(name='',
                      default=2.0,
                      min=0.00001,
                      max=100,
                      step=1,
                      precision=3)
    n = IntProperty(name='', default=8, min=1, max=100, step=1)

    def draw(self, context):
        cen0 = context.scene.arch_custom_props.en0

        layout = self.layout
        layout.label('Arch type:')
        layout.prop(context.scene.arch_custom_props, 'en0', expand=False)
        layout.label('Number of sides:')
        layout.prop(self, 'n', slider=True)

        if cen0 == 'opt0':
            pass
        elif cen0 == 'opt1':
            layout.label('Height:')
            layout.prop(self, 'd')
        elif cen0 == 'opt2':
            layout.label('Height:')
            layout.prop(self, 'd')
        elif cen0 == 'opt3':
            pass
        elif cen0 == 'opt4':
            layout.label('Height:')
            layout.prop(self, 'd')
        elif cen0 == 'opt5':
            pass

    def execute(self, context):
        cen0 = context.scene.arch_custom_props.en0

        n = self.n
        d = self.d

        edit_mode_out()
        ob_act = context.active_object
        me = ob_act.data

        list_0 = [list(e.key) for e in me.edges if e.select]

        if len(list_0) != 2:
            self.report({'INFO'}, 'Two adjacent edges must be selected.')
            edit_mode_in()
            return {'CANCELLED'}
        else:
            f_(me, context, list_0, n, d)

        edit_mode_in()
        bpy.ops.mesh.delete(type='VERT')
        return {'FINISHED'}
Esempio n. 2
0
class GenSeriesNode(bpy.types.Node, SverchCustomTreeNode):
    ''' Generator series '''
    bl_idname = 'GenSeriesNode'
    bl_label = 'List Series'
    bl_icon = 'OUTLINER_OB_EMPTY'

    start_ = FloatProperty(name='start',
                           description='start',
                           default=0,
                           options={'ANIMATABLE'},
                           update=updateNode)
    stop_ = FloatProperty(name='stop',
                          description='stop',
                          default=10,
                          options={'ANIMATABLE'},
                          update=updateNode)
    step_ = FloatProperty(name='step',
                          description='step',
                          default=1,
                          options={'ANIMATABLE'},
                          update=updateNode)

    def sv_init(self, context):
        self.inputs.new('StringsSocket', "Start", "Start")
        self.inputs.new('StringsSocket', "Stop", "Stop")
        self.inputs.new('StringsSocket', "Step", "Step")
        self.outputs.new('StringsSocket', "Series", "Series")

    def draw_buttons(self, context, layout):
        layout.prop(self, "start_", text="start")
        layout.prop(self, "stop_", text="stop")
        layout.prop(self, "step_", text="step")

    def process(self):
        # inputs
        if 'Start' in self.inputs and self.inputs['Start'].links:
            tmp = SvGetSocketAnyType(self, self.inputs['Start'])
            Start = tmp[0][0]
        else:
            Start = self.start_

        if 'Stop' in self.inputs and self.inputs['Stop'].links:
            tmp = SvGetSocketAnyType(self, self.inputs['Stop'])
            Stop = tmp[0][0]
        else:
            Stop = self.stop_

        if 'Step' in self.inputs and self.inputs['Step'].links:
            tmp = SvGetSocketAnyType(self, self.inputs['Step'])
            Step = tmp[0][0]
        else:
            Step = self.step_

        # outputs
        if 'Series' in self.outputs and len(self.outputs['Series'].links) > 0:
            #print (Start, Stop, Step)
            if Step < 0:
                Step = 1
            if Stop < Start:
                Stop = Start + 1
            series = [c for c in self.xfrange(Start, Stop, Step)]

            SvSetSocketAnyType(self, 'Series', [series])

    def xfrange(self, start, stop, step):
        while start < stop:
            yield start
            start += step
Esempio n. 3
0
class VisibleVertices(bpy.types.Operator):
    bl_idname = "mesh.visiblevertices"
    bl_label = "VisibleVertices"
    bl_options = {'REGISTER', 'UNDO'}

    fullScene = BoolProperty(
        name="Full Scene",
        default=True,
        description="Check wether the view is blocked by objects in the scene."
    )
    distWeight = BoolProperty(
        name="Distance Weight",
        default=True,
        description="Give less weight to vertices further away from the camera."
    )
    addModifier = BoolProperty(
        name="Add Modifier",
        default=True,
        description="Add a vertex weight modifier for additional control.")
    margin = FloatProperty(
        name="Camera Margin",
        default=0.0,
        description=
        "Add extra margin to the visual area from te camera (might be negative as well)."
    )

    @classmethod
    def poll(self, context):
        p = (context.mode == 'PAINT_WEIGHT'
             and isinstance(context.scene.objects.active, bpy.types.Object)
             and isinstance(context.scene.objects.active.data, bpy.types.Mesh))
        return p

    def execute(self, context):
        bpy.ops.object.mode_set(mode='OBJECT')

        ob = context.active_object
        vertex_group = ob.vertex_groups.active
        if vertex_group is None:
            bpy.ops.object.vertex_group_add()
            vertex_group = ob.vertex_groups.active
        scene = context.scene
        cam_ob = scene.camera
        cam = bpy.data.cameras[
            cam_ob.name]  # camera in scene is object type, not a camera type
        cam_mat = cam_ob.matrix_world
        view_frame = cam.view_frame(
            scene
        )  # without a scene the aspect ratio of the camera is not taken into account
        view_frame = [cam_mat * v for v in view_frame]
        cam_pos = cam_mat * Vector((0, 0, 0))
        view_center = sum(view_frame, Vector((0, 0, 0))) / len(view_frame)
        view_normal = (view_center - cam_pos).normalized()

        if self.margin != 0.0:
            view_frame = [((v - view_center) * (1 + self.margin)) + view_center
                          for v in view_frame]

        mesh_mat = ob.matrix_world
        mesh = ob.data
        distances = []
        max_distance = 0
        min_distance = None
        for v in mesh.vertices:
            vertex_coords = mesh_mat * v.co
            d = None
            intersection = intersect_ray_quad_3d(
                view_frame, vertex_coords,
                cam_pos)  # check intersection with the camera frame
            # print(intersection, end=" | ")
            if intersection is not None:
                d = (intersection - vertex_coords)
                if d.dot(
                        view_normal
                ) < 0:  # only take into account vertices in front of the camera, not behind it.
                    d = d.length
                    if self.fullScene:
                        if intersect_ray_scene(
                                scene, vertex_coords, cam_pos
                        ):  # check intersection with all other objects in scene. We revert the direction, ie. look from the camera to avoid self intersection
                            d = None
                else:
                    d = None
            if d is not None:
                if d > max_distance:
                    max_distance = d
                if min_distance is None or d < min_distance:
                    min_distance = d
            distances.append((v.index, d))

        drange = max_distance - min_distance if min_distance is not None else max_distance  # prevent exception if the was not a single visible vertex
        # print(min_distance, max_distance, drange)
        if self.distWeight and drange > 1e-7:
            # print("weighted")
            for vindex, d in distances:
                # print(d, end=' ')
                if d is None:
                    vertex_group.add([vindex], 0.0, 'REPLACE')
                else:
                    vertex_group.add([vindex],
                                     1.0 - ((d - min_distance) / drange),
                                     'REPLACE')
        else:
            # print("not weighted")
            for vindex, d in distances:
                # print(d, end='')
                if d is None:
                    vertex_group.add([vindex], 0.0, 'REPLACE')
                else:
                    vertex_group.add([vindex], 1.0 if d > 0.0 else 0.0,
                                     'REPLACE')

        bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
        context.scene.update()

        if self.addModifier:
            bpy.ops.object.modifier_add(type='VERTEX_WEIGHT_EDIT')
            ob.modifiers[-1].vertex_group = ob.vertex_groups.active.name
            ob.modifiers[-1].falloff_type = 'CURVE'
            # make modifier panel visible to atract some attention because this is a lesser known modifier
            ws = context.window_manager.windows
            for a in ws[0].screen.areas:
                if (a.type == 'PROPERTIES'):
                    for s in a.spaces:
                        if s.type == 'PROPERTIES':
                            s.context = 'MODIFIER'

        return {'FINISHED'}
Esempio n. 4
0
class OBJECT_OT_gem_add(Operator):
    bl_label = "Add Gem"
    bl_description = "Add gemstone to the scene"
    bl_idname = "object.jewelcraft_gem_add"
    bl_options = {"REGISTER", "UNDO"}

    cut: EnumProperty(name="Cut",
                      items=dynamic_list.cuts,
                      update=upd_set_weight)
    stone: EnumProperty(name="Stone",
                        items=dynamic_list.stones,
                        update=upd_set_weight)
    size: FloatProperty(
        name="Size",
        default=1.0,
        min=0.0001,
        step=5,
        precision=2,
        unit="LENGTH",
        update=upd_set_weight,
    )
    weight: FloatProperty(
        name="Carats",
        description="Round diamonds only",
        default=0.004,
        min=0.0001,
        step=0.1,
        precision=3,
        update=upd_weight,
    )

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False

        layout.prop(self, "size")
        col = layout.column()
        col.enabled = self.stone == "DIAMOND" and self.cut == "ROUND"
        col.prop(self, "weight")
        layout.prop(self, "stone")
        split = layout.split(factor=0.385)
        split.row()
        split.template_icon_view(self, "cut", show_labels=True)

    def execute(self, context):
        scene = context.scene
        view_layer = context.view_layer
        space_data = context.space_data
        cut_name = var.CUTS[self.cut].name
        stone_name = var.STONES[self.stone].name
        color = var.STONES[self.stone].color or self.color

        for ob in context.selected_objects:
            ob.select_set(False)

        imported = asset.asset_import(var.GEM_ASSET_FILEPATH, ob_name=cut_name)
        ob = imported.objects[0]
        context.collection.objects.link(ob)

        if space_data.local_view:
            ob.local_view_set(space_data, True)

        ob.scale *= self.size
        ob.location = scene.cursor.location
        ob.select_set(True)
        ob["gem"] = {"cut": self.cut, "stone": self.stone}

        asset.add_material(ob, name=stone_name, color=color, is_gem=True)

        if context.mode == "EDIT_MESH":
            asset.ob_copy_to_faces(ob)
            bpy.ops.object.mode_set(mode="OBJECT")

        view_layer.objects.active = ob

        return {"FINISHED"}

    def invoke(self, context, event):
        self.color = asset.color_rnd()

        wm = context.window_manager
        return wm.invoke_props_dialog(self)
Esempio n. 5
0
class Symmetrize(bpy.types.Operator):
    bl_idname = "machin3.symmetrize"
    bl_label = "MACHIN3: Symmetrize"
    bl_options = {'REGISTER', 'UNDO'}

    # onlyselected = BoolProperty(name="Selected Only", default=False)

    axis = EnumProperty(name="Axis", items=axisitems, default="X")
    direction = EnumProperty(name="Direction",
                             items=directionitems,
                             default="POSITIVE")

    cnmirror = BoolProperty(name="Mirror Custom Normals", default=True)

    cnmirrormethod = EnumProperty(name="CN Mirror Method",
                                  items=cnmirrormethoditems,
                                  default="INDEX")

    fixcenter = BoolProperty(name="Fix Center Seam", default=False)
    fixcentermethod = EnumProperty(name="Fix Center Method",
                                   items=fixcentermethoditems,
                                   default="CLEAR")
    clearsharps = BoolProperty(name="Clear Center Sharps", default=True)

    # hidden
    hascustomnormals = BoolProperty(default=False)

    # debug
    debug = BoolProperty(default=False)
    alpha = FloatProperty(name="Alpha", default=0.3, min=0.1, max=1)

    def check(self, context):
        return True

    def draw(self, context):
        layout = self.layout

        column = layout.column()

        row = column.row()
        row.prop(self, "axis", expand=True)
        row.prop(self, "direction", expand=True)

        if self.hascustomnormals:
            column.separator()
            column.prop(self, "cnmirror")

            if self.cnmirror:
                box = column.box()
                box.label("Custom Normal Pairing Method")
                row = box.row()
                row.prop(self, "cnmirrormethod", expand=True)

                column.separator()
                column.prop(self, "fixcenter")

                if self.fixcenter:
                    box = column.box()

                    row = box.row()
                    row.label("Fix Center Method")
                    row.prop(self, "clearsharps")

                    row = box.row()
                    row.prop(self, "fixcentermethod", expand=True)

    def execute(self, context):
        # if self.debug:
        # try:
        # bpy.types.SpaceView3D.draw_handler_remove(self.VIEW3D, 'WINDOW')
        # except:
        # pass

        self.active = m3.get_active()

        try:
            custom_normals, ret = self.main(self.active)

            if custom_normals:
                original, mirror, center, mirror_verts, mirror_faces, mirror_loops = ret
            else:
                original, mirror, center = ret

            # if we want to draw the symmetrize while maintaining the ability to REDO the symmetrize op,
            # we need to do the drawing with a seperate op that doesn't have REDO in the bl_options otherwise there will be crashes

            # set the verts for the drawing op
            global vertids
            vertids = mirror + center

            bpy.ops.machin3.draw_symmetrize()

        except:
            output_traceback(self)

        # if self.debug:
        # original, mirror, center, mirror_verts, mirror_faces, mirror_loops = ret

        # # debug mirror verts
        # self.mvs = mirror_verts
        # args = (self, context)
        # self.VIEW3D = bpy.types.SpaceView3D.draw_handler_add(self.draw_VIEW3D_debug_pairing, (args, ), 'WINDOW', 'POST_VIEW')

        return {'FINISHED'}

    def main(self, active):
        # self.debug = True

        if self.debug:
            m3.clear()
            m3.debug_idx()

        print("\nSymmetrizing %s" % (active.name))

        mesh = active.data
        self.hascustomnormals = mesh.has_custom_normals

        nrmsrc = False
        if self.hascustomnormals:
            print(" » Custom Normals detected!")

            if self.cnmirror and self.fixcenter and self.fixcentermethod == "TRANSFER":
                print(" » Creating normal source!")

                active.update_from_editmode()

                nrmsrc = active.copy()
                nrmsrc.data = active.data.copy()

        # unhide and select all, as the symmetrize op works on selections
        m3.unhide_all("MESH")
        m3.select_all("MESH")

        direction = "%s_%s" % (self.direction, self.axis)
        bpy.ops.mesh.symmetrize(direction=direction, threshold=0.0001)

        m3.unselect_all("MESH")

        # custom normals
        if self.hascustomnormals and self.cnmirror:
            # its possible the mesh has custom normas, but has auto smooth turned off
            # force it on so as to not losse them, because you cant mirror them with it turned off and expect to turn it on afterwards with normals intact
            if not mesh.use_auto_smooth:
                mesh.use_auto_smooth = True

            m3.set_mode("OBJECT")

            # get existing loop normals
            mesh = active.data
            mesh.calc_normals_split()

            loop_normals = []
            for idx, loop in enumerate(mesh.loops):
                loop_normals.append(
                    loop.normal.normalized()
                )  # normalized them, or you will run into weird issues at the end!
                if self.debug:
                    print(idx, loop.normal)

            # create new bmesh
            bm = bmesh.new()
            bm.from_mesh(mesh)
            bm.verts.ensure_lookup_table()
            bm.faces.ensure_lookup_table()

            # some of the loop indices are invalid, interesting, as all that was done is call a bpy.ops and create a fresh bm
            loop_index_update(bm)

            # get vertex lists for each side + center line
            sides = self.sort_verts_into_sides(bm,
                                               self.axis,
                                               self.direction,
                                               debug=self.debug)

            # get vertex pairs in form of a dict {v_original: v_mirror, ...}
            # LOCATION is 1.5-2x slower as it's matching individual vertex locations
            if self.cnmirrormethod == "INDEX":
                mirror_verts = self.get_mirror_verts_via_index(
                    bm, *sides, debug=self.debug)
            elif self.cnmirrormethod == "LOCATION":
                mirror_verts = self.get_mirror_verts_via_location(
                    bm, *sides, self.axis, debug=self.debug)

            # we are then matching faces with their mirrored faces
            mirror_faces, loops = self.get_mirror_faces(bm, mirror_verts)

            # finally we set up a loop dict, that we can can then use to  associate each loop of a face with it's mirrored part
            mirror_loops = self.get_mirror_loops(bm, mirror_verts,
                                                 mirror_faces, loops)

            # edit the original loop_normals list and replace the normals of the mirrord verts, with reflections of the original normals
            if self.axis == "X":
                mirror = mathutils.Vector((1, 0, 0))
            elif self.axis == "Y":
                mirror = mathutils.Vector((0, 1, 0))
            elif self.axis == "Z":
                mirror = mathutils.Vector((0, 0, 1))

            for ml in mirror_loops:
                loop_normals[mirror_loops[ml]] = loop_normals[ml].reflect(
                    mirror)

            # set the new normals on the active obj's mesh
            mesh.normals_split_custom_set(loop_normals)

            # fix the center / go back into edit mode
            if sides[
                    2]:  # only attempt to do it, if there actually are center verts!
                self.fix_center_seam(active, sides[2], nrmsrc)

            if nrmsrc:
                print(" » Removing normal source!")
                bpy.data.objects.remove(nrmsrc, do_unlink=True)

            return True, (sides[0], sides[1], sides[2], mirror_verts,
                          mirror_faces, mirror_loops)

        else:
            m3.set_mode("OBJECT")

            mesh = active.data

            # create new bmesh
            bm = bmesh.new()
            bm.from_mesh(mesh)
            bm.verts.ensure_lookup_table()
            bm.faces.ensure_lookup_table()

            # some of the loop indices are invalid, interesting, as all that was done is call a bpy.ops and create a fresh bm
            loop_index_update(bm)

            # get vertex lists for each side + center line
            sides = self.sort_verts_into_sides(bm,
                                               self.axis,
                                               self.direction,
                                               debug=self.debug)

            m3.set_mode("EDIT")

        return False, (sides[0], sides[1], sides[2])

    def fix_center_seam(self, active, center, nrmsrc):
        if self.fixcenter:
            if self.fixcentermethod == "CLEAR":
                print(" » Fixing Center Seam by clearing normals.")
            elif self.fixcentermethod == "TRANFER":
                print(" » Fixing Center Seam by transfering normals")

            # select center line
            for v in active.data.vertices:
                if v.index in center:
                    v.select = True

        m3.set_mode("EDIT")

        if self.fixcenter:
            mode = m3.get_mode()
            if mode != "VERT":
                m3.set_mode("VERT")

            # sometimes not all center verts are marked for some reason, so loop select
            bpy.ops.mesh.loop_multi_select(ring=False)

            # clear sharps
            if self.clearsharps:
                print(" » Removing Center Seam Sharps.")
                bpy.ops.mesh.mark_sharp(clear=True)

            # clear or transfer
            if self.fixcentermethod == "CLEAR":
                normal_clear(self.active, limit=False)
            elif self.fixcentermethod == "TRANSFER":
                normal_transfer_from_obj(active,
                                         nrmsrc,
                                         vertids=center,
                                         remove_vgroup=True)

            m3.unselect_all("MESH")

            if mode != "VERT":
                m3.set_mode(mode)

    def get_mirror_loops(self, bm, mirror_verts, mirror_faces, loops):
        # set up a dict to select loops via (face.index, vert.index) tuples
        mirror_loops = {}
        for fidx in mirror_faces:
            for loop in bm.faces[fidx].loops:
                mirror_loops[loop.index] = loops[(
                    mirror_faces[fidx], mirror_verts[loop.vert.index])]

        if self.debug:
            print("loops")
            for ml in mirror_loops:
                print(ml, mirror_loops[ml])

            for face in bm.faces:
                print("face:", face.index)
                for loop in face.loops:
                    print(" » ",
                          "loop: %d, vert: %d" % (loop.index, loop.vert.index))

        return mirror_loops

    def get_mirror_faces(self, bm, mirror_verts):
        # we are using frozensets of the per face vert indices as keys
        # for frozensets - as with sets -  the order doesnt matter, which is important as the order of face.verts is probably not the same on both sides
        # sets are not hashable, so cant be used as keys for dicts, but frozensets are and can!
        faces = {}
        loops = {}
        for face in bm.faces:
            vertlist = [v.index for v in face.verts]
            faces[frozenset(vertlist)] = face.index

            # we are also creating a loops dict, with (face.index, vert.index) tuples as keys. the face, vert combination uniquely identifies every loop
            for loop in face.loops:
                loops[(face.index, loop.vert.index)] = loop.index

        if self.debug:
            print(faces)
            print()
            print(loops)
            print()

        mirror_faces = {}
        for vertlist in faces:
            # you can only find mirror verts with original verts, not the other way around
            # we also only want to find the mirror faces using the original ones
            try:
                mirrored_vertlist = frozenset(
                    [mirror_verts[idx] for idx in vertlist])
                mirror_faces[faces[vertlist]] = faces[mirrored_vertlist]
            except:
                pass

        if self.debug:
            print("faces")
            for mf in mirror_faces:
                print(mf, mirror_faces[mf])
            print()

        return mirror_faces, loops

    def sort_verts_into_sides(self, bm, axis, direction, debug=False):
        original = []
        mirror = []
        center = []

        # threshold to correct vertices that should be at zero but aren't (due to float precision issues? due to the symmetrize threshold?)
        # this can prevent cases where the original and mirror lists are of different lengths
        # if that happens, you'll get a keyerror in the LOCATION based pairing
        # it looks like this also fixes the INDEX issues that led to the creation of the LOCATION method in the first place

        threshold = 0.0001  # expose this?

        for v in bm.verts:

            # X axis
            if axis == "X":
                if -threshold < v.co[0] < threshold:
                    v.co[0] = 0
                    if debug:
                        print("centered vertex %d" % (v.index))

                if direction == "POSITIVE":
                    if v.co[0] == 0:
                        center.append(v.index)
                    elif v.co[0] > 0:
                        original.append(v.index)
                    else:
                        mirror.append(v.index)
                elif direction == "NEGATIVE":
                    if v.co[0] == 0:
                        center.append(v.index)
                    elif v.co[0] < 0:
                        original.append(v.index)
                    else:
                        mirror.append(v.index)

            # Y axis
            if axis == "Y":
                if -threshold < v.co[1] < threshold:
                    v.co[1] = 0
                    if debug:
                        print("centered vertex %d" % (v.index))

                if direction == "POSITIVE":
                    if v.co[1] == 0:
                        center.append(v.index)
                    elif v.co[1] > 0:
                        original.append(v.index)
                    else:
                        mirror.append(v.index)
                elif direction == "NEGATIVE":
                    if v.co[1] == 0:
                        center.append(v.index)
                    elif v.co[1] < 0:
                        original.append(v.index)
                    else:
                        mirror.append(v.index)

            # Z axis
            if axis == "Z":
                if -threshold < v.co[2] < threshold:
                    v.co[2] = 0
                    if debug:
                        print("centered vertex %d" % (v.index))

                if direction == "POSITIVE":
                    if v.co[2] == 0:
                        center.append(v.index)
                    elif v.co[2] > 0:
                        original.append(v.index)
                    else:
                        mirror.append(v.index)
                elif direction == "NEGATIVE":
                    if v.co[2] == 0:
                        center.append(v.index)
                    elif v.co[2] < 0:
                        original.append(v.index)
                    else:
                        mirror.append(v.index)

            v.select = False
        bm.select_flush(False)

        # warn if list sizes are still uneven
        if len(original) != len(mirror):
            print(" ! WARNING, uneven vertex list sizes!")

        return original, mirror, center

    def get_mirror_verts_via_index(self,
                                   bm,
                                   original,
                                   mirror,
                                   center,
                                   debug=False):
        # match vetices on both sides
        # it turns out, they are often in perfect order already and can be matched simply by their positions in the original/mirror lists
        # so we can set up the mirror vert pairs in a dict by iterating over both sides in parallel
        # this allows us to pick a vert on the original side and retrieve it's mirror vert

        mirror_verts = {}
        for vm, vp in zip(mirror, original):
            mirror_verts[vp] = vm

        # now add the center verts as double pairs
        for vz in center:
            mirror_verts[vz] = vz

        if debug:
            print("verts")
            for mv in mirror_verts:
                print(mv, mirror_verts[mv])
            print()

        return mirror_verts

    def get_mirror_verts_via_location(self,
                                      bm,
                                      original,
                                      mirror,
                                      center,
                                      axis,
                                      debug=False):
        precision = 10

        if debug:
            print("original:", original)
            print("mirror:", mirror)

        # create a dictionary of dictionaries to select verts by their secondary location axis set as keys first
        # (y, z) for X mirror, (x, z) for Y mirror and (x, y) for Z mirrorm
        # then add dicts as values, using the mirror axis as a key and the vertex index as the value

        if axis == "X":
            yz = {}
        elif axis == "Y":
            xz = {}
        elif axis == "Z":
            xy = {}

        for v in bm.verts:
            x = "%.*f" % (precision, v.co[0])
            y = "%.*f" % (precision, v.co[1])
            z = "%.*f" % (precision, v.co[2])

            if debug:
                print(v.index, "»", x, y, z)

            if axis == "X":
                if (y, z) not in yz:
                    yz[(y, z)] = {}

                yz[(y, z)][x] = v.index
            elif axis == "Y":
                if (x, z) not in xz:
                    xz[(x, z)] = {}

                xz[(x, z)][y] = v.index
            elif axis == "Z":
                if (x, y) not in xy:
                    xy[(x, y)] = {}

                xy[(x, y)][z] = v.index

        if debug:
            print()
            if axis == "X":
                print("yz keys")
                for vert in yz:
                    print(vert)
                    print(" »", yz[vert])
            elif axis == "Y":
                print("xz keys")
                for vert in xz:
                    print(vert)
                    print(" »", xz[vert])
            elif axis == "Z":
                print("xy keys")
                for vert in xy:
                    print(vert)
                    print(" »", xy[vert])

        # create the mirror pairs
        mirror_verts = {}

        for idx in original:
            vo = bm.verts[idx]

            x = "%.*f" % (precision, vo.co[0])
            y = "%.*f" % (precision, vo.co[1])
            z = "%.*f" % (precision, vo.co[2])

            if axis == "X":
                mirror_verts[idx] = yz[(y, z)][negate_string(x)]
            elif axis == "Y":
                mirror_verts[idx] = xz[(x, z)][negate_string(y)]
            elif axis == "Z":
                mirror_verts[idx] = xy[(x, y)][negate_string(z)]

        # now add the center verts as double pairs
        for vc in center:
            mirror_verts[vc] = vc

        if debug:
            for mv in mirror_verts:
                print(mv, mirror_verts[mv])

        return mirror_verts
Esempio n. 6
0
def register():
    bpy.utils.register_class(AchmInfoMtMeshCustomMenuAdd)
    bpy.utils.register_class(AchmInfoMtMeshDecorationAdd)
    bpy.utils.register_class(achm_room_maker.AchmRoom)
    bpy.utils.register_class(achm_room_maker.AchmRoomGeneratorPanel)
    bpy.utils.register_class(achm_room_maker.AchmExportRoom)
    bpy.utils.register_class(achm_room_maker.AchmImportRoom)
    bpy.utils.register_class(achm_door_maker.AchmDoor)
    bpy.utils.register_class(achm_door_maker.AchmDoorObjectgeneratorpanel)
    bpy.utils.register_class(achm_window_maker.AchmWindows)
    bpy.utils.register_class(achm_window_maker.AchmWindowObjectgeneratorpanel)
    bpy.utils.register_class(achm_roof_maker.AchmRoof)
    bpy.utils.register_class(achm_column_maker.AchmColumn)
    bpy.utils.register_class(achm_stairs_maker.AchmStairs)
    bpy.utils.register_class(achm_kitchen_maker.AchmKitchen)
    bpy.utils.register_class(achm_kitchen_maker.AchmExportInventory)
    bpy.utils.register_class(achm_shelves_maker.AchmShelves)
    bpy.utils.register_class(achm_books_maker.AchmBooks)
    bpy.utils.register_class(achm_lamp_maker.AchmLamp)
    bpy.utils.register_class(achm_curtain_maker.AchmRoller)
    bpy.utils.register_class(achm_curtain_maker.AchmJapan)
    bpy.utils.register_class(achm_venetian_maker.AchmVenetian)
    bpy.utils.register_class(
        achm_venetian_maker.AchmVenetianObjectgeneratorpanel)
    bpy.utils.register_class(achm_main_panel.ArchimeshMainPanel)
    bpy.utils.register_class(achm_main_panel.AchmHoleAction)
    bpy.utils.register_class(achm_main_panel.AchmPencilAction)
    bpy.utils.register_class(achm_main_panel.AchmRunHintDisplayButton)
    bpy.utils.register_class(achm_window_panel.AchmWinPanel)
    bpy.utils.register_class(achm_window_panel.AchmWindowEditPanel)
    bpy.utils.register_class(Archi_Pref)
    INFO_MT_mesh_add.append(AchmMenu_func)

    # Define properties
    Scene.archimesh_select_only = BoolProperty(
        name="Only selected",
        description="Apply auto holes only to selected objects",
        default=False,
    )
    Scene.archimesh_ceiling = BoolProperty(
        name="Ceiling",
        description="Create a ceiling",
        default=False,
    )
    Scene.archimesh_floor = BoolProperty(
        name="Floor",
        description="Create a floor automatically",
        default=False,
    )

    Scene.archimesh_merge = BoolProperty(
        name="Close walls",
        description="Close walls to create a full closed room",
        default=False,
    )

    Scene.archimesh_text_color = FloatVectorProperty(
        name="Hint color",
        description="Color for the text and lines",
        default=(0.173, 0.545, 1.0, 1.0),
        min=0.1,
        max=1,
        subtype='COLOR',
        size=4,
    )
    Scene.archimesh_walltext_color = FloatVectorProperty(
        name="Hint color",
        description="Color for the wall label",
        default=(1, 0.8, 0.1, 1.0),
        min=0.1,
        max=1,
        subtype='COLOR',
        size=4,
    )
    Scene.archimesh_font_size = IntProperty(
        name="Text Size",
        description="Text size for hints",
        default=14,
        min=10,
        max=150,
    )
    Scene.archimesh_wfont_size = IntProperty(
        name="Text Size",
        description="Text size for wall labels",
        default=16,
        min=10,
        max=150,
    )
    Scene.archimesh_hint_space = FloatProperty(
        name='Separation',
        min=0,
        max=5,
        default=0.1,
        precision=2,
        description='Distance from object to display hint',
    )
    Scene.archimesh_gl_measure = BoolProperty(
        name="Measures",
        description="Display measures",
        default=True,
    )
    Scene.archimesh_gl_name = BoolProperty(
        name="Names",
        description="Display names",
        default=True,
    )
    Scene.archimesh_gl_ghost = BoolProperty(
        name="All",
        description="Display measures for all objects,"
        " not only selected",
        default=True,
    )

    # OpenGL flag
    wm = WindowManager
    # register internal property
    wm.archimesh_run_opengl = BoolProperty(default=False)
    def register(cls):
        cls.cache_info_type = EnumProperty(
                name="Cache Info Display Mode",
                description="Type of cache info to display",
                items=types.cache_info_modes,
                default='CACHE_INFO',
                update=lambda self, context: self._update_cache_info_type(context),
                )
        cls.current_info_frame = IntProperty(
                name="Frame", 
                description="Select frame number", 
                min=0,
                default=0,
                update=lambda self, context: self._update_current_info_frame(context),
                )
        cls.lock_info_frame_to_timeline = BoolProperty(
                name="Lock To Timeline",
                description="Set frame number to current frame in timeline",
                default=True,
                update=lambda self, context: self._update_lock_info_frame_to_timeline(context),
                )
        temp_directory = vcu.get_blender_preferences(bpy.context).filepaths.temporary_directory
        cls.csv_save_filepath = StringProperty(
                name="",
                default=os.path.join(temp_directory, "flip_fluid_stats.csv"), 
                subtype='FILE_PATH'
                )
        cls.csv_region_format = EnumProperty(
                name="Region Format",
                description="CSV region formatting",
                items=types.csv_regions,
                default='CSV_REGION_US',
                )

        cls.stats_filename = bpy.props.StringProperty(default='flipstats.data')
        cls.is_stats_current = bpy.props.BoolProperty(default=False)

        # Cache Info
        cls.cache_info_simulation_stats_expanded = BoolProperty(default=True)
        cls.cache_info_timing_stats_expanded = BoolProperty(default=True)
        cls.cache_info_mesh_stats_expanded = BoolProperty(default=True)
        cls.is_cache_info_available = BoolProperty(default=False)
        cls.num_cache_frames = IntProperty(default=-1)
        cls.estimated_frame_speed = FloatProperty(default=-1)
        cls.estimated_time_remaining = IntProperty(default=-1)
        cls.estimated_time_remaining_timestamp = IntProperty(default=-1)
        cls.is_estimated_time_remaining_available = BoolProperty(default=False)
        cls.cache_bytes = PointerProperty(type=ByteProperty)

        # Frame Info
        cls.frame_info_simulation_stats_expanded = BoolProperty(default=True)
        cls.frame_info_timing_stats_expanded = BoolProperty(default=True)
        cls.frame_info_mesh_stats_expanded = BoolProperty(default=True)
        cls.display_frame_viscosity_timing_stats = BoolProperty(default=False)
        cls.display_frame_diffuse_timing_stats = BoolProperty(default=False)
        cls.display_frame_diffuse_particle_stats = BoolProperty(default=False)
        cls.is_frame_info_available = bpy.props.BoolProperty(default=False)
        cls.frame_info_id = IntProperty(default=-1)
        cls.frame_substeps = IntProperty(default=-1)
        cls.frame_delta_time = FloatProperty(default=0.0)
        cls.frame_fluid_particles = IntProperty(default=-1)
        cls.frame_diffuse_particles = IntProperty(default=-1)

        # Mesh Info
        cls.surface_mesh = PointerProperty(type=MeshStatsProperties)
        cls.preview_mesh = PointerProperty(type=MeshStatsProperties)
        cls.surfaceblur_mesh = PointerProperty(type=MeshStatsProperties)
        cls.foam_mesh = PointerProperty(type=MeshStatsProperties)
        cls.bubble_mesh = PointerProperty(type=MeshStatsProperties)
        cls.spray_mesh = PointerProperty(type=MeshStatsProperties)
        cls.foamblur_mesh = PointerProperty(type=MeshStatsProperties)
        cls.bubbleblur_mesh = PointerProperty(type=MeshStatsProperties)
        cls.sprayblur_mesh = PointerProperty(type=MeshStatsProperties)
        cls.particle_mesh = PointerProperty(type=MeshStatsProperties)
        cls.obstacle_mesh = PointerProperty(type=MeshStatsProperties)

        # Time Info
        cls.time_mesh = PointerProperty(type=TimeStatsProperties)
        cls.time_advection = PointerProperty(type=TimeStatsProperties)
        cls.time_particles = PointerProperty(type=TimeStatsProperties)
        cls.time_pressure = PointerProperty(type=TimeStatsProperties)
        cls.time_diffuse = PointerProperty(type=TimeStatsProperties)
        cls.time_viscosity = PointerProperty(type=TimeStatsProperties)
        cls.time_objects = PointerProperty(type=TimeStatsProperties)
        cls.time_other = PointerProperty(type=TimeStatsProperties)
Esempio n. 8
0
class add_tapercurve(Operator):
    bl_idname = "curve.tapercurve"
    bl_label = "Add Curve as Taper"
    bl_description = ("Add taper curve to Active Curve\n"
                      "Needs an existing Active Curve")
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}

    scale_ends1: FloatProperty(name="End Width Left",
                               description="Adjust left end taper",
                               default=0.0,
                               min=0.0)
    scale_ends2: FloatProperty(name="End Width Right",
                               description="Adjust right end taper",
                               default=0.0,
                               min=0.0)
    scale_mid: FloatProperty(name="Center Width",
                             description="Adjust taper at center",
                             default=1.0,
                             min=0.0)
    link1: BoolProperty(
        name="Link Ends",
        description="Link the End Width Left / Right settings\n"
        "End Width Left will be editable ",
        default=True)
    link2: BoolProperty(
        name="Link Ends / Center",
        description="Link the End Widths with the Center Width",
        default=False)
    diff: FloatProperty(
        name="Difference",
        default=1,
        description="Difference between ends and center while linked")
    edit_mode: BoolProperty(name="Show in edit mode",
                            default=True,
                            description="Show in edit mode")

    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return context.mode == 'OBJECT' and obj and obj.type == "CURVE"

    def draw(self, context):
        layout = self.layout

        col = layout.column(align=True)
        col.label(text="Settings:")
        split = layout.split(factor=0.95, align=True)
        split.active = not self.link2
        col = split.column(align=True)
        col.prop(self, "scale_ends1")

        row = split.row(align=True)
        row.scale_y = 2.0
        col_sub = col.column(align=True)
        col_sub.active = not self.link1
        col_sub.prop(self, "scale_ends2")
        row.prop(self, "link1", toggle=True, text="", icon="LINKED")

        split = layout.split(factor=0.95, align=True)
        col = split.column(align=True)
        col.prop(self, "scale_mid")

        row = split.row(align=True)
        row.scale_y = 2.0
        col_sub = col.column(align=True)
        col_sub.active = self.link2
        row.prop(self, "link2", toggle=True, text="", icon="LINKED")
        col_sub.prop(self, "diff")

        col = layout.column()
        col.row().prop(self, "edit_mode", expand=True)

    def execute(self, context):
        if self.link1:
            self.scale_ends2 = self.scale_ends1

        if self.link2:
            self.scale_ends2 = self.scale_ends1 = self.scale_mid - self.diff

        add_taper(self, context)

        if self.edit_mode:
            bpy.ops.object.mode_set(mode='EDIT')
        else:
            bpy.ops.object.mode_set(mode='OBJECT')

        return {'FINISHED'}
Esempio n. 9
0
class add_bevelcurve(Operator, AddObjectHelper):
    bl_idname = "curve.bevelcurve"
    bl_label = "Add Curve as Bevel"
    bl_description = ("Add bevel curve to Active Curve\n"
                      "Needs an existing Active Curve")
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}

    types: IntProperty(name="Type",
                       description="Type of bevel curve",
                       default=1,
                       min=1,
                       max=5)
    scale_x: FloatProperty(name="Scale X",
                           description="Scale on X axis",
                           default=1.0)
    scale_y: FloatProperty(name="Scale Y",
                           description="Scale on Y axis",
                           default=1.0)
    link: BoolProperty(name="Link XY",
                       description="Link the Scale on X/Y axis",
                       default=True)
    edit_mode: BoolProperty(name="Show in edit mode",
                            default=True,
                            description="Show in edit mode")

    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return context.mode == 'OBJECT' and obj and obj.type == "CURVE"

    def draw(self, context):
        layout = self.layout

        col = layout.column(align=True)
        # AddObjectHelper props
        col.prop(self, "align")
        col.prop(self, "location")
        col.prop(self, "rotation")

        col = layout.column(align=True)
        col.label(text="Settings:")
        col.prop(self, "types")

        split = layout.split(factor=0.95, align=True)
        col = split.column(align=True)
        col.prop(self, "scale_x")
        row = split.row(align=True)
        row.scale_y = 2.0
        col.prop(self, "scale_y")
        row.prop(self, "link", toggle=True, text="", icon="LINKED")

        col = layout.column()
        col.row().prop(self, "edit_mode", expand=True)

    def execute(self, context):
        if self.link:
            self.scale_y = self.scale_x
        if self.types == 1:
            add_type1(self, context)
        if self.types == 2:
            add_type2(self, context)
        if self.types == 3:
            add_type3(self, context)
        if self.types == 4:
            add_type4(self, context)
        if self.types == 5:
            add_type5(self, context)

        if self.edit_mode:
            bpy.ops.object.mode_set(mode='EDIT')
        else:
            bpy.ops.object.mode_set(mode='OBJECT')

        return {'FINISHED'}
Esempio n. 10
0
class pipe_nightmare(Operator):
    bl_idname = 'object.pipe_nightmare'
    bl_label = 'Add Pipes'
    bl_description = 'Generate random pipes.'
    bl_options = {'PRESET', 'REGISTER', 'UNDO'}

    amount = IntProperty(name='Pipes',
                         description='Number of pipes',
                         min=1,
                         soft_max=250,
                         default=default['amount'])

    width = FloatProperty(
        name='Region Width',
        description='Width of the area that the pipes occupy.',
        subtype='DISTANCE',
        min=0.001,
        soft_min=0.1,
        soft_max=10.0,
        default=default['width'])

    height = FloatProperty(
        name='Region Height',
        description='Height of the area that the pipes occupy',
        subtype='DISTANCE',
        min=0.001,
        soft_min=0.1,
        soft_max=10.0,
        default=default['height'])

    depth = FloatProperty(
        name='Region Depth',
        description='Depth of the area that the pipes occupy',
        subtype='DISTANCE',
        min=0.001,
        soft_min=0.1,
        soft_max=10.0,
        default=default['depth'])

    uniform = BoolProperty(
        name='Uniform Placement',
        description=
        'Place the generated pipes at equal intervals throughout the region depth.',
        default=default['uniform'])

    length_x_min = FloatProperty(
        name='Minimum',
        description='Minimum length of horizantal pipes.',
        subtype='DISTANCE',
        min=0.001,
        soft_min=0.1,
        soft_max=10.0,
        default=default['length_x_min'])

    length_x_max = FloatProperty(
        name='Maximum',
        description='Maximum length of horizantal pipes.',
        subtype='DISTANCE',
        min=0.001,
        soft_min=0.1,
        soft_max=10.0,
        default=default['length_x_max'])

    length_y_min = FloatProperty(
        name='Minimum',
        description='Minimum length of vertical pipes.',
        subtype='DISTANCE',
        min=0.001,
        soft_min=0.1,
        soft_max=10.0,
        default=default['length_y_min'])

    length_y_max = FloatProperty(
        name='Maximum',
        description='Maximum length of vertical pipes.',
        subtype='DISTANCE',
        min=0.001,
        soft_min=0.1,
        soft_max=10.0,
        default=default['length_y_max'])

    thickness_min = FloatProperty(
        name='Minimum',
        description='The minimum thickness of the pipes.',
        subtype='DISTANCE',
        min=0.001,
        soft_max=0.2,
        precision=3,
        default=default['thickness_min'])

    thickness_max = FloatProperty(
        name='Maximum',
        description='The maximum thickness of the pipes.',
        subtype='DISTANCE',
        min=0.001,
        soft_max=0.2,
        precision=3,
        default=default['thickness_max'])

    straight = IntProperty(name='Straight Pipes',
                           description='The amount of pipes that are straight',
                           subtype='PERCENTAGE',
                           min=0,
                           max=100,
                           default=default['straight'])

    decoration = IntProperty(
        name='Decorations',
        description=
        'Amount of pipes that have additional decorations located along them.',
        subtype='PERCENTAGE',
        min=0,
        max=100,
        default=default['decoration'])

    split = IntProperty(
        name='Split',
        description=
        'Amount of pipes that should be split up into smaller pipes that occupy the same path.',
        subtype='PERCENTAGE',
        min=0,
        max=100,
        default=default['split'])

    bevel = IntProperty(
        name='Bevel',
        description='Amount of pipes that should have rounded corners.',
        subtype='PERCENTAGE',
        min=0,
        max=100,
        default=default['bevel'])

    bevel_size = IntProperty(
        name='Bevel Size',
        description=
        'Percentage size of the beveled corner compared to shortest length of pipe leading to/from the corner.',
        subtype='PERCENTAGE',
        min=0,
        max=50,
        default=default['bevel_size'])

    surface = IntProperty(name='Surface',
                          description='The surface resolution of the pipes.',
                          min=1,
                          max=64,
                          default=default['surface'])

    seed = IntProperty(
        name='Seed',
        description='The seed random basis for generating pipes.',
        default=default['seed'])

    convert = BoolProperty(
        name='Convert to Mesh',
        description='Convert the generated pipes into a single mesh object.',
        default=default['convert'])

    create_empty = BoolProperty(
        name='Create Empty',
        description=
        'Create an empty as the parent for all the pipes. (Slower but allows for easier control)',
        default=default['create_empty'])

    tile = BoolProperty(
        name='Tileable',
        description='Make the pipes tileable along the Y axis.',
        default=default['tile'])

    depth_locations = []

    @classmethod
    def poll(operator, context):

        return context.mode == 'OBJECT'

    def check(self, context):

        return True

    def draw(self, context):

        interface.operator(self, context)

    def execute(self, context):

        utilities.generate(self, context)

        return {'FINISHED'}
Esempio n. 11
0
class nfxProcessList(bpy.types.PropertyGroup):
    nfxCurrentOut = StringProperty()
    nfxCurrentTree = StringProperty()
    nfxSimEndFrame = FloatProperty()
Esempio n. 12
0
class VHACD(bpy.types.Operator):
    bl_idname = 'object.vhacd'
    bl_label = 'Hierarchical Approximate Convex Decomposition'
    bl_description = 'Hierarchical Approximate Convex Decomposition, see http://code.google.com/p/v-hacd/'
    bl_options = {'PRESET'}

    # -------------------
    # pre-process options
    remove_doubles = BoolProperty(
        name='Remove Doubles',
        description='Collapse overlapping vertices in generated mesh',
        default=True)

    apply_transforms = EnumProperty(
        name='Apply',
        description='Apply Transformations to generated mesh',
        items=(
            ('LRS', 'Location + Rotation + Scale',
             'Apply location, rotation and scale'),
            ('RS', 'Rotation + Scale', 'Apply rotation and scale'),
            ('S', 'Scale', 'Apply scale only'),
            ('NONE', 'None', 'Do not apply transformations'),
        ),
        default='RS')

    # ---------------
    # VHACD parameters
    resolution = IntProperty(
        name='Voxel Resolution',
        description=
        'Maximum number of voxels generated during the voxelization stage',
        default=100000,
        min=10000,
        max=64000000)

    depth = IntProperty(
        name='Clipping Depth',
        description=
        'Maximum number of clipping stages. During each split stage, all the model parts (with a concavity higher than the user defined threshold) are clipped according the "best" clipping plane',
        default=20,
        min=1,
        max=32)

    concavity = FloatProperty(name='Maximum Concavity',
                              description='Maximum concavity',
                              default=0.0025,
                              min=0.0,
                              max=1.0,
                              precision=4)

    planeDownsampling = IntProperty(
        name='Plane Downsampling',
        description='Granularity of the search for the "best" clipping plane',
        default=4,
        min=1,
        max=16)

    convexhullDownsampling = IntProperty(
        name='Convex Hull Downsampling',
        description=
        'Precision of the convex-hull generation process during the clipping plane selection stage',
        default=4,
        min=1,
        max=16)

    alpha = FloatProperty(
        name='Alpha',
        description='Bias toward clipping along symmetry planes',
        default=0.05,
        min=0.0,
        max=1.0,
        precision=4)

    beta = FloatProperty(
        name='Beta',
        description='Bias toward clipping along revolution axes',
        default=0.05,
        min=0.0,
        max=1.0,
        precision=4)

    gamma = FloatProperty(
        name='Gamma',
        description='Maximum allowed concavity during the merge stage',
        default=0.00125,
        min=0.0,
        max=1.0,
        precision=5)

    pca = BoolProperty(
        name='PCA',
        description=
        'Enable/disable normalizing the mesh before applying the convex decomposition',
        default=False)

    mode = EnumProperty(name='ACD Mode',
                        description='Approximate convex decomposition mode',
                        items=(('VOXEL', 'Voxel', 'Voxel ACD Mode'),
                               ('TETRAHEDRON', 'Tetrahedron',
                                'Tetrahedron ACD Mode')),
                        default='VOXEL')

    maxNumVerticesPerCH = IntProperty(
        name='Maximum Vertices Per CH',
        description='Maximum number of vertices per convex-hull',
        default=32,
        min=4,
        max=1024)

    minVolumePerCH = FloatProperty(
        name='Minimum Volume Per CH',
        description='Minimum volume to add vertices to convex-hulls',
        default=0.0001,
        min=0.0,
        max=0.01,
        precision=5)

    # -------------------
    # post-process options
    show_transparent = BoolProperty(
        name='Show Transparent',
        description='Enable transparency for ACD hulls',
        default=True)

    use_generated = BoolProperty(
        name='Use Generated Mesh',
        description=
        'Use triangulated mesh generated for V-HACD (for game engine visuals; otherwise use original object)',
        default=True)

    hide_render = BoolProperty(
        name='Hide Render',
        description='Disable rendering of convex hulls (for game engine)',
        default=True)

    mass_com = BoolProperty(
        name='Center of Mass',
        description=
        'Calculate physics mass and set center of mass (origin) based on volume and density (best to apply rotation and scale)',
        default=True)

    density = FloatProperty(
        name='Density',
        description='Material density used to calculate mass from volume',
        default=10.0,
        min=0.0)

    def execute(self, context):

        # Check textVHACD executable path
        vhacd_path = bpy.path.abspath(context.scene.vhacd.vhacd_path)
        if os_path.isdir(vhacd_path):
            vhacd_path = os_path.join(vhacd_path, 'testVHACD')
        elif not os_path.isfile(vhacd_path):
            self.report({'ERROR'}, 'Path to testVHACD executable required')
            return {'CANCELLED'}
        if not os_path.exists(vhacd_path):
            self.report({'ERROR'},
                        'Cannot find testVHACD executable at specified path')
            return {'CANCELLED'}

        # Check Data path
        data_path = bpy.path.abspath(context.scene.vhacd.data_path)
        if data_path.endswith('/') or data_path.endswith('\\'):
            data_path = os_path.dirname(data_path)
        if not os_path.exists(data_path):
            self.report({'ERROR'}, 'Invalid data directory')
            return {'CANCELLED'}

        selected = bpy.context.selected_objects
        if not selected:
            self.report({'ERROR'}, 'Object(s) must be selected first')
            return {'CANCELLED'}
        for ob in selected:
            ob.select = False

        new_objects = []
        for ob in selected:
            filename = ''.join(
                c for c in ob.name
                if c.isalnum() or c in (' ', '.', '_')).rstrip()

            off_filename = os_path.join(data_path, '{}.off'.format(filename))
            outFileName = os_path.join(data_path, '{}.wrl'.format(filename))
            logFileName = os_path.join(data_path,
                                       '{}_log.txt'.format(filename))

            try:
                mesh = ob.to_mesh(context.scene,
                                  True,
                                  'PREVIEW',
                                  calc_tessface=False)
            except:
                continue

            translation, quaternion, scale = ob.matrix_world.decompose()
            scale_matrix = Matrix(((scale.x, 0, 0, 0), (0, scale.y, 0, 0),
                                   (0, 0, scale.z, 0), (0, 0, 0, 1)))
            if self.apply_transforms in ['S', 'RS', 'LRS']:
                pre_matrix = scale_matrix
                post_matrix = Matrix()
            else:
                pre_matrix = Matrix()
                post_matrix = scale_matrix
            if self.apply_transforms in ['RS', 'LRS']:
                pre_matrix = quaternion.to_matrix().to_4x4() * pre_matrix
            else:
                post_matrix = quaternion.to_matrix().to_4x4() * post_matrix
            if self.apply_transforms == 'LRS':
                pre_matrix = Matrix.Translation(translation) * pre_matrix
            else:
                post_matrix = Matrix.Translation(translation) * post_matrix

            mesh.transform(pre_matrix)

            bm = bmesh.new()
            bm.from_mesh(mesh)
            if self.remove_doubles:
                bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
            bmesh.ops.triangulate(bm, faces=bm.faces)
            bm.to_mesh(mesh)
            bm.free()

            print('\nExporting mesh for V-HACD: {}...'.format(off_filename))
            off_export(mesh, off_filename)
            cmd_line = '"{}" --input "{}" --resolution {} --depth {} --concavity {:g} --planeDownsampling {} --convexhullDownsampling {} --alpha {:g} --beta {:g} --gamma {:g} --pca {:b} --mode {:b} --maxNumVerticesPerCH {} --minVolumePerCH {:g} --output "{}" --log "{}"'.format(
                vhacd_path, off_filename, self.resolution, self.depth,
                self.concavity, self.planeDownsampling,
                self.convexhullDownsampling, self.alpha, self.beta, self.gamma,
                self.pca, self.mode == 'TETRAHEDRON', self.maxNumVerticesPerCH,
                self.minVolumePerCH, outFileName, logFileName)

            print('Running V-HACD...\n{}\n'.format(cmd_line))
            vhacd_process = Popen(cmd_line,
                                  bufsize=-1,
                                  close_fds=True,
                                  shell=True)

            mass = 1.0
            com = Vector()
            if self.mass_com:
                mass, com = physics_mass_center(mesh)
                mass *= self.density
                post_matrix = Matrix.Translation(
                    com * post_matrix) * post_matrix
                pre_matrix = Matrix.Translation(-com) * pre_matrix
            if not self.use_generated:
                bpy.data.meshes.remove(mesh)

            vhacd_process.wait()
            if not os_path.exists(outFileName):
                continue

            bpy.ops.import_scene.x3d(filepath=outFileName,
                                     axis_forward='Y',
                                     axis_up='Z')
            imported = bpy.context.selected_objects
            new_objects.extend(imported)
            parent = None

            for hull in imported:
                # Make hull a compound rigid body
                hull.select = False
                hull.show_transparent = self.show_transparent
                if self.mass_com:
                    for vert in hull.data.vertices:
                        vert.co -= com
                hull.game.physics_type = 'RIGID_BODY'
                hull.game.use_collision_bounds = True
                hull.game.collision_bounds_type = 'CONVEX_HULL'
                hull.game.mass = mass
                hull.game.use_collision_compound = True
                hull.hide_render = self.hide_render
                if not parent:
                    # Use first hull as compound parent
                    parent = hull
                    hull.matrix_basis = post_matrix
                    # Attach visual mesh as child...
                    ob.game.physics_type = 'NO_COLLISION'
                    if self.use_generated:
                        if self.mass_com:
                            for vert in mesh.vertices:
                                vert.co -= com
                        obc = bpy.data.objects.new(ob.name + '_GM', mesh)
                        bpy.context.scene.objects.link(obc)
                        obc.game.physics_type = 'NO_COLLISION'
                        obc.parent = parent
                        new_objects.append(obc)
                    else:
                        ob.matrix_basis = pre_matrix
                        ob.parent = parent
                else:
                    hull.parent = parent
                new_name = ob.name + '_ACD'
                hull.name = hull.name.replace('ShapeIndexedFaceSet', new_name)
                hull.data.name = hull.data.name.replace(
                    'ShapeIndexedFaceSet', new_name)

        if len(new_objects):
            for ob in new_objects:
                ob.select = True
        else:
            for ob in selected:
                ob.select = True
            self.report({'WARNING'}, 'No meshes to process!')
            return {'CANCELLED'}

        return {'FINISHED'}

    def invoke(self, context, event):
        wm = context.window_manager
        return wm.invoke_props_dialog(self, width=384)

    def draw(self, context):
        layout = self.layout
        col = layout.column()
        col.label('Pre-Processing Options (generated mesh):')
        row = col.row()
        row.prop(self, 'remove_doubles')
        row.prop(self, 'apply_transforms')

        layout.separator()
        col = layout.column()
        col.label('V-HACD Parameters:')
        col.prop(self, 'resolution')
        col.prop(self, 'depth')
        col.prop(self, 'concavity')
        col.prop(self, 'planeDownsampling')
        col.prop(self, 'convexhullDownsampling')
        row = col.row()
        row.prop(self, 'alpha')
        row.prop(self, 'beta')
        row.prop(self, 'gamma')
        row = col.row()
        row.prop(self, 'pca')
        row.prop(self, 'mode')
        col.prop(self, 'maxNumVerticesPerCH')
        col.prop(self, 'minVolumePerCH')

        layout.separator()
        col = layout.column()
        col.label('Post-Processing Options:')
        row = col.row()
        row.prop(self, 'show_transparent')
        row.prop(self, 'use_generated')
        row = col.row()
        row.prop(self, 'hide_render')
        row.prop(self, 'mass_com')
        row.prop(self, 'density')

        layout.separator()
        col = layout.column()
        col.label('WARNING:', icon='ERROR')
        col.label(' -> Processing can take several minutes per object!')
        col.label(' -> ALL selected objects will be processed sequentially!')
        col.label(' -> Game Engine physics compound generated for each object')
        col.label(' -> See Console Window for progress..,')
Esempio n. 13
0
class AddTree(Operator):
    bl_idname = "curve.tree_add"
    bl_label = "Sapling: Add Tree"
    bl_options = {'REGISTER', 'UNDO'}

    def objectList(self, context):
        objects = []
        bObjects = bpy.data.objects

        for obj in bObjects:
            if (obj.type in ['MESH', 'CURVE', 'SURFACE']) and (obj.name not in ['tree', 'leaves']):
                objects.append((obj.name, obj.name, ""))

        return (objects if objects else
                [('NONE', "No objects", "No appropriate objects in the Scene")])

    def update_tree(self, context):
        self.do_update = True

    def update_leaves(self, context):
        if self.showLeaves:
            self.do_update = True
        else:
            self.do_update = False

    def no_update_tree(self, context):
        self.do_update = False

    do_update = BoolProperty(
        name='Do Update',
        default=True, options={'HIDDEN'}
        )
    chooseSet = EnumProperty(
        name='Settings',
        description='Choose the settings to modify',
        items=settings,
        default='0', update=no_update_tree
        )
    bevel = BoolProperty(
        name='Bevel',
        description='Whether the curve is beveled',
        default=False, update=update_tree
        )
    prune = BoolProperty(
        name='Prune',
        description='Whether the tree is pruned',
        default=False, update=update_tree
        )
    showLeaves = BoolProperty(
        name='Show Leaves',
        description='Whether the leaves are shown',
        default=False, update=update_tree
        )
    useArm = BoolProperty(
        name='Use Armature',
        description='Whether the armature is generated',
        default=False, update=update_tree
        )
    seed = IntProperty(
        name='Random Seed',
        description='The seed of the random number generator',
        default=0, update=update_tree
        )
    handleType = IntProperty(
        name='Handle Type',
        description='The type of curve handles',
        min=0,
        max=1,
        default=0, update=update_tree
        )
    levels = IntProperty(
        name='Levels',
        description='Number of recursive branches (Levels)',
        min=1,
        max=6,
        soft_max=4,
        default=3, update=update_tree
        )
    length = FloatVectorProperty(
        name='Length',
        description='The relative lengths of each branch level (nLength)',
        min=0.000001,
        default=[1, 0.3, 0.6, 0.45],
        size=4, update=update_tree
        )
    lengthV = FloatVectorProperty(
        name='Length Variation',
        description='The relative length variations of each level (nLengthV)',
        min=0.0,
        max=1.0,
        default=[0, 0, 0, 0],
        size=4, update=update_tree
        )
    taperCrown = FloatProperty(
        name='Taper Crown',
        description='Shorten trunk splits toward outside of tree',
        min=0.0,
        soft_max=1.0,
        default=0, update=update_tree
        )
    branches = IntVectorProperty(
        name='Branches',
        description='The number of branches grown at each level (nBranches)',
        min=0,
        default=[50, 30, 10, 10],
        size=4, update=update_tree
        )
    curveRes = IntVectorProperty(
        name='Curve Resolution',
        description='The number of segments on each branch (nCurveRes)',
        min=1,
        default=[3, 5, 3, 1],
        size=4, update=update_tree
        )
    curve = FloatVectorProperty(
        name='Curvature',
        description='The angle of the end of the branch (nCurve)',
        default=[0, -40, -40, 0],
        size=4, update=update_tree
        )
    curveV = FloatVectorProperty(
        name='Curvature Variation',
        description='Variation of the curvature (nCurveV)',
        default=[20, 50, 75, 0],
        size=4, update=update_tree
        )
    curveBack = FloatVectorProperty(
        name='Back Curvature',
        description='Curvature for the second half of a branch (nCurveBack)',
        default=[0, 0, 0, 0],
        size=4, update=update_tree
        )
    baseSplits = IntProperty(
        name='Base Splits',
        description='Number of trunk splits at its base (nBaseSplits)',
        min=0,
        default=0, update=update_tree
        )
    segSplits = FloatVectorProperty(
        name='Segment Splits',
        description='Number of splits per segment (nSegSplits)',
        min=0,
        soft_max=3,
        default=[0, 0, 0, 0],
        size=4, update=update_tree
        )
    splitByLen = BoolProperty(
        name='Split relative to length',
        description='Split proportional to branch length',
        default=False, update=update_tree
        )
    rMode = EnumProperty(
        name="",  # "Branching Mode"
        description='Branching and Rotation Mode',
        items=branchmodes,
        default="rotate", update=update_tree
        )
    splitAngle = FloatVectorProperty(
        name='Split Angle',
        description='Angle of branch splitting (nSplitAngle)',
        default=[0, 0, 0, 0],
        size=4, update=update_tree
        )
    splitAngleV = FloatVectorProperty(
        name='Split Angle Variation',
        description='Variation in the split angle (nSplitAngleV)',
        default=[0, 0, 0, 0],
        size=4, update=update_tree
        )
    scale = FloatProperty(
        name='Scale',
        description='The tree scale (Scale)',
        min=0.0,
        default=13.0, update=update_tree)
    scaleV = FloatProperty(name='Scale Variation',
        description='The variation in the tree scale (ScaleV)',
        default=3.0, update=update_tree
        )
    attractUp = FloatVectorProperty(
        name='Vertical Attraction',
        description='Branch upward attraction',
        default=[0, 0, 0, 0],
        size=4, update=update_tree
        )
    attractOut = FloatVectorProperty(
        name='Outward Attraction',
        description='Branch outward attraction',
        default=[0, 0, 0, 0],
        min=0.0,
        max=1.0,
        size=4, update=update_tree
        )
    shape = EnumProperty(
        name='Shape',
        description='The overall shape of the tree (Shape)',
        items=shapeList3,
        default='7', update=update_tree
        )
    shapeS = EnumProperty(
        name='Secondary Branches Shape',
        description='The shape of secondary splits',
        items=shapeList4,
        default='4', update=update_tree
        )
    customShape = FloatVectorProperty(
        name='Custom Shape',
        description='custom shape branch length at (Base, Middle, Middle Position, Top)',
        size=4,
        min=.01,
        max=1,
        default=[.5, 1.0, .3, .5], update=update_tree
        )
    branchDist = FloatProperty(
        name='Branch Distribution',
        description='Adjust branch spacing to put more branches at the top or bottom of the tree',
        min=0.1,
        soft_max=10,
        default=1.0, update=update_tree
        )
    nrings = IntProperty(
        name='Branch Rings',
        description='grow branches in rings',
        min=0,
        default=0, update=update_tree
        )
    baseSize = FloatProperty(
        name='Trunk Height',
        description='Fraction of tree height with no branches (Base Size)',
        min=0.0,
        max=1.0,
        default=0.4, update=update_tree
        )
    baseSize_s = FloatProperty(
        name='Secondary Base Size',
        description='Factor to decrease base size for each level',
        min=0.0,
        max=1.0,
        default=0.25, update=update_tree
        )
    splitHeight = FloatProperty(
        name='Split Height',
        description='Fraction of tree height with no splits',
        min=0.0,
        max=1.0,
        default=0.2, update=update_tree
        )
    splitBias = FloatProperty(
        name='splitBias',
        description='Put more splits at the top or bottom of the tree',
        soft_min=-2.0,
        soft_max=2.0,
        default=0.0, update=update_tree
        )
    ratio = FloatProperty(
        name='Ratio',
        description='Base radius size (Ratio)',
        min=0.0,
        default=0.015, update=update_tree
        )
    minRadius = FloatProperty(
        name='Minimum Radius',
        description='Minimum branch Radius',
        min=0.0,
        default=0.0, update=update_tree
        )
    closeTip = BoolProperty(
        name='Close Tip',
        description='Set radius at branch tips to zero',
        default=False, update=update_tree
        )
    rootFlare = FloatProperty(
        name='Root Flare',
        description='Root radius factor',
        min=1.0,
        default=1.0, update=update_tree
        )
    autoTaper = BoolProperty(
        name='Auto Taper',
        description='Calculate taper automatically based on branch lengths',
        default=True, update=update_tree
        )
    taper = FloatVectorProperty(
        name='Taper',
        description='The fraction of tapering on each branch (nTaper)',
        min=0.0,
        max=1.0,
        default=[1, 1, 1, 1],
        size=4, update=update_tree
        )
    radiusTweak = FloatVectorProperty(
        name='Tweak Radius',
        description='multiply radius by this factor',
        min=0.0,
        max=1.0,
        default=[1, 1, 1, 1],
        size=4, update=update_tree
        )
    ratioPower = FloatProperty(
        name='Branch Radius Ratio',
        description=('Power which defines the radius of a branch compared to '
        'the radius of the branch it grew from (RatioPower)'),
        min=0.0,
        default=1.2, update=update_tree
        )
    downAngle = FloatVectorProperty(
        name='Down Angle',
        description=('The angle between a new branch and the one it grew '
        'from (nDownAngle)'),
        default=[90, 60, 45, 45],
        size=4, update=update_tree
        )
    downAngleV = FloatVectorProperty(
        name='Down Angle Variation',
        description="Angle to decrease Down Angle by towards end of parent branch "
                    "(negative values add random variation)",
        default=[0, -50, 10, 10],
        size=4, update=update_tree
        )
    useOldDownAngle = BoolProperty(
        name='Use old down angle variation',
        default=False, update=update_tree
        )
    useParentAngle = BoolProperty(
        name='Use parent angle',
        description='(first level) Rotate branch to match parent branch',
        default=True, update=update_tree
        )
    rotate = FloatVectorProperty(
        name='Rotate Angle',
        description="The angle of a new branch around the one it grew from "
                    "(negative values rotate opposite from the previous)",
        default=[137.5, 137.5, 137.5, 137.5],
        size=4, update=update_tree
        )
    rotateV = FloatVectorProperty(
        name='Rotate Angle Variation',
        description='Variation in the rotate angle (nRotateV)',
        default=[0, 0, 0, 0],
        size=4, update=update_tree
        )
    scale0 = FloatProperty(
        name='Radius Scale',
        description='The scale of the trunk radius (0Scale)',
        min=0.0,
        default=1.0, update=update_tree
        )
    scaleV0 = FloatProperty(
        name='Radius Scale Variation',
        description='Variation in the radius scale (0ScaleV)',
        min=0.0,
        max=1.0,
        default=0.2, update=update_tree
        )
    pruneWidth = FloatProperty(
        name='Prune Width',
        description='The width of the envelope (PruneWidth)',
        min=0.0,
        default=0.4, update=update_tree
        )
    pruneBase = FloatProperty(
        name='Prune Base Height',
        description='The height of the base of the envelope, bound by trunk height',
        min=0.0,
        max=1.0,
        default=0.3, update=update_tree
        )
    pruneWidthPeak = FloatProperty(
        name='Prune Width Peak',
        description=("Fraction of envelope height where the maximum width "
                     "occurs (PruneWidthPeak)"),
        min=0.0,
        default=0.6, update=update_tree
        )
    prunePowerHigh = FloatProperty(
        name='Prune Power High',
        description=('Power which determines the shape of the upper portion '
        'of the envelope (PrunePowerHigh)'),
        default=0.5, update=update_tree
        )
    prunePowerLow = FloatProperty(
        name='Prune Power Low',
        description=('Power which determines the shape of the lower portion '
        'of the envelope (PrunePowerLow)'),
        default=0.001, update=update_tree
        )
    pruneRatio = FloatProperty(
        name='Prune Ratio',
        description='Proportion of pruned length (PruneRatio)',
        min=0.0,
        max=1.0,
        default=1.0, update=update_tree
        )
    leaves = IntProperty(
        name='Leaves',
        description="Maximum number of leaves per branch (negative values grow "
                    "leaves from branch tip (palmate compound leaves))",
        default=25, update=update_tree
        )
    leafDownAngle = FloatProperty(
        name='Leaf Down Angle',
        description='The angle between a new leaf and the branch it grew from',
        default=45, update=update_leaves
        )
    leafDownAngleV = FloatProperty(
        name='Leaf Down Angle Variation',
        description="Angle to decrease Down Angle by towards end of parent branch "
                    "(negative values add random variation)",
        default=10, update=update_tree
        )
    leafRotate = FloatProperty(
        name='Leaf Rotate Angle',
        description="The angle of a new leaf around the one it grew from "
                    "(negative values rotate opposite from previous)",
        default=137.5, update=update_tree
        )
    leafRotateV = FloatProperty(
        name='Leaf Rotate Angle Variation',
        description='Variation in the rotate angle',
        default=0.0, update=update_leaves
        )
    leafScale = FloatProperty(
        name='Leaf Scale',
        description='The scaling applied to the whole leaf (LeafScale)',
        min=0.0,
        default=0.17, update=update_leaves
        )
    leafScaleX = FloatProperty(
        name='Leaf Scale X',
        description=('The scaling applied to the x direction of the leaf '
        '(LeafScaleX)'),
        min=0.0,
        default=1.0, update=update_leaves
        )
    leafScaleT = FloatProperty(
        name='Leaf Scale Taper',
        description='scale leaves toward the tip or base of the patent branch',
        min=-1.0,
        max=1.0,
        default=0.0, update=update_leaves
        )
    leafScaleV = FloatProperty(
        name='Leaf Scale Variation',
        description='randomize leaf scale',
        min=0.0,
        max=1.0,
        default=0.0, update=update_leaves
        )
    leafShape = EnumProperty(
        name='Leaf Shape',
        description='The shape of the leaves',
        items=(('hex', 'Hexagonal', '0'), ('rect', 'Rectangular', '1'),
               ('dFace', 'DupliFaces', '2'), ('dVert', 'DupliVerts', '3')),
        default='hex', update=update_leaves
        )
    leafDupliObj = EnumProperty(
        name='Leaf Object',
        description='Object to use for leaf instancing if Leaf Shape is DupliFaces or DupliVerts',
        items=objectList,
        update=update_leaves
        )
    """
    bend = FloatProperty(
        name='Leaf Bend',
        description='The proportion of bending applied to the leaf (Bend)',
        min=0.0,
        max=1.0,
        default=0.0, update=update_leaves
        )
    """
    leafangle = FloatProperty(
        name='Leaf Angle',
        description='Leaf vertical attraction',
        default=0.0, update=update_leaves
        )
    horzLeaves = BoolProperty(
        name='Horizontal leaves',
        description='Leaves face upwards',
        default=True, update=update_leaves
        )
    leafDist = EnumProperty(
        name='Leaf Distribution',
        description='The way leaves are distributed on branches',
        items=shapeList4,
        default='6', update=update_tree
        )
    bevelRes = IntProperty(
        name='Bevel Resolution',
        description='The bevel resolution of the curves',
        min=0,
        max=32,
        default=0, update=update_tree
        )
    resU = IntProperty(
        name='Curve Resolution',
        description='The resolution along the curves',
        min=1,
        default=4, update=update_tree
        )
    handleType = EnumProperty(
        name='Handle Type',
        description='The type of handles used in the spline',
        items=handleList,
        default='0', update=update_tree
        )
    armAnim = BoolProperty(
        name='Armature Animation',
        description='Whether animation is added to the armature',
        default=False, update=update_tree
        )
    previewArm = BoolProperty(
        name='Fast Preview',
        description='Disable armature modifier, hide tree, and set bone display to wire, for fast playback',
        # Disable skin modifier and hide tree and armature, for fast playback
        default=False, update=update_tree
        )
    leafAnim = BoolProperty(
        name='Leaf Animation',
        description='Whether animation is added to the leaves',
        default=False, update=update_tree
        )
    frameRate = FloatProperty(
        name='Animation Speed',
        description=('Adjust speed of animation, relative to scene frame rate'),
        min=0.001,
        default=1, update=update_tree
        )
    loopFrames = IntProperty(
        name='Loop Frames',
        description='Number of frames to make the animation loop for, zero is disabled',
        min=0,
        default=0, update=update_tree
        )
    """
    windSpeed = FloatProperty(
        name='Wind Speed',
        description='The wind speed to apply to the armature',
        default=2.0, update=update_tree
        )
    windGust = FloatProperty(
        name='Wind Gust',
        description='The greatest increase over Wind Speed',
        default=0.0, update=update_tree
        )
    """
    wind = FloatProperty(
        name='Overall Wind Strength',
        description='The intensity of the wind to apply to the armature',
        default=1.0, update=update_tree
        )
    gust = FloatProperty(
        name='Wind Gust Strength',
        description='The amount of directional movement, (from the positive Y direction)',
        default=1.0, update=update_tree
        )
    gustF = FloatProperty(
        name='Wind Gust Fequency',
        description='The Frequency of directional movement',
        default=0.075, update=update_tree
        )
    af1 = FloatProperty(
        name='Amplitude',
        description='Multiplier for noise amplitude',
        default=1.0, update=update_tree
        )
    af2 = FloatProperty(
        name='Frequency',
        description='Multiplier for noise fequency',
        default=1.0, update=update_tree
        )
    af3 = FloatProperty(
        name='Randomness',
        description='Random offset in noise',
        default=4.0, update=update_tree
        )
    makeMesh = BoolProperty(
        name='Make Mesh',
        description='Convert curves to mesh, uses skin modifier, enables armature simplification',
        default=False, update=update_tree
        )
    armLevels = IntProperty(
        name='Armature Levels',
        description='Number of branching levels to make bones for, 0 is all levels',
        min=0,
        default=2, update=update_tree
        )
    boneStep = IntVectorProperty(
        name='Bone Length',
        description='Number of stem segments per bone',
        min=1,
        default=[1, 1, 1, 1],
        size=4, update=update_tree
        )
    presetName = StringProperty(
        name='Preset Name',
        description='The name of the preset to be saved',
        default='',
        subtype='FILE_NAME', update=no_update_tree
        )
    limitImport = BoolProperty(
        name='Limit Import',
        description='Limited imported tree to 2 levels & no leaves for speed',
        default=True, update=no_update_tree
        )
    overwrite = BoolProperty(
        name='Overwrite',
        description='When checked, overwrite existing preset files when saving',
        default=False, update=no_update_tree
        )
    """
    startCurv = FloatProperty(
        name='Trunk Starting Angle',
        description=('The angle between vertical and the starting direction'
        'of the trunk'),
        min=0.0,
        max=360,
        default=0.0, update=update_tree
        )
    """

    @classmethod
    def poll(cls, context):
        return context.mode == 'OBJECT'

    def draw(self, context):
        layout = self.layout

        # Branch specs
        # layout.label('Tree Definition')

        layout.prop(self, 'chooseSet')

        if self.chooseSet == '0':
            box = layout.box()
            box.label("Geometry:")
            box.prop(self, 'bevel')

            row = box.row()
            row.prop(self, 'bevelRes')
            row.prop(self, 'resU')

            box.prop(self, 'handleType')
            box.prop(self, 'shape')

            col = box.column()
            col.prop(self, 'customShape')

            row = box.row()
            box.prop(self, 'shapeS')
            box.prop(self, 'branchDist')
            box.prop(self, 'nrings')
            box.prop(self, 'seed')

            box.label("Tree Scale:")
            row = box.row()
            row.prop(self, 'scale')
            row.prop(self, 'scaleV')

            # Here we create a dict of all the properties.
            # Unfortunately as_keyword doesn't work with vector properties,
            # so we need something custom. This is it
            data = []
            for a, b in (self.as_keywords(
                                    ignore=("chooseSet", "presetName", "limitImport",
                                            "do_update", "overwrite", "leafDupliObj"))).items():
                # If the property is a vector property then add the slice to the list
                try:
                    len(b)
                    data.append((a, b[:]))
                # Otherwise, it is fine so just add it
                except:
                    data.append((a, b))
            # Create the dict from the list
            data = dict(data)

            row = box.row()
            row.prop(self, 'presetName')
            # Send the data dict and the file name to the exporter
            row.operator('sapling.exportdata').data = repr([repr(data), self.presetName, self.overwrite])
            row = box.row()
            row.label(" ")
            row.prop(self, 'overwrite')
            row = box.row()
            row.menu('SAPLING_MT_preset', text='Load Preset')
            row.prop(self, 'limitImport')

        elif self.chooseSet == '1':
            box = layout.box()
            box.label("Branch Radius:")

            row = box.row()
            row.prop(self, 'bevel')
            row.prop(self, 'bevelRes')

            box.prop(self, 'ratio')
            row = box.row()
            row.prop(self, 'scale0')
            row.prop(self, 'scaleV0')
            box.prop(self, 'ratioPower')

            box.prop(self, 'minRadius')
            box.prop(self, 'closeTip')
            box.prop(self, 'rootFlare')

            box.prop(self, 'autoTaper')

            split = box.split()
            col = split.column()
            col.prop(self, 'taper')
            col = split.column()
            col.prop(self, 'radiusTweak')

        elif self.chooseSet == '2':
            box = layout.box()
            box.label("Branch Splitting:")
            box.prop(self, 'levels')
            box.prop(self, 'baseSplits')
            row = box.row()
            row.prop(self, 'baseSize')
            row.prop(self, 'baseSize_s')
            box.prop(self, 'splitHeight')
            box.prop(self, 'splitBias')
            box.prop(self, 'splitByLen')

            split = box.split()

            col = split.column()
            col.prop(self, 'branches')
            col.prop(self, 'splitAngle')
            col.prop(self, 'rotate')
            col.prop(self, 'attractOut')

            col = split.column()
            col.prop(self, 'segSplits')
            col.prop(self, 'splitAngleV')
            col.prop(self, 'rotateV')

            col.label("Branching Mode:")
            col.prop(self, 'rMode')

            box.column().prop(self, 'curveRes')

        elif self.chooseSet == '3':
            box = layout.box()
            box.label("Branch Growth:")

            box.prop(self, 'taperCrown')

            split = box.split()

            col = split.column()
            col.prop(self, 'length')
            col.prop(self, 'downAngle')
            col.prop(self, 'curve')
            col.prop(self, 'curveBack')

            col = split.column()
            col.prop(self, 'lengthV')
            col.prop(self, 'downAngleV')
            col.prop(self, 'curveV')
            col.prop(self, 'attractUp')

            box.prop(self, 'useOldDownAngle')
            box.prop(self, 'useParentAngle')

        elif self.chooseSet == '4':
            box = layout.box()
            box.label("Prune:")
            box.prop(self, 'prune')
            box.prop(self, 'pruneRatio')
            row = box.row()
            row.prop(self, 'pruneWidth')
            row.prop(self, 'pruneBase')
            box.prop(self, 'pruneWidthPeak')

            row = box.row()
            row.prop(self, 'prunePowerHigh')
            row.prop(self, 'prunePowerLow')

        elif self.chooseSet == '5':
            box = layout.box()
            box.label("Leaves:")
            box.prop(self, 'showLeaves')
            box.prop(self, 'leafShape')
            box.prop(self, 'leafDupliObj')
            box.prop(self, 'leaves')
            box.prop(self, 'leafDist')

            box.label("")
            row = box.row()
            row.prop(self, 'leafDownAngle')
            row.prop(self, 'leafDownAngleV')

            row = box.row()
            row.prop(self, 'leafRotate')
            row.prop(self, 'leafRotateV')
            box.label("")

            row = box.row()
            row.prop(self, 'leafScale')
            row.prop(self, 'leafScaleX')

            row = box.row()
            row.prop(self, 'leafScaleT')
            row.prop(self, 'leafScaleV')

            box.prop(self, 'horzLeaves')
            box.prop(self, 'leafangle')

            # box.label(" ")
            # box.prop(self, 'bend')

        elif self.chooseSet == '6':
            box = layout.box()
            box.label("Armature:")
            row = box.row()
            row.prop(self, 'useArm')
            box.prop(self, 'makeMesh')
            box.label("Armature Simplification:")
            box.prop(self, 'armLevels')
            box.prop(self, 'boneStep')

        elif self.chooseSet == '7':
            box = layout.box()
            box.label("Finalize All Other Settings First!")
            box.prop(self, 'armAnim')
            box.prop(self, 'leafAnim')
            box.prop(self, 'previewArm')
            box.prop(self, 'frameRate')
            box.prop(self, 'loopFrames')

            # row = box.row()
            # row.prop(self, 'windSpeed')
            # row.prop(self, 'windGust')

            box.label('Wind Settings:')
            box.prop(self, 'wind')
            row = box.row()
            row.prop(self, 'gust')
            row.prop(self, 'gustF')

            box.label('Leaf Wind Settings:')
            box.prop(self, 'af1')
            box.prop(self, 'af2')
            box.prop(self, 'af3')

    def execute(self, context):
        # Ensure the use of the global variables
        global settings, useSet
        start_time = time.time()
        # bpy.ops.ImportData.filename = "quaking_aspen"
        # If we need to set the properties from a preset then do it here
        if useSet:
            for a, b in settings.items():
                setattr(self, a, b)
            if self.limitImport:
                setattr(self, 'levels', min(settings['levels'], 2))
                setattr(self, 'showLeaves', False)
            useSet = False
        if not self.do_update:
            return {'PASS_THROUGH'}
        utils.addTree(self)
        # cProfile.runctx("addTree(self)", globals(), locals())
        print("Tree creation in %0.1fs" % (time.time() - start_time))

        return {'FINISHED'}

    def invoke(self, context, event):
        bpy.ops.sapling.importdata(filename="quaking_aspen.py")
        return self.execute(context)
class MorphologyPanel(bpy.types.Panel):
    """Morphology tools panel"""

    ################################################################################################
    # Panel parameters
    ################################################################################################
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_label = 'Morphology Toolbox'
    bl_category = 'NeuroMorphoVis'
    bl_options = {'DEFAULT_CLOSED'}

    ################################################################################################
    # Panel options
    ################################################################################################
    # Build soma
    bpy.types.Scene.BuildSoma = EnumProperty(
        items=[(nmv.enums.Soma.Representation.IGNORE, 'Ignore',
                'Ignore soma reconstruction'),
               (nmv.enums.Soma.Representation.SPHERE, 'Sphere',
                'Represent the soma by a sphere'),
               (nmv.enums.Soma.Representation.REALISTIC, 'Profile',
                'Reconstruct a 3D profile of the soma')],
        name='Soma',
        default=nmv.enums.Soma.Representation.SPHERE)

    # Build axon
    bpy.types.Scene.BuildAxon = BoolProperty(
        name="Build Axon",
        description="Select this flag to reconstruct the axon",
        default=True)

    # Axon branching order
    # Since the axon is so complicated, we will set its default branching order to 5
    bpy.types.Scene.AxonBranchingLevel = IntProperty(
        name="Branching Order",
        description="Branching order for the axon",
        default=nmv.consts.Arbors.AXON_DEFAULT_BRANCHING_ORDER,
        min=1,
        max=100)

    # Build basal dendrites
    bpy.types.Scene.BuildBasalDendrites = BoolProperty(
        name="Build Basal Dendrites",
        description="Select this flag to reconstruct the basal dendrites",
        default=True)

    # Basal dendrites branching order
    bpy.types.Scene.BasalDendritesBranchingLevel = IntProperty(
        name="Branching Order",
        description="Branching order for the basal dendrites",
        default=nmv.consts.Arbors.MAX_BRANCHING_ORDER,
        min=1,
        max=100)

    # Build apical dendrite
    bpy.types.Scene.BuildApicalDendrite = BoolProperty(
        name="Build Apical Dendrites",
        description=
        "Select this flag to reconstruct the apical dendrite (if exists)",
        default=True)

    # Apical dendrite branching order
    bpy.types.Scene.ApicalDendriteBranchingLevel = IntProperty(
        name="Branching Order",
        description="Branching order for the apical dendrite",
        default=nmv.consts.Arbors.MAX_BRANCHING_ORDER,
        min=1,
        max=100)

    # Display bounding box info
    bpy.types.Scene.DisplayBoundingBox = BoolProperty(
        name="Display Bounding Box Info",
        description="Displays the bounding box of the morphology",
        default=False)

    # Morphology material
    bpy.types.Scene.MorphologyMaterial = EnumProperty(
        items=nmv.enums.Shading.MATERIAL_ITEMS,
        name="Material",
        default=nmv.enums.Shading.LAMBERT_WARD)

    # Color arbor by part
    bpy.types.Scene.ColorArborByPart = BoolProperty(
        name="Color Arbor By Part",
        description=
        "Each component of the arbor will be assigned a different color",
        default=False)

    # Color arbor using black and white alternatives
    bpy.types.Scene.ColorArborBlackAndWhite = BoolProperty(
        name="Black / White",
        description=
        "Each component of the arbor will be assigned a either black or white",
        default=False)

    # Use single color for the all the objects in the morphology
    bpy.types.Scene.MorphologyHomogeneousColor = BoolProperty(
        name="Homogeneous Color",
        description=
        "Use a single color for rendering all the objects of the morphology",
        default=False)

    # A homogeneous color for all the objects of the morphology
    bpy.types.Scene.NeuronMorphologyColor = FloatVectorProperty(
        name="Membrane Color",
        subtype='COLOR',
        default=nmv.enums.Color.SOMA,
        min=0.0,
        max=1.0,
        description=
        "The homogeneous color of the reconstructed morphology membrane")

    # Soma color
    bpy.types.Scene.SomaColor = FloatVectorProperty(
        name="Soma Color",
        subtype='COLOR',
        default=nmv.enums.Color.SOMA,
        min=0.0,
        max=1.0,
        description="The color of the reconstructed soma")

    # Axon color
    bpy.types.Scene.AxonColor = FloatVectorProperty(
        name="Axon Color",
        subtype='COLOR',
        default=nmv.enums.Color.AXONS,
        min=0.0,
        max=1.0,
        description="The color of the reconstructed axon")

    # Basal dendrites color
    bpy.types.Scene.BasalDendritesColor = FloatVectorProperty(
        name="Basal Dendrites  Color",
        subtype='COLOR',
        default=nmv.enums.Color.BASAL_DENDRITES,
        min=0.0,
        max=1.0,
        description="The color of the reconstructed basal dendrites")

    # Apical dendrite color
    bpy.types.Scene.ApicalDendriteColor = FloatVectorProperty(
        name="Apical Dendrite Color",
        subtype='COLOR',
        default=nmv.enums.Color.APICAL_DENDRITES,
        min=0.0,
        max=1.0,
        description="The color of the reconstructed apical dendrite")

    # Articulation color
    bpy.types.Scene.ArticulationColor = FloatVectorProperty(
        name="Articulation Color",
        subtype='COLOR',
        default=nmv.enums.Color.ARTICULATION,
        min=0.0,
        max=1.0,
        description=
        "The color of the articulations in the Articulated Section mode")

    # Reconstruction method
    bpy.types.Scene.MorphologyReconstructionTechnique = EnumProperty(
        items=
        [(nmv.enums.Skeletonization.Method.DISCONNECTED_SEGMENTS,
          'Disconnected Segments',
          "Each segment is an independent object (this approach is time consuming)"
          ),
         (nmv.enums.Skeletonization.Method.DISCONNECTED_SECTIONS,
          'Disconnected Sections', "Each section is an independent object"),
         (nmv.enums.Skeletonization.Method.ARTICULATED_SECTIONS,
          'Articulated Sections',
          "Each section is an independent object, but connected with a pivot"),
         (nmv.enums.Skeletonization.Method.SAMPLES, 'Samples',
          "Each sample is drawn as a sphere (this approach is very time consuming)"
          ),
         (nmv.enums.Skeletonization.Method.CONNECTED_SECTION_ORIGINAL,
          'Connected Sections (Original)',
          "The sections of a single arbor are connected together"),
         (nmv.enums.Skeletonization.Method.CONNECTED_SECTION_REPAIRED,
          'Connected Sections (Repaired)',
          "The morphology is repaired and fully reconstructed ")],
        name="Method",
        default=nmv.enums.Skeletonization.Method.DISCONNECTED_SECTIONS)

    # Arbors style
    bpy.types.Scene.ArborsStyle = EnumProperty(
        items=nmv.enums.Arbors.Style.MORPHOLOGY_STYLE_ITEMS,
        name="Skeleton Style",
        default=nmv.enums.Arbors.Style.ORIGINAL)

    # Branching, is it based on angles or radii
    bpy.types.Scene.MorphologyBranching = EnumProperty(items=[
        (nmv.enums.Skeletonization.Branching.ANGLES, 'Angles',
         'Make the branching based on the angles at branching points'),
        (nmv.enums.Skeletonization.Branching.RADII, 'Radii',
         'Make the branching based on the radii of the children at the branching points'
         )
    ],
                                                       name='Branching Style',
                                                       default=nmv.enums.
                                                       Skeletonization.
                                                       Branching.ANGLES)

    # Soma connection to roots
    bpy.types.Scene.SomaConnectionToRoot = EnumProperty(items=[
        (nmv.enums.Arbors.Roots.CONNECTED_TO_ORIGIN, 'Connect Connected',
         'Connect the arbors that are physically connected to the origin of the soma'
         ),
        (nmv.enums.Arbors.Roots.ALL_CONNECTED_TO_ORIGIN, 'All Connected',
         'Connect the all the arbors to the origin of the soma even if they intersect'
         ),
        (nmv.enums.Arbors.Roots.DISCONNECTED_FROM_SOMA, 'All Disconnected',
         'Disconnect all the arbors from the soma')
    ],
                                                        name='Arbors To Soma',
                                                        default=nmv.enums.
                                                        Arbors.Roots.
                                                        CONNECTED_TO_ORIGIN)

    # Arbor quality
    bpy.types.Scene.ArborQuality = IntProperty(
        name="Sides",
        description=
        "Number of vertices of the cross-section of each segment along the arbor",
        default=16,
        min=4,
        max=128)

    # Section radius
    bpy.types.Scene.SectionsRadii = EnumProperty(
        items=[
            (nmv.enums.Skeletonization.ArborsRadii.AS_SPECIFIED,
             'As Specified in Morphology',
             "Use the cross-sectional radii reported in the morphology file"),
            (nmv.enums.Skeletonization.ArborsRadii.FIXED,
             'At a Fixed Diameter', "Set all the arbors to a fixed radius"),
            (nmv.enums.Skeletonization.ArborsRadii.SCALED, 'With Scale Factor',
             "Scale all the arbors using a specified scale factor"),
            (nmv.enums.Skeletonization.ArborsRadii.FILTERED, 'Filtered',
             "Filter section with lower values than the threshold"),
        ],
        name="Sections Radii",
        default=nmv.enums.Skeletonization.ArborsRadii.AS_SPECIFIED)

    # Fixed section radius value
    bpy.types.Scene.FixedRadiusValue = FloatProperty(
        name="Value (micron)",
        description=
        "The value of the radius in microns between (0.05 and 5.0) microns",
        default=1.0,
        min=0.05,
        max=5.0)

    # Threshold value for the radius
    bpy.types.Scene.FilteredRadiusThreshold = FloatProperty(
        name="Threshold",
        description=
        "The value of the threshold radius in microns between (0.005 and 5.0) microns",
        default=1.0,
        min=0.005,
        max=5.0)

    # Global radius scale value
    bpy.types.Scene.RadiusScaleValue = FloatProperty(
        name="Scale",
        description=
        "A scale factor for scaling the radii of the arbors between (0.01 and 5.0)",
        default=1.0,
        min=0.01,
        max=5.0)

    # Rendering type
    bpy.types.Scene.RenderingType = EnumProperty(
        items=[(
            nmv.enums.Skeletonization.Rendering.Resolution.FIXED_RESOLUTION,
            'Fixed Resolution',
            'Renders a full view of the morphology at a specified resolution'),
               (nmv.enums.Skeletonization.Rendering.Resolution.TO_SCALE,
                'To Scale',
                'Renders an image of the full view at the right scale in (um)')
               ],
        name='Type',
        default=nmv.enums.Skeletonization.Rendering.Resolution.FIXED_RESOLUTION
    )

    # Rendering view
    bpy.types.Scene.MorphologyRenderingView = EnumProperty(
        items=[
            (nmv.enums.Skeletonization.Rendering.View.WIDE_SHOT_VIEW,
             'Wide Shot', 'Renders an image of the full view'),
            (nmv.enums.Skeletonization.Rendering.View.MID_SHOT_VIEW,
             'Mid Shot', 'Renders an image of the reconstructed arbors only'),
            (nmv.enums.Skeletonization.Rendering.View.CLOSE_UP_VIEW,
             'Close Up', 'Renders a close up image the focuses on the soma')
        ],
        name='View',
        default=nmv.enums.Skeletonization.Rendering.View.MID_SHOT_VIEW)

    # Frame resolution
    bpy.types.Scene.MorphologyFrameResolution = IntProperty(
        name="Resolution",
        default=512,
        min=128,
        max=1024 * 10,
        description=
        "The resolution of the image generated from rendering the morphology")

    # Frame scale factor 'for rendering to scale option '
    bpy.types.Scene.MorphologyFrameScaleFactor = FloatProperty(
        name="Scale",
        default=1.0,
        min=1.0,
        max=100.0,
        description="The scale factor for rendering a morphology to scale")

    # Morphology close up dimensions
    bpy.types.Scene.MorphologyCloseUpDimensions = FloatProperty(
        name="Dimensions",
        default=20,
        min=5,
        max=100,
        description=
        "The dimensions of the view that will be rendered in microns")

    ################################################################################################
    # @draw
    ################################################################################################
    def draw(self, context):
        """Draw the panel.

        :param context:
            Panel context.
        """

        # Get a reference to the layout of the panel
        layout = self.layout

        # Get a reference to the scene
        current_scene = context.scene

        # Set the skeleton options
        nmv.interface.ui.morphology_panel_options.set_skeleton_options(
            layout=layout,
            scene=current_scene,
            options=nmv.interface.ui_options)

        # Set the reconstruction options
        nmv.interface.ui.morphology_panel_options.set_reconstruction_options(
            layout=layout,
            scene=current_scene,
            options=nmv.interface.ui_options)

        # Set the color options
        nmv.interface.ui.morphology_panel_options.set_color_options(
            layout=layout,
            scene=current_scene,
            options=nmv.interface.ui_options)

        # Reconstruction button
        quick_reconstruction_row = layout.row()
        quick_reconstruction_row.label(text='Quick Reconstruction:',
                                       icon='PARTICLE_POINT')
        reconstruct_morphology_button_row = layout.row()
        reconstruct_morphology_button_row.operator('reconstruct.morphology',
                                                   icon='RNA_ADD')
        reconstruct_morphology_button_row.enabled = True

        # Set the rendering options
        nmv.interface.ui.morphology_panel_options.set_rendering_options(
            layout=layout,
            scene=current_scene,
            options=nmv.interface.ui_options)

        # Set the rendering options
        nmv.interface.ui.morphology_panel_options.set_export_options(
            layout=layout,
            scene=current_scene,
            options=nmv.interface.ui_options)

        # Enable or disable the layout
        nmv.interface.enable_or_disable_layout(layout)
Esempio n. 15
0
def fprop_generator(**altprops):
    # min can be overwritten by passing in min=some_value into the altprops dict
    default_dict_vals = dict(update=updateNode, precision=3, min=0.0, max=1.0)
    default_dict_vals.update(**altprops)
    return FloatProperty(**default_dict_vals)
class Sequencer_Extra_FadeInOut(bpy.types.Operator):
    bl_idname = 'sequencerextra.fadeinout'
    bl_label = 'Fade...'
    bl_description = 'Fade volume or opacity of active strip'
    mode = EnumProperty(
        name='Direction',
        items=(('IN', 'Fade In...', ''), ('OUT', 'Fade Out...', ''),
               ('INOUT', 'Fade In and Out...', '')),
        default='IN',
    )
    bl_options = {'REGISTER', 'UNDO'}

    fade_duration = IntProperty(name='Duration',
                                description='Number of frames to fade',
                                min=1,
                                max=250,
                                default=25)
    fade_amount = FloatProperty(name='Amount',
                                description='Maximum value of fade',
                                min=0.0,
                                max=100.0,
                                default=1.0)

    @classmethod
    def poll(cls, context):
        scn = context.scene
        if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
            return True
        else:
            return False

    def execute(self, context):
        seq = context.scene.sequence_editor
        scn = context.scene
        strip = seq.active_strip
        tmp_current_frame = context.scene.frame_current

        if strip.type == 'SOUND':
            if (self.mode) == 'OUT':
                scn.frame_current = strip.frame_final_end - self.fade_duration
                strip.volume = self.fade_amount
                strip.keyframe_insert('volume')
                scn.frame_current = strip.frame_final_end
                strip.volume = 0
                strip.keyframe_insert('volume')
            elif (self.mode) == 'INOUT':
                scn.frame_current = strip.frame_final_start
                strip.volume = 0
                strip.keyframe_insert('volume')
                scn.frame_current += self.fade_duration
                strip.volume = self.fade_amount
                strip.keyframe_insert('volume')
                scn.frame_current = strip.frame_final_end - self.fade_duration
                strip.volume = self.fade_amount
                strip.keyframe_insert('volume')
                scn.frame_current = strip.frame_final_end
                strip.volume = 0
                strip.keyframe_insert('volume')
            else:
                scn.frame_current = strip.frame_final_start
                strip.volume = 0
                strip.keyframe_insert('volume')
                scn.frame_current += self.fade_duration
                strip.volume = self.fade_amount
                strip.keyframe_insert('volume')

        else:
            if (self.mode) == 'OUT':
                scn.frame_current = strip.frame_final_end - self.fade_duration
                strip.blend_alpha = self.fade_amount
                strip.keyframe_insert('blend_alpha')
                scn.frame_current = strip.frame_final_end
                strip.blend_alpha = 0
                strip.keyframe_insert('blend_alpha')
            elif (self.mode) == 'INOUT':
                scn.frame_current = strip.frame_final_start
                strip.blend_alpha = 0
                strip.keyframe_insert('blend_alpha')
                scn.frame_current += self.fade_duration
                strip.blend_alpha = self.fade_amount
                strip.keyframe_insert('blend_alpha')
                scn.frame_current = strip.frame_final_end - self.fade_duration
                strip.blend_alpha = self.fade_amount
                strip.keyframe_insert('blend_alpha')
                scn.frame_current = strip.frame_final_end
                strip.blend_alpha = 0
                strip.keyframe_insert('blend_alpha')
            else:
                scn.frame_current = strip.frame_final_start
                strip.blend_alpha = 0
                strip.keyframe_insert('blend_alpha')
                scn.frame_current += self.fade_duration
                strip.blend_alpha = self.fade_amount
                strip.keyframe_insert('blend_alpha')

        scn.frame_current = tmp_current_frame

        scn.kr_default_fade_duration = self.fade_duration
        scn.kr_default_fade_amount = self.fade_amount
        return {'FINISHED'}

    def invoke(self, context, event):
        scn = context.scene
        functions.initSceneProperties(context)
        self.fade_duration = scn.kr_default_fade_duration
        self.fade_amount = scn.kr_default_fade_amount
        return context.window_manager.invoke_props_dialog(self)
Esempio n. 17
0
class MESH_OT_edges_floor_plan(Operator):
    bl_idname = "mesh.edges_floor_plan"
    bl_label = "Edges Floor Plan"
    bl_description = "Top View, Extrude Flat Along Edges"
    bl_options = {'REGISTER', 'UNDO'}

    wid = FloatProperty(name="Wall width:",
                        description="Set the width of the generated walls\n",
                        default=0.1,
                        min=0.001,
                        max=30000)
    depth = FloatProperty(name="Inner height:",
                          description="Set the height of the inner wall edges",
                          default=0.0,
                          min=0,
                          max=10)
    connect_ends = BoolProperty(
        name="Connect Ends",
        description="Connect the ends of the boundary Edge loops",
        default=False)
    repeat_cleanup = IntProperty(
        name="Recursive Prepare",
        description="Number of times that the preparation phase runs\n"
        "at the start of the script\n"
        "If parts of the mesh are not modified, increase this value",
        min=1,
        max=20,
        default=1)
    fill_items = [
        ('EDGE_NET', "Edge Net",
         "Edge Net Method for mesh preparation - Initial Fill\n"
         "The filled in faces will be Inset individually\n"
         "Supports simple 3D objects"),
        ('SINGLE_FACE', "Single Face",
         "Single Face Method for mesh preparation - Initial Fill\n"
         "The produced face will be Triangulated before Inset Region\n"
         "Good for edges forming a circle, avoid 3D objects"),
        ('SOLIDIFY', "Solidify", "Extrude and Solidify Method\n"
         "Useful for complex meshes, however works best on flat surfaces\n"
         "as the extrude direction has to be defined")
    ]
    fill_type = EnumProperty(
        name="Fill Type",
        items=fill_items,
        description="Choose the method for creating geometry",
        default='SOLIDIFY')
    keep_faces = BoolProperty(name="Keep Faces",
                              description="Keep or not the fill faces\n"
                              "Can depend on Remove Ngons state",
                              default=False)
    tri_faces = BoolProperty(name="Triangulate Faces",
                             description="Triangulate the created fill faces\n"
                             "Sometimes can lead to unsatisfactory results",
                             default=False)
    initial_extrude = FloatVectorProperty(name="Initial Extrude",
                                          description="",
                                          default=(0.0, 0.0, 0.1),
                                          min=-20.0,
                                          max=20.0,
                                          subtype='XYZ',
                                          precision=3,
                                          size=3)
    remove_ngons = BoolProperty(
        name="Remove Ngons",
        description="Keep or not the Ngon Faces\n"
        "Note about limitations:\n"
        "Sometimes the kept Faces could be Ngons\n"
        "Removing the Ngons can lead to no geometry created",
        default=True)
    offset = FloatProperty(
        name="Wall Offset:",
        description="Set the offset for the Solidify modifier",
        default=0.0,
        min=-1.0,
        max=1.0)
    only_rim = BoolProperty(name="Rim Only",
                            description="Solidify Fill Rim only option",
                            default=False)

    @classmethod
    def poll(cls, context):
        ob = context.active_object
        return (ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')

    def check_edge(self, context):
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.mode_set(mode='EDIT')
        obj = bpy.context.object
        me_check = obj.data
        if len(me_check.edges) < 1:
            return False

        return True

    @staticmethod
    def ensure(bm):
        if bm:
            bm.verts.ensure_lookup_table()
            bm.edges.ensure_lookup_table()
            bm.faces.ensure_lookup_table()

    def solidify_mod(self, context, ob, wid, offset, only_rim):
        try:
            mods = ob.modifiers.new(name="_Mesh_Solidify_Wall",
                                    type='SOLIDIFY')
            mods.thickness = wid
            mods.use_quality_normals = True
            mods.offset = offset
            mods.use_even_offset = True
            mods.use_rim = True
            mods.use_rim_only = only_rim
            mods.show_on_cage = True

            bpy.ops.object.modifier_apply(modifier="_Mesh_Solidify_Wall")
        except Exception as e:
            error_handlers(self,
                           e,
                           reports="Adding a Solidify Modifier failed")
            pass

    def draw(self, context):
        layout = self.layout

        box = layout.box()
        box.label(text="Choose Method:", icon="SCRIPTWIN")
        box.prop(self, "fill_type")

        col = box.column(align=True)

        if self.fill_type == 'EDGE_NET':
            col.prop(self, "repeat_cleanup")
            col.prop(self, "remove_ngons", toggle=True)

        elif self.fill_type == 'SOLIDIFY':
            col.prop(self, "offset", slider=True)
            col.prop(self, "initial_extrude")

        else:
            col.prop(self, "remove_ngons", toggle=True)
            col.prop(self, "tri_faces", toggle=True)

        box = layout.box()
        box.label(text="Settings:", icon="MOD_BUILD")

        col = box.column(align=True)
        col.prop(self, "wid")

        if self.fill_type != 'SOLIDIFY':
            col.prop(self, "depth")
            col.prop(self, "connect_ends", toggle=True)
            col.prop(self, "keep_faces", toggle=True)
        else:
            col.prop(self, "only_rim", toggle=True)

    def execute(self, context):
        if not self.check_edge(context):
            self.report(
                {'WARNING'},
                "Operation Cancelled. Needs a Mesh with at least one edge")
            return {'CANCELLED'}

        wid = self.wid * 0.1
        depth = self.depth * 0.1
        offset = self.offset * 0.1
        store_selection_mode = context.tool_settings.mesh_select_mode
        # Note: the remove_doubles called after bmesh creation would make
        # blender crash with certain meshes - keep it in mind for the future
        bpy.ops.mesh.remove_doubles(threshold=0.003)
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.mode_set(mode='EDIT')
        ob = bpy.context.object

        me = ob.data
        bm = bmesh.from_edit_mesh(me)

        bmesh.ops.delete(bm, geom=bm.faces, context=3)
        self.ensure(bm)
        context.tool_settings.mesh_select_mode = (False, True, False)
        original_edges = [edge.index for edge in bm.edges]
        original_verts = [vert.index for vert in bm.verts]
        self.ensure(bm)
        bpy.ops.mesh.select_all(action='DESELECT')

        if self.fill_type == 'EDGE_NET':
            for i in range(self.repeat_cleanup):
                bmesh.ops.edgenet_prepare(bm, edges=bm.edges)
                self.ensure(bm)
            bmesh.ops.edgenet_fill(bm,
                                   edges=bm.edges,
                                   mat_nr=0,
                                   use_smooth=True,
                                   sides=0)
            self.ensure(bm)
            if self.remove_ngons:
                ngons = [face for face in bm.faces if len(face.edges) > 4]
                self.ensure(bm)
                bmesh.ops.delete(bm, geom=ngons, context=5)  # 5 - delete faces
                del ngons
                self.ensure(bm)

        elif self.fill_type == 'SOLIDIFY':
            for vert in bm.verts:
                vert.normal_update()
            self.ensure(bm)
            bmesh.ops.extrude_edge_only(bm,
                                        edges=bm.edges,
                                        use_select_history=False)
            self.ensure(bm)
            verts_extrude = [
                vert for vert in bm.verts if vert.index in original_verts
            ]
            self.ensure(bm)
            bmesh.ops.translate(bm,
                                verts=verts_extrude,
                                vec=(self.initial_extrude))
            self.ensure(bm)
            del verts_extrude
            self.ensure(bm)

            for edge in bm.edges:
                if edge.is_boundary:
                    edge.select = True

            bm = bmesh.update_edit_mesh(ob.data, 1, 1)

            bpy.ops.object.mode_set(mode='OBJECT')
            self.solidify_mod(context, ob, wid, offset, self.only_rim)

            bpy.ops.object.mode_set(mode='EDIT')

            context.tool_settings.mesh_select_mode = store_selection_mode

            return {'FINISHED'}

        else:
            bm.faces.new(bm.verts)
            self.ensure(bm)

            if self.tri_faces:
                bmesh.ops.triangle_fill(bm,
                                        use_beauty=True,
                                        use_dissolve=False,
                                        edges=bm.edges)
                self.ensure(bm)

        if self.remove_ngons and self.fill_type != 'EDGE_NET':
            ngons = [face for face in bm.faces if len(face.edges) > 4]
            self.ensure(bm)
            bmesh.ops.delete(bm, geom=ngons, context=5)  # 5 - delete faces
            del ngons
            self.ensure(bm)

        del_boundary = [
            edge for edge in bm.edges if edge.index not in original_edges
        ]
        self.ensure(bm)

        del original_edges
        self.ensure(bm)

        if self.fill_type == 'EDGE_NET':
            extrude_inner = bmesh.ops.inset_individual(
                bm,
                faces=bm.faces,
                thickness=wid,
                depth=depth,
                use_even_offset=True,
                use_interpolate=False,
                use_relative_offset=False)
        else:
            extrude_inner = bmesh.ops.inset_region(bm,
                                                   faces=bm.faces,
                                                   faces_exclude=[],
                                                   use_boundary=True,
                                                   use_even_offset=True,
                                                   use_interpolate=False,
                                                   use_relative_offset=False,
                                                   use_edge_rail=False,
                                                   thickness=wid,
                                                   depth=depth,
                                                   use_outset=False)
        self.ensure(bm)

        del_faces = [
            faces for faces in bm.faces if faces not in extrude_inner["faces"]
        ]
        self.ensure(bm)
        del extrude_inner
        self.ensure(bm)

        if not self.keep_faces:
            bmesh.ops.delete(bm, geom=del_faces, context=5)  # 5 delete faces
        del del_faces
        self.ensure(bm)

        face_del = set()
        for face in bm.faces:
            for edge in del_boundary:
                if isinstance(edge, bmesh.types.BMEdge):
                    if edge in face.edges:
                        face_del.add(face)
        self.ensure(bm)
        face_del = list(face_del)
        self.ensure(bm)

        del del_boundary
        self.ensure(bm)

        if not self.connect_ends:
            bmesh.ops.delete(bm, geom=face_del, context=5)
            self.ensure(bm)

        del face_del
        self.ensure(bm)

        for edge in bm.edges:
            if edge.is_boundary:
                edge.select = True

        bm = bmesh.update_edit_mesh(ob.data, 1, 1)

        context.tool_settings.mesh_select_mode = store_selection_mode

        return {'FINISHED'}
Esempio n. 18
0
class TerrainPanel(Panel):
    """Creates a Panel in the Object properties window for terrain objects"""
    bl_label = "Terrain Model"
    bl_idname = "OBJECT_PT_terrain"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"

    # Allow the user to specify a new resolution factor for reloading the
    # terrain data at. This is useful because it allows the user to stage
    # a scene with a low resolution terrain map, apply textures, modifiers,
    # etc. and then increase the resolution to prepare for final rendering.
    #
    # Displaying this value as a percentage (0, 100] is an intuitive way
    # for users to grasp what this value does. The DTM importer, however,
    # wants to recieve a value between (0, 1]. This is obviously a
    # straightforward conversion:
    #
    #     f(x) = x / 100
    #
    # But this conversion should happen here, in the terrain panel, rather
    # than in the DTM importing utility itself. We can't pass get/set
    # functions to the property itself because they result in a recursion
    # error. Instead, we use another, hidden, property to store the scaled
    # resolution.
    bpy.types.Object.dtm_resolution = FloatProperty(
        subtype="PERCENTAGE",
        name="New Resolution",
        description=(
            "Percentage scale for terrain model resolution. 100\% loads the "
            "model at full resolution (i.e. one vertex for each post in the "
            "original terrain model) and is *MEMORY INTENSIVE*. Downsampling "
            "uses Nearest Neighbors. The downsampling algorithm may need to "
            "alter the resolution you specify here to ensure it results in a "
            "whole number of vertices. If it needs to alter the value you "
            "specify, you are guaranteed that it will shrink it (i.e. "
            "decrease the DTM resolution"),
        min=1.0,
        max=100.0,
        default=10.0)
    bpy.types.Object.scaled_dtm_resolution = FloatProperty(
        options={'HIDDEN'},
        name="Scaled Terrain Model Resolution",
        get=(lambda self: self.dtm_resolution / 100.0))

    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return obj and obj.get("IS_TERRAIN", False)

    def draw(self, context):
        obj = context.active_object
        layout = self.layout

        # User Controls
        layout.prop(obj, 'dtm_resolution')
        layout.operator("terrain.reload")

        # Metadata
        self.draw_metadata_panel(context)

    def draw_metadata_panel(self, context):
        """Display some metadata about the DTM"""
        obj = context.active_object
        layout = self.layout

        metadata_panel = layout.box()

        dtm_resolution = metadata_panel.row()
        dtm_resolution.label('Current Resolution: ')
        dtm_resolution.label('{:9,.2%}'.format(obj['DTM_RESOLUTION']))

        mesh_scale = metadata_panel.row()
        mesh_scale.label('Current Scale: ')
        mesh_scale.label('{:9,.2f} m/post'.format(obj['MESH_SCALE']))

        dtm_scale = metadata_panel.row()
        dtm_scale.label('Original Scale: ')
        dtm_scale.label('{:9,.2f} m/post'.format(obj['MAP_SCALE']))

        return {'FINISHED'}
Esempio n. 19
0
class MaterialMorphData(PropertyGroup):
    """
    """
    related_mesh = StringProperty(
        name='Related Mesh',
        description=
        'Stores a reference to the mesh where this morph data belongs to',
        set=_set_related_mesh,
        get=_get_related_mesh,
    )
    offset_type = EnumProperty(name='Offset Type',
                               description='Select offset type',
                               items=[('MULT', 'Multiply', '', 0),
                                      ('ADD', 'Add', '', 1)],
                               default='ADD')
    material = StringProperty(
        name='Material',
        description='Target material',
        get=_get_material,
        set=_set_material,
    )

    material_id = IntProperty(
        name='Material ID',
        default=-1,
    )

    diffuse_color = FloatVectorProperty(
        name='Diffuse Color',
        description='Diffuse color',
        subtype='COLOR',
        size=4,
        soft_min=0,
        soft_max=1,
        precision=3,
        step=0.1,
        default=[0, 0, 0, 1],
    )

    specular_color = FloatVectorProperty(
        name='Specular Color',
        description='Specular color',
        subtype='COLOR',
        size=3,
        soft_min=0,
        soft_max=1,
        precision=3,
        step=0.1,
        default=[0, 0, 0],
    )

    shininess = FloatProperty(
        name='Reflect',
        description='Reflect',
        soft_min=0,
        soft_max=500,
        step=100.0,
        default=0.0,
    )

    ambient_color = FloatVectorProperty(
        name='Ambient Color',
        description='Ambient color',
        subtype='COLOR',
        size=3,
        soft_min=0,
        soft_max=1,
        precision=3,
        step=0.1,
        default=[0, 0, 0],
    )

    edge_color = FloatVectorProperty(
        name='Edge Color',
        description='Edge color',
        subtype='COLOR',
        size=4,
        soft_min=0,
        soft_max=1,
        precision=3,
        step=0.1,
        default=[0, 0, 0, 1],
    )

    edge_weight = FloatProperty(
        name='Edge Weight',
        description='Edge weight',
        soft_min=0,
        soft_max=2,
        step=0.1,
        default=0,
    )

    texture_factor = FloatVectorProperty(
        name='Texture factor',
        description='Texture factor',
        subtype='COLOR',
        size=4,
        soft_min=0,
        soft_max=1,
        precision=3,
        step=0.1,
        default=[0, 0, 0, 1],
    )

    sphere_texture_factor = FloatVectorProperty(
        name='Sphere Texture factor',
        description='Sphere texture factor',
        subtype='COLOR',
        size=4,
        soft_min=0,
        soft_max=1,
        precision=3,
        step=0.1,
        default=[0, 0, 0, 1],
    )

    toon_texture_factor = FloatVectorProperty(
        name='Toon Texture factor',
        description='Toon texture factor',
        subtype='COLOR',
        size=4,
        soft_min=0,
        soft_max=1,
        precision=3,
        step=0.1,
        default=[0, 0, 0, 1],
    )
Esempio n. 20
0
class UvPackmasterPreferences(AddonPreferences):
    bl_idname = __package__

    # Supporeted features
    FEATURE_demo: BoolProperty(name='', description='', default=False)

    FEATURE_island_rotation: BoolProperty(name='',
                                          description='',
                                          default=False)

    FEATURE_overlap_check: BoolProperty(name='', description='', default=False)

    FEATURE_packing_depth: BoolProperty(name='', description='', default=False)

    FEATURE_heuristic_search: BoolProperty(name='',
                                           description='',
                                           default=False)

    FEATURE_advanced_heuristic: BoolProperty(name='',
                                             description='',
                                             default=False)

    FEATURE_pack_ratio: BoolProperty(name='', description='', default=False)

    FEATURE_pack_to_others: BoolProperty(name='',
                                         description='',
                                         default=False)

    FEATURE_grouped_pack: BoolProperty(name='', description='', default=False)

    FEATURE_lock_overlapping: BoolProperty(name='',
                                           description='',
                                           default=False)

    FEATURE_self_intersect_processing: BoolProperty(name='',
                                                    description='',
                                                    default=False)

    FEATURE_validation: BoolProperty(name='', description='', default=False)

    platform_supported: BoolProperty(name='', description='', default=True)

    not_supported_message: StringProperty(name='', description='', default='')

    label_message: StringProperty(name='', description='', default='')

    write_to_file: BoolProperty(name='Write UV data to file',
                                description='',
                                default=False)

    simplify_disable: BoolProperty(name='Simplify Disable',
                                   description='',
                                   default=False)

    benchmark: BoolProperty(name='Benchmark', description='', default=False)

    multithreaded: BoolProperty(name='Mulithreaded',
                                description='',
                                default=True)

    overlap_check: BoolProperty(
        name='Automatic Overlap Check',
        description=
        'Automatically check for overlapping islands after packing is done',
        default=True)

    area_measure: BoolProperty(
        name='Automatic Area Measurement',
        description='Automatically measure islands area after packing is done',
        default=True)

    iterations: IntProperty(
        name='Iterations',
        description=
        'Number describing how exact the algorithm will be when searching for island placement. Too low value may cause islands to overlap',
        default=200,
        min=10,
        max=10000)

    margin: FloatProperty(name='Margin',
                          description='Margin to apply during packing',
                          default=0.005,
                          precision=3)

    rot_enable: BoolProperty(
        name='Rotation Enable',
        description=
        'Allow the packer to rotate islands in order to achieve better result',
        default=True)

    prerot_disable: BoolProperty(
        name='Pre-Rotation Disable',
        description=
        'Disable the initial rotatation of islands before generating other orientations. The pre-rotation operation usually optimizes packing, use this option only if you have a good reason',
        default=False)

    postscale_disable: BoolProperty(
        name='Post-Scaling Disable',
        description=
        'Do not scale islands after packing in order to fit them into unit UV square. Enabling this option is not recommended in most cases',
        default=False)

    rot_step: IntProperty(
        name='Rotation Step',
        description="Rotation step in degrees to apply during packing",
        default=90,
        min=0,
        max=180)

    packing_depth: IntProperty(name='Packing Depth',
                               description='',
                               default=1,
                               min=1,
                               max=100)

    tex_ratio: BoolProperty(
        name='Use Texture Ratio',
        description=
        'Take into consideration the ratio of the active texture dimensions during packing. WARNING: make sure only one UV editor is opened in the Blender interface when using this option, otherwise the result is undefined',
        default=False)

    pack_to_others: BoolProperty(
        name='Pack To Others',
        description=
        'Add selected islands into those already packed in the unit UV square (no scaling will be applied)',
        default=False)

    grouped_pack: BoolProperty(
        name='Group Islands (Experimental)',
        description=
        "Make sure islands belonging to the same group are packed together. Island groups are defined by the 'Grouping Method' parameter. This feature is experimental: especially it can block when used together with 'Pack To Others' option in case no appropriate place is found for an island in the unit UV square. In such situation simply press ESC in order to cancel the process. For some UV layouts it is required to use the 'Heuristic Search' option in order to obtain a decent result from the grouped packing",
        default=False)

    grouping_method: EnumProperty(items=((str(UvGroupingMethod.EXTERNAL),
                                          'Material', ''),
                                         (str(UvGroupingMethod.SIMILARITY),
                                          'Similarity', '')),
                                  name="Grouping Method",
                                  description="Grouping method to use")

    lock_overlapping: BoolProperty(
        name='Lock Overlapping',
        description='Treat overlapping islands as a single island',
        default=False)

    extended_topo_analysis: BoolProperty(
        name='Extended Topology Analysis',
        description=
        "Use the extended method of topology analysis if basic method fails for a particular island. If add-on reports invalid topology for an island you can enable this option in order to force it to use more sophisticated algorithm and try to process the island anyway. WARNING: enabling this option is not recommended in most cases - if the basic method reports the invalid topology error it probably means that you should verify your topology and fix it. If you enable this option the add-on may not notify you about such issues in your UV map",
        default=False)

    allow_self_intersect: BoolProperty(
        name='Process Self-Intersecting UV Faces',
        description=
        "With this option enabled add-on will try to process self-intersecting UV faces during the extended topology analysis procedure",
        default=False)

    heuristic_search_time: IntProperty(
        name='Heuristic Search Time',
        description=
        "The time in seconds the add-on will spend searching the optimal packing solution using the heuristic algorithm. Value '0' means the feature is disabled. This feature is most useful when a single packing pass doesn't take much time (a few seconds). Use it with a limited number of islands and with limited island orientations considered ('Rotation Step' == 90). The current heuristic algorithm is most efficient for packing UV maps containing limited number of big islands of irregular shape. Before doing a long search it is recommended to run a single packing pass in order to determine whether overlaps are not likely to happen for given 'Iterations' and 'Margin' parameters",
        default=0,
        min=0,
        max=1000)

    advanced_heuristic: BoolProperty(
        name='Advanced Heuristic',
        description=
        "Use advanced methods during a heuristic search. With this option enabled add-on will examine a broader set of solutions when searching for an optimal one. As the number of solutions to check is much bigger it is recommended to use longer search times in this mode. Note that in many cases this method provides best results with 'Rotation Step' set to a large value (e.g. 90 degress) because such setting considerably increses the number of packing iterations which can be performed in a given time",
        default=False)

    similarity_threshold: FloatProperty(
        name='Similarity Threshold',
        description=
        "A greater value of this parameter means islands will be more likely recognized as a similar in shape. '0.5' is a good threshold value to start with. Accuracy of the similar islands detection also depends on other factors: 1. 'Rotation Step' paramter: the lower rotation step value the better accuracy of the operation. Rotation step set to 90 should be sufficient in most cases though. 2. 'Iterations' paramter: more iterations means better accuracy. 200 iterations is a sufficient value in most cases. This value should be increased in the first place if the similarity detection returns incorrect results (especially when dealing with really small islands).",
        default=0.5,
        min=0.0,
        precision=3)

    seed: IntProperty(name='Seed', description='', default=0, min=0, max=10000)

    test_param: IntProperty(name='Test Parameter',
                            description='',
                            default=0,
                            min=0,
                            max=10000)
 def register(cls):
     cls.bytes = FloatProperty(
             default=-1.0, 
             get=lambda self: self._get_bytes(),
             set=lambda self, value: self._set_bytes(value),
             )
Esempio n. 22
0
class SvAdaptivePlotCurveNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Adaptive Plot Curve
    Tooltip: Adaptive Plot Curve
    """
    bl_idname = 'SvAdaptivePlotCurveNode'
    bl_label = 'Adaptive Plot Curve'
    bl_icon = 'CURVE_NCURVE'

    sample_size: IntProperty(name="Segments",
                             default=50,
                             min=3,
                             update=updateNode)

    @throttle_and_update_node
    def update_sockets(self, context):
        self.inputs['Seed'].hide_safe = not self.random
        self.inputs['Count'].hide_safe = self.gen_mode != 'TOTAL'
        self.inputs['MinPpe'].hide_safe = self.gen_mode == 'TOTAL'
        self.inputs['MaxPpe'].hide_safe = self.gen_mode == 'TOTAL'

    modes = [('TOTAL', "Total count",
              "Specify total number of points to generate", 0),
             ('SEGMENT', "Per segment",
              "Specify minimum and maximum number of points per segment", 1)]

    gen_mode: EnumProperty(name="Points count",
                           items=modes,
                           default='TOTAL',
                           update=update_sockets)

    min_ppe: IntProperty(
        name="Min per segment",
        description=
        "Minimum number of new points per regular sampling interval",
        min=0,
        default=0,
        update=updateNode)

    max_ppe: IntProperty(
        name="Max per segment",
        description=
        "Minimum number of new points per regular sampling interval",
        min=1,
        default=5,
        update=updateNode)

    count: IntProperty(
        name="Count",
        description=
        "Total number of points; NOTE: with Random mode enabled, actual number of generated points can be smaller than specified here",
        min=2,
        default=50,
        update=updateNode)

    random: BoolProperty(
        name="Random",
        description=
        "Distribute points randomly; NOTE: in this mode, if Total Count is specified, actual number of generated points can be less than specified",
        default=False,
        update=update_sockets)

    seed: IntProperty(name="Seed",
                      description="Random Seed value",
                      default=0,
                      update=updateNode)

    by_curvature: BoolProperty(name="By Curvature",
                               default=True,
                               update=updateNode)

    by_length: BoolProperty(name="By Length", default=False, update=updateNode)

    curvature_clip: FloatProperty(
        name="Clip Curvature",
        description=
        "Do not consider curvature values bigger than specified one; set to 0 to consider all curvature values",
        default=100,
        min=0,
        update=updateNode)

    def draw_buttons(self, context, layout):
        row = layout.row(align=True)
        row.prop(self, 'by_curvature', toggle=True)
        row.prop(self, 'by_length', toggle=True)
        layout.prop(self, 'gen_mode')
        layout.prop(self, 'random', toggle=True)

    def draw_buttons_ext(self, context, layout):
        self.draw_buttons(context, layout)
        if self.by_curvature:
            layout.prop(self, 'curvature_clip')

    def sv_init(self, context):
        self.inputs.new('SvCurveSocket', "Curve")
        self.inputs.new('SvStringsSocket',
                        "Segments").prop_name = 'sample_size'
        self.inputs.new('SvStringsSocket', "MinPpe").prop_name = 'min_ppe'
        self.inputs.new('SvStringsSocket', "MaxPpe").prop_name = 'max_ppe'
        self.inputs.new('SvStringsSocket', "Count").prop_name = 'count'
        self.inputs.new('SvStringsSocket', "Seed").prop_name = 'seed'
        self.outputs.new('SvVerticesSocket', "Vertices")
        self.outputs.new('SvStringsSocket', "Edges")
        self.outputs.new('SvStringsSocket', "T")
        self.update_sockets(context)

    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        curve_s = self.inputs['Curve'].sv_get()
        curve_s = ensure_nesting_level(curve_s, 2, data_types=(SvCurve, ))
        samples_s = self.inputs['Segments'].sv_get()
        count_s = self.inputs['Count'].sv_get()
        min_ppe_s = self.inputs['MinPpe'].sv_get()
        max_ppe_s = self.inputs['MaxPpe'].sv_get()
        seed_s = self.inputs['Seed'].sv_get()

        verts_out = []
        edges_out = []
        ts_out = []
        inputs = zip_long_repeat(curve_s, samples_s, min_ppe_s, max_ppe_s,
                                 count_s, seed_s)
        for curves, samples_i, min_ppe_i, max_ppe_i, count_i, seed_i in inputs:
            objects = zip_long_repeat(curves, samples_i, min_ppe_i, max_ppe_i,
                                      count_i, seed_i)
            for curve, samples, min_ppe, max_ppe, count, seed in objects:
                if not self.random:
                    seed = None
                if self.gen_mode == 'SEGMENT':
                    controller = MinMaxPerSegment(min_ppe, max_ppe)
                else:
                    controller = TotalCount(count)
                new_t = populate_curve(curve,
                                       samples + 1,
                                       by_length=self.by_length,
                                       by_curvature=self.by_curvature,
                                       population_controller=controller,
                                       curvature_clip=self.curvature_clip,
                                       seed=seed)
                n = len(new_t)
                ts_out.append(new_t.tolist())
                new_verts = curve.evaluate_array(new_t).tolist()
                verts_out.append(new_verts)
                new_edges = [(i, i + 1) for i in range(n - 1)]
                edges_out.append(new_edges)

        self.outputs['Vertices'].sv_set(verts_out)
        self.outputs['Edges'].sv_set(edges_out)
        self.outputs['T'].sv_set(ts_out)
Esempio n. 23
0
class ExportUVLayout(bpy.types.Operator):
    """Export UV layout to file"""

    bl_idname = "uv.export_layout"
    bl_label = "Export UV Layout"
    bl_options = {'REGISTER', 'UNDO'}

    filepath: StringProperty(
        subtype='FILE_PATH',
    )
    export_all: BoolProperty(
        name="All UVs",
        description="Export all UVs in this mesh (not just visible ones)",
        default=False,
    )
    modified: BoolProperty(
        name="Modified",
        description="Exports UVs from the modified mesh",
        default=False,
    )
    mode: EnumProperty(
        items=(
            ('SVG', "Scalable Vector Graphic (.svg)",
             "Export the UV layout to a vector SVG file"),
            ('EPS', "Encapsulate PostScript (.eps)",
             "Export the UV layout to a vector EPS file"),
            ('PNG', "PNG Image (.png)",
             "Export the UV layout to a bitmap image"),
        ),
        name="Format",
        description="File format to export the UV layout to",
        default='PNG',
    )
    size: IntVectorProperty(
        size=2,
        default=(1024, 1024),
        min=8, max=32768,
        description="Dimensions of the exported file",
    )
    opacity: FloatProperty(
        name="Fill Opacity",
        min=0.0, max=1.0,
        default=0.25,
        description="Set amount of opacity for exported UV layout",
    )

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

    def invoke(self, context, event):
        self.size = self.get_image_size(context)
        self.filepath = self.get_default_file_name(context) + "." + self.mode.lower()
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}

    def get_default_file_name(self, context):
        AMOUNT = 3
        objects = list(self.iter_objects_to_export(context))
        name = " ".join(sorted([obj.name for obj in objects[:AMOUNT]]))
        if len(objects) > AMOUNT:
            name += " and more"
        return name

    def check(self, context):
        if any(self.filepath.endswith(ext) for ext in (".png", ".eps", ".svg")):
            self.filepath = self.filepath[:-4]

        ext = "." + self.mode.lower()
        self.filepath = bpy.path.ensure_ext(self.filepath, ext)
        return True

    def execute(self, context):
        obj = context.active_object
        is_editmode = (obj.mode == 'EDIT')
        if is_editmode:
            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

        filepath = self.filepath
        filepath = bpy.path.ensure_ext(filepath, "." + self.mode.lower())

        meshes = list(self.iter_meshes_to_export(context))
        polygon_data = list(self.iter_polygon_data_to_draw(context, meshes))
        different_colors = set(color for _, color in polygon_data)
        if self.modified:
          depsgraph = context.evaluated_depsgraph_get()
          for obj in self.iter_objects_to_export(context):
              obj_eval = obj.evaluated_get(depsgraph)
              obj_eval.to_mesh_clear()

        export = self.get_exporter()
        export(filepath, polygon_data, different_colors, self.size[0], self.size[1], self.opacity)

        if is_editmode:
            bpy.ops.object.mode_set(mode='EDIT', toggle=False)

        return {'FINISHED'}

    def iter_meshes_to_export(self, context):
        depsgraph = context.evaluated_depsgraph_get()
        for obj in self.iter_objects_to_export(context):
            if self.modified:
                yield obj.evaluated_get(depsgraph).to_mesh()
            else:
                yield obj.data

    @staticmethod
    def iter_objects_to_export(context):
        for obj in {*context.selected_objects, context.active_object}:
            if obj.type != 'MESH':
                continue
            mesh = obj.data
            if mesh.uv_layers.active is None:
                continue
            yield obj

    @staticmethod
    def currently_image_image_editor(context):
        return isinstance(context.space_data, bpy.types.SpaceImageEditor)

    def get_currently_opened_image(self, context):
        if not self.currently_image_image_editor(context):
            return None
        return context.space_data.image

    def get_image_size(self, context):
        # fallback if not in image context
        image_width = self.size[0]
        image_height = self.size[1]

        # get size of "active" image if some exist
        image = self.get_currently_opened_image(context)
        if image is not None:
            width, height = image.size
            if width and height:
                image_width = width
                image_height = height

        return image_width, image_height

    def iter_polygon_data_to_draw(self, context, meshes):
        for mesh in meshes:
            uv_layer = mesh.uv_layers.active.data
            for polygon in mesh.polygons:
                if self.export_all or polygon.select:
                    start = polygon.loop_start
                    end = start + polygon.loop_total
                    uvs = tuple(tuple(uv.uv) for uv in uv_layer[start:end])
                    yield (uvs, self.get_polygon_color(mesh, polygon))

    @staticmethod
    def get_polygon_color(mesh, polygon, default=(0.8, 0.8, 0.8)):
        if polygon.material_index < len(mesh.materials):
            material = mesh.materials[polygon.material_index]
            if material is not None:
                return tuple(material.diffuse_color)[:3]
        return default

    def get_exporter(self):
        if self.mode == 'PNG':
            from . import export_uv_png
            return export_uv_png.export
        elif self.mode == 'EPS':
            from . import export_uv_eps
            return export_uv_eps.export
        elif self.mode == 'SVG':
            from . import export_uv_svg
            return export_uv_svg.export
        else:
            assert False
Esempio n. 24
0
class VertexChamfer(Operator):
    bl_idname = "mesh.vertex_chamfer"
    bl_label = "Chamfer Vertex"
    bl_description = "Tri chamfer selected vertices"
    bl_options = {'REGISTER', 'UNDO'}

    factor = FloatProperty(name="Factor",
                           description="Size of the Champfer",
                           default=0.1,
                           min=0.0,
                           soft_max=1.0)
    relative = BoolProperty(
        name="Relative",
        description="If Relative, Champfer size is relative to the edge length",
        default=True)
    dissolve = BoolProperty(
        name="Remove",
        description="Remove/keep the original selected vertices\n"
        "Remove creates a new triangle face between the Champfer edges,\n"
        "similar to the Dissolve Vertices operator",
        default=True)
    displace = FloatProperty(
        name="Displace",
        description="Active only if Remove option is disabled\n"
        "Displaces the original selected vertices along the normals\n"
        "defined by the Champfer edges",
        soft_min=-5.0,
        soft_max=5.0)

    @classmethod
    def poll(self, context):
        return (context.active_object.type == 'MESH'
                and context.mode == 'EDIT_MESH')

    def draw(self, context):
        layout = self.layout
        layout.prop(self,
                    "factor",
                    text="Distance" if self.relative else "Factor")
        sub = layout.row()
        sub.prop(self, "relative")
        sub.prop(self, "dissolve")
        if not self.dissolve:
            layout.prop(self, "displace")

    def execute(self, context):
        ob = context.active_object
        me = ob.data
        bm = bmesh.from_edit_mesh(me)

        bm.select_flush(True)

        fac = self.factor
        rel = self.relative
        dissolve = self.dissolve
        displace = self.displace

        for v in bm.verts:
            v.tag = False

        # Loop over edges to find those with both verts selected
        for e in bm.edges[:]:
            e.tag = e.select
            if not e.select:
                continue
            elen = e.calc_length()
            val = fac if rel else fac / elen
            val = min(val, 0.5)
            # Loop over the verts of the edge to split
            for v in e.verts:
                # if val == 0.5 and e.other_vert(v).tag:
                #    continue
                en, vn = bmesh.utils.edge_split(e, v, val)
                en.tag = vn.tag = True
                val = 1.0 if val == 1.0 else val / (1.0 - val)

        # Get all verts which are selected but not created previously
        verts = [v for v in bm.verts if v.select and not v.tag]

        # Loop over all verts to split their linked edges
        for v in verts:
            for e in v.link_edges[:]:
                if e.tag:
                    continue
                elen = e.calc_length()
                val = fac if rel else fac / elen
                bmesh.utils.edge_split(e, v, val)

            # Loop over all the loops of the vert
            for l in v.link_loops:
                # Split the face
                bmesh.utils.face_split(l.face, l.link_loop_next.vert,
                                       l.link_loop_prev.vert)

            # Remove the vert or displace otherwise
            if dissolve:
                bmesh.utils.vert_dissolve(v)
            else:
                v.co += displace * v.normal

        me.calc_tessface()

        return {'FINISHED'}
Esempio n. 25
0
class SvVoronoiOnSolidNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Voronoi Solid
    Tooltip: Generate Voronoi diagram on the Solid object
    """
    bl_idname = 'SvVoronoiOnSolidNode'
    bl_label = 'Voronoi on Solid'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_VORONOI'

    modes = [
            ('SURFACE', "Surface", "Generate regions of Voronoi diagram on the surface of the solid", 0),
            ('VOLUME', "Volume", "Split volume of the solid body into regions of Voronoi diagram", 2)
        ]

    mode : EnumProperty(
        name = "Mode",
        items = modes,
        update = updateNode)
    
    accuracy : IntProperty(
            name = "Accuracy",
            description = "Accuracy for mesh to solid transformation",
            default = 6,
            min = 1,
            update = updateNode)

    inset : FloatProperty(
        name = "Inset",
        min = 0.0, max = 1.0,
        default = 0.1,
        update = updateNode)

    scale_types = [
            ('SITE', "Site", "Scale each region relative to corresponding site location", 0),
            ('MEAN', "Barycenter", "Scale each region relative to it's barycenter, i.e. average location of it's vertices", 1)
        ]

    scale_center : EnumProperty(
            name = "Scale around",
            description = "Defines the center, along which the regions of Voronoi diagram are to be scaled in order to make inset",
            items = scale_types,
            default = 'SITE',
            update = updateNode)

    flat_output : BoolProperty(
        name = "Flat output",
        description = "If checked, output single flat list of fragments for all input solids; otherwise, output a separate list of fragments for each solid.",
        default = True,
        update = updateNode)

    def sv_init(self, context):
        self.inputs.new('SvSolidSocket', 'Solid')
        self.inputs.new('SvVerticesSocket', "Sites")
        self.inputs.new('SvStringsSocket', "Inset").prop_name = 'inset'
        self.outputs.new('SvSolidSocket', "InnerSolid")
        self.outputs.new('SvSolidSocket', "OuterSolid")

    def draw_buttons(self, context, layout):
        layout.prop(self, "mode")
        layout.prop(self, "flat_output")

    def draw_buttons_ext(self, context, layout):
        self.draw_buttons(context, layout)
        layout.prop(self, 'scale_center')
        layout.prop(self, 'accuracy')

    def scale_cells(self, verts, sites, insets, precision):
        if all(i == 0.0 for i in insets):
            return verts
        verts_out = []
        for vs, site, inset in zip(verts, sites, insets):
            if inset >= 1.0:
                continue
            if self.scale_center == 'SITE':
                c = site
            else:
                c = center(vs)
            vs1 = scale_relative(vs, c, 1.0 - inset)
            if diameter(vs1, axis=None) <= precision:
                continue
            verts_out.append(vs1)
        return verts_out

    def process(self):

        if not any(socket.is_linked for socket in self.outputs):
            return

        solid_in = self.inputs['Solid'].sv_get()
        sites_in = self.inputs['Sites'].sv_get()
        inset_in = self.inputs['Inset'].sv_get()

        solid_in = ensure_nesting_level(solid_in, 2, data_types=(Part.Shape,))
        input_level = get_data_nesting_level(sites_in)
        sites_in = ensure_nesting_level(sites_in, 4)
        inset_in = ensure_min_nesting(inset_in, 2)

        nested_output = input_level > 3
        need_inner = self.outputs['InnerSolid'].is_linked
        need_outer = self.outputs['OuterSolid'].is_linked

        precision = 10 ** (-self.accuracy)

        inner_fragments_out = []
        outer_fragments_out = []
        for params in zip_long_repeat(solid_in, sites_in, inset_in):
            new_inner_fragments = []
            new_outer_fragments = []
            for solid, sites, inset in zip_long_repeat(*params):
                verts, edges, faces = voronoi_on_solid(solid, sites,
                            do_clip=True, clipping=None)

                if isinstance(inset, list):
                    inset = repeat_last_for_length(inset, len(sites))
                else:
                    inset = [inset for i in range(len(sites))]
                verts = self.scale_cells(verts, sites, inset, precision)
                fragments = [svmesh_to_solid(vs, fs, precision, method=BMESH, remove_splitter=False) for vs, fs in zip(verts, faces)]

                if self.mode == 'SURFACE':
                    if solid.Shells:
                        shell = solid.Shells[0]
                    else:
                        shell = Part.Shell(solid.Faces)
                    src = shell
                else: # VOLUME
                    src = solid

                if need_inner:
                    inner = [src.common(fragment) for fragment in fragments]
                    if self.flat_output:
                        new_inner_fragments.extend(inner)
                    else:
                        new_inner_fragments.append(inner)

                if need_outer:
                    outer = [src.cut(fragments)]
                    if self.flat_output:
                        new_outer_fragments.extend(outer)
                    else:
                        new_outer_fragments.append(outer)

            if nested_output:
                inner_fragments_out.append(new_inner_fragments)
                outer_fragments_out.append(new_outer_fragments)
            else:
                inner_fragments_out.extend(new_inner_fragments)
                outer_fragments_out.extend(new_outer_fragments)

        self.outputs['InnerSolid'].sv_set(inner_fragments_out)
        self.outputs['OuterSolid'].sv_set(outer_fragments_out)
Esempio n. 26
0
class SvEvolverNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Genetics algorithm
    Tooltip: Advanced node to find the best solution to a defined problem using a genetics algorithm technic
    """
    bl_idname = 'SvEvolverNode'
    bl_label = 'Evolver'
    bl_icon = 'RNA'

    def props_changed(self, context):
        if self.node_id in evolver_mem:
            self.info_label = "Props changed since execution"

    def props_changed_and_update(self, context):
        if self.node_id in evolver_mem:
            self.info_label = "Props changed since execution"
        updateNode(self, context)

    output_all: BoolProperty(
        name="Output all iterations",
        description="Output all iterations data or just last generation",
        default=False,
        update=updateNode)
    genotype: EnumProperty(
        name="Genotype",
        description="Define frame containing genotype or use all number nodes",
        items=get_framenodes,
        update=props_changed)
    mode_items = [
        ('MAX', 'Maximum', '', 0),
        ('MIN', 'Minimum', '', 1),
    ]
    mode: EnumProperty(name="Mode",
                       description="Set Fitness as maximun or as minimum",
                       items=mode_items,
                       update=props_changed)
    population_n: IntProperty(default=20,
                              name='Population amount',
                              description='Number of agents',
                              update=props_changed)
    iterations: IntProperty(default=1,
                            min=1,
                            name='Iterations',
                            description='Iterations',
                            update=props_changed)

    r_seed: IntProperty(default=1,
                        min=1,
                        name='Random Seed',
                        description='Random Seed',
                        update=props_changed)

    mutation: FloatProperty(name="Mutation",
                            description="Mutation Factor",
                            default=0.01,
                            min=0,
                            update=props_changed)
    fitness_goal: FloatProperty(
        name="Goal",
        description="Stop if fitness achieves or improves this value",
        default=0.01,
        update=props_changed)
    use_fitness_goal: BoolProperty(
        name="Stop on Goal",
        description="Stop evolving if defined value is achieved or improved",
        default=False,
        update=props_changed_and_update)
    fitness_booster: IntProperty(
        name="Fitness boost",
        description=
        "Fittest population will be more probable to be choosen (power)",
        default=3,
        min=1,
        update=props_changed)

    max_time: IntProperty(default=10,
                          min=1,
                          name='Max Seconds',
                          description='Maximum execution Time',
                          update=props_changed)

    info_label: StringProperty(default="Not Executed")

    def sv_init(self, context):
        self.width = 200
        self.inputs.new('SvStringsSocket', 'Fitness')
        self.outputs.new('SvStringsSocket', 'Genes')
        self.outputs.new('SvStringsSocket', 'Population')
        self.outputs.new('SvStringsSocket', 'Fitness')

    def draw_buttons(self, context, layout):
        layout.label(text=self.info_label)
        genotype_row = layout.split(factor=0.4, align=False)
        genotype_row.label(text="Genotype:")
        genotype_row.prop(self, "genotype", text="")
        mode_row = layout.split(factor=0.4, align=False)
        mode_row.label(text="Mode:")
        mode_row.prop(self, "mode", text="")
        layout.prop(self, "population_n")
        layout.prop(self, "iterations")
        layout.prop(self, "r_seed")
        layout.prop(self, "fitness_booster")
        layout.prop(self, "mutation")
        layout.prop(self, "max_time")
        if self.use_fitness_goal:
            goal_row = layout.row(align=True)
            goal_row.prop(self, "use_fitness_goal", text="")
            goal_row.prop(self, "fitness_goal")
        else:
            layout.prop(self, "use_fitness_goal")
        self.wrapper_tracked_ui_draw_op(layout,
                                        "node.evolver_run",
                                        icon='RNA',
                                        text="RUN")
        if self.node_id in evolver_mem:
            self.wrapper_tracked_ui_draw_op(layout,
                                            "node.evolver_set_fittest",
                                            icon='RNA_ADD',
                                            text="Set Fittest")
            layout.prop(self, "output_all")

    def process(self):

        if self.node_id in evolver_mem and 'genes' in evolver_mem[
                self.node_id]:
            outputs = self.outputs
            outputs['Genes'].sv_set(evolver_mem[self.node_id]['genes'])
            if self.output_all:
                outputs['Population'].sv_set(
                    evolver_mem[self.node_id]['population_all'])
                outputs['Fitness'].sv_set(
                    evolver_mem[self.node_id]['fitness_all'])
            else:
                outputs['Population'].sv_set(
                    [evolver_mem[self.node_id]['population']])
                outputs['Fitness'].sv_set(
                    [evolver_mem[self.node_id]['fitness']])
        else:
            self.info_label = "Not Executed"
            for s in self.outputs:
                s.sv_set([])
Esempio n. 27
0
class MIDIAddonPreferences(AddonPreferences):
    ''' ICON Prefs '''
    bl_idname = __name__

    def enum_previews_from_directory_items(self, context):
        """EnumProperty callback"""
        enum_items = []

        if context is None:
            return enum_items

        # Get the preview collection (defined in register func).
        pcoll = preview_collections["main"]

        i = 0
        for key, thumb in pcoll.items():
            if not key.startswith(self.collection):
                continue

            # lstrip gave wierd results
            name = key.replace("%s_" % self.collection, "")
            enum_items.append((name, name, "", thumb.icon_id, 2**i))
            i += 1

        #pcoll.sd_icons = enum_items
        #pcoll.sd_icons_dir = directory
        return enum_items

    collection = EnumProperty(
        items=[(n, n, n) for n in subs],
        name="Item Collections",
        description="Icons from folder",
        default="main",
    )
    icon_dir = StringProperty(
        name="Icon Directory",
        description="Directory SoundDrivers Uses to store icons",
        subtype='DIR_PATH',
        default=icon_dir,
    )

    icon_preview_zoom = FloatProperty(min=0.5, max=5.0, default=5.0)
    sd_icons = EnumProperty(items=enum_previews_from_directory_items, )

    def draw(self, context):
        layout = self.layout
        # icon support
        # TODO change collection enum
        # TODO add a new icon
        # TODO copy icon code to clipboard
        for collection in preview_collections:
            layout.template_icon_view(self,
                                      "sd_icons",
                                      show_labels=True,
                                      scale=self.icon_preview_zoom)
            row = layout.row()
            split = row.split(percentage=0.4)
            # TODO fix this collection nightmare
            sub = split.row(align=True)
            sub.prop(self, "collection", text="")
            sub.prop(self, "sd_icons", expand=False, text="")
            split.alignment = 'LEFT'
            for key, icon in preview_collections[collection].items():
                if not key.startswith(self.collection):
                    continue
                split.label("", icon_value=icon.icon_id)
            '''
class Curveaceous_galore(bpy.types.Operator):
    """Add many types of curves"""
    bl_idname = "mesh.curveaceous_galore"
    bl_label = "Curve Profiles"
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}

    # align_matrix for the invoke
    align_matrix = None

    #### general properties
    ProfileTypes = [('Profile', 'Profile', 'Profile'),
                    ('Miscellaneous', 'Miscellaneous', 'Miscellaneous'),
                    ('Flower', 'Flower', 'Flower'), ('Star', 'Star', 'Star'),
                    ('Arc', 'Arc', 'Arc'),
                    ('Cogwheel', 'Cogwheel', 'Cogwheel'),
                    ('Nsided', 'Nsided', 'Nsided'),
                    ('Splat', 'Splat', 'Splat'),
                    ('Cycloid', 'Cycloid', 'Cycloid'),
                    ('Helix', 'Helix (3D)', 'Helix')]
    ProfileType = EnumProperty(name="Type",
                               description="Form of Curve to create",
                               items=ProfileTypes)
    SplineTypes = [('POLY', 'Poly', 'POLY'), ('NURBS', 'Nurbs', 'NURBS'),
                   ('BEZIER', 'Bezier', 'BEZIER')]
    outputType = EnumProperty(name="Output splines",
                              description="Type of splines to output",
                              items=SplineTypes)

    #### Curve Options
    shapeItems = [('2D', '2D', '2D'), ('3D', '3D', '3D')]
    shape = EnumProperty(name="2D / 3D",
                         items=shapeItems,
                         description="2D or 3D Curve")
    use_cyclic_u = BoolProperty(name="Cyclic",
                                default=True,
                                description="make curve closed")
    endp_u = BoolProperty(name="use_endpoint_u",
                          default=True,
                          description="stretch to endpoints")
    order_u = IntProperty(name="order_u",
                          default=4,
                          min=2,
                          soft_min=2,
                          max=6,
                          soft_max=6,
                          description="Order of nurbs spline")
    bezHandles = [('VECTOR', 'Vector', 'VECTOR'),
                  ('AUTOMATIC', 'Auto', 'AUTOMATIC')]
    handleType = EnumProperty(name="Handle type",
                              description="bezier handles type",
                              items=bezHandles)

    #### ProfileCurve properties
    ProfileCurveType = IntProperty(name="Type",
                                   min=1,
                                   soft_min=1,
                                   max=5,
                                   soft_max=5,
                                   default=1,
                                   description="Type of ProfileCurve")
    ProfileCurvevar1 = FloatProperty(name="var_1",
                                     default=0.25,
                                     description="var1 of ProfileCurve")
    ProfileCurvevar2 = FloatProperty(name="var_2",
                                     default=0.25,
                                     description="var2 of ProfileCurve")

    #### MiscCurve properties
    MiscCurveType = IntProperty(name="Type",
                                min=1,
                                soft_min=1,
                                max=6,
                                soft_max=6,
                                default=1,
                                description="Type of MiscCurve")
    MiscCurvevar1 = FloatProperty(name="var_1",
                                  default=1.0,
                                  description="var1 of MiscCurve")
    MiscCurvevar2 = FloatProperty(name="var_2",
                                  default=0.5,
                                  description="var2 of MiscCurve")
    MiscCurvevar3 = FloatProperty(name="var_3",
                                  default=0.1,
                                  min=0,
                                  soft_min=0,
                                  description="var3 of MiscCurve")

    #### Common properties
    innerRadius = FloatProperty(name="Inner radius",
                                default=0.5,
                                min=0,
                                soft_min=0,
                                description="Inner radius")
    middleRadius = FloatProperty(name="Middle radius",
                                 default=0.95,
                                 min=0,
                                 soft_min=0,
                                 description="Middle radius")
    outerRadius = FloatProperty(name="Outer radius",
                                default=1.0,
                                min=0,
                                soft_min=0,
                                description="Outer radius")

    #### Flower properties
    petals = IntProperty(name="Petals",
                         default=8,
                         min=2,
                         soft_min=2,
                         description="Number of petals")
    petalWidth = FloatProperty(name="Petal width",
                               default=2.0,
                               min=0.01,
                               soft_min=0.01,
                               description="Petal width")

    #### Star properties
    starPoints = IntProperty(name="Star points",
                             default=8,
                             min=2,
                             soft_min=2,
                             description="Number of star points")
    starTwist = FloatProperty(name="Twist", default=0.0, description="Twist")

    #### Arc properties
    arcSides = IntProperty(name="Arc sides",
                           default=6,
                           min=1,
                           soft_min=1,
                           description="Sides of arc")
    startAngle = FloatProperty(name="Start angle",
                               default=0.0,
                               description="Start angle")
    endAngle = FloatProperty(name="End angle",
                             default=90.0,
                             description="End angle")
    arcType = IntProperty(name="Arc type",
                          default=3,
                          min=1,
                          soft_min=1,
                          max=3,
                          soft_max=3,
                          description="Sides of arc")

    #### Cogwheel properties
    teeth = IntProperty(name="Teeth",
                        default=8,
                        min=2,
                        soft_min=2,
                        description="number of teeth")
    bevel = FloatProperty(name="Bevel",
                          default=0.5,
                          min=0,
                          soft_min=0,
                          max=1,
                          soft_max=1,
                          description="Bevel")

    #### Nsided property
    Nsides = IntProperty(name="Sides",
                         default=8,
                         min=3,
                         soft_min=3,
                         description="Number of sides")

    #### Splat properties
    splatSides = IntProperty(name="Splat sides",
                             default=24,
                             min=3,
                             soft_min=3,
                             description="Splat sides")
    splatScale = FloatProperty(name="Splat scale",
                               default=1.0,
                               min=0.0001,
                               soft_min=0.0001,
                               description="Splat scale")
    seed = IntProperty(name="Seed",
                       default=0,
                       min=0,
                       soft_min=0,
                       description="Seed")
    basis = IntProperty(name="Basis",
                        default=0,
                        min=0,
                        soft_min=0,
                        max=14,
                        soft_max=14,
                        description="Basis")

    #### Helix properties
    helixPoints = IntProperty(name="resolution",
                              default=100,
                              min=3,
                              soft_min=3,
                              description="resolution")
    helixHeight = FloatProperty(name="Height",
                                default=2.0,
                                min=0,
                                soft_min=0,
                                description="Helix height")
    helixStart = FloatProperty(name="Start angle",
                               default=0.0,
                               description="Helix start angle")
    helixEnd = FloatProperty(name="Endangle",
                             default=360.0,
                             description="Helix end angle")
    helixWidth = FloatProperty(name="Width",
                               default=1.0,
                               description="Helix width")
    helix_a = FloatProperty(name="var_1",
                            default=0.0,
                            description="Helix var1")
    helix_b = FloatProperty(name="var_2",
                            default=0.0,
                            description="Helix var2")

    #### Cycloid properties
    cycloPoints = IntProperty(name="Resolution",
                              default=100,
                              min=3,
                              soft_min=3,
                              description="Resolution")
    cyclo_d = FloatProperty(name="var_3",
                            default=1.5,
                            description="Cycloid var3")
    cycloType = IntProperty(name="Type",
                            default=0,
                            min=0,
                            soft_min=0,
                            max=0,
                            soft_max=0,
                            description="resolution")
    cyclo_a = FloatProperty(name="var_1",
                            default=5.0,
                            min=0.01,
                            soft_min=0.01,
                            description="Cycloid var1")
    cyclo_b = FloatProperty(name="var_2",
                            default=0.5,
                            min=0.01,
                            soft_min=0.01,
                            description="Cycloid var2")
    cycloStart = FloatProperty(name="Start angle",
                               default=0.0,
                               description="Cycloid start angle")
    cycloEnd = FloatProperty(name="End angle",
                             default=360.0,
                             description="Cycloid end angle")

    ##### DRAW #####
    def draw(self, context):
        layout = self.layout

        # general options
        col = layout.column()
        col.prop(self, 'ProfileType')
        col.label(text=self.ProfileType + " Options:")

        # options per ProfileType
        box = layout.box()
        if self.ProfileType == 'Profile':
            box.prop(self, 'ProfileCurveType')
            box.prop(self, 'ProfileCurvevar1')
            box.prop(self, 'ProfileCurvevar2')

        elif self.ProfileType == 'Miscellaneous':
            box.prop(self, 'MiscCurveType')
            box.prop(self, 'MiscCurvevar1', text='Width')
            box.prop(self, 'MiscCurvevar2', text='Height')
            if self.MiscCurveType == 5:
                box.prop(self, 'MiscCurvevar3', text='Rounded')

        elif self.ProfileType == 'Flower':
            box.prop(self, 'petals')
            box.prop(self, 'petalWidth')
            box.prop(self, 'innerRadius')
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Star':
            box.prop(self, 'starPoints')
            box.prop(self, 'starTwist')
            box.prop(self, 'innerRadius')
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Arc':
            box.prop(self, 'arcSides')
            box.prop(self, 'arcType')  # has only one Type?
            box.prop(self, 'startAngle')
            box.prop(self, 'endAngle')
            box.prop(self, 'innerRadius')  # doesn't seem to do anything
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Cogwheel':
            box.prop(self, 'teeth')
            box.prop(self, 'bevel')
            box.prop(self, 'innerRadius')
            box.prop(self, 'middleRadius')
            box.prop(self, 'outerRadius')

        elif self.ProfileType == 'Nsided':
            box.prop(self, 'Nsides')
            box.prop(self, 'outerRadius', text='Radius')

        elif self.ProfileType == 'Splat':
            box.prop(self, 'splatSides')
            box.prop(self, 'outerRadius')
            box.prop(self, 'splatScale')
            box.prop(self, 'seed')
            box.prop(self, 'basis')

        elif self.ProfileType == 'Helix':
            box.prop(self, 'helixPoints')
            box.prop(self, 'helixHeight')
            box.prop(self, 'helixWidth')
            box.prop(self, 'helixStart')
            box.prop(self, 'helixEnd')
            box.prop(self, 'helix_a')
            box.prop(self, 'helix_b')

        elif self.ProfileType == 'Cycloid':
            box.prop(self, 'cycloPoints')
            #box.prop(self, 'cycloType') # needs the other types first
            box.prop(self, 'cycloStart')
            box.prop(self, 'cycloEnd')
            box.prop(self, 'cyclo_a')
            box.prop(self, 'cyclo_b')
            box.prop(self, 'cyclo_d')

        col = layout.column()
        col.label(text="Output Curve Type:")
        col.row().prop(self, 'outputType', expand=True)
        col.label(text="Curve Options:")

        # output options
        box = layout.box()
        if self.outputType == 'NURBS':
            box.row().prop(self, 'shape', expand=True)
            #box.prop(self, 'use_cyclic_u')
            #box.prop(self, 'endp_u')
            box.prop(self, 'order_u')

        elif self.outputType == 'POLY':
            box.row().prop(self, 'shape', expand=True)
            #box.prop(self, 'use_cyclic_u')

        elif self.outputType == 'BEZIER':
            box.row().prop(self, 'shape', expand=True)
            box.row().prop(self, 'handleType', expand=True)
            #box.prop(self, 'use_cyclic_u')

    ##### POLL #####
    @classmethod
    def poll(cls, context):
        return context.scene != None

    ##### EXECUTE #####
    def execute(self, context):
        # turn off undo
        undo = context.user_preferences.edit.use_global_undo
        context.user_preferences.edit.use_global_undo = False

        # deal with 2D - 3D curve differences
        if self.ProfileType in ['Helix', 'Cycloid']:
            self.shape = '3D'
        #else:
        #self.shape = '2D'     # someone decide if we want this

        if self.ProfileType in ['Helix']:
            self.use_cyclic_u = False
        else:
            self.use_cyclic_u = True

        # main function
        main(context, self, self.align_matrix or Matrix())

        # restore pre operator undo state
        context.user_preferences.edit.use_global_undo = undo

        return {'FINISHED'}

    ##### INVOKE #####
    def invoke(self, context, event):
        # store creation_matrix
        self.align_matrix = align_matrix(context)
        self.execute(context)

        return {'FINISHED'}
class AddZFunctionSurface(Operator):
    bl_idname = "mesh.primitive_z_function_surface"
    bl_label = "Add Z Function Surface"
    bl_description = "Add a surface defined defined by a function z=f(x,y)"
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}

    equation: StringProperty(
                name="Z Equation",
                description="Equation for z=f(x,y)",
                default="1 - ( x**2 + y**2 )"
                )
    div_x: IntProperty(
                name="X Subdivisions",
                description="Number of vertices in x direction",
                default=16,
                min=3,
                max=256
                )
    div_y: IntProperty(
                name="Y Subdivisions",
                description="Number of vertices in y direction",
                default=16,
                min=3,
                max=256
                )
    size_x: FloatProperty(
                name="X Size",
                description="Size of the x axis",
                default=2.0,
                min=0.01,
                max=100.0,
                unit="LENGTH"
                )
    size_y: FloatProperty(
                name="Y Size",
                description="Size of the y axis",
                default=2.0,
                min=0.01,
                max=100.0,
                unit="LENGTH"
                )

    def execute(self, context):
        equation = self.equation
        div_x = self.div_x
        div_y = self.div_y
        size_x = self.size_x
        size_y = self.size_y

        verts = []
        faces = []

        delta_x = size_x / (div_x - 1)
        delta_y = size_y / (div_y - 1)
        start_x = -(size_x / 2.0)
        start_y = -(size_y / 2.0)

        edgeloop_prev = []

        if equation:
            try:
                expr_args = (
                    compile(equation, __file__, 'eval'),
                    {"__builtins__": None},
                    safe_dict)
            except:
                import traceback
                # WARNING is used to prevent the constant pop-up spam
                self.report({'WARNING'},
                            "Error parsing expression: {} "
                            "(Check the console for more info)".format(equation))
                print("\n[Add Z Function Surface]:\n\n", traceback.format_exc(limit=1))

                return {'CANCELLED'}

            for row_x in range(div_x):
                edgeloop_cur = []
                x = start_x + row_x * delta_x

                for row_y in range(div_y):
                    y = start_y + row_y * delta_y
                    z = 0.0

                    safe_dict['x'] = x
                    safe_dict['y'] = y

                    # Try to evaluate the equation.
                    try:
                        z = float(eval(*expr_args))
                    except:
                        import traceback
                        self.report({'WARNING'},
                                    "Error evaluating expression: {} "
                                    "(Check the console for more info)".format(equation))
                        print("\n[Add Z Function Surface]:\n\n", traceback.format_exc(limit=1))

                        return {'CANCELLED'}

                    edgeloop_cur.append(len(verts))
                    verts.append((x, y, z))

                if len(edgeloop_prev) > 0:
                    faces_row = createFaces(edgeloop_prev, edgeloop_cur)
                    faces.extend(faces_row)

                edgeloop_prev = edgeloop_cur

            base = create_mesh_object(context, verts, [], faces, "Z Function")
        else:
            self.report({'WARNING'}, "Z Equation - No expression is given")

            return {'CANCELLED'}

        return {'FINISHED'}
Esempio n. 30
0
class DMX_Model_Param(PropertyGroup):
    value: FloatProperty(name="DMX: Model Parameter", default=0)