/* 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. * * version: 201910.2 * */ #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_,pf_,si_,ci_,ri_) bndr_emitVal(concat("'",ax_,"' axis scan resolution"),sr_,0) bndr_emitVal("scans per face",pf_,0) bndr_emitVal("scan axis increment",si_,8) bndr_emitVal("face col increment",ci_,8) bndr_emitVal("face row increment",ri_,8) #end /* print assessment of BB fit TODO abs? */ #macro bndr_emitGrade(dims_,bbl_,bbu_) #local ldiff_ = ; #local udiff_ = ; #local pc5_ = dims_ * .05; #local pc1_ = dims_ * .01; #local spc_ = " "; /* 2 spaces */ #debug concat(spc_,spc_,bndr_hyphens(20),"\n") bndr_emit3V("difference from BB min",ldiff_,8) bndr_emit3V("difference from BB max",udiff_,8) #debug concat(spc_,"\n") #if ((pc1_.x >= ldiff_.x) & (pc1_.y >= ldiff_.y) & (pc1_.z >= ldiff_.z)) #debug concat(spc_,"object bounding box is (near) optimal.","\n") #elseif ((pc5_.x > ldiff_.x) & (pc5_.y > ldiff_.y) & (pc5_.z > ldiff_.z)) #debug concat(spc_,"object bounding box is good, ", "less than 5% \"slack\".","\n") #else #debug concat(spc_,"object bounding box has at least 5% \"slack\".","\n") #end #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) /* place object at origin */ bndr_emit3V("object \"as is\" (BB) min",min_extent(obj_),6) bndr_emit3V("object \"as is\" (BB) max",max_extent(obj_),6) #local o_ = object {Align_Object(obj_,<-1,-1,-1>,<0,0,0>)}; #local dims_ = max_extent(o_) - min_extent(o_); bndr_emit3V("object aligned (BB) max",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(dims_,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. * * --------------------------------------------------------------- */