Created
June 3, 2011 13:23
-
-
Save benlangfeld/1006331 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright 2004-2005, @Last Software, Inc. | |
# This software is provided as an example of using the Ruby interface | |
# to SketchUp. | |
# Permission to use, copy, modify, and distribute this software for | |
# any purpose and without fee is hereby granted, provided that the above | |
# copyright notice appear in all copies. | |
# 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. | |
#----------------------------------------------------------------------------- | |
# Name : Parametric 1.0 | |
# Description : This file defines the Parametric module that lets you define parametric | |
# objects that you can edit. | |
# Menu Item : NONE | |
# Context Menu: NONE | |
# Usage : N/A | |
# Date : 9/10/2004 | |
# Type : Tool | |
#----------------------------------------------------------------------------- | |
# This file defines the Parametric module that lets you define parametric | |
# objects that you can edit. | |
require 'sketchup.rb' | |
#============================================================================= | |
class Parametric | |
# Initialize a newly created instance of the object | |
def initialize(*args) | |
data = args[0] | |
data = self.prompt("Create") if not data | |
return if not data | |
if( data.kind_of? Sketchup::Entity ) | |
@entity = data | |
else | |
return if not validate_parameters(data) | |
model = Sketchup.active_model | |
model.start_operation self.class.name | |
self.create_entity(model) | |
container = self.get_container | |
if not container | |
model.abort_operation | |
return | |
end | |
self.create_entities(data, container) | |
# Set the parameters for the object | |
self.set_attributes(data) | |
# Apply the transform if one was given | |
t = args[1] | |
if( t.kind_of? Geom::Transformation ) | |
@entity.transformation = t | |
end | |
model.commit_operation | |
@entity | |
end | |
end | |
# The name to give to the new object | |
def compute_name | |
self.class.name | |
end | |
# Create a new parametric Entity. The default implementation creates | |
# a Group. Derived classes can over-ride this method to create a | |
# ComponentDefinition or ComponentInstance instead. | |
def create_entity(model) | |
@entity = model.active_entities.add_group | |
end | |
# Get the container in which to add new Entities. | |
# This method should not need to be over-ridden by derived classes | |
def get_container | |
if( @entity.kind_of? Sketchup::Group ) | |
container = @entity.entities | |
elsif( @entity.kind_of? Sketchup::ComponentInstance ) | |
container = @entity.definition.entities | |
elsif( @entity.kind_of? Sketchup::ComponentDefinition ) | |
container = @entity.entities | |
else | |
container = nil | |
end | |
container | |
end | |
# Get the attribute dictionary | |
def Parametric.attribute_holder(entity) | |
if( entity.kind_of? Sketchup::Group ) | |
return entity | |
elsif( entity.kind_of? Sketchup::ComponentInstance ) | |
return entity.definition | |
elsif( entity.kind_of? Sketchup::ComponentDefinition ) | |
return entity | |
end | |
nil | |
end | |
def attribute_dictionary(create_if_needed = false) | |
attrib_holder = Parametric.attribute_holder(@entity) | |
attrib_holder ? attrib_holder.attribute_dictionary("skpp", create_if_needed) : nil | |
end | |
# Get the parameter data from an entity | |
def parameters | |
return nil if not @entity | |
attribs = self.attribute_dictionary | |
return nil if not attribs | |
data = {} | |
attribs.each do |key, value| | |
if( key != "class" ) | |
data[key] = value | |
end | |
end | |
data | |
end | |
# Show a dialog and get the values from the user | |
# TODO: The data variable is a Hash of values to get from the user. | |
# Because it is a Hash, the order is not specified. I really need some way | |
# for the derived classes to control the order that the parameters are | |
# displayed to the user. | |
def prompt(operation) | |
# get the parameters | |
if( @entity ) | |
data = self.parameters | |
else | |
data = self.default_parameters | |
end | |
if( not data ) | |
puts "No parameters attached to the entity" | |
return nil | |
end | |
title = operation + " " + self.class.name | |
keys = [] | |
prompts = [] | |
values = [] | |
data.each do |key, value| | |
if( key != "class" ) | |
keys.push key | |
prompts.push self.translate_key(key) | |
values.push value | |
end | |
end | |
results = inputbox( prompts, values, title ) | |
return nil if not results | |
# Store the results back into data | |
# results will be an Array with one value for each prmopt | |
results.each_index { |i| data[keys[i]] = results[i] } | |
data | |
end | |
# Attach attributes to the object | |
def set_attributes(data) | |
# Get the AttributeDictionary - create it if needed | |
attribs = attribute_dictionary(true) | |
# Set the class name | |
attribs["class"] = self.class.name | |
# now set the data values | |
data.each { |key, value| attribs[key] = value } | |
attribs | |
end | |
def entity | |
@entity | |
end | |
# Edit the parameteric object. This will prompt for the new values | |
# and then regenerate the geometry | |
def edit | |
if( not @entity ) | |
puts "There is no Entity to Edit" | |
return false | |
end | |
data = self.prompt "Edit" | |
return false if not data | |
# Make sure that valid values were entered | |
ok = self.validate_parameters(data) | |
if( not ok ) | |
return false | |
end | |
# Now clear the old definition and regen the entities | |
container = self.get_container | |
model = @entity.model | |
model.start_operation "Edit " + self.class.name | |
container.clear! | |
self.create_entities(data, container) | |
self.set_attributes(data) | |
model.commit_operation | |
@entity | |
end | |
#----------------------------------------------------------------------------- | |
# Class methods for editing parameteric objects | |
# Determine the class of a parametric entity | |
def Parametric.get_class(ent) | |
attrib_holder = Parametric.attribute_holder(ent) | |
return nil if not attrib_holder | |
attrib_holder.get_attribute "skpp", "class" | |
end | |
# Determine if an Entity is a parametric object | |
def Parametric.parametric?(ent) | |
klass = Parametric.get_class(ent) | |
return false if not klass | |
# Make sure that we can actually create an instance of this class. | |
begin | |
new_method = eval "#{klass}.method :new" | |
rescue | |
# If we couldn't find the new method, it probably means that | |
# the code for this kind of parametric object wasn't loaded | |
puts "Could not find implementation of #{klass}" | |
return false | |
end | |
# return the class name | |
klass | |
end | |
def Parametric.selection_parametric? | |
ss = Sketchup.active_model.selection | |
false if ss.count != 1 | |
Parametric.parametric? ss.first | |
end | |
def Parametric.edit(ent) | |
if( not Parametric.parametric?(ent) ) | |
UI.beep | |
puts "#{ent} is not a parametric Entity" | |
return false | |
end | |
# Get the class of the parametric object | |
klass = Parametric.get_class(ent) | |
# Create a new parametric object of that class | |
new_method = eval "#{klass}.method :new" | |
obj = new_method.call ent | |
if not obj | |
puts "Could not create the parametric object for #{klass}" | |
return false | |
end | |
# Now edit the object | |
obj.edit | |
end | |
# Edit the current selection | |
def Parametric.edit_selection | |
if not Parametric.selection_parametric? | |
UI.beep | |
puts "The selected Entity is not parametric" | |
return false | |
end | |
Parametric.edit Sketchup.active_model.selection.first | |
end | |
#----------------------------------------------------------------------------- | |
# The following methods should be implemented by derived classes. Some of them | |
# are required, and some are only optional | |
# create_entities is called to create the entities for the parametric object. | |
# the parameters needed to create the object are passed in as a Hash. | |
# This must be implemented by any class that includes Parametric | |
def create_entities(data, container) | |
puts "create_entities must be implemented by #{self.class.name}" | |
end | |
# Get the default parameters for the object. | |
def default_parameters | |
puts "default_parameters must be implemented by #{self.class.name}" | |
end | |
# Check that valid parameters were entered | |
# return true if the parameters are OK or false if they are not | |
def validate_parameters(data) | |
true | |
end | |
# This allows the object to translate the keys used to store the parameters | |
# into different prompts to display in the UI. If not implemented, the | |
# parameter keys will be used for the prompts | |
def translate_key(key) | |
key | |
end | |
end | |
#============================================================================= | |
# Add a context menu handler that will add a menu choice to a context menu | |
# for editing parametric objects | |
if( not $parametric_loaded ) | |
UI.add_context_menu_handler do |menu| | |
klass = Parametric.selection_parametric? | |
if( klass ) | |
menu.add_separator | |
menu.add_item("Edit #{klass}") { Parametric.edit_selection } | |
end | |
end | |
$parametric_loaded = true | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment