Skip to content
Snippets Groups Projects
primitives.py 75.4 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>
    
    
    ############ To get POV-Ray specific objects In and Out of Blender ###########
    
    import bpy
    
    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,
            )
    
    
    Campbell Barton's avatar
    Campbell Barton committed
        Vector,
        Matrix,
    )
    
    
    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()
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        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_idname = "pov.addlathe"
        bl_label = "Lathe"
        bl_options = {'REGISTER','UNDO'}
        bl_description = "adds lathe"
    
    
        def execute(self, context):
    
            #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),
    
                #layers=layers,
    
            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
    
    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:
            assert(ob)
            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 = []
        r=1
    
        stepSegment=360/v*pi/180
        stepRing=pi/u
        angSegment=0
        angRing=-pi/2
    
        step=0
        for ring in range(0,u-1):
            angRing += stepRing
            for segment in range(0,v):
                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):
                    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):
                    y = -y
                z = r*(abs(sin(angRing))**n1)
                if sin(angRing) < 0:
                    z = -z
                x = round(x,4)
                y = round(y,4)
                z = round(z,4)
                verts.append((x,y,z))
        if edit == 'TRIANGLES':
            verts.append((0,0,1))
            verts.append((0,0,-1))
    
        faces = []
    
        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)
                    faces.append(face)
                if i == v-1:
                    face=(indexDown,i,0)
                    faces.append(face)
            for i in range(0,v):
                if i < v-1:
                    face=(indexUp,i+indexStartDown,i+indexStartDown+1)
                    faces.append(face)
                if i == v-1:
                    face=(indexUp,i+indexStartDown,indexStartDown)
                    faces.append(face)
        if edit == 'NGONS':
            face=[]
            for i in range(0,v):
                face.append(i)
            faces.append(face)
            face=[]
            indexUp=len(verts)-1
            for i in range(0,v):
                face.append(indexUp-i)
            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?
            ob = context.object
            ob.name =  ob.data.name = "PovSuperellipsoid"
            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):
            pov_superellipsoid_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_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):
                fan = True
            else:
                return None
        total = len(vertIdx2)
        if closed:
            if flipped:
                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]]
                faces.append(face)
    
        return faces
    
    def power(a,b):
        if a < 0:
            return -((-a)**b)
        return a**b
    
    def supertoroid(R,r,u,v,n1,n2):
        a = 2*pi/u
        b = 2*pi/v
        verts = []
        faces = []
        for i in range(u):
            s = power(sin(i*a),n1)
            c = power(cos(i*a),n1)
            for j in range(v):
                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))?
            if i > 0:
                f = createFaces(range((i-1)*v,i*v),range(i*v,(i+1)*v),closed = True)
                faces.extend(f)
        f = createFaces(range((u-1)*v,u*v),range(v),closed=True)
        faces.extend(f)
        return verts, faces
    
    
    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:
    
    Dalai Felinto's avatar
    Dalai Felinto committed
                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="",
    
                            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'}
    
    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
    
            n=props.loft_n
            thick = props.loft_thick
            side = props.loft_rings_side
            bottom = props.loft_rings_bottom
            h = props.loft_height
            r = props.loft_r
            distB = r/bottom
            r0 = 0.00001
            z = -h/2
            print("New")
            for i in range(bottom+1):
                coords = []
                angle = 0
                for p in range(n):
                    x = r0*cos(angle)
                    y = r0*sin(angle)
                    coords.append((x,y,z))
                    angle+=pi*2/n
                r0+=distB
                nurbs = loftData.splines.new('NURBS')
                nurbs.points.add(len(coords)-1)
                for i, coord in enumerate(coords):
                    x,y,z = coord
                    nurbs.points[i].co = (x, y, z, 1)
                nurbs.use_cyclic_u = True
            for i in range(side):
                z+=h/side
                coords = []
                angle = 0
                for p in range(n):
                    x = r*cos(angle)
                    y = r*sin(angle)
                    coords.append((x,y,z))
                    angle+=pi*2/n
                nurbs = loftData.splines.new('NURBS')
                nurbs.points.add(len(coords)-1)
                for i, coord in enumerate(coords):
                    x,y,z = coord
                    nurbs.points[i].co = (x, y, z, 1)
                nurbs.use_cyclic_u = True
            r-=thick
            for i in range(side):
                coords = []
                angle = 0
                for p in range(n):
                    x = r*cos(angle)
                    y = r*sin(angle)
                    coords.append((x,y,z))
                    angle+=pi*2/n
                nurbs = loftData.splines.new('NURBS')
                nurbs.points.add(len(coords)-1)
                for i, coord in enumerate(coords):
                    x,y,z = coord
                    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):
                coords = []
                angle = 0
                for p in range(n):
                    x = r*cos(angle)
                    y = r*sin(angle)
                    coords.append((x,y,z))
                    angle+=pi*2/n
                r-=distB
                nurbs = loftData.splines.new('NURBS')
                nurbs.points.add(len(coords)-1)
                for i, coord in enumerate(coords):
                    x,y,z = coord
                    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)
    
            ob.pov.curveshape = "loft"
            return {'FINISHED'}
    
    class POVRAY_OT_plane_add(bpy.types.Operator):
    
    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):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            #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[0] = loc[0]
            loc_cap[1] = loc[1]
            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.
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        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(
    
            precision=6,
            default=(0.0, 0.0, 0.0))
    
        imported_cyl_loc_cap: FloatVectorProperty(
    
            precision=6,
    
            ob = context.object
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            #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:
            assert(ob)
            R = ob.pov.sphere_radius
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            #keep object rotation and location for the add object operator
            obrot = ob.rotation_euler
            #obloc = ob.location
            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')
            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')
    
        if not ob:
            bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, radius=R, location=loc)
            ob = context.object
            ob.name =  ob.data.name = "PovSphere"
            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(
    
            precision=6,
    
        def execute(self,context):
            props = self.properties
            R = props.R
            ob = context.object
    
                    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")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            ## layers = 20*[False]
            ## layers[0] = True
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            # 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'}
    class POVRAY_OT_sphere_update(bpy.types.Operator):
    
    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"
        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):
    
            pov_sphere_define(context, None, context.object,context.object.location)
    
    
            return {'FINISHED'}
    
    
    
    ####################################CONE#######################################
    def pov_cone_define(context, op, ob):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV cone using pov_define_mesh() function.
    
        Blender cone does not offer the same features such as a second radius."""
    
        verts = []
        faces = []
        if op:
            mesh = None
            base = op.base
            cap = op.cap
            seg = op.seg
            height = op.height
        else:
            assert(ob)
            mesh = ob.data
            base = ob.pov.cone_base_radius
            cap = ob.pov.cone_cap_radius
            seg = ob.pov.cone_segments
    
            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:
    
    Dalai Felinto's avatar
    Dalai Felinto committed
            ob = object_utils.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(bpy.types.Operator):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        """Add the representation of POV cone using pov_cone_define() function."""
    
    
        bl_idname = "pov.cone_add"
        bl_label = "Cone"
        bl_description = "Add Cone"
        bl_options = {'REGISTER', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        # XXX Keep it in sync with __init__.py's RenderPovSettingsConePrimitive
    
        #     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(
    
            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)
    
        def execute(self, context):
            pov_cone_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_cone_update(bpy.types.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"""