Skip to content
Snippets Groups Projects
primitives.py 79.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ##### BEGIN GPL LICENSE BLOCK #####
    #
    #  This program is free software; you can redistribute it and/or
    #  modify it under the terms of the GNU General Public License
    #  as published by the Free Software Foundation; either version 2
    #  of the License, or (at your option) any later version.
    #
    #  This program is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this program; if not, write to the Free Software Foundation,
    #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    #
    # ##### END GPL LICENSE BLOCK #####
    
    # <pep8 compliant>
    
    
    """ Get POV-Ray specific objects In and Out of Blender """
    
    import os.path
    
    from bpy_extras.io_utils import ImportHelper
    from bpy_extras import object_utils
    
    from bpy.utils import register_class
    
    from math import atan, pi, degrees, sqrt, cos, sin
    
    
    from bpy.props import (
    
        StringProperty,
        BoolProperty,
        IntProperty,
        FloatProperty,
        FloatVectorProperty,
        EnumProperty,
        PointerProperty,
        CollectionProperty,
    
    from mathutils import Vector, Matrix
    
    # import collections
    
    
    
    def pov_define_mesh(mesh, verts, edges, faces, name, hide_geometry=True):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Generate proxy mesh."""
    
        if mesh is None:
            mesh = bpy.data.meshes.new(name)
        mesh.from_pydata(verts, edges, faces)
        mesh.update()
    
        mesh.validate(
            verbose=False
        )  # Set it to True to see debug messages (helps ensure you generate valid geometry).
    
        if hide_geometry:
            mesh.vertices.foreach_set("hide", [True] * len(mesh.vertices))
            mesh.edges.foreach_set("hide", [True] * len(mesh.edges))
            mesh.polygons.foreach_set("hide", [True] * len(mesh.polygons))
        return mesh
    
    
    class POVRAY_OT_lathe_add(bpy.types.Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV lathe using a screw modifier."""
    
        bl_options = {'REGISTER', 'UNDO'}
    
            # ayers=[False]*20
            # layers[0]=True
    
    Campbell Barton's avatar
    Campbell Barton committed
            bpy.ops.curve.primitive_bezier_curve_add(
    
                location=context.scene.cursor.location,
    
    Campbell Barton's avatar
    Campbell Barton committed
                rotation=(0, 0, 0),
    
            ob = context.view_layer.objects.active
    
    Campbell Barton's avatar
    Campbell Barton committed
            ob_data = ob.data
            ob.name = ob_data.name = "PovLathe"
            ob_data.dimensions = '2D'
            ob_data.transform(Matrix.Rotation(-pi / 2.0, 4, 'Z'))
    
            ob.pov.object_as = 'LATHE'
    
    Campbell Barton's avatar
    Campbell Barton committed
            self.report({'INFO'}, "This native POV-Ray primitive")
    
            ob.pov.curveshape = "lathe"
            bpy.ops.object.modifier_add(type='SCREW')
    
    Campbell Barton's avatar
    Campbell Barton committed
            mod = ob.modifiers[-1]
            mod.axis = 'Y'
            mod.show_render = False
    
            return {'FINISHED'}
    
    
    def pov_superellipsoid_define(context, op, ob):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Create the proxy mesh of a POV superellipsoid using the pov_superellipsoid_define() function."""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        if op:
            mesh = None
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            u = op.se_u
            v = op.se_v
            n1 = op.se_n1
            n2 = op.se_n2
            edit = op.se_edit
    
            se_param1 = n2  # op.se_param1
            se_param2 = n1  # op.se_param2
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        else:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            mesh = ob.data
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            u = ob.pov.se_u
            v = ob.pov.se_v
            n1 = ob.pov.se_n1
            n2 = ob.pov.se_n2
            edit = ob.pov.se_edit
            se_param1 = ob.pov.se_param1
            se_param2 = ob.pov.se_param2
    
        verts = []
    
        stepSegment = 360 / v * pi / 180
        stepRing = pi / u
        angSegment = 0
        angRing = -pi / 2
    
        step = 0
        for ring in range(0, u - 1):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            angRing += stepRing
    
            for segment in range(0, v):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                step += 1
                angSegment += stepSegment
    
                x = r * (abs(cos(angRing)) ** n1) * (abs(cos(angSegment)) ** n2)
                if (cos(angRing) < 0 and cos(angSegment) > 0) or (
                    cos(angRing) > 0 and cos(angSegment) < 0
                ):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    x = -x
    
                y = r * (abs(cos(angRing)) ** n1) * (abs(sin(angSegment)) ** n2)
                if (cos(angRing) < 0 and sin(angSegment) > 0) or (
                    cos(angRing) > 0 and sin(angSegment) < 0
                ):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    y = -y
    
                z = r * (abs(sin(angRing)) ** n1)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                if sin(angRing) < 0:
                    z = -z
    
                x = round(x, 4)
                y = round(y, 4)
                z = round(z, 4)
                verts.append((x, y, z))
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        if edit == 'TRIANGLES':
    
            verts.append((0, 0, 1))
            verts.append((0, 0, -1))
    
        for i in range(0, u - 2):
            m = i * v
            for p in range(0, v):
                if p < v - 1:
                    face = (m + p, 1 + m + p, v + 1 + m + p, v + m + p)
                if p == v - 1:
                    face = (m + p, m, v + m, v + m + p)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        if edit == 'TRIANGLES':
    
            indexUp = len(verts) - 2
            indexDown = len(verts) - 1
            indexStartDown = len(verts) - 2 - v
            for i in range(0, v):
                if i < v - 1:
                    face = (indexDown, i, i + 1)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    faces.append(face)
    
                if i == v - 1:
                    face = (indexDown, i, 0)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    faces.append(face)
    
            for i in range(0, v):
                if i < v - 1:
                    face = (indexUp, i + indexStartDown, i + indexStartDown + 1)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    faces.append(face)
    
                if i == v - 1:
                    face = (indexUp, i + indexStartDown, indexStartDown)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    faces.append(face)
        if edit == 'NGONS':
    
            face = []
            for i in range(0, v):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                face.append(i)
            faces.append(face)
    
            face = []
            indexUp = len(verts) - 1
            for i in range(0, v):
                face.append(indexUp - i)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            faces.append(face)
        mesh = pov_define_mesh(mesh, verts, [], faces, "SuperEllipsoid")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        if not ob:
            ob = object_utils.object_data_add(context, mesh, operator=None)
    
            # engine = context.scene.render.engine what for?
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob = context.object
    
            ob.name = ob.data.name = "PovSuperellipsoid"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob.pov.object_as = 'SUPERELLIPSOID'
            ob.pov.se_param1 = n2
            ob.pov.se_param2 = n1
    
            ob.pov.se_u = u
            ob.pov.se_v = v
            ob.pov.se_n1 = n1
            ob.pov.se_n2 = n2
            ob.pov.se_edit = edit
    
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
    
    class POVRAY_OT_superellipsoid_add(bpy.types.Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV superellipsoid using the pov_superellipsoid_define() function."""
    
        bl_idname = "pov.addsuperellipsoid"
        bl_label = "Add SuperEllipsoid"
        bl_description = "Create a SuperEllipsoid"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        # XXX Keep it in sync with __init__'s RenderPovSettingsConePrimitive
        #     If someone knows how to define operators' props from a func, I'd be delighted to learn it!
    
        se_param1: FloatProperty(
    
            name="Parameter 1", description="", min=0.00, max=10.0, default=0.04
        )
    
        se_param2: FloatProperty(
    
            name="Parameter 2", description="", min=0.00, max=10.0, default=0.04
        )
    
        se_u: IntProperty(
            name="U-segments",
            description="radial segmentation",
            default=20,
            min=4,
            max=265,
        )
        se_v: IntProperty(
            name="V-segments",
            description="lateral segmentation",
            default=20,
            min=4,
            max=265,
        )
        se_n1: FloatProperty(
            name="Ring manipulator",
            description="Manipulates the shape of the Ring",
            default=1.0,
            min=0.01,
            max=100.0,
        )
        se_n2: FloatProperty(
            name="Cross manipulator",
            description="Manipulates the shape of the cross-section",
            default=1.0,
            min=0.01,
            max=100.0,
        )
        se_edit: EnumProperty(
            items=[
                ("NOTHING", "Nothing", ""),
                ("NGONS", "N-Gons", ""),
                ("TRIANGLES", "Triangles", ""),
            ],
            name="Fill up and down",
            description="",
            default='TRIANGLES',
        )
    
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
    
            return engine in cls.COMPAT_ENGINES
    
        def execute(self, context):
    
            self.report(
                {'INFO'},
                "This native POV-Ray primitive won't have any vertex to show in edit mode",
            )
    
    class POVRAY_OT_superellipsoid_update(bpy.types.Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Update the superellipsoid.
    
        Delete its previous proxy geometry and rerun pov_superellipsoid_define() function
        with the new parameters"""
    
    
        bl_idname = "pov.superellipsoid_update"
        bl_label = "Update"
        bl_description = "Update Superellipsoid"
        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 == '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_superellipsoid_define(context, None, context.object)
    
            return {'FINISHED'}
    
    
    def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
        faces = []
        if not vertIdx1 or not vertIdx2:
            return None
        if len(vertIdx1) < 2 and len(vertIdx2) < 2:
            return None
        fan = False
    
        if len(vertIdx1) != len(vertIdx2):
            if len(vertIdx1) == 1 and len(vertIdx2) > 1:
    
                face = [vertIdx1[0], vertIdx2[0], vertIdx2[total - 1]]
    
                if not fan:
                    face.append(vertIdx1[total - 1])
                faces.append(face)
    
            else:
                face = [vertIdx2[0], vertIdx1[0]]
                if not fan:
                    face.append(vertIdx1[total - 1])
                face.append(vertIdx2[total - 1])
                faces.append(face)
        for num in range(total - 1):
            if flipped:
                if fan:
                    face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]]
                else:
    
                    face = [
                        vertIdx2[num],
                        vertIdx1[num],
                        vertIdx1[num + 1],
                        vertIdx2[num + 1],
                    ]
    
                faces.append(face)
            else:
                if fan:
                    face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]]
                else:
    
                    face = [
                        vertIdx1[num],
                        vertIdx2[num],
                        vertIdx2[num + 1],
                        vertIdx1[num + 1],
                    ]
    
            return -((-a) ** b)
        return a ** b
    
    
    def supertoroid(R, r, u, v, n1, n2):
        a = 2 * pi / u
        b = 2 * pi / v
    
            s = power(sin(i * a), n1)
            c = power(cos(i * a), n1)
    
                c2 = R + r * power(cos(j * b), n2)
                s2 = r * power(sin(j * b), n2)
                verts.append(
                    (c * c2, s * c2, s2)
                )  # type as a (mathutils.Vector(c*c2,s*c2,s2))?
    
                f = createFaces(
                    range((i - 1) * v, i * v),
                    range(i * v, (i + 1) * v),
                    closed=True,
                )
    
        f = createFaces(range((u - 1) * v, u * v), range(v), closed=True)
    
    def pov_supertorus_define(context, op, ob):
    
        if op:
            mesh = None
            st_R = op.st_R
            st_r = op.st_r
            st_u = op.st_u
            st_v = op.st_v
            st_n1 = op.st_n1
            st_n2 = op.st_n2
            st_ie = op.st_ie
            st_edit = op.st_edit
    
        else:
            assert ob
            mesh = ob.data
            st_R = ob.pov.st_major_radius
            st_r = ob.pov.st_minor_radius
            st_u = ob.pov.st_u
            st_v = ob.pov.st_v
            st_n1 = ob.pov.st_ring
            st_n2 = ob.pov.st_cross
            st_ie = ob.pov.st_ie
            st_edit = ob.pov.st_edit
    
        if st_ie:
            rad1 = (st_R + st_r) / 2
            rad2 = (st_R - st_r) / 2
            if rad2 > rad1:
                [rad1, rad2] = [rad2, rad1]
        else:
            rad1 = st_R
            rad2 = st_r
            if rad2 > rad1:
                rad1 = rad2
        verts, faces = supertoroid(rad1, rad2, st_u, st_v, st_n1, st_n2)
        mesh = pov_define_mesh(mesh, verts, [], faces, "PovSuperTorus", True)
        if not ob:
            ob = object_utils.object_data_add(context, mesh, operator=None)
            ob.pov.object_as = 'SUPERTORUS'
            ob.pov.st_major_radius = st_R
            ob.pov.st_minor_radius = st_r
            ob.pov.st_u = st_u
            ob.pov.st_v = st_v
            ob.pov.st_ring = st_n1
            ob.pov.st_cross = st_n2
            ob.pov.st_ie = st_ie
            ob.pov.st_edit = st_edit
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV supertorus using the pov_supertorus_define() function."""
    
    
        bl_idname = "pov.addsupertorus"
        bl_label = "Add Supertorus"
        bl_description = "Create a SuperTorus"
        bl_options = {'REGISTER', 'UNDO'}
    
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
    
        st_R: FloatProperty(
            name="big radius",
            description="The radius inside the tube",
            default=1.0,
            min=0.01,
            max=100.0,
        )
        st_r: FloatProperty(
            name="small radius",
            description="The radius of the tube",
            default=0.3,
            min=0.01,
            max=100.0,
        )
        st_u: IntProperty(
            name="U-segments",
            description="radial segmentation",
            default=16,
            min=3,
            max=265,
        )
        st_v: IntProperty(
            name="V-segments",
            description="lateral segmentation",
            default=8,
            min=3,
            max=265,
        )
        st_n1: FloatProperty(
            name="Ring manipulator",
            description="Manipulates the shape of the Ring",
            default=1.0,
            min=0.01,
            max=100.0,
        )
        st_n2: FloatProperty(
            name="Cross manipulator",
            description="Manipulates the shape of the cross-section",
            default=1.0,
            min=0.01,
            max=100.0,
        )
        st_ie: BoolProperty(
            name="Use Int.+Ext. radii",
            description="Use internal and external radii",
            default=False,
        )
        st_edit: BoolProperty(
            name="", description="", default=False, options={'HIDDEN'}
        )
    
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
    
            return engine in cls.COMPAT_ENGINES
    
    
        def execute(self, context):
            pov_supertorus_define(context, self, None)
    
    
            self.report(
                {'INFO'},
                "This native POV-Ray primitive won't have any vertex to show in edit mode",
            )
    
            return {'FINISHED'}
    
    class POVRAY_OT_supertorus_update(bpy.types.Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Update the supertorus.
    
        Delete its previous proxy geometry and rerun pov_supetorus_define() function
        with the new parameters"""
    
        bl_idname = "pov.supertorus_update"
        bl_label = "Update"
        bl_description = "Update SuperTorus"
        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 == '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_supertorus_define(context, None, context.object)
    
            return {'FINISHED'}
    
    #########################################################################################################
    class POVRAY_OT_loft_add(bpy.types.Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Create the representation of POV loft using Blender curves."""
    
    
        bl_idname = "pov.addloft"
        bl_label = "Add Loft Data"
        bl_description = "Create a Curve data for Meshmaker"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        loft_n: IntProperty(
            name="Segments",
            description="Vertical segments",
            default=16,
            min=3,
            max=720,
        )
        loft_rings_bottom: IntProperty(
            name="Bottom", description="Bottom rings", default=5, min=2, max=100
        )
        loft_rings_side: IntProperty(
            name="Side", description="Side rings", default=10, min=2, max=100
        )
        loft_thick: FloatProperty(
            name="Thickness",
            description="Manipulates the shape of the Ring",
            default=0.3,
            min=0.01,
            max=1.0,
        )
        loft_r: FloatProperty(
            name="Radius", description="Radius", default=1, min=0.01, max=10
        )
        loft_height: FloatProperty(
            name="Height",
            description="Manipulates the shape of the Ring",
            default=2,
            min=0.01,
            max=10.0,
        )
    
        def execute(self, context):
    
            props = self.properties
            loftData = bpy.data.curves.new('Loft', type='CURVE')
            loftData.dimensions = '3D'
            loftData.resolution_u = 2
    
            # loftData.show_normal_face = False # deprecated in 2.8
    
            thick = props.loft_thick
            side = props.loft_rings_side
            bottom = props.loft_rings_bottom
            h = props.loft_height
            r = props.loft_r
    
            for i in range(bottom + 1):
    
                    x = r0 * cos(angle)
                    y = r0 * sin(angle)
                    coords.append((x, y, z))
                    angle += pi * 2 / n
                r0 += distB
    
                nurbs.points.add(len(coords) - 1)
    
                    nurbs.points[i].co = (x, y, z, 1)
                nurbs.use_cyclic_u = True
            for i in range(side):
    
                    x = r * cos(angle)
                    y = r * sin(angle)
                    coords.append((x, y, z))
                    angle += pi * 2 / n
    
                nurbs.points.add(len(coords) - 1)
    
                    nurbs.points[i].co = (x, y, z, 1)
                nurbs.use_cyclic_u = True
    
                    x = r * cos(angle)
                    y = r * sin(angle)
                    coords.append((x, y, z))
                    angle += pi * 2 / n
    
                nurbs.points.add(len(coords) - 1)
    
                    nurbs.points[i].co = (x, y, z, 1)
                nurbs.use_cyclic_u = True
    
                z -= h / side
            z = (-h / 2) + thick
            distB = (r - 0.00001) / bottom
            for i in range(bottom + 1):
    
                    x = r * cos(angle)
                    y = r * sin(angle)
                    coords.append((x, y, z))
                    angle += pi * 2 / n
                r -= distB
    
                nurbs.points.add(len(coords) - 1)
    
                    nurbs.points[i].co = (x, y, z, 1)
                nurbs.use_cyclic_u = True
            ob = bpy.data.objects.new('Loft_shape', loftData)
            scn = bpy.context.scene
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            scn.collection.objects.link(ob)
    
            context.view_layer.objects.active = ob
    
            ob.select_set(True)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV infinite plane using just a very big Blender Plane.
    
        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.addplane"
        bl_label = "Plane"
        bl_description = "Add Plane"
        bl_options = {'REGISTER', 'UNDO'}
    
    
        def execute(self, context):
            # layers = 20*[False]
            # layers[0] = True
            bpy.ops.mesh.primitive_plane_add(size=100000)
    
            ob = context.object
            ob.name = ob.data.name = 'PovInfinitePlane'
            bpy.ops.object.mode_set(mode="EDIT")
    
            self.report(
                {'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.pov.object_as = "PLANE"
            return {'FINISHED'}
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV box using a simple 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.addbox"
        bl_label = "Box"
        bl_description = "Add Box"
        bl_options = {'REGISTER', 'UNDO'}
    
    
        def execute(self, context):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            # layers = 20*[False]
            # layers[0] = True
            bpy.ops.mesh.primitive_cube_add()
    
            ob = context.object
            ob.name = ob.data.name = 'PovBox'
            bpy.ops.object.mode_set(mode="EDIT")
    
            self.report(
                {'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.pov.object_as = "BOX"
            return {'FINISHED'}
    
    
    
    def pov_cylinder_define(context, op, ob, radius, loc, loc_cap):
        if op:
            R = op.R
    
            loc = bpy.context.scene.cursor.location
    
            loc_cap[2] = loc[2] + 2
    
        vec = Vector(loc_cap) - Vector(loc)
        depth = vec.length
        rot = Vector((0, 0, 1)).rotation_difference(vec)  # Rotation from Z axis.
    
        trans = rot @ Vector(
            (0, 0, depth / 2)
        )  # Such that origin is at center of the base of the cylinder.
    
        roteuler = rot.to_euler()
        if not ob:
            bpy.ops.object.add(type='MESH', location=loc)
            ob = context.object
            ob.name = ob.data.name = "PovCylinder"
            ob.pov.cylinder_radius = radius
            ob.pov.cylinder_location_cap = vec
            ob.pov.object_as = "CYLINDER"
        else:
            ob.location = loc
    
        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_cylinder_add(
            radius=radius,
            depth=depth,
            location=loc,
            rotation=roteuler,
            end_fill_type='NGON',
        )  #'NOTHING'
    
        bpy.ops.transform.translate(value=trans)
    
        bpy.ops.mesh.hide(unselected=False)
        bpy.ops.object.mode_set(mode="OBJECT")
        bpy.ops.object.shade_smooth()
    
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV cylinder using pov_cylinder_define() function.
    
        Use imported_cyl_loc when this operator is run by POV importer."""
    
        bl_idname = "pov.addcylinder"
        bl_label = "Cylinder"
        bl_description = "Add Cylinder"
        bl_options = {'REGISTER', 'UNDO'}
    
    
        # XXX Keep it in sync with __init__'s cylinder Primitive
    
        R: FloatProperty(name="Cylinder radius", min=0.00, max=10.0, default=1.0)
    
        imported_cyl_loc: FloatVectorProperty(
    
            name="Imported Pov base location", precision=6, default=(0.0, 0.0, 0.0)
        )
    
        imported_cyl_loc_cap: FloatVectorProperty(
    
            name="Imported Pov cap location", precision=6, default=(0.0, 0.0, 2.0)
        )
    
        def execute(self, context):
    
            ob = context.object
    
            # layers = 20*[False]
            # layers[0] = True
    
            if ob:
                if ob.pov.imported_cyl_loc:
                    LOC = ob.pov.imported_cyl_loc
                if ob.pov.imported_cyl_loc_cap:
                    LOC_CAP = ob.pov.imported_cyl_loc_cap
            else:
                if not props.imported_cyl_loc:
    
                    LOC_CAP = LOC = bpy.context.scene.cursor.location
    
                    LOC_CAP[2] += 2.0
                else:
                    LOC = props.imported_cyl_loc
                    LOC_CAP = props.imported_cyl_loc_cap
    
                self.report(
                    {'INFO'},
                    "This native POV-Ray primitive "
                    "won't have any vertex to show in edit mode",
                )
    
    
            pov_cylinder_define(context, self, None, self.R, LOC, LOC_CAP)
    
            return {'FINISHED'}
    
    
    class POVRAY_OT_cylinder_update(bpy.types.Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Update the POV cylinder.
    
        Delete its previous proxy geometry and rerun pov_cylinder_define() function
        with the new parameters"""
    
    
        bl_idname = "pov.cylinder_update"
        bl_label = "Update"
        bl_description = "Update Cylinder"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
    
            return (
                ob
                and ob.data
                and ob.type == 'MESH'
                and ob.pov.object_as == "CYLINDER"
                and engine in cls.COMPAT_ENGINES
            )
    
    
        def execute(self, context):
            ob = context.object
            radius = ob.pov.cylinder_radius
            loc = ob.location
            loc_cap = loc + ob.pov.cylinder_location_cap
    
            pov_cylinder_define(context, None, ob, radius, loc, loc_cap)
    
    ################################SPHERE##########################################
    def pov_sphere_define(context, op, ob, loc):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """create the representation of POV sphere using a Blender icosphere.
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        Its nice platonic solid curvature better represents pov rendertime
        tesselation than a UV sphere"""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        if op:
            R = op.R
            loc = bpy.context.scene.cursor.location
        else:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            R = ob.pov.sphere_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
            obscale = ob.scale
    
    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_ico_sphere_add(
                subdivisions=4,
                radius=ob.pov.sphere_radius,
                location=loc,
                rotation=obrot,
            )
            # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            bpy.ops.transform.resize(value=obscale)
    
            # 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")
            bpy.ops.object.shade_smooth()
    
            # bpy.ops.transform.rotate(axis=obrot,orient_type='GLOBAL')
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
        if not ob:
    
            bpy.ops.mesh.primitive_ico_sphere_add(
                subdivisions=4, radius=R, location=loc
            )
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob = context.object
    
            ob.name = ob.data.name = "PovSphere"
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ob.pov.object_as = "SPHERE"
            ob.pov.sphere_radius = R
            bpy.ops.object.mode_set(mode="EDIT")
            bpy.ops.mesh.hide(unselected=False)
            bpy.ops.object.mode_set(mode="OBJECT")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV sphere using pov_sphere_define() function.
    
        Use imported_loc when this operator is run by POV importer."""
    
    
        bl_idname = "pov.addsphere"
        bl_label = "Sphere"
        bl_description = "Add Sphere Shape"
        bl_options = {'REGISTER', 'UNDO'}
    
        # XXX Keep it in sync with __init__'s torus Primitive
    
        R: FloatProperty(name="Sphere radius", min=0.00, max=10.0, default=0.5)
    
        imported_loc: FloatVectorProperty(
    
            name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0)
        )
    
        def execute(self, context):
    
                    LOC = bpy.context.scene.cursor.location
    
                    LOC = props.imported_loc
    
                    self.report(
                        {'INFO'},
                        "This native POV-Ray primitive "
                        "won't have any vertex to show in edit mode",
                    )
    
        ## layers = 20*[False]
        ## layers[0] = True
    
        # bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, radius=ob.pov.sphere_radius)
        # ob = context.object
        # bpy.ops.object.mode_set(mode="EDIT")
        # self.report({'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.pov.object_as = "SPHERE"
        # ob.name = ob.data.name = 'PovSphere'
        # return {'FINISHED'}
    
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Update the POV sphere.
    
        Delete its previous proxy geometry and rerun pov_sphere_define() function
        with the new parameters"""
    
    
        bl_idname = "pov.sphere_update"
        bl_label = "Update"
        bl_description = "Update Sphere"