class Oozby::Environment
Constants
- ResolutionDefaults
Attributes
active[RW]
Public Class Methods
new(ooz: nil)
click to toggle source
# File lib/oozby/environment.rb, line 15 def initialize(ooz: nil) @parent = ooz @ast = [] @defaults = {center: false} @resolution = ResolutionDefaults.dup @modifier = nil @one_time_modifier = nil @preprocess = true @method_preprocessor = Oozby::Preprocessor.new(env: self, ooz: @parent) @scanned_scad_files = [] end
Public Instance Methods
_abstract_tree()
click to toggle source
returns the abstract tree
# File lib/oozby/environment.rb, line 274 def _abstract_tree; @ast; end
_apply_modifier(new_modifier, &children)
click to toggle source
# File lib/oozby/environment.rb, line 261 def _apply_modifier new_modifier, &children if children previously = @modifier @modifier = new_modifier instance_eval &children @modifier = previously else @one_time_modifier = new_modifier end end
_execute_oozby(&code)
click to toggle source
run some oozby code contained inside a proc
# File lib/oozby/environment.rb, line 233 def _execute_oozby &code previously = self.class.active self.class.active = self result = instance_exec(&code) self.class.active = previously return result end
_fragments_for(diameter: nil, radius: nil)
click to toggle source
# File lib/oozby/environment.rb, line 184 def _fragments_for diameter: nil, radius: nil radius = diameter.to_f / 2.0 if diameter if @resolution[:fragments] != 0 @resolution[:fragments] else max = (radius.to_f * Math::PI * 2.0) / @resolution[:minimum].to_f if @resolution[:fragments_per_turn] > max max else @resolution[:fragments_per_turn] end end end
_require_scad_file(filename, execute: true)
click to toggle source
# File lib/oozby/environment.rb, line 224 def _require_scad_file filename, execute: true raise "OpenSCAD file #{filename} not found" unless File.exists? filename _scan_methods_from_scad_file filename # add include statement to resulting openscad code @ast.push(execute: !!execute, import: filename) end
_scan_methods_from_scad_file(filename)
click to toggle source
# File lib/oozby/environment.rb, line 241 def _scan_methods_from_scad_file filename raise "OpenSCAD file #{filename} not found" unless File.exists? filename data = File.read(filename) @scanned_scad_files.push filename # parse out method definitions to add to our environment data.gsub!(/\/\/.+?\n/m, "\n") # filter off single line comments data.gsub!(/\/\*.+?\*\//m, '') # filter out multiline comments data.scan /module[ \t]([a-zA-Z_9-9]+)/ do |module_name| @method_preprocessor.openscad_methods.push module_name.first.to_sym end # find any references to more files and recurse in to those data.scan /(use|include)[ \t]\<(.+?)\>/ do |filename| unless @scanned_scad_files.include? filename _scan_methods_from_scad_file filename end end end
_subscope(*args, &proc)
click to toggle source
create a new scope that inherits from this one, and capture syntax tree created
# File lib/oozby/environment.rb, line 28 def _subscope *args, &proc # capture instance variables capture = {} instance_variables.each { |key| capture[key] = self.instance_variable_get(key) } # reset for ast capture @ast = [] @one_time_modifier = nil @defaults = @defaults.dup @resolution = @resolution.dup proc[*args] syntax_tree = @ast # restore instance variables capture.each { |key, value| self.instance_variable_set(key, value) } return syntax_tree end
defaults(settings = nil, &proc)
click to toggle source
# File lib/oozby/environment.rb, line 122 def defaults settings = nil, &proc return @defaults if settings == nil previous = @defaults @defaults = @defaults.merge(settings) if proc ret = instance_eval &proc @defaults = previous end ret end
ghost(&proc)
click to toggle source
the background modifier
# File lib/oozby/environment.rb, line 199 def ghost &proc _apply_modifier('%', &proc) end
highlight(&proc)
click to toggle source
the debug modifier
# File lib/oozby/environment.rb, line 204 def highlight &proc _apply_modifier('#', &proc) end
inject_abstract_tree(code)
click to toggle source
# File lib/oozby/environment.rb, line 47 def inject_abstract_tree code code = [code] unless code.is_a? Array @ast.push(*code) end
inspect()
click to toggle source
make backtraces clearer
# File lib/oozby/environment.rb, line 277 def inspect; "OozbyFile"; end
lookup(key, table)
click to toggle source
implement the openscad lookup function Look up value in table, and linearly interpolate if there’s no exact match. The first argument is the value to look up. The second is the lookup table – a vector of key-value pairs. table can be an array of key/value subarray pairs, or a hash with numeric keys
# File lib/oozby/environment.rb, line 138 def lookup key, table table = table.to_a if table.is_a? Hash table.sort! { |x,y| x[0] <=> y[0] } b = table.bsearch { |x| x[0] >= key } || table.last index_b = table.index(b) a = if index_b > 0 then table[index_b - 1] else b end return a[1] if key <= a[0] return b[1] if key >= b[0] key_difference = b[0] - a[0] value_proportion = (key - a[0]).to_f / key_difference (a[1].to_f * value_proportion) + (b[1].to_f * (1.0 - value_proportion)) end
method_missing(method_name, *args, **hash, &proc)
click to toggle source
Calls superclass method
# File lib/oozby/environment.rb, line 57 def method_missing method_name, *args, **hash, &proc # unless we know of this method in OpenSCAD or the preprocessor, abort! unless oozby_method_defined? method_name # grab a list of all known methods, suggest a guess to user known = @method_preprocessor.known known.push(*public_methods(false)) known.push(*Oozby.constants) known.delete_if { |x| x.to_s.start_with? '_' } matcher = Amatch::Sellers.new(method_name.to_s) suggestion = known.min_by { |item| matcher.match(item.to_s) } warn "Called unknown method #{method_name}()" warn "Perhaps you meant #{suggestion}?" if suggestion return super # continue to raise the usual error and all that end oozby_send_method method_name, *args, **hash, &proc end
oozby_method_defined?(name)
click to toggle source
do we know of this method
# File lib/oozby/environment.rb, line 53 def oozby_method_defined? name @method_preprocessor.known?(name.to_sym) or !@preprocess or respond_to?(name) end
oozby_send_method(method_name, *args, **hash, &proc)
click to toggle source
# File lib/oozby/environment.rb, line 77 def oozby_send_method method_name, *args, **hash, &proc if proc children = _subscope(&proc) else children = [] end element = Oozby::Element.new({ method: method_name, args: args, named_args: hash, children: children, modifier: @one_time_modifier || @modifier, call_address: @ast.length }) @ast.push(comment: "oozby: #{element}") if @parent.debug element = @method_preprocessor.transform_call(element) if @preprocess element.abduct @ast @one_time_modifier = nil return element end
preprocessor(state, &proc)
click to toggle source
# File lib/oozby/environment.rb, line 115 def preprocessor state, &proc previous = @transform @preprocess = state instance_eval &proc @preprocess = previous end
require(*args)
click to toggle source
# File lib/oozby/environment.rb, line 213 def require *args file = args.first if file.end_with? '.scad' _require_scad_file(*args) elsif File.exists? "#{file}.scad" _require_scad_file("#{args.shift}.scad", *args) else Kernel.require(*args) end end
resolution(**settings, &proc)
click to toggle source
gets and sets resolution settings
# File lib/oozby/environment.rb, line 164 def resolution **settings, &proc warn "Setting fragments_per_turn and degrees_per_fragment together makes no sense!" if settings[:fragments_per_turn] && settings[:degrees_per_fragment] settings[:fragments_per_turn] ||= settings.delete(:facets_per_turn) settings[:degrees_per_fragment] ||= settings.delete(:degrees_per_facet) settings[:fragments] ||= settings.delete(:facets) settings.delete_if { |key,value| value == nil } previous_settings = @resolution @resolution.merge! settings @resolution[:degrees_per_fragment] = 360.0 / settings[:fragments_per_turn].to_f if settings[:fragments_per_turn] @resolution[:fragments_per_turn] = 360.0 / settings[:degrees_per_fragment].to_f if settings[:degrees_per_fragment] if proc return_data = instance_eval(&proc) @resolution = previous_settings return_data else @resolution.dup end end
root(&proc)
click to toggle source
the root modifier
# File lib/oozby/environment.rb, line 209 def root &proc _apply_modifier('!', &proc) end
turn(iterations = nil, &proc)
click to toggle source
utility for rotating around in a full circle and doing stuff
# File lib/oozby/environment.rb, line 154 def turn iterations = nil, &proc if iterations raise "Iterations must be Numeric" unless iterations.is_a? Numeric (0.0...360.0).step(360.0 / iterations, &proc) else 0.0...360.0 # return a range which can be iterated however end end