############################################################################################################
#
# Copyright (c) 2012 Kofi Garbrah 
#
# Provided under The MIT License http://opensource.org/licenses/mit-license.php
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# 
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
# Description:
# This blender add-on resizes the selected object(s) to fit within the specified maximum height. 
# Proportions are maintained for all selected objects.
#
# This blender add-on
# 1) Imports and Global variables
# 2) Model
# 3) View (Panel)
# 4) Controller (button)
#
############################################################################################################

bl_info = {
    "name": "ReScale",
    "author": "Kofi Garbrah",
    "version": (1,0),
    "blender": (2, 63, 0),
    "location": "View3D > Properties > Rescale",
    "description": "Re-scales all selected items to the specified maximum height.",
    "warning": "",
    "wiki_url": "http://www.4colorgrafix.net/bpy#rescale",
    "tracker_url": "http://www.4colorgrafix.net/bpy#rescale",
    "category": "System"}
    
#
# 1) Imports and Global variables
#

import bpy
from bpy.props import *

import math
from math import *
from mathutils import *
from mathutils import Vector
from mathutils import Matrix

import time 

bpy.types.Scene.max_height = FloatProperty(
        name = "Maximum Mesh Height", 
        description = "Enter a float",
        default = 2.0,
        min = 0,
        max = 100)

############################################################################################################

#
# 2) Model
#

class RescaleModel:

    #   
    # Set location to the ground. 
    #                     
    def resize( self, context):
        print( "\n\nSet mesh height" )

        maxY = float("-inf")
        minY = float("inf") 
        i = 0

        # Set orientation of figure
        bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)

        # find highest point and lowest point in the selected meshes
        for obj in context.selected_objects:
            if obj.type == "MESH":
               for v in obj.data.vertices:
                  vec = self.transpose_yz( v.co )
                  y = vec[1]
                  if maxY < y:
                     maxY = y
                  if minY > y:
                     minY = y

        # Re-Scale
        ratio = 1
        max_height = context.scene.max_height
        if maxY > minY:
           ratio = max_height / (maxY - minY)   
   
        for obj in context.selected_objects:
            if obj.type == "MESH":
               obj.dimensions = obj.dimensions * ratio
               
        bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

    #    # Transposes Y-axis with Z-axis. 
    #
    # In most 3d software, the Z-axis represents depth not height. For example 
    # look at ZBrush, Silo, Maya, Cinema4D, and OpenGL. Also look up the terms 
    # Z-Buffering and Z-Culling.
    #
    # Blender uses the Z-axis to represent height on the screen but the camera in 
    # Blender uses the Z-axis to represent depth for rendering. This routine
    # compensates for Blender's quirk.
    #        
    def transpose_yz( self, v ):
        return Vector( (v[0], v[2], v[1] ) )

############################################################################################################

#
# 3) View
#

rs = RescaleModel()

# Panel
class RescaleView(bpy.types.Panel):

    """Creates a Panel in the VIEW 3D UI"""
    bl_idname = "ReScale"
    bl_label = "ReScale"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_context = "object"

    # Draws layout for Panel
    def draw(self, context):
        layout = self.layout

        if len(context.selected_objects) > 0:
           row = layout.row()
           row.alignment = "EXPAND"        
           row.operator("rescale_controller.button", text="Re-Scale Selected Figures")
           row = layout.row()
           row.prop( context.scene, 'max_height' )

############################################################################################################

#
# 4) Controller
#                

#   Button
class RescaleController(bpy.types.Operator):
    bl_idname = "rescale_controller.button"
    bl_label = "RC Button"

    def execute(self, context):
        time_start = time.time()
        rs.resize(context)
        print("Execution time: {:.4} sec".format(time.time() - time_start) )

        return{'FINISHED'}    
 
#    Registration

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

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

if __name__ == '__main__':
    register()
