# Copyright (c) 2012 Jorge Hernandez - Melendez

# ##### 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 #####

# TODO : prop names into English, add missing tooltips

bl_info = {
    "name": "Rope Creator",
    "description": "Dynamic rope (with cloth) creator",
    "author": "Jorge Hernandez - Melenedez",
    "version": (0, 2, 2),
    "blender": (2, 7, 3),
    "location": "Left Toolbar > ClothRope",
    "warning": "",
    "wiki_url": "",
    "category": "Add Mesh"
}


import bpy
from bpy.types import Operator
from bpy.props import (
        BoolProperty,
        FloatProperty,
        IntProperty,
        )


def desocultar(quien):
    if quien == "todo":
        for ob in bpy.data.objects:
            ob.hide = False
    else:
        bpy.data.objects[quien].hide = False


def deseleccionar_todo():
    bpy.ops.object.select_all(action='DESELECT')


def seleccionar_todo():
    bpy.ops.object.select_all(action='SELECT')


def salir_de_editmode():
    if bpy.context.mode in ["EDIT", "EDIT_MESH", "EDIT_CURVE"]:
        bpy.ops.object.mode_set(mode='OBJECT')


# Clear scene:
def reset_scene():
    desocultar("todo")
    # playback to the start
    bpy.ops.screen.frame_jump(end=False)
    try:
        salir_de_editmode()
    except:
        pass
    try:
        area = bpy.context.area
        # expand everything in the outliner to be able to select children
        old_type = area.type
        area.type = 'OUTLINER'
        bpy.ops.outliner.expanded_toggle()

        # restore the original context
        area.type = old_type

        seleccionar_todo()
        bpy.ops.object.delete(use_global=False)

    except Exception as e:
        print("\n[rope_alpha]\nfunction: reset_scene\nError: %s" % e)


def entrar_en_editmode():
    if bpy.context.mode == "OBJECT":
        bpy.ops.object.mode_set(mode='EDIT')


def select_all_in_edit_mode(ob):
    if ob.mode != 'EDIT':
        entrar_en_editmode()
    bpy.ops.mesh.select_all(action="DESELECT")
    bpy.context.tool_settings.mesh_select_mode = (True, False, False)
    salir_de_editmode()
    for v in ob.data.vertices:
        if not v.select:
            v.select = True
    entrar_en_editmode()


def deselect_all_in_edit_mode(ob):
    if ob.mode != 'EDIT':
        entrar_en_editmode()
    bpy.ops.mesh.select_all(action="DESELECT")
    bpy.context.tool_settings.mesh_select_mode = (True, False, False)
    salir_de_editmode()
    for v in ob.data.vertices:
        if not v.select:
            v.select = False
    entrar_en_editmode()


def which_vertex_are_selected(ob):
    for v in ob.data.vertices:
        if v.select:
            print(str(v.index))
            print("Vertex " + str(v.index) + " is selected")


def seleccionar_por_nombre(nombre):
    scn = bpy.context.scene
    bpy.data.objects[nombre].select = True

    scn.objects.active = bpy.data.objects[nombre]


def deseleccionar_por_nombre(nombre):
    bpy.data.objects[nombre].select = False


def crear_vertices(ob):
    ob.data.vertices.add(1)
    ob.data.update


def borrar_elementos_seleccionados(tipo):
    if tipo == "vertices":
        bpy.ops.mesh.delete(type='VERT')


def obtener_coords_vertex_seleccionados():
    coordenadas_de_vertices = []
    for ob in bpy.context.selected_objects:
        if ob.type == 'MESH':
            for v in ob.data.vertices:
                if v.select:
                    coordenadas_de_vertices.append([v.co[0], v.co[1], v.co[2]])
            return coordenadas_de_vertices[0]


def crear_locator(pos):
    bpy.ops.object.empty_add(
            type='PLAIN_AXES', radius=1, view_align=False,
            location=(pos[0], pos[1], pos[2]),
            layers=(True, False, False, False, False, False, False,
                    False, False, False, False, False, False, False,
                    False, False, False, False, False, False)
            )


def extruir_vertices(longitud, cuantos_segmentos):
    bpy.ops.mesh.extrude_region_move(
            MESH_OT_extrude_region={"mirror": False},
            TRANSFORM_OT_translate={
                    "value": (longitud / cuantos_segmentos, 0, 0),
                    "constraint_axis": (True, False, False),
                    "constraint_orientation": 'GLOBAL', "mirror": False,
                    "proportional": 'DISABLED', "proportional_edit_falloff": 'SMOOTH',
                    "proportional_size": 1, "snap": False, "snap_target": 'CLOSEST',
                    "snap_point": (0, 0, 0), "snap_align": False, "snap_normal": (0, 0, 0),
                    "gpencil_strokes": False, "texture_space": False,
                    "remove_on_cancel": False, "release_confirm": False
                    }
            )


def select_all_vertex_in_curve_bezier(bc):
    for i in range(len(bc.data.splines[0].points)):
        bc.data.splines[0].points[i].select = True


def deselect_all_vertex_in_curve_bezier(bc):
    for i in range(len(bc.data.splines[0].points)):
        bc.data.splines[0].points[i].select = False


def ocultar_relationships():
    for area in bpy.context.screen.areas:
        if area.type == 'VIEW_3D':
            area.spaces[0].show_relationship_lines = False


class ClothRope(Operator):
    bl_idname = "clot.rope"
    bl_label = "Rope Cloth"
    bl_description = ("Create a new Scene with a Cloth modifier\n"
                      "Rope Simulation with hooked Helper Objects")

    ropelength = IntProperty(
            name="Rope Length",
            description="Length of the generated Rope",
            default=5
            )
    ropesegments = IntProperty(
            name="Rope Segments",
            description="Number of the Rope Segments",
            default=5
            )
    qcr = IntProperty(
            name="Collision Quality",
            description="Rope's Cloth modifier collsion quality",
            min=1, max=20,
            default=20
            )
    substeps = IntProperty(
            name="Rope Substeps",
            description="Rope's Cloth modifier quality",
            min=4, max=80,
            default=50
            )
    resrope = IntProperty(
            name="Rope Resolution",
            description="Rope's Bevel resolution",
            default=5
            )
    radiusrope = FloatProperty(
            name="Radius",
            description="Rope's Radius",
            min=0.04, max=1,
            default=0.04
            )
    hide_emptys = BoolProperty(
            name="Hide Empties",
            description="Hide Helper Objects",
            default=False
            )

    def execute(self, context):
        # add a new scene
        bpy.ops.scene.new(type="NEW")
        scene = bpy.context.scene
        scene.name = "Test Rope"
        seleccionar_todo()
        longitud = self.ropelength

        # For the middle to have x segments between the first and
        # last point, must add 1 to the quantity:
        cuantos_segmentos = self.ropesegments + 1
        calidad_de_colision = self.qcr
        substeps = self.substeps
        deseleccionar_todo()
        # collect the possible empties that already exist in the data
        empties_prev = [obj.name for obj in bpy.data.objects if obj.type == "EMPTY"]

        # create an empty that will be the parent of everything
        bpy.ops.object.empty_add(
                type='SPHERE', radius=1, view_align=False, location=(0, 0, 0),
                layers=(True, False, False, False, False, False, False, False,
                        False, False, False, False, False, False, False, False,
                        False, False, False, False)
                )
        ob = bpy.context.selected_objects[0]
        ob.name = "Rope"
        # .001 and friends
        rope_name = ob.name
        deseleccionar_todo()

        # create a plane and delete it
        bpy.ops.mesh.primitive_plane_add(
                radius=1, view_align=False, enter_editmode=False, location=(0, 0, 0),
                layers=(True, False, False, False, False, False, False, False, False,
                        False, False, False, False, False, False, False, False,
                        False, False, False)
                )
        ob = bpy.context.selected_objects[0]
        # rename:
        ob.name = "cuerda"
        # .001 and friends
        cuerda_1_name = ob.name

        entrar_en_editmode()  # enter edit mode
        select_all_in_edit_mode(ob)

        borrar_elementos_seleccionados("vertices")
        salir_de_editmode()  # leave edit mode
        crear_vertices(ob)  # create a vertex

        # Creating a Group for the PIN
        # Group contains the vertices of the pin and the Group.001 contains the single main line
        entrar_en_editmode()  # enter edit mode
        bpy.ops.object.vertex_group_add()  # create a group
        select_all_in_edit_mode(ob)
        bpy.ops.object.vertex_group_assign()  # assign it

        salir_de_editmode()  # leave edit mode
        ob.vertex_groups[0].name = "Pin"
        deseleccionar_todo()
        seleccionar_por_nombre(cuerda_1_name)

        # extrude vertices:
        for i in range(cuantos_segmentos):
            entrar_en_editmode()
            extruir_vertices(longitud, cuantos_segmentos)
            # delete the PIN group
            bpy.ops.object.vertex_group_remove_from()
            # get the direction to create the locator on it's position
            pos = obtener_coords_vertex_seleccionados()

            salir_de_editmode()  # leave edit mode
            # create locator at position
            crear_locator(pos)
            deseleccionar_todo()
            seleccionar_por_nombre(cuerda_1_name)
        deseleccionar_todo()

        seleccionar_por_nombre(cuerda_1_name)  # select the rope
        entrar_en_editmode()

        pos = obtener_coords_vertex_seleccionados()  # get their positions
        salir_de_editmode()
        # create the last locator
        crear_locator(pos)
        deseleccionar_todo()
        seleccionar_por_nombre(cuerda_1_name)
        entrar_en_editmode()  # enter edit mode
        bpy.ops.object.vertex_group_add()  # Creating Master guide group
        select_all_in_edit_mode(ob)
        bpy.ops.object.vertex_group_assign()  # and assign it
        ob.vertex_groups[1].name = "Guide_rope"

        # extrude the Curve so it has a minimum thickness for collide
        bpy.ops.mesh.extrude_region_move(
                MESH_OT_extrude_region={"mirror": False},
                TRANSFORM_OT_translate={
                        "value": (0, 0.005, 0), "constraint_axis": (False, True, False),
                        "constraint_orientation": 'GLOBAL', "mirror": False,
                        "proportional": 'DISABLED', "proportional_edit_falloff": 'SMOOTH',
                        "proportional_size": 1, "snap": False, "snap_target": 'CLOSEST',
                        "snap_point": (0, 0, 0), "snap_align": False, "snap_normal": (0, 0, 0),
                        "gpencil_strokes": False, "texture_space": False,
                        "remove_on_cancel": False, "release_confirm": False
                        }
                )
        bpy.ops.object.vertex_group_remove_from()
        deselect_all_in_edit_mode(ob)
        salir_de_editmode()
        bpy.ops.object.modifier_add(type='CLOTH')
        bpy.context.object.modifiers["Cloth"].settings.use_pin_cloth = True
        bpy.context.object.modifiers["Cloth"].settings.vertex_group_mass = "Pin"
        bpy.context.object.modifiers["Cloth"].collision_settings.collision_quality = calidad_de_colision
        bpy.context.object.modifiers["Cloth"].settings.quality = substeps

        # Duplicate to convert into Curve:
        # select the vertices that are the part of the Group.001
        seleccionar_por_nombre(cuerda_1_name)
        entrar_en_editmode()
        bpy.ops.mesh.select_all(action="DESELECT")
        bpy.context.tool_settings.mesh_select_mode = (True, False, False)
        salir_de_editmode()
        gi = ob.vertex_groups["Guide_rope"].index  # get group index

        for v in ob.data.vertices:
            for g in v.groups:
                if g.group == gi:  # compare with index in VertexGroupElement
                    v.select = True

        # now we have to make a table of names of cuerdas to see which one will be new
        cuerda_names = [obj.name for obj in bpy.data.objects if "cuerda" in obj.name]

        entrar_en_editmode()

        # we already have the selected guide:
        # duplicate it:
        bpy.ops.mesh.duplicate_move(
                MESH_OT_duplicate={"mode": 1},
                TRANSFORM_OT_translate={
                        "value": (0, 0, 0), "constraint_axis": (False, False, False),
                        "constraint_orientation": 'GLOBAL', "mirror": False,
                        "proportional": 'DISABLED', "proportional_edit_falloff": 'SMOOTH',
                        "proportional_size": 1, "snap": False, "snap_target": 'CLOSEST',
                        "snap_point": (0, 0, 0), "snap_align": False, "snap_normal": (0, 0, 0),
                        "gpencil_strokes": False, "texture_space": False,
                        "remove_on_cancel": False, "release_confirm": False
                        }
                )
        # separate the selections:
        bpy.ops.mesh.separate(type='SELECTED')
        salir_de_editmode()
        deseleccionar_todo()

        cuerda_2_name = "cuerda.001"
        test = []
        for obj in bpy.data.objects:
            if "cuerda" in obj.name and obj.name not in cuerda_names:
                cuerda_2_name = obj.name
                test.append(obj.name)

        seleccionar_por_nombre(cuerda_2_name)

        # from the newly created curve remove the Cloth:
        bpy.ops.object.modifier_remove(modifier="Cloth")
        # convert the Curve:
        bpy.ops.object.convert(target='CURVE')

        # all Empties that are not previously present
        emptys = []
        for eo in bpy.data.objects:
            if eo.type == 'EMPTY' and eo.name not in empties_prev:
                if eo.name != rope_name:
                    emptys.append(eo)

        # select and deselect:
        bc = bpy.data.objects[cuerda_2_name]
        n = 0

        for e in emptys:
            deseleccionar_todo()
            seleccionar_por_nombre(e.name)
            seleccionar_por_nombre(bc.name)
            entrar_en_editmode()
            deselect_all_vertex_in_curve_bezier(bc)
            bc.data.splines[0].points[n].select = True
            bpy.ops.object.hook_add_selob(use_bone=False)
            salir_de_editmode()
            n = n + 1

        ob = bpy.data.objects[cuerda_1_name]
        n = 0

        for e in emptys:
            deseleccionar_todo()
            seleccionar_por_nombre(e.name)
            seleccionar_por_nombre(ob.name)
            entrar_en_editmode()
            bpy.ops.mesh.select_all(action="DESELECT")
            bpy.context.tool_settings.mesh_select_mode = (True, False, False)
            salir_de_editmode()

            for v in ob.data.vertices:
                if v.select:
                    v.select = False
            ob.data.vertices[n].select = True
            entrar_en_editmode()
            bpy.ops.object.vertex_parent_set()

            salir_de_editmode()
            n = n + 1

            # hide the Empties:
            deseleccionar_todo()

        # all parented to the spherical empty:
        seleccionar_por_nombre(cuerda_2_name)
        seleccionar_por_nombre(cuerda_1_name)
        seleccionar_por_nombre(rope_name)
        bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
        deseleccionar_todo()

        # do not display the relations
        ocultar_relationships()
        seleccionar_por_nombre(cuerda_2_name)

        # curved rope settings:
        bpy.context.object.data.fill_mode = 'FULL'
        bpy.context.object.data.bevel_depth = self.radiusrope
        bpy.context.object.data.bevel_resolution = self.resrope

        return {'FINISHED'}

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

    def draw(self, context):
        layout = self.layout
        box = layout.box()
        col = box.column(align=True)

        col.label("Rope settings:")
        rowsub0 = col.row()
        rowsub0.prop(self, "ropelength", text="Length")
        rowsub0.prop(self, "ropesegments", text="Segments")
        rowsub0.prop(self, "radiusrope", text="Radius")

        col.label("Quality Settings:")
        col.prop(self, "resrope", text="Resolution curve")
        col.prop(self, "qcr", text="Quality Collision")
        col.prop(self, "substeps", text="Substeps")


class BallRope(Operator):
    bl_idname = "ball.rope"
    bl_label = "Wrecking Ball"
    bl_description = ("Create a new Scene with a Rigid Body simulation of\n"
                      "Wrecking Ball on a rope")

    # defaults rope ball
    ropelength2 = IntProperty(
            name="Rope Length",
            description="Length of the Wrecking Ball rope",
            default=10
            )
    ropesegments2 = IntProperty(
            name="Rope Segments",
            description="Number of the Wrecking Ball rope segments",
            min=0, max=999,
            default=6
            )
    radiuscubes = FloatProperty(
            name="Cube Radius",
            description="Size of the Linked Cubes helpers",
            default=0.5
            )
    radiusrope = FloatProperty(
            name="Rope Radius",
            description="Radius of the Rope",
            default=0.4
            )
    worldsteps = IntProperty(
            name="World Steps",
            description="Rigid Body Solver world steps per second (update)",
            min=60, max=1000,
            default=250
            )
    solveriterations = IntProperty(
            name="Solver Iterations",
            description="How many times the Rigid Body Solver should run",
            min=10, max=100,
            default=50
            )
    massball = IntProperty(
            name="Ball Mass",
            description="Mass of the Wrecking Ball",
            default=1
            )
    resrope = IntProperty(
            name="Resolution",
            description="Rope resolution",
            default=4
            )
    grados = FloatProperty(
            name="Degrees",
            description="Angle of the Wrecking Ball compared to the Ground Plane",
            default=45
            )
    separacion = FloatProperty(
            name="Link Cubes Gap",
            description="Space between the Rope's Linked Cubes",
            default=0.1
            )
    hidecubes = BoolProperty(
            name="Hide Link Cubes",
            description="Hide helper geometry for the Rope",
            default=False
            )

    def execute(self, context):
        world_steps = self.worldsteps
        solver_iterations = self.solveriterations
        longitud = self.ropelength2

        # make a + 2, so the segments will be between the two end points...
        segmentos = self.ropesegments2 + 2
        offset_del_suelo = 1
        offset_del_suelo_real = (longitud / 2) + (segmentos / 2)
        radio = self.radiuscubes
        radiorope = self.radiusrope
        masa = self.massball
        resolucion = self.resrope
        rotrope = self.grados
        separation = self.separacion
        hidecubeslinks = self.hidecubes

        # add new scene
        bpy.ops.scene.new(type="NEW")
        scene = bpy.context.scene
        scene.name = "Test Ball"

        # collect the possible constraint empties that already exist in the data
        constraint_prev = [obj.name for obj in bpy.data.objects if
                           obj.type == "EMPTY" and "Constraint" in obj.name]
        # floor:
        bpy.ops.mesh.primitive_cube_add(
                radius=1, view_align=False, enter_editmode=False, location=(0, 0, 0),
                layers=(True, False, False, False, False, False, False, False, False,
                        False, False, False, False, False, False, False, False,
                        False, False, False)
                )
        bpy.context.object.scale.x = 10 + longitud
        bpy.context.object.scale.y = 10 + longitud
        bpy.context.object.scale.z = 0.05
        bpy.context.object.name = "groundplane"
        # The secret agents .001, 002 etc.
        groundplane_name = bpy.context.object.name

        bpy.ops.rigidbody.objects_add(type='PASSIVE')

        # create the first cube:
        cuboslink = []
        n = 0
        for i in range(segmentos):
            # if 0 start from 1
            if i == 0:
                i = offset_del_suelo
            else:  # if it is not 0, add one so it doesn't step on the first one starting from 1
                i = i + offset_del_suelo
            separacion = longitud * 2 / segmentos  # distance between linked cubes
            bpy.ops.mesh.primitive_cube_add(
                    radius=1, view_align=False, enter_editmode=False,
                    location=(0, 0, i * separacion),
                    layers=(True, False, False, False, False, False, False, False,
                            False, False, False, False, False, False, False, False,
                            False, False, False, False)
                    )
            bpy.ops.rigidbody.objects_add(type='ACTIVE')
            bpy.context.object.name = "CubeLink"
            if n != 0:
                bpy.context.object.draw_type = 'WIRE'
                bpy.context.object.hide_render = True
            n += 1
            bpy.context.object.scale.z = (longitud * 2) / (segmentos * 2) - separation
            bpy.context.object.scale.x = radio
            bpy.context.object.scale.y = radio
            cuboslink.append(bpy.context.object)

        for i in range(len(cuboslink)):
            deseleccionar_todo()
            if i != len(cuboslink) - 1:
                nombre1 = cuboslink[i]
                nombre2 = cuboslink[i + 1]
                seleccionar_por_nombre(nombre1.name)
                seleccionar_por_nombre(nombre2.name)
                bpy.ops.rigidbody.connect()

        # select by name
        constraint_new = [
                    obj.name for obj in bpy.data.objects if
                    obj.type == "EMPTY" and "Constraint" in obj.name and
                    obj.name not in constraint_prev
                    ]

        for names in constraint_new:
            seleccionar_por_nombre(names)

        for c in bpy.context.selected_objects:
            c.rigid_body_constraint.type = 'POINT'
        deseleccionar_todo()

        # create a Bezier curve:
        bpy.ops.curve.primitive_bezier_curve_add(
                radius=1, view_align=False, enter_editmode=False, location=(0, 0, 0),
                layers=(True, False, False, False, False, False, False, False, False,
                False, False, False, False, False, False, False, False, False, False, False)
                )
        bpy.context.object.name = "Cuerda"
        # Blender will automatically append the .001
        # if it is already in data
        real_name = bpy.context.object.name

        for i in range(len(cuboslink)):
            cubonombre = cuboslink[i].name
            seleccionar_por_nombre(cubonombre)
            seleccionar_por_nombre(real_name)
            x = cuboslink[i].location[0]
            y = cuboslink[i].location[1]
            z = cuboslink[i].location[2]

            # if it is 0 make it start from 1 as the offset from the ground...
            if i == 0:
                i = offset_del_suelo
            else:  # if it is not 0, add one so it doesn't step on the first one starting from 1
                i = i + offset_del_suelo

            salir_de_editmode()
            entrar_en_editmode()

            if i == 1:
                # select all the vertices and delete them
                select_all_vertex_in_curve_bezier(bpy.data.objects[real_name])
                bpy.ops.curve.delete(type='VERT')
                # create the first vertex:
                bpy.ops.curve.vertex_add(location=(x, y, z))
            else:
                # extrude the rest:
                bpy.ops.curve.extrude_move(
                        CURVE_OT_extrude={"mode": 'TRANSLATION'},
                        TRANSFORM_OT_translate={
                            "value": (0, 0, z / i),
                            "constraint_axis": (False, False, True),
                            "constraint_orientation": 'GLOBAL', "mirror": False,
                            "proportional": 'DISABLED', "proportional_edit_falloff": 'SMOOTH',
                            "proportional_size": 1, "snap": False, "snap_target": 'CLOSEST',
                            "snap_point": (0, 0, 0), "snap_align": False, "snap_normal": (0, 0, 0),
                            "gpencil_strokes": False, "texture_space": False,
                            "remove_on_cancel": False, "release_confirm": False
                            }
                        )
            bpy.ops.object.hook_add_selob(use_bone=False)
            salir_de_editmode()
            bpy.context.object.data.bevel_resolution = resolucion
            deseleccionar_todo()

        # create a sphere ball:
        deseleccionar_todo()
        seleccionar_por_nombre(cuboslink[0].name)
        entrar_en_editmode()
        z = cuboslink[0].scale.z + longitud / 2
        bpy.ops.view3d.snap_cursor_to_selected()
        bpy.ops.mesh.primitive_uv_sphere_add(
                view_align=False, enter_editmode=False,
                layers=(True, False, False, False, False, False, False,
                        False, False, False, False, False, False, False,
                        False, False, False, False, False, False)
                )
        bpy.ops.transform.translate(
                value=(0, 0, -z + 2), constraint_axis=(False, False, True),
                constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
                proportional_edit_falloff='SMOOTH', proportional_size=1
                )
        bpy.ops.transform.resize(
                value=(longitud / 2, longitud / 2, longitud / 2),
                constraint_axis=(False, False, False),
                constraint_orientation='GLOBAL',
                mirror=False, proportional='DISABLED',
                proportional_edit_falloff='SMOOTH', proportional_size=1
                )
        deselect_all_in_edit_mode(cuboslink[0])
        salir_de_editmode()
        bpy.ops.object.shade_smooth()
        bpy.context.object.rigid_body.mass = masa
        bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS')

        # move it all up a bit more:
        seleccionar_todo()
        deseleccionar_por_nombre(groundplane_name)
        bpy.ops.transform.translate(
                value=(0, 0, offset_del_suelo_real),
                constraint_axis=(False, False, True),
                constraint_orientation='GLOBAL', mirror=False,
                proportional='DISABLED', proportional_edit_falloff='SMOOTH',
                proportional_size=1
                )

        deseleccionar_todo()
        seleccionar_por_nombre(cuboslink[-1].name)
        bpy.ops.rigidbody.objects_add(type='PASSIVE')

        bpy.context.scene.rigidbody_world.steps_per_second = world_steps
        bpy.context.scene.rigidbody_world.solver_iterations = solver_iterations

        # move everything from the top one:
        seleccionar_por_nombre(cuboslink[-1].name)
        bpy.ops.view3d.snap_cursor_to_selected()
        seleccionar_todo()
        deseleccionar_por_nombre(groundplane_name)
        deseleccionar_por_nombre(cuboslink[-1].name)
        bpy.context.space_data.pivot_point = 'CURSOR'
        bpy.ops.transform.rotate(
                value=rotrope, axis=(1, 0, 0),
                constraint_axis=(True, False, False),
                constraint_orientation='GLOBAL',
                mirror=False, proportional='DISABLED',
                proportional_edit_falloff='SMOOTH',
                proportional_size=1
                )
        bpy.context.space_data.pivot_point = 'MEDIAN_POINT'
        deseleccionar_todo()

        seleccionar_por_nombre(real_name)
        bpy.context.object.data.fill_mode = 'FULL'
        bpy.context.object.data.bevel_depth = radiorope
        for ob in bpy.data.objects:
            if ob.name != cuboslink[0].name:
                if ob.name.find("CubeLink") >= 0:
                    deseleccionar_todo()
                    seleccionar_por_nombre(ob.name)
                    if hidecubeslinks:
                        bpy.context.object.hide = True
        ocultar_relationships()
        deseleccionar_todo()
        return {'FINISHED'}

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

    def draw(self, context):
        layout = self.layout
        box = layout.box()
        col = box.column(align=True)

        col.label("Rope settings:")
        rowsub0 = col.row()
        rowsub0.prop(self, "hidecubes", text="Hide Link Cubes")

        rowsub1 = col.row(align=True)
        rowsub1.prop(self, "ropelength2", text="Length")
        rowsub1.prop(self, "ropesegments2", text="Segments")

        rowsub2 = col.row(align=True)
        rowsub2.prop(self, "radiuscubes", text="Radius Link Cubes")
        rowsub2.prop(self, "radiusrope", text="Radius Rope")

        rowsub3 = col.row(align=True)
        rowsub3.prop(self, "grados", text="Degrees")
        rowsub3.prop(self, "separacion", text="Separation Link Cubes")

        col.label("Quality Settings:")
        col.prop(self, "resrope", text="Resolution Rope")
        col.prop(self, "massball", text="Ball Mass")
        col.prop(self, "worldsteps", text="World Steps")
        col.prop(self, "solveriterations", text="Solver Iterarions")


# Register

def register():
    bpy.utils.register_module(__name__)


def unregister():
    bpy.utils.unregister_module(__name__)


if __name__ == "__main__":
    register()
