=begin
Copyright 2012-2013 (c) TIG
All Rights Reserved.
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 
WARRANTIES,INCLUDING,WITHOUT LIMITATION,THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
###
TIG-Descaler.rb
###
If a selected group or component-instance has been scaled this tool 'descales' 
it; that is, it makes it the same size but no longer scaled; and it also 
'descales' any textured materials on faces within it.
If there is more than one instance of a 'container' it is first made_unique.
It iterates into nested groups/instances to 'descale' them too.
Usage:
Select the 'container[s]' and from the context-menu run 'TIG.Descaler'.
This menu-item only shows if there's a suitable selection - i.e.
a group or component-instance which has a scale other than 1.0 in x or y or z.
It is one step undo-able.
Note that it does not work on scaled DCs, these need built-in 'tricks'...
###
Donations:
Via Paypal.com to info@revitrev.org
###
Version:
1.0 20121216 First issue.
1.1 20121218 Doesn't change DCs. Code more robust and faster.
=end

require('sketchup.rb')

module TIG

module Descaler

	unless file_loaded?(__FILE__)
	UI.add_context_menu_handler{|menu|
		if self.suitable?()
			menu.add_item("TIG.Descaler"){self.new()}
		end
	}
    end
	file_loaded(__FILE__)
	
	def self.suitable?()
		@model=Sketchup.active_model
		@ss=@model.selection
		@cs=[]
		@ss.each{|e|
			@cs << e if e.is_a?(Sketchup::Group) || e.is_a?(Sketchup::ComponentInstance)
		}
		@cs.each{|e|
			if ! e.attribute_dictionary("dynamic_attributes") && (e.transformation.xscale != 1.0 || e.transformation.yscale != 1.0 || e.transformation.zscale != 1.0)
				return true
				break
			end
		}
		return false
	end#suitable?

	def self.new(cs=[])
		@model=Sketchup.active_model
	   @model.start_operation("TIG.Descaler")
		cs=@cs unless cs[0]
		cs.each{|c|
			next if c.attribute_dictionary("dynamic_attributes")
			self.process(c)
		}
	   @model.commit_operation
	end#new
	
	def self.process(c=nil)
		return nil unless c
		return nil if c.attribute_dictionary("dynamic_attributes")
		### trap for nested DCs
		if c.is_a?(Sketchup::Group)
			defn=c.entities.parent
			c.make_unique if defn.instances[1]
			defn=c.entities.parent
		else ### it's a ComponentInstance
			defn=c.definition
			c.make_unique if defn.instances[1]
			defn=c.definition
		end
		###
		bm=c.bounds.center
		tc=c.transformation
		ct=tc.origin
		tx=tc.xscale
		ty=tc.yscale
		tz=tc.zscale
		###
		ts=Geom::Transformation.scaling(ct, 1.0/tx, 1.0/ty, 1.0/tz)
		c.transform!(ts) ### reset scale
		###
		cs=[]
		es=[]
		dents=defn.entities
		dents.to_a.each{|e|
			if e.is_a?(Sketchup::Group) || e.is_a?(Sketchup::ComponentInstance)
				cs << e
			elsif e.is_a?(Sketchup::Edge)
				es << e
			end
		}
		### rescale geom without re-distorting the textures again !
		tv=Geom::Transformation.scaling(ct, tx, ty, tz)
		dents.transform_entities(tv, es) if es[0]
		dents.transform_entities(tv, cs) if cs[0]
		bmm=c.bounds.center
		vv=bmm.vector_to(bm)
		tt=Geom::Transformation.translation(vv)
		c.transform!(tt)
		### mine into nested things
		cs.each{|c|self.process(c)}
		###
	end#process

end#Descaler

end#TIG
