# Copyright 2013, Trimble Navigation Limited# 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'#=============================================================================moduleSketchup::SamplesclassParametric# Initialize a newly created instance of the objectdefinitialize(*args) data = args[0] data = self.prompt("Create") ifnot datareturnifnot dataif( data.kind_of? Sketchup::Entity ) @entity = dataelsereturnifnot validate_parameters(data) model =Sketchup.active_model model.start_operation self.class.name self.create_entity(model) container = self.get_containerifnot container model.abort_operationreturnend 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 = tend model.commit_operation @entityendend# The name to give to the new objectdefcompute_name self.class.nameend# 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.defcreate_entity(model) @entity = model.active_entities.add_groupend# Get the container in which to add new Entities.# This method should not need to be over-ridden by derived classesdefget_containerif( @entity.kind_of? Sketchup::Group ) container = @entity.entitieselsif( @entity.kind_of? Sketchup::ComponentInstance ) container = @entity.definition.entitieselsif( @entity.kind_of? Sketchup::ComponentDefinition ) container = @entity.entitieselse container =nilend containerend# Get the attribute dictionarydefParametric.attribute_holder(entity)if( entity.kind_of? Sketchup::Group )return entityelsif( entity.kind_of? Sketchup::ComponentInstance )return entity.definitionelsif( entity.kind_of? Sketchup::ComponentDefinition )return entityendnilenddefattribute_dictionary(create_if_needed=false) attrib_holder =Parametric.attribute_holder(@entity) attrib_holder ? attrib_holder.attribute_dictionary("skpp", create_if_needed) :nilend# Get the parameter data from an entitydefparametersreturnnilifnot @entity attribs = self.attribute_dictionaryreturnnilifnot attribs data = {} attribs.each do|key, value|if( key !="class" ) data[key] = valueendend dataend# 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.defprompt(operation)# get the parametersif( @entity ) data = self.parameterselse data = self.default_parametersendif( not data )puts"No parameters attached to the entity"returnnilend 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 valueendend results = inputbox( prompts, values, title )returnnilifnot 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] } dataend# Attach attributes to the objectdefset_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 } attribsenddefentity @entityend# Edit the parameteric object. This will prompt for the new values# and then regenerate the geometrydefeditif( not @entity )puts"There is no Entity to Edit"returnfalseend data = self.prompt "Edit"returnfalseifnot data# Make sure that valid values were entered ok = self.validate_parameters(data)if( not ok )returnfalseend# 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 @entityend#-----------------------------------------------------------------------------# Class methods for editing parameteric objects# Determine the class of a parametric entitydefParametric.get_class(ent) attrib_holder =Parametric.attribute_holder(ent)returnnilifnot attrib_holder attrib_holder.get_attribute "skpp","class"end# Determine if an Entity is a parametric objectdefParametric.parametric?(ent) klass =Parametric.get_class(ent)returnfalseifnot 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 loadedputs"Could not find implementation of #{klass}"returnfalseend# return the class name klassenddefParametric.selection_parametric? ss =Sketchup.active_model.selectionfalseif ss.count !=1Parametric.parametric? ss.firstenddefParametric.edit(ent)if( notParametric.parametric?(ent) )UI.beepputs"#{ent} is not a parametric Entity"returnfalseend# 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 entifnot objputs"Could not create the parametric object for #{klass}"returnfalseend# Now edit the object obj.editend# Edit the current selectiondefParametric.edit_selectionifnotParametric.selection_parametric?UI.beepputs"The selected Entity is not parametric"returnfalseendParametric.edit Sketchup.active_model.selection.firstend#-----------------------------------------------------------------------------# 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 Parametricdefcreate_entities(data, container)puts"create_entities must be implemented by #{self.class.name}"end# Get the default parameters for the object.defdefault_parametersputs"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 notdefvalidate_parameters(data)trueend# 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 promptsdeftranslate_key(key) keyendend# class Parametric#=============================================================================# Add a context menu handler that will add a menu choice to a context menu# for editing parametric objectsif (not $parametric_loaded) $parametric_loaded =trueUI.add_context_menu_handler do|menu| klass =Parametric.selection_parametric?if( klass ) menu.add_separator menu.add_item("Edit #{klass}") { Parametric.edit_selection }endendendend# module Sketchup::Samples