|
|
"Samuel B." <stb### [at] hotmailcom> wrote:
> [...] Macro coming up shortly.
Here it is. The outer and inner arches are defined separately by width, height
and corner radius (smallest circle). Everything else applies to the entire
object.
#macro FourCenteredArch
(
AW1, // arch width 1 (from center)
AH1, // arch height 1 (from ground)
CR1, // radius 1 (outer corner, >=0 & <=AW1)
AW2, // arch width 2 (from center)
AH2, // arch height 2 (from ground)
CR2, // radius 2 (inner corner, >=0 & <=AW2)
AD, // arch depth (to -z)
BV, // edge bevel radius
)
// a small value
#local Eps = .0001;
// intersection of a vertical line and circle, produces a y value (circle
radius, line x-position)
#macro CircleLineIntercept(CirR, LinX)
#local V = pow(CirR, 2) - pow(LinX, 2);
#if(V>=0)
(sqrt(V))
#else
(0)
#end
#end
// calculate and return various values for shape and bevel macros
#macro GetValues(AW, AH, CR, IO) // IO = is outside inside shape
#declare CR = max(CR, BV*IO+Eps); // prevent circle radius from being negative
#if(CR>=AW) #declare CR = AW-Eps; #end // prevent degenerate plane normal
#declare CV = <AW-CR, AH, 0>; // small circle position
#declare CRT = 2 * CV.x; // get a temporarory circle radius based on distance
between initial circle centers
#declare CY = (CircleLineIntercept(CRT, CV.x)); // get intercept of line and
1st circle
#declare CV2 = CV - 2 * <CV.x, CY, 0>; // large circle's position (will be
used directly for geometry)
#declare CRL = 2 * CRT + CR; // large (second) circle's radius
#declare CY2 = (CircleLineIntercept(CRL, CV2.x)); // value needed for shifting
geometry down (get y intercept of line and 2nd circle)
#declare CO = (CV2.y+CY2-AH); // offset amount to shift geometry downward, to
fit inside box and top margin
#declare CV = <CV.x, CV.y-CO, 0>; // offset CV
#declare CV2 = <CV2.x, CV2.y-CO, 0>; // offset CV2
#declare Dir = vnormalize(CV - CV2); // angle between 1st and 2nd circle
centers, used for various things
#declare DirP = <Dir.y, -Dir.x, 0>; // perpendicular to Dir
#declare ISP = <CV2.x-(CV2.y-CV.y)*Dir.x/Dir.y, CV.y, 0>; // find an
intersection to be used to prevent future CSG issues
#declare PlaneDirP = plane{<CV2.y-CV.y, -CV2.x+CV.x, 0>, 0 translate CV}
#end
// basic shape
#macro MakeShape(AW, AH, CR, AD, IC, IO)
GetValues(AW, AH, CR, IO)
#local IC = Eps * IC; // is a cutting object, so make an offset
union{
// solid portion under curve
box{<-IC, -IC, 0-IC>, <AW, CV.y+Eps, AD+IC>}
#macro Curve()
union{
difference{
cylinder{
z*(-IC), z*(AD+IC), CR
translate CV
}
plane{y, CV.y-Eps}
object{PlaneDirP inverse}
}
difference{
cylinder{
z*(-IC), z*(AD+IC), CRL
translate CV2
}
plane{x, -IC}
object{PlaneDirP translate -y*IC}
}
}
#end
object{Curve()}
translate -z*AD
}
#end
// bevels for curved portion
#macro MakeBevel(AW, AH, CR, IO)
GetValues(AW, AH, CR, IO)
union{
difference{
torus{
CR, BV
rotate x*90
translate CV+z*(BV-AD)
}
plane{y, CV.y}
object{PlaneDirP inverse}
}
difference{
torus{
CRL, BV
rotate x*90
translate CV2+z*(BV-AD)
}
plane{x, 0}
object{PlaneDirP}
}
}
#end
// final object
union{
#local ArchHalf =
union{
// shape offset +z by bevel value
difference{
MakeShape(AW1, AH1, CR1, AD-BV, false, true)
MakeShape(AW2, AH2, CR2, AD-BV, true, false)
}
// shape inset by bevel value
#if(BV>0)
difference{
MakeShape(AW1-BV, AH1-BV, CR1-BV, AD, false, true)
MakeShape(AW2+BV, AH2+BV, CR2+BV, AD, true, false)
}
// bevels
union{
object{MakeBevel(AW1-BV, AH1-BV, CR1-BV, true)}
cylinder{<AW1-BV, 0, -AD+BV>, <AW1-BV, CV.y, -AD+BV>, BV}
object{MakeBevel(AW2+BV, AH2+BV, CR2+BV, false)}
cylinder{<AW2+BV, 0, -AD+BV>, <AW2+BV, CV.y, -AD+BV>, BV}
}
#end
}
object{ArchHalf}
object{ArchHalf scale <-1, 1, 1>}
}
#end
Here's how to call the macro:
object{
FourCenteredArch(
1.0, // arch width 1 (from center)
2.0, // arch height 1 (from ground)
0.5, // radius 1 (outer corner, >=0 & <=arch width 1)
0.6, // arch width 2 (from center)
1.4, // arch height 2 (from ground)
0.2, // radius 2 (inner corner, >=0 & <=arch width 2)
0.3, // arch depth (to -z)
0.03 // edge bevel radius (>arch depth)
)
}
Post a reply to this message
|
|