Skip to content
Snippets Groups Projects
object_primitives.py 63.1 KiB
Newer Older
  • Learn to ignore specific revisions
  •         height = ob.pov.cone_height
    
    
        zc = height / 2
        zb = -zc
        angle = 2 * pi / seg
        t = 0
        for i in range(seg):
            xb = base * cos(t)
            yb = base * sin(t)
            xc = cap * cos(t)
            yc = cap * sin(t)
            verts.append((xb, yb, zb))
            verts.append((xc, yc, zc))
            t += angle
        for i in range(seg):
            f = i * 2
            if i == seg - 1:
                faces.append([0, 1, f + 1, f])
            else:
                faces.append([f + 2, f + 3, f + 1, f])
        if base != 0:
            base_face = []
            for i in range(seg - 1, -1, -1):
                p = i * 2
                base_face.append(p)
            faces.append(base_face)
        if cap != 0:
            cap_face = []
            for i in range(seg):
                p = i * 2 + 1
                cap_face.append(p)
            faces.append(cap_face)
    
        mesh = pov_define_mesh(mesh, verts, [], faces, "PovCone", True)
        if not ob:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob = object_data_add(context, mesh, operator=None)
    
            ob.pov.object_as = "CONE"
            ob.pov.cone_base_radius = base
            ob.pov.cone_cap_radius = cap
            ob.pov.cone_height = height
            ob.pov.cone_base_z = zb
            ob.pov.cone_cap_z = zc
    
    
    
    class POVRAY_OT_cone_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV cone using pov_cone_define() function."""
    
    
        bl_label = "Cone"
        bl_description = "Add Cone"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        # Keep in sync within object_properties.py section Cone
    
        #     If someone knows how to define operators' props from a func, I'd be delighted to learn it!
    
        base: FloatProperty(
    
            name="Base radius",
            description="The first radius of the cone",
            default=1.0,
            min=0.01,
            max=100.0,
        )
    
        cap: FloatProperty(
    
            name="Cap radius",
            description="The second radius of the cone",
            default=0.3,
            min=0.0,
            max=100.0,
        )
    
        seg: IntProperty(
    
            name="Segments",
            description="Radial segmentation of the proxy mesh",
            default=16,
            min=3,
            max=265,
        )
    
        height: FloatProperty(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            name="Height", description="Height of the cone", default=2.0, min=0.01, max=100.0
    
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
    
            return engine in cls.COMPAT_ENGINES
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                {'INFO'}, "This native POV-Ray primitive" "won't have any vertex to show in edit mode"
    
    class POVRAY_OT_cone_update(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Update the POV cone.
    
        Delete its previous proxy geometry and rerun pov_cone_define() function
        with the new parameters"""
    
    
        bl_idname = "pov.cone_update"
        bl_label = "Update"
        bl_description = "Update Cone"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            ob = context.object
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
    
    
        def execute(self, context):
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.reveal()
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.delete(type='VERT')
            bpy.ops.object.mode_set(mode="OBJECT")
    
            pov_cone_define(context, None, context.object)
    
            return {'FINISHED'}
    
    # ----------------------------------- ISOSURFACES ----------------------------------- #
    
    def pov_isosurface_view_define(context, op, ob, loc):
        """create the representation of POV isosurface using a Blender empty."""
    
        if op:
            eq = op.isosurface_eq
    
            loc = bpy.context.scene.cursor.location
    
        else:
            assert ob
            eq = ob.pov.isosurface_eq
    
            # keep object rotation and location for the add object operator
            obrot = ob.rotation_euler
            # obloc = ob.location
            obscale = ob.scale
    
            #bpy.ops.object.empty_add(type='CUBE', location=loc, rotation=obrot)
            bpy.ops.mesh.primitive_emptyvert_add()
    
            # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
            bpy.ops.transform.resize(value=obscale)
            # bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
            bpy.ops.object.mode_set(mode="OBJECT")
        if not ob:
            #bpy.ops.object.empty_add(type='CUBE', location=loc)
            bpy.ops.mesh.primitive_emptyvert_add()
            ob = context.object
            ob.name = ob.data.name = "PovIsosurface"
            ob.pov.object_as = "ISOSURFACE_VIEW"
            ob.pov.isosurface_eq = eq
            ob.pov.contained_by = 'box'
            bpy.ops.object.mode_set(mode="OBJECT")
    
    class POVRAY_OT_isosurface_add(Operator):
        """Add the representation of POV isosurface sphere by a Blender mesh icosphere.
    
        Flag its primitive type with a specific pov.object_as attribute and lock edit mode
        to keep proxy consistency by hiding edit geometry."""
    
        bl_idname = "pov.addisosurface"
        bl_label = "Generic Isosurface"
        bl_description = "Add Isosurface"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        # Keep in sync within object_properties.py section Sphere
        # as this allows interactive update
        isosurface_eq: StringProperty(
            name="f(x,y,z)=",
            description="Type the POV Isosurface function syntax for equation, "
            "pattern,etc. ruling an implicit surface to be rendered",
            default="sqrt(pow(x,2) + pow(y,2) + pow(z,2)) - 1.5",
        )
        imported_loc: FloatVectorProperty(
            name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0)
        )
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
            props = self.properties
            ob = context.object
            if ob:
                if ob.pov.imported_loc:
                    LOC = ob.pov.imported_loc
            elif not props.imported_loc:
                LOC = bpy.context.scene.cursor.location
            else:
                LOC = props.imported_loc
            pov_isosurface_view_define(context, self, None, LOC)
            self.report(
                {'INFO'}, "This native POV-Ray primitive " "is only an abstract proxy in Blender"
            )
            return {'FINISHED'}
    
    
    
    class POVRAY_OT_isosurface_update(Operator):
        """Update the POV isosurface.
    
        Rerun pov_isosurface_view_define() function
        with the new parameters"""
    
        bl_idname = "pov.isosurface_update"
        bl_label = "Update"
        bl_description = "Update Isosurface"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            ob = context.object
            return ob and ob.data and ob.type == 'ISOSURFACE_VIEW' and engine in cls.COMPAT_ENGINES
    
        def execute(self, context):
    
            pov_isosurface_view_define(context, None, context.object, context.object.location)
    
            return {'FINISHED'}
    
    
    
    class POVRAY_OT_isosurface_box_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV isosurface box using also just a Blender mesh cube.
    
        Flag its primitive type with a specific pov.object_as attribute and lock edit mode
        to keep proxy consistency by hiding edit geometry."""
    
    
        bl_idname = "pov.addisosurfacebox"
        bl_label = "Isosurface Box"
        bl_description = "Add Isosurface contained by Box"
        bl_options = {'REGISTER', 'UNDO'}
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
    
            bpy.ops.mesh.primitive_cube_add()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
    
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
    
            ob.name = 'PovIsosurfaceBox'
    
    class POVRAY_OT_isosurface_sphere_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV isosurface sphere by a Blender mesh icosphere.
    
        Flag its primitive type with a specific pov.object_as attribute and lock edit mode
        to keep proxy consistency by hiding edit geometry."""
    
    
        bl_idname = "pov.addisosurfacesphere"
        bl_label = "Isosurface Sphere"
        bl_description = "Add Isosurface contained by Sphere"
        bl_options = {'REGISTER', 'UNDO'}
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
    
            bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
    
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
            bpy.ops.object.shade_smooth()
    
            ob.name = 'PovIsosurfaceSphere'
    
    class POVRAY_OT_sphere_sweep_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV sphere_sweep using a Blender NURBS curve.
    
        Flag its primitive type with a specific ob.pov.curveshape attribute and
        leave access to edit mode to keep user editable handles."""
    
    
        bl_idname = "pov.addspheresweep"
        bl_label = "Sphere Sweep"
        bl_description = "Create Sphere Sweep along curve"
        bl_options = {'REGISTER', 'UNDO'}
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
    
            bpy.ops.curve.primitive_nurbs_curve_add()
    
            ob = context.object
            ob.name = ob.data.name = "PovSphereSweep"
            ob.pov.curveshape = "sphere_sweep"
            ob.data.bevel_depth = 0.02
            ob.data.bevel_resolution = 4
            ob.data.fill_mode = 'FULL'
    
            # ob.data.splines[0].order_u = 4
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV blob using a Blender meta ball.
    
        No need to flag its primitive type as meta are exported to blobs
        and leave access to edit mode to keep user editable thresholds."""
    
    
        bl_idname = "pov.addblobsphere"
        bl_label = "Blob Sphere"
        bl_description = "Add Blob Sphere"
        bl_options = {'REGISTER', 'UNDO'}
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
            bpy.ops.object.metaball_add(type='BALL')
    
    class POVRAY_OT_blobcapsule_add(Operator):
        """Add the representation of POV blob using a Blender meta ball.
    
        No need to flag its primitive type as meta are exported to blobs
        and leave access to edit mode to keep user editable thresholds."""
    
        bl_idname = "pov.addblobcapsule"
        bl_label = "Blob Capsule"
        bl_description = "Add Blob Capsule"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
            bpy.ops.object.metaball_add(type='CAPSULE')
            ob = context.object
            ob.name = "PovBlob"
            return {'FINISHED'}
    
    
    class POVRAY_OT_blobplane_add(Operator):
        """Add the representation of POV blob using a Blender meta ball.
    
        No need to flag its primitive type as meta are exported to blobs
        and leave access to edit mode to keep user editable thresholds."""
    
        bl_idname = "pov.addblobplane"
        bl_label = "Blob Plane"
        bl_description = "Add Blob Plane"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
            bpy.ops.object.metaball_add(type='PLANE')
            ob = context.object
            ob.name = "PovBlob"
            return {'FINISHED'}
    
    
    class POVRAY_OT_blobellipsoid_add(Operator):
        """Add the representation of POV blob using a Blender meta ball.
    
        No need to flag its primitive type as meta are exported to blobs
        and leave access to edit mode to keep user editable thresholds."""
    
        bl_idname = "pov.addblobellipsoid"
        bl_label = "Blob Ellipsoid"
        bl_description = "Add Blob Ellipsoid"
        bl_options = {'REGISTER', 'UNDO'}
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
            bpy.ops.object.metaball_add(type='ELLIPSOID')
            ob = context.object
            ob.name = "PovBlob"
            return {'FINISHED'}
    
    
    class POVRAY_OT_blobcube_add(Operator):
        """Add the representation of POV blob using a Blender meta ball.
    
        No need to flag its primitive type as meta are exported to blobs
        and leave access to edit mode to keep user editable thresholds."""
    
        bl_idname = "pov.addblobcube"
        bl_label = "Blob Cube"
        bl_description = "Add Blob Cube"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
            bpy.ops.object.metaball_add(type='CUBE')
            ob = context.object
            ob.name = "PovBlob"
            return {'FINISHED'}
    
    
    
    class POVRAY_OT_rainbow_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV rainbow using a Blender spot light.
    
        Rainbows indeed propagate along a visibility cone.
        Flag its primitive type with a specific ob.pov.object_as attribute
        and leave access to edit mode to keep user editable handles.
        Add a constraint to orient it towards camera because POV Rainbows
        are view dependant and having it always initially visible is less
        confusing """
    
    
        bl_idname = "pov.addrainbow"
        bl_label = "Rainbow"
        bl_description = "Add Rainbow"
        bl_options = {'REGISTER', 'UNDO'}
    
        def execute(self, context):
    
            bpy.ops.object.light_add(type='SPOT', radius=1)
    
            ob = context.object
            ob.data.show_cone = False
            ob.data.spot_blend = 0.5
    
            # ob.data.shadow_buffer_clip_end = 0 # deprecated in 2.8
    
            ob.data.shadow_buffer_clip_start = 4 * cam.location.length
    
            ob.data.energy = 0
    
            ob.name = ob.data.name = "PovRainbow"
            ob.pov.object_as = "RAINBOW"
    
            # obj = context.object
    
            bpy.ops.object.constraint_add(type='DAMPED_TRACK')
    
            ob.constraints["Damped Track"].target = cam
            ob.constraints["Damped Track"].track_axis = 'TRACK_NEGATIVE_Z'
            ob.location = -cam.location
    
    
            # refocus on the actual rainbow
    
            bpy.context.view_layer.objects.active = ob
    
            ob.select_set(True)
    
    class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV height_field using a displaced grid.
    
        texture slot fix and displace modifier will be needed because noise
        displace operator was deprecated in 2.8"""
    
    
        bl_idname = "pov.addheightfield"
        bl_label = "Height Field"
    
        bl_description = "Add Height Field"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        # Keep in sync within object_properties.py section HeightFields
        # as this allows interactive update
    
    
        # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
        # options={'HIDDEN'},
        # )
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        quality: IntProperty(name="Quality", description="", default=100, min=1, max=100)
    
        hf_filename: StringProperty(maxlen=1024)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        hf_gamma: FloatProperty(name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        hf_premultiplied: BoolProperty(name="Premultiplied", description="Premultiplied", default=True)
    
        hf_smooth: BoolProperty(name="Smooth", description="Smooth", default=False)
    
        hf_water: FloatProperty(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            name="Water Level", description="Wather Level", min=0.00, max=1.00, default=0.0
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        hf_hierarchy: BoolProperty(name="Hierarchy", description="Height field hierarchy", default=True)
    
    
        def execute(self, context):
    
            props = self.properties
            impath = bpy.path.abspath(self.filepath)
            img = bpy.data.images.load(impath)
            im_name = img.name
            im_name, file_extension = os.path.splitext(im_name)
    
            hf_tex = bpy.data.textures.new('%s_hf_image' % im_name, type='IMAGE')
    
            mat = bpy.data.materials.new('Tex_%s_hf' % im_name)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            hf_slot = mat.pov_texture_slots.add()
            hf_slot.texture = hf_tex.name
    
            # layers = 20*[False]
            # layers[0] = True
    
            res = 100 / quality
            w, h = hf_tex.image.size[:]
            w = int(w / res)
            h = int(h / res)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            bpy.ops.mesh.primitive_grid_add(x_subdivisions=w, y_subdivisions=h, size=0.5)
    
            ob.name = ob.data.name = '%s' % im_name
    
            ob.data.materials.append(mat)
            bpy.ops.object.mode_set(mode="EDIT")
    
            # bpy.ops.mesh.noise(factor=1) # TODO replace by displace modifier, noise deprecated in 2.8
    
            # needs a loop to select by index?
            # bpy.ops.object.material_slot_remove()
            # material just left there for now
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            mat.pov_texture_slots.clear()
    
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
            ob.pov.object_as = 'HEIGHT_FIELD'
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            # POV-Ray will soon use only forwards slashes on every OS and already can
            forward_impath = impath.replace(os.sep, '/')
            ob.pov.hf_filename = forward_impath
    
    # ----------------------------------- TORUS ----------------------------------- #
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV torus using just a Blender torus.
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        Picking properties either from creation operator, import, or data update.
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        But flag its primitive type with a specific pov.object_as attribute and lock edit mode
        to keep proxy consistency by hiding edit geometry."""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        if op:
            mas = op.mas
            mis = op.mis
            mar = op.mar
            mir = op.mir
        else:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            mas = ob.pov.torus_major_segments
            mis = ob.pov.torus_minor_segments
            mar = ob.pov.torus_major_radius
            mir = ob.pov.torus_minor_radius
    
            # keep object rotation and location for the add object operator
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            obrot = ob.rotation_euler
            obloc = ob.location
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.reveal()
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.delete(type='VERT')
    
            bpy.ops.mesh.primitive_torus_add(
                rotation=obrot,
                location=obloc,
                major_segments=mas,
                minor_segments=mis,
                major_radius=mar,
                minor_radius=mir,
            )
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
    
        if not ob:
    
            bpy.ops.mesh.primitive_torus_add(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                major_segments=mas, minor_segments=mis, major_radius=mar, minor_radius=mir
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob = context.object
    
            ob.name = ob.data.name = "PovTorus"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob.pov.object_as = "TORUS"
            ob.pov.torus_major_segments = mas
            ob.pov.torus_minor_segments = mis
            ob.pov.torus_major_radius = mar
            ob.pov.torus_minor_radius = mir
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
    
    class POVRAY_OT_torus_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV torus using using pov_torus_define() function."""
    
    
        bl_idname = "pov.addtorus"
        bl_label = "Torus"
        bl_description = "Add Torus"
        bl_options = {'REGISTER', 'UNDO'}
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        # Keep in sync within object_properties.py section Torus
        # as this allows interactive update
        mas: IntProperty(name="Major Segments", description="", default=48, min=3, max=720)
        mis: IntProperty(name="Minor Segments", description="", default=12, min=3, max=720)
    
        mar: FloatProperty(name="Major Radius", description="", default=1.0)
        mir: FloatProperty(name="Minor Radius", description="", default=0.25)
    
        def execute(self, context):
    
            props = self.properties
            mar = props.mar
            mir = props.mir
            mas = props.mas
            mis = props.mis
            pov_torus_define(context, self, None)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
    
    class POVRAY_OT_torus_update(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Update the POV torus.
    
        Delete its previous proxy geometry and rerun pov_torus_define() function
        with the new parameters"""
    
    
        bl_idname = "pov.torus_update"
        bl_label = "Update"
        bl_description = "Update Torus"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            ob = context.object
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
    
    
        def execute(self, context):
    
            pov_torus_define(context, None, context.object)
    
    
            return {'FINISHED'}
    
    
    # -----------------------------------------------------------------------------
    
    class POVRAY_OT_prism_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV prism using using an extruded curve."""
    
    
        bl_idname = "pov.addprism"
        bl_label = "Prism"
        bl_description = "Create Prism"
        bl_options = {'REGISTER', 'UNDO'}
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        prism_n: IntProperty(name="Sides", description="Number of sides", default=5, min=3, max=720)
    
        prism_r: FloatProperty(name="Radius", description="Radius", default=1.0)
    
        def execute(self, context):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            loft_data = bpy.data.curves.new('Prism', type='CURVE')
            loft_data.dimensions = '2D'
            loft_data.resolution_u = 2
            # loft_data.show_normal_face = False
            loft_data.extrude = 2
    
            n = props.prism_n
            r = props.prism_r
    
                x = r * cos(angle)
                y = r * sin(angle)
                coords.append((x, y, z))
                angle += pi * 2 / n
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            poly = loft_data.splines.new('POLY')
    
            poly.points.add(len(coords) - 1)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob = bpy.data.objects.new('Prism_shape', loft_data)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            scn.collection.objects.link(ob)
    
            context.view_layer.objects.active = ob
    
            ob.select_set(True)
    
            ob.pov.curveshape = "prism"
            ob.name = ob.data.name = "Prism"
            return {'FINISHED'}
    
    # ----------------------------------- PARAMETRIC ----------------------------------- #
    
    def pov_parametric_define(context, op, ob):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV parametric surfaces by math surface from add mesh extra objects addon.
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        Picking properties either from creation operator, import, or data update.
        But flag its primitive type with a specific pov.object_as attribute and lock edit mode
        to keep proxy consistency by hiding edit geometry."""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        if op:
            u_min = op.u_min
            u_max = op.u_max
            v_min = op.v_min
            v_max = op.v_max
            x_eq = op.x_eq
            y_eq = op.y_eq
            z_eq = op.z_eq
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        else:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            u_min = ob.pov.u_min
            u_max = ob.pov.u_max
            v_min = ob.pov.v_min
            v_max = ob.pov.v_max
            x_eq = ob.pov.x_eq
            y_eq = ob.pov.y_eq
            z_eq = ob.pov.z_eq
    
    
            # keep object rotation and location for the updated object
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            obloc = ob.location
    
            obrot = ob.rotation_euler  # In radians
            # Parametric addon has no loc rot, some extra work is needed
            # in case cursor has moved
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            curloc = bpy.context.scene.cursor.location
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.reveal()
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.delete(type='VERT')
    
            bpy.ops.mesh.primitive_xyz_function_surface(
                x_eq=x_eq,
                y_eq=y_eq,
                z_eq=z_eq,
                range_u_min=u_min,
                range_u_max=u_max,
                range_v_min=v_min,
                range_v_max=v_max,
            )
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            bpy.ops.mesh.select_all(action='SELECT')
    
            # extra work:
            bpy.ops.transform.translate(value=(obloc - curloc), proportional_size=1)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            # XXX TODO : https://devtalk.blender.org/t/bpy-ops-transform-rotate-option-axis/6235/7
            # to complete necessary extra work rotation, after updating from blender version > 2.92
            # update and uncomment below, but simple axis deprecated since 2.8
            # bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
    
        if not ob:
    
            bpy.ops.mesh.primitive_xyz_function_surface(
                x_eq=x_eq,
                y_eq=y_eq,
                z_eq=z_eq,
                range_u_min=u_min,
                range_u_max=u_max,
                range_v_min=v_min,
                range_v_max=v_max,
            )
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob = context.object
    
            ob.name = ob.data.name = "PovParametric"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob.pov.object_as = "PARAMETRIC"
    
            ob.pov.u_min = u_min
            ob.pov.u_max = u_max
            ob.pov.v_min = v_min
            ob.pov.v_max = v_max
            ob.pov.x_eq = x_eq
            ob.pov.y_eq = y_eq
            ob.pov.z_eq = z_eq
    
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
    
    class POVRAY_OT_parametric_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV parametric surfaces using pov_parametric_define() function."""
    
        bl_idname = "pov.addparametric"
        bl_label = "Parametric"
        bl_description = "Add Paramertic"
        bl_options = {'REGISTER', 'UNDO'}
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        # Keep in sync within object_properties.py section Parametric primitive
        # as this allows interactive update
    
        u_min: FloatProperty(name="U Min", description="", default=0.0)
        v_min: FloatProperty(name="V Min", description="", default=0.0)
        u_max: FloatProperty(name="U Max", description="", default=6.28)
        v_max: FloatProperty(name="V Max", description="", default=12.57)
        x_eq: StringProperty(maxlen=1024, default="cos(v)*(1+cos(u))*sin(v/8)")
        y_eq: StringProperty(maxlen=1024, default="sin(u)*sin(v/8)+cos(v/8)*1.5")
        z_eq: StringProperty(maxlen=1024, default="sin(v)*(1+cos(u))*sin(v/8)")
    
        def execute(self, context):
    
            props = self.properties
            u_min = props.u_min
            v_min = props.v_min
            u_max = props.u_max
            v_max = props.v_max
            x_eq = props.x_eq
            y_eq = props.y_eq
            z_eq = props.z_eq
    
            try:
                pov_parametric_define(context, self, None)
                self.report(
                    {'INFO'}, "This native POV-Ray primitive " "won't have any vertex to show in edit mode"
                )
            except AttributeError:
                self.report(
                    {'INFO'}, "Please enable Add Mesh: Extra Objects addon"
                )
    
    class POVRAY_OT_parametric_update(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Update the representation of POV parametric surfaces.
    
        Delete its previous proxy geometry and rerun pov_parametric_define() function
        with the new parameters"""
    
        bl_idname = "pov.parametric_update"
        bl_label = "Update"
        bl_description = "Update parametric object"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            ob = context.object
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            return ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES
    
    
        def execute(self, context):
    
            pov_parametric_define(context, None, context.object)
    
            return {'FINISHED'}
    
    # -----------------------------------------------------------------------------
    
    class POVRAY_OT_shape_polygon_to_circle_add(Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the proxy mesh for POV Polygon to circle lofting macro"""
    
    
        bl_idname = "pov.addpolygontocircle"
        bl_label = "Polygon To Circle Blending"
        bl_description = "Add Polygon To Circle Blending Surface"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        # Keep in sync within object_properties.py section PolygonToCircle properties
        # as this allows interactive update
    
        polytocircle_resolution: IntProperty(
            name="Resolution", description="", default=3, min=0, max=256
        )
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        polytocircle_ngon: IntProperty(name="NGon", description="", min=3, max=64, default=5)
        polytocircle_ngonR: FloatProperty(name="NGon Radius", description="", default=0.3)
        polytocircle_circleR: FloatProperty(name="Circle Radius", description="", default=1.0)
    
    
        def execute(self, context):
    
            props = self.properties
            ngon = props.polytocircle_ngon
            ngonR = props.polytocircle_ngonR
            circleR = props.polytocircle_circleR
            resolution = props.polytocircle_resolution
    
            # layers = 20*[False]
            # layers[0] = True
            bpy.ops.mesh.primitive_circle_add(
                vertices=ngon, radius=ngonR, fill_type='NGON', enter_editmode=True
            )
    
            bpy.ops.transform.translate(value=(0, 0, 1))
            bpy.ops.mesh.subdivide(number_cuts=resolution)
    
            numCircleVerts = ngon + (ngon * resolution)
    
            bpy.ops.mesh.primitive_circle_add(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                vertices=numCircleVerts, radius=circleR, fill_type='NGON', enter_editmode=True
    
            bpy.ops.transform.translate(value=(0, 0, -1))
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.bridge_edge_loops()
            if ngon < 5:
                bpy.ops.mesh.select_all(action='DESELECT')
    
                bpy.ops.mesh.primitive_circle_add(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    vertices=ngon, radius=ngonR, fill_type='TRIFAN', enter_editmode=True
    
                bpy.ops.transform.translate(value=(0, 0, 1))
                bpy.ops.mesh.select_all(action='SELECT')
                bpy.ops.mesh.remove_doubles()
            bpy.ops.object.mode_set(mode='OBJECT')
            ob = context.object
            ob.name = "Polygon_To_Circle"
            ob.pov.object_as = 'POLYCIRCLE'
            ob.pov.ngon = ngon
            ob.pov.ngonR = ngonR
            ob.pov.circleR = circleR
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
            return {'FINISHED'}
    
    classes = (
        POVRAY_OT_lathe_add,
        POVRAY_OT_superellipsoid_add,
        POVRAY_OT_superellipsoid_update,
        POVRAY_OT_supertorus_add,
        POVRAY_OT_supertorus_update,
        POVRAY_OT_loft_add,
        POVRAY_OT_plane_add,
        POVRAY_OT_box_add,
        POVRAY_OT_cylinder_add,
        POVRAY_OT_cylinder_update,
        POVRAY_OT_sphere_add,
        POVRAY_OT_sphere_update,
        POVRAY_OT_cone_add,
        POVRAY_OT_cone_update,
    
        POVRAY_OT_isosurface_add,
        POVRAY_OT_isosurface_update,
    
        POVRAY_OT_isosurface_box_add,
        POVRAY_OT_isosurface_sphere_add,
        POVRAY_OT_sphere_sweep_add,
    
        POVRAY_OT_blobsphere_add,
        POVRAY_OT_blobcapsule_add,
        POVRAY_OT_blobplane_add,
        POVRAY_OT_blobellipsoid_add,
        POVRAY_OT_blobcube_add,
    
        POVRAY_OT_rainbow_add,
        POVRAY_OT_height_field_add,
        POVRAY_OT_torus_add,
        POVRAY_OT_torus_update,
        POVRAY_OT_prism_add,
        POVRAY_OT_parametric_add,
        POVRAY_OT_parametric_update,
        POVRAY_OT_shape_polygon_to_circle_add,
    )
    
    
    def register():
        for cls in classes:
            register_class(cls)
    
    
    def unregister():
    
        for cls in reversed(classes):
    
            unregister_class(cls)