/* bounder.inc * * "not a cad, just a bounder." ;-) * * macro Bounder(obj, optional res) * calculate an object's required bounding box, compare it to the * existing, and suggest tighter bounds where possible. * the optional second argument, resolution, determines the number * of probes/scans per POV unit; multiples of 5, range: 5,..,10000. * the pretty-print output goes to the '#debug' stream. * returns (expands to) nothing. * * Bounder_{min,max}_diff * the calculated differences from the actual BB's min + max_extents. * these variables are declared _only_ if the macro reported any kind * of "slack"; running the macro unsets existing variables. * * with (belated) thanks to Thomas de Groot, whose comments helped shape * the macro's output. * * version: 201910.4 * */ #ifndef (Bounder_include_temp) #declare Bounder_include_temp = version; #version 3.8; #ifdef (View_POV_Include_Stack) #debug "including bounder.inc\n" #end #include "shapes.inc" /* -----[helpers]----------------------------------------------------------- */ /* legal resolutions multiples of 5, range: 5,..,10000 */ #macro bndr_checkRes(r_) #local v_ = <1,1,1> * r_; /* "promote" */ #if (mod(v_.x,5) | mod(v_.y,5) | mod(v_.z,5)) #local e_ = 1; #elseif (5 > v_.x | 5 > v_.y | 5 > v_.z) #local e_ = 1; #elseif (10000 < v_.x | 10000 < v_.y | 10000 < v_.z) #local e_ = 1; #end #ifdef (local.e_) #error concat("oops, bad resolution <",vstr(3,v_,",",0,0),">, ", "must be divisible by 5, range: 5,..,10000.\n") #end v_ #end /* pretty printing */ #macro bndr_hyphens(n_) #local s_ = ""; #for (i_,1,n_) #local s_ = concat(s_,"-"); #end s_ #end #macro bndr_strFmt(s_) #local w_ = 28; #local n_ = strlen(s_); #if (w_ > n_) #local s_ = concat(substr(" ",1,(w_-n_)),s_); #end s_ #end #macro bndr_emit3V(s_,v_,p_) #debug concat(bndr_strFmt(s_),": <",vstr(3,v_,", ",0,p_),">\n") #end #macro bndr_emitStr(s_,v_) #debug concat(bndr_strFmt(s_),": ",v_,"\n") #end #macro bndr_emitVal(s_,v_,p_) #debug concat(bndr_strFmt(s_),": ",str(v_,0,p_),"\n") #end /* axis info */ #macro bndr_emitInfo(ax_,sr_,sf_,si_,ci_,ri_) bndr_emitVal(concat("'",ax_,"' axis scan resolution"),sr_,0) bndr_emitVal("scans per face",sf_,0) bndr_emitVal("scan axis increment",si_,8) bndr_emitVal("face col increment",ci_,8) bndr_emitVal("face row increment",ri_,8) #end /* assess BB fit, export calculated diffs */ #macro bndr_emitGrade(ail_,aiu_,bbl_,bbu_) #local dims_ = aiu_ - ail_; #local ld_ = ; #local ud_ = ; #local pc5_ = dims_ * .05; #local pc1_ = dims_ * .01; #local spc_ = " "; #debug concat(spc_,"\n") #if ((pc1_.x >= ld_.x) & (pc1_.y >= ld_.y) & (pc1_.z >= ld_.z)) #debug concat(spc_,"object bounding box is (near) optimal.","\n") #break // done. #elseif ((pc5_.x > ld_.x) & (pc5_.y > ld_.y) & (pc5_.z > ld_.z)) #debug concat(spc_,"object bounding box is good, ", "less than 5% \"slack\".","\n\n") #else #debug concat(spc_,"object bounding box has at least 5% \"slack\".", "\n\n") #end #declare Bounder_min_diff = ld_; #declare Bounder_max_diff = ud_; #local ol_ = ail_ + ld_; #local ou_ = aiu_ - ud_; bndr_emit3V("difference from BB min",ld_,6) bndr_emit3V("difference from BB max",ud_,6) bndr_emit3V("min_extent optimised BB",ol_,6) bndr_emit3V("max_extent optimised BB",ou_,6) bndr_emit3V("BB optimised dimensions",(ou_-ol_),6) #end /* -----["main"]------------------------------------------------------------ */ #macro Bounder(obj_,optional res_) #debug concat(bndr_hyphens(10),"[Bounder info]",bndr_hyphens(48),"\n") #ifndef (local.res_) #local res_ = <1,1,1> * 50; /* low-ish */ #else #local res_ = bndr_checkRes(res_); #end bndr_emit3V("resolutions (per POV unit)",res_,0) /* remove existing variables */ #ifdef (global.Bounder_max_diff) #undef Bounder_max_diff #end #ifdef (global.Bounder_min_diff) #undef Bounder_min_diff #end /* place object at origin */ #local ail_ = min_extent(obj_); #local aiu_ = max_extent(obj_); bndr_emit3V("min_extent \"as is\" BB",ail_,6) bndr_emit3V("max_extent \"as is\" BB",aiu_,6) #local o_ = object {Align_Object(obj_,<-1,-1,-1>,<0,0,0>)}; #local dims_ = max_extent(o_) - min_extent(o_); bndr_emit3V("BB aligned dimensions",dims_,6) /* calc N steps + increments */ #local nstep_ = ; #local incr_ = ; /* three scans by axis, into both "faces" of each. * find last point(s) outside of object. */ #local bbl_ = <0,0,0>; #local bbu_ = dims_; /* scan axis 'X', face ZY */ bndr_emitInfo("X",nstep_.x,(nstep_.z*nstep_.y),incr_.x,incr_.z,incr_.y) bndr_emitStr(bndr_hyphens(1),"...scanning...") /* flags control negative/positive axis scan */ #local nflag_ = 1; #local pflag_ = 1; #local cnt_ = 0; #for (n_,0,nstep_.x-1) #if (pflag_) #for (j_,0,nstep_.y-1) #for (i_,0,nstep_.z-1) #local p_ = ; #if (inside(o_,p_)) #local pflag_ = 0; #end #local cnt_ = cnt_ + 1; #end #end /* no hit? record the new "last" */ #if (pflag_) #local bbl_ = ; #end #end #if (nflag_) #for (j_,0,nstep_.y-1) #for (i_,0,nstep_.z-1) #local p_ = ; #if (inside(o_,p_)) #local nflag_ = 0; #end #local cnt_ = cnt_ + 1; #end #end #if (nflag_) #local bbu_ = ; #end #end #if (!(nflag_ | pflag_)) #break #end #end bndr_emitVal("inside() calls",cnt_,0) /* scan axis 'Y', face XZ */ bndr_emitInfo("Y",nstep_.y,(nstep_.x*nstep_.z),incr_.y,incr_.x,incr_.z) bndr_emitStr(bndr_hyphens(1),"...scanning...") #local nflag_ = 1; #local pflag_ = 1; #local cnt_ = 0; #for (n_,0,nstep_.y-1) #if (pflag_) #for (j_,0,nstep_.z-1) #for (i_,0,nstep_.x-1) #local p_ = ; #if (inside(o_,p_)) #local pflag_ = 0; #end #local cnt_ = cnt_ + 1; #end #end #if (pflag_) #local bbl_ = ; #end #end #if (nflag_) #for (j_,0,nstep_.z-1) #for (i_,0,nstep_.x-1) #local p_ = ; #if (inside(o_,p_)) #local nflag_ = 0; #end #local cnt_ = cnt_ + 1; #end #end #if (nflag_) #local bbu_ = ; #end #end #if (!(nflag_ | pflag_)) #break #end #end bndr_emitVal("inside() calls",cnt_,0) /* scan axis 'Z', face XY */ bndr_emitInfo("Z",nstep_.z,(nstep_.x*nstep_.y),incr_.z,incr_.x,incr_.y) bndr_emitStr(bndr_hyphens(1),"...scanning...") #local nflag_ = 1; #local pflag_ = 1; #local cnt_ = 0; #for (n_,0,nstep_.z-1) #if (pflag_) #for (j_,0,nstep_.y-1) #for (i_,0,nstep_.x-1) #local p_ = ; #if (inside(o_,p_)) #local pflag_ = 0; #end #local cnt_ = cnt_ + 1; #end #end #if (pflag_) #local bbl_ = ; #end #end #if (nflag_) #for (j_,0,nstep_.y-1) #for (i_,0,nstep_.x-1) #local p_ = ; #if (inside(o_,p_)) #local nflag_ = 0; #end #local cnt_ = cnt_ + 1; #end #end #if (nflag_) #local bbu_ = ; #end #end #if (!(nflag_ | pflag_)) #break #end #end bndr_emitVal("inside() calls",cnt_,0) bndr_emitGrade(ail_,aiu_,bbl_,bbu_) #debug concat(bndr_hyphens(72),"\n") #end #version Bounder_include_temp; #end /* --------------------------------------------------------------- * * the content above is covered by the GPLv3+, see file COPYING. * * copyright (c) 2019 jr . * * all rights reserved. * * --------------------------------------------------------------- */