# ##### 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 #####
#
#
#  Author: Sebastian Schneider
#  Web: http://www.noeol.de/attractors
#
#  Update: Jul/09/2011
#
#  tested with:
#  Blender 2.5.8.1 r38019 
#  MacOS 10.5.8 (64-Bit Intel)
#



bl_info = {
    'name': "Strange Attractors",
    'author': "Sebastian Schneider <s.schneider@noeol.de>",
    'version': (0, 3),
    'blender': (2, 5, 8),
    'api': 38019,
    'location': "View3D > Add > Mesh > Attractors",
    'description': "Adds an strange attractor mesh",
    'warning': "", 
    'wiki_url': "",
    'tracker_url': "",
    'category': "Add Mesh"}


 
import bpy
import math

from bpy.props import FloatProperty, BoolProperty, FloatVectorProperty, IntProperty



#
# Add a Peter de Jong Attractor mesh
#
class AddPeterDeJongAttractor(bpy.types.Operator):
    '''Add a Peter de Jong attractor mesh'''
    bl_idname = "mesh.peter_de_jong_attractor_add"
    bl_label = "Peter de Jong Attractor"
    bl_options = {'REGISTER', 'UNDO'}

    
    # max vertices/points
    max = IntProperty(attr="max_vertices",name="Vertices", description='', min=1, soft_min=1, default=10000)
    
    # values
    a = bpy.props.FloatProperty(attr="dejong_a",name='a',description='',default=  1.4)
    b = bpy.props.FloatProperty(attr="dejong_b",name='b',description='',default= -2.1)
    c = bpy.props.FloatProperty(attr="dejong_c",name='c',description='',default=  2.4)
    d = bpy.props.FloatProperty(attr="dejong_d",name='d',description='',default= -2.1)
    
    # fake 3-D (default = 0.0 = 2-D)
    e = bpy.props.FloatProperty(attr="dejong_e",name='e',description='',default=  0.0)
    
    # generic transform props
    view_align = BoolProperty(name="Align to View",default=False)
    location = FloatVectorProperty(name="Location",subtype='TRANSLATION')
    rotation = FloatVectorProperty(name="Rotation",subtype='EULER')


    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.prop(self, "max", text="Vertices")
        
        col = layout.column(align=True)
        col.prop(self, "a", text="a")
        col.prop(self, "b", text="b")
        col.prop(self, "c", text="c")
        col.prop(self, "d", text="d")
        
        row = layout.row()
        row.prop(self, "e", text="z")

     
    def execute(self, context):
        # create a new attractor
        mesh = bpy.data.meshes.new('Attractor')
        mesh.vertices.add(self.max)

		#import add_object_utils # 2.57
        #add_object_utils.object_data_add(context, mesh, operator=self)

        from bpy_extras import object_utils # 2.58
        object_utils.object_data_add(context, mesh, operator=None)
        
        # start at
        x = 0.1
        y = 0.0
    
        # loop to set the vertices/points
        itr = 0
        while itr < self.max:
            # Peter de Jong:
            new_x = math.sin(self.a*y)-math.cos(self.b*x)
            new_y = math.sin(self.c*x)-math.cos(self.d*y)
            new_z = self.e*math.sin(x)
            x = new_x
            y = new_y
            z = new_z
            mesh.vertices[itr].co = (x,y,z)
            itr += 1
        
        # add the halo material    
        add_halo_material()
    
        return {'FINISHED'}



#
# Add a Clifford Attractor mesh
#
class AddCliffordAttractor(bpy.types.Operator):
    '''Add a Clifford attractor mesh'''
    bl_idname = "mesh.clifford_attractor_add"
    bl_label = "Clifford Attractor"
    bl_options = {'REGISTER', 'UNDO'}

    
    # max vertices/points
    max = IntProperty(attr="max_vertices",name="Vertices", description='', min=1, soft_min=1, default=10000)
    
    # values
    a = bpy.props.FloatProperty(attr="clifford_a",name='a',description='',default=  3.0)
    b = bpy.props.FloatProperty(attr="clifford_b",name='b',description='',default=  9.0)
    c = bpy.props.FloatProperty(attr="clifford_c",name='c',description='',default=  4.0)
    d = bpy.props.FloatProperty(attr="clifford_d",name='d',description='',default= -4.0)
    
    # fake 3-D (default = 0.0 = 2-D)
    e = bpy.props.FloatProperty(attr="clifford_e",name='e',description='',default=  0.0)
    
    # generic transform props
    view_align = BoolProperty(name="Align to View",default=False)
    location = FloatVectorProperty(name="Location",subtype='TRANSLATION')
    rotation = FloatVectorProperty(name="Rotation",subtype='EULER')


    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.prop(self, "max", text="Vertices")
        
        col = layout.column(align=True)
        col.prop(self, "a", text="a")
        col.prop(self, "b", text="b")
        col.prop(self, "c", text="c")
        col.prop(self, "d", text="d")
        
        row = layout.row()
        row.prop(self, "e", text="z")

     
    def execute(self, context):
        # create a new attractor
        mesh = bpy.data.meshes.new('Attractor')
        mesh.vertices.add(self.max)

		#import add_object_utils # 2.57
        #add_object_utils.object_data_add(context, mesh, operator=self)

        from bpy_extras import object_utils # 2.58
        object_utils.object_data_add(context, mesh, operator=None)

        # start at
        x = 0.1
        y = 0.0
    
        # loop to set the vertices/points
        itr = 0
        while itr < self.max:
            # Clifford:
            new_x = math.sin(self.a*y)+self.c*math.cos(self.a*x)
            new_y = math.sin(self.b*x)+self.d*math.cos(self.b*y)
            new_z = self.e*math.sin(x)
            x = new_x
            y = new_y
            z = new_z
            mesh.vertices[itr].co = (x,y,z)
            itr += 1
        
        # add the halo material    
        add_halo_material()
    
        return {'FINISHED'}



#
# Add a Lorenz Attractor mesh
#
class AddLorenzAttractor(bpy.types.Operator):
    '''Add a Lorenz attractor mesh'''
    bl_idname = "mesh.lorenz_attractor_add"
    bl_label = "Lorenz Attractor"
    bl_options = {'REGISTER', 'UNDO'}

    
    # max vertices/points
    max = IntProperty(attr="max_vertices",name="Vertices", description='', min=1, soft_min=1, default=10000)
    
    # values
    h = bpy.props.FloatProperty(attr="lorenz_h",name='h',description='',default=  0.01)
    a = bpy.props.FloatProperty(attr="lorenz_a",name='a',description='',default= 10.00)
    b = bpy.props.FloatProperty(attr="lorenz_b",name='b',description='',default= 28.00)
    c = bpy.props.FloatProperty(attr="lorenz_c",name='c',description='',default= (8/3))
    
    # generic transform props
    view_align = BoolProperty(name="Align to View",default=False)
    location = FloatVectorProperty(name="Location",subtype='TRANSLATION')
    rotation = FloatVectorProperty(name="Rotation",subtype='EULER')


    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.prop(self, "max", text="Vertices")
        
        col = layout.column(align=True)
        col.prop(self, "h", text="h")
        col.prop(self, "a", text="a")
        col.prop(self, "b", text="b")
        col.prop(self, "c", text="c")

     
    def execute(self, context):
        # create a new attractor
        mesh = bpy.data.meshes.new('Attractor')
        mesh.vertices.add(self.max)

		#import add_object_utils # 2.57
        #add_object_utils.object_data_add(context, mesh, operator=self)

        from bpy_extras import object_utils # 2.58
        object_utils.object_data_add(context, mesh, operator=None)

        # start at
        x = 0.1
        y = 0.0
        z = 0.0
    
        # loop to set the vertices/points
        itr = 0
        while itr < self.max:
            # Lorenz:
            new_x = x + self.h * self.a * (y - x)
            new_y = y + self.h * (x * (self.b - z) - y)
            new_z = z + self.h * (x * y - self.c * z)
            x = new_x
            y = new_y
            z = new_z
            mesh.vertices[itr].co = (x,y,z)
            itr += 1
        
        # scale down
        obj = bpy.context.active_object
        obj.scale[0] = 0.08
        obj.scale[1] = 0.08
        obj.scale[2] = 0.08
        
        
        # add the halo material    
        add_halo_material(0.016, (1,1,1))
    
        return {'FINISHED'}



#
# Add a halo material
#
def add_halo_material(size=0.008, color=(1,1,1)):
    
        # check for existing halo material    
        mat_exists = False
        for mat in bpy.data.materials:
            if(mat.name == 'Attractor Halo'):
                mat_exists = True

        if(mat_exists):
            # get the halo material
            obj = bpy.context.active_object
            mat = bpy.data.materials['Attractor Halo']
            mat.diffuse_color = color
            haloMat = mat.halo
            haloMat.size = size
            obj.data.materials.append(mat)
        else:
            # create a new halo material
            obj = bpy.context.active_object
            mat = bpy.data.materials.new('Attractor Halo')
            mat.type = 'HALO'
            mat.diffuse_color = color
            haloMat = mat.halo
            haloMat.size = size
            haloMat.hardness = 127
            obj.data.materials.append(mat)

  
  
#  
# 3dView > add > mesh > 'Attractors' menu  
#  
class INFO_MT_mesh_attractor_add(bpy.types.Menu):
    bl_idname = "INFO_MT_mesh_attractor_add"
    bl_label = "Attractors"

    def draw(self, context):
        layout = self.layout
        layout.operator_context = 'INVOKE_REGION_WIN'
        layout.operator("mesh.peter_de_jong_attractor_add",text="Peter de Jong")
        layout.operator("mesh.clifford_attractor_add",text="Clifford")       
        layout.operator("mesh.lorenz_attractor_add",text="Lorenz")


        
# 3dview add menu
def menu_func(self, context):
    self.layout.menu("INFO_MT_mesh_attractor_add", icon="PLUGIN")
        

def register():
    bpy.utils.register_module(__name__)
    bpy.types.INFO_MT_mesh_add.append(menu_func)


def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.INFO_MT_mesh_add.remove(menu_func)


if __name__ == "__main__":
    register()
    
