/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * */ /* * INSTRUCTIONS * */ /* * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* //The Master of Puppets Font is easy to use. You may set various options or use the default values. The //following example demonstrates all you need to do to use the font: #declare MOP_Gap = .16; //Set the distance between characters (optional, default = .16) #declare MOP_Space = .7; //Set the distance between words (optional, default = .7) #declare MOP_FontRadius = .06; //Set the radius of the strokes (optional, default = .06) #declare MOP_ApplyKerning = yes; //Apply automatic kerning (yes or no) (optional, default = yes) #include "MasterOfPuppetsFont.inc" CreateMOP_TextObject ("Your text goes here.", MOP_Gap, MOP_Space, MOP_FontRadius, MOP_ApplyKerning) object {MOP_TextObject texture {YourTextureHere} translate <-MOP_TextObjectWidth / 2, 0, 0>} //The macro will create a CSG object from the string you specify. It will set a variable called //MOP_TextObjectWidth and the object will extend from x = 0 to x = MOP_TextObjectWidth. In the example //above the object will be centered horizontally with the base of the characters at y = 0. The characters //will be 1.12 (1 + MOP_FontRadius * 2) units tall. A variable called MOP_TextObjectHeight will be set //for you as well, and the characters will extend from y = 0 to y = MOP_TextObjectHeight. The back of the //object will be at z = 0 and the object will extend -MOP_FontRadius * 2 in the z direction. //Good values for MOP_FontRadius are > 0 to <= .0986. At larger values the "Q" will develop glitches. At //values > .1 the "S" will begin to have glitches. //Note that only capital letters, [SPACE], [DASH], and [PERIOD] are defined. //Advanced instructions: //In the event that you need to apply different textures to the individual characters in your string, or //perform some other operation on the individual characters, you can use the following method instead of //the CreateMOP_TextObject () macro: #declare MOP_TextObject = object { #local CurrentX = 0; union { object {MOP_Character [P_] texture {P_Color} translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [P_] + MOP_FontRadius * 2 + MOP_Gap; object {MOP_Character [O_] texture {O_Color} translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [O_] + MOP_FontRadius * 2 + MOP_Gap; object {MOP_Character [V_] texture {V_Color} translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [V_] + MOP_FontRadius * 2 + MOP_Gap; object {MOP_Character [DASH_] texture {DASH_Color} translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [DASH_] + MOP_FontRadius * 2 + MOP_Gap; object {MOP_Character [R_] texture {R_Color} translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [R_] + MOP_FontRadius * 2 + MOP_Gap; object {MOP_Character [A_] texture {A_Color} translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [A_] + MOP_FontRadius * 2 + MOP_Gap; object {MOP_Character [Y_] texture {Y_Color} translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [Y_] + MOP_FontRadius * 2 + MOP_Gap; } //union translate //The lower left corner/back of the text object will be at the origin. #declare MOP_TextObjectWidth = CurrentX - MOP_Gap; } //object object {MOP_TextObject translate <-MOP_TextObjectWidth / 2, 0, 0>} */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * */ /* * MACROS * */ /* * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #macro GenericRoundedCorner (P0_, A0_, A1_, R_, CornerRadius_) //P0: The point where the two cylinders that are to be connected meet //A0: The angle of one of the cylinders (+x = 0, +y = 90, -x = 180, -y = 270) //A1: The angle of the other cylinder //R: The radius of the cylinders that are to be connected //CornerRadius: The radius of the rounded corner #local P0 = P0_; #local A0 = A0_; #local A1 = A1_; #local R = R_; #local CornerRadius = CornerRadius_; #local A0 = mod (A0, 360); #if (A0 < 0) #local A0 = A0 + 360; #end #local A1 = mod (A1, 360); #if (A1 < 0) #local A1 = A1 + 360; #end #if (A0 > A1) #local Temp = A0; #local A0 = A1; #local A1 = Temp; #end //#if #local MiddleAngle = (A0 + A1) / 2; #local AngleDifference = A1 - A0; #if (AngleDifference > 180) #local AngleDifference = 360 - AngleDifference; #local MiddleAngle = MiddleAngle - 180; #local Flip = yes; #else #local Flip = no; #end //#if #local L0 = CornerRadius / sin (radians (AngleDifference / 2)); #local P1 = ; object { union { intersection { torus {CornerRadius, R sturm rotate 90 * x} plane {y, 0 inverse rotate (A0 + 90) * z} plane {y, 0 inverse rotate (A1 + 90) * z} } //intersection intersection { difference { box {<-L0 - .1, -L0 - .1, -R> } cylinder {<0, 0, -R - .1> <0, 0, R + .1>, CornerRadius} } //difference plane {y, 0 inverse rotate (A0 + 90) * z} plane {y, 0 inverse rotate (A1 + 90) * z} #if (Flip) plane {y, 0 rotate A0 * z translate P0 - P1} plane {y, 0 inverse rotate A1 * z translate P0 - P1} #else plane {y, 0 inverse rotate A0 * z translate P0 - P1} plane {y, 0 rotate A1 * z translate P0 - P1} #end //#if } //intersection } //union translate P1 } //object #end //#macro GenericRoundedCorner #macro CreateMOP_Characters (MOP_FontRadius) #if (MOP_FontRadius > .0986) #warning "\nMOPFont Message: MOP_FontRadius should not be > .0986.\n" #end //#if #local R = MOP_FontRadius; #local CornerRadius = R * 1.25; #local RoundedCorner = object { union { intersection { torus {CornerRadius, R sturm rotate 90 * x translate } plane {y, CornerRadius} plane {x, CornerRadius} } //intersection difference { box {<0, 0, -R> } cylinder { , CornerRadius} } //difference } //union } //object #local Quadrant1 = 0; #local Quadrant2 = 90; #local Quadrant3 = 180; #local Quadrant4 = 270; #local VerticalBar = object { union { cylinder {<0, 0, 0> <0, 1, 0>, R} sphere {<0, 0, 0>, R} sphere {<0, 1, 0>, R} } //union } //object #declare MOP_Character [A_] = object { #local A1 = .03; #local A2 = .59; //Determines angle of sides #local A3 = .06; #local A4 = .13; //Width of top flat part, must be longer than A3 * 2 #local A_A0 = atan (1 / A2); #local A_L0 = sqrt (A2 * A2 + 1); #local A_L1 = A_L0 - A3; #local A_L2 = A_L0 - A1; #local A_L3 = .28; //Determines height of crossbar #local A_L4 = .145; //Adjust length of legs #local A_X1 = A_L1 * cos (A_A0); #local A_Y1 = A_L1 * sin (A_A0); #local A_X2 = A_L2 * cos (A_A0); #local A_Y2 = A_L2 * sin (A_A0); #local A_X3 = A_L3 * cos (A_A0); #local A_Y3 = A_L3 * sin (A_A0); #local A_X4 = A_L4 * cos (A_A0); #local A_Y4 = A_L4 * sin (A_A0); union { sphere_sweep { b_spline 14 <-A2, -1, 0>, R , R , R , R , R , R , R , R , R , R , R , R , R , R } //sphere_sweep cylinder {, , R} #local TCornerRadius = CornerRadius * 1.1; GenericRoundedCorner (, degrees (A_A0), 0, R, CornerRadius) GenericRoundedCorner (, degrees (A_A0) + 180, 0, R, TCornerRadius) GenericRoundedCorner (, degrees (-A_A0) + 180, 180, R, CornerRadius) GenericRoundedCorner (, degrees (-A_A0), 180, R, TCornerRadius) } //union #declare MOP_CharacterWidth [A_] = A2 + A4 + A2; } //object #declare MOP_Character [B_] = object { #local B1 = .12; #local B2 = 1.16; //Top width #local B3 = .2; #local B4 = .52; //Vertical #local B5 = B2 + .045; //Bottom width union { object {VerticalBar} sphere {<.2, 0, 0>, R} sphere {<.2, B4, 0>, R} sphere {<.2, 1, 0>, R} cylinder {<0, 0, 0> <.2, 0, 0>, R} cylinder {<0, B4, 0> <.2, B4, 0>, R} cylinder {<0, 1, 0> <.2, 1, 0>, R} intersection { sphere_sweep { //Top b_spline 13 <-2, 1, 0>, R <-1, 1, 0>, R //Shouldn't be necessary, but seems to minimize a glitch <.5, 1, 0>, R , R , R , R , R , R , R , R , R <.5, B4, 0>, R <-2, B4, 0>, R } //sphere_sweep plane {x, .2 inverse} } //intersection intersection { sphere_sweep { //Bottom b_spline 13 <-2, B4, 0>, R <-1, B4, 0>, R //Shouldn't be necessary, but seems to minimize a glitch <.5, B4, 0>, R , R , R , R , R , R , R , R , R <.5, 0, 0>, R <-2, 0, 0>, R } //sphere_sweep plane {x, .2 inverse} } //intersection object {RoundedCorner rotate Quadrant4 * z translate <0, 1, 0>} object {RoundedCorner translate <0, B4, 0>} object {RoundedCorner rotate Quadrant4 * z translate <0, B4, 0>} object {RoundedCorner} } //union #declare MOP_CharacterWidth [B_] = B5; } //object #declare MOP_Character [C_] = object { #local C1 = .12; #local C2 = 1.24; //Width #local C3 = .2; #local C4 = .015; //Shorten top width #local C5 = .15; #local C6 = .22; //Length of ends union { difference { sphere_sweep { b_spline 20 , R , R , R , R , R , R , R , R <0, C1, 0>, R <0, C1 + C3, 0>, R <0, 1 - C1 - C3, 0>, R <0, 1 - C1, 0>, R , R , R , R , R , R , R , R , R } //sphere_sweep box { } } //difference intersection { //Bottom sphere {<0, 0, 0>, R} plane {y, 0 inverse} translate } //intersection intersection { //Top sphere {<0, 0, 0>, R} plane {y, 0} translate } //intersection } //union #declare MOP_CharacterWidth [C_] = C2; } //object #declare MOP_Character [D_] = object { #local D1 = .12; #local D2 = 1.27; //Width #local D3 = .2; union { object {VerticalBar} sphere {<.2, 0, 0>, R} sphere {<.2, 1, 0>, R} cylinder {<0, 0, 0> <.2, 0, 0>, R} cylinder {<0, 1, 0> <.2, 1, 0>, R} intersection { sphere_sweep { b_spline 13 <-2, 1, 0>, R <-1, 1, 0>, R //Shouldn't be necessary, but seems to minimize a glitch <.5, 1, 0>, R , R , R , R , R , R , R , R , R <.5, 0, 0>, R <-2, 0, 0>, R } //sphere_sweep plane {x, .2 inverse} } //intersection object {RoundedCorner rotate Quadrant4 * z translate <0, 1, 0>} object {RoundedCorner} } //union #declare MOP_CharacterWidth [D_] = D2; } //object #declare MOP_Character [E_] = object { #local E1 = .98; //Top and bottom bars #local E2 = .945; //Middle bar #local E3 = .52; //Vertical union { object {VerticalBar} cylinder {<0, 0, 0> , R} sphere {, R} cylinder {<0, E3, 0> , R} sphere {, R} cylinder {<0, 1, 0> , R} sphere {, R} object {RoundedCorner rotate Quadrant4 * z translate <0, 1, 0>} object {RoundedCorner translate <0, E3, 0>} object {RoundedCorner rotate Quadrant4 * z translate <0, E3, 0>} object {RoundedCorner} } //union #declare MOP_CharacterWidth [E_] = E1; } //object #declare MOP_Character [F_] = object { #local F1 = .95; //Top bar #local F2 = .91; //Bottom bar #local F3 = .52; //Vertical union { object {VerticalBar} cylinder {<0, F3, 0> , R} sphere {, R} cylinder {<0, 1, 0> , R} sphere {, R} object {RoundedCorner rotate Quadrant4 * z translate <0, 1, 0>} object {RoundedCorner translate <0, F3, 0>} object {RoundedCorner rotate Quadrant4 * z translate <0, F3, 0>} } //union #declare MOP_CharacterWidth [F_] = F1; } //object #declare MOP_Character [G_] = object { #local G1 = .12; #local G2 = 1.26; //Width #local G3 = .2; #local G4 = G1 + G3 + .115; //Vertical, G4 must be > G1 + G3 #local G5 = G2 / 2 + .04; union { difference { sphere_sweep { b_spline 18 , R , R , R , R , R , R , R , R <0, G1, 0>, R <0, G1 + G3, 0>, R <0, 1 - G1 - G3, 0>, R <0, 1 - G1, 0>, R , R , R , R , R , R , R } //sphere_sweep box { } } //difference sphere {, R} sphere {, R} cylinder { , R} object {RoundedCorner rotate Quadrant3 * z translate } } //union #declare MOP_CharacterWidth [G_] = G2; } //object #declare MOP_Character [H_] = object { #local H1 = 1.18; //Width #local H2 = .52; //Vertical union { object {VerticalBar} object {VerticalBar translate H1 * x} cylinder {<0, H2, 0> , R} object {RoundedCorner translate <0, H2, 0>} object {RoundedCorner rotate Quadrant4 * z translate <0, H2, 0>} object {RoundedCorner rotate Quadrant2 * z translate } object {RoundedCorner rotate Quadrant3 * z translate } } //union #declare MOP_CharacterWidth [H_] = H1; } //object #declare MOP_Character [I_] = object { object {VerticalBar} #declare MOP_CharacterWidth [I_] = 0; } //object #declare MOP_Character [J_] = object { #local J1 = .12; #local J2 = 1.11; //Width #local J3 = .2; #local J4 = J1 + J3 + .01; //J4 must be > J1 + J3 sphere_sweep { b_spline 11 <0, J4, 0>, R <0, J1 + J3, 0>, R <0, J1, 0>, R , R , R , R , R , R , R , R , R } //sphere_sweep #declare MOP_CharacterWidth [J_] = J2; } //object #declare MOP_Character [K_] = object { #local K1 = .29; //Width of horizontal bar #local K2 = .52; //Vertical #local K_A0 = 30; union { object {VerticalBar} cylinder {<0, K2, 0> , R} sphere {, R} #local K3_Top = sin (radians (90 - K_A0)) * (1 - K2) / sin (radians (K_A0)); #local K3_Bottom = sin (radians (90 - K_A0)) * K2 / sin (radians (K_A0)); #local K_L0_Top = sqrt (K3_Top * K3_Top + (1 - K2) * (1 - K2)); #local K_L0_Bottom = sqrt (K3_Bottom * K3_Bottom + K2 * K2); #local Bar_Top = object { union { cylinder {<0, 0, 0> , R} sphere {, R} } //union } //object #local Bar_Bottom = object { union { cylinder {<0, 0, 0> , R} sphere {, R} } //union } //object object {Bar_Top rotate K_A0 * z translate } object {Bar_Bottom rotate -K_A0 * z translate } #local TCornerRadius = CornerRadius * 6.5; GenericRoundedCorner (, 180, K_A0, R, TCornerRadius) GenericRoundedCorner (, 180, -K_A0, R, TCornerRadius) GenericRoundedCorner (, K_A0, -K_A0, R, CornerRadius) object {RoundedCorner rotate Quadrant4 * z translate <0, K2, 0>} object {RoundedCorner translate <0, K2, 0>} } //union #declare MOP_CharacterWidth [K_] = K1 + K3_Bottom; } //object #declare MOP_Character [L_] = object { #local L1 = 1.03; //Width union { object {VerticalBar} cylinder {<0, 0, 0> , R} sphere {, R} object {RoundedCorner} } //union #declare MOP_CharacterWidth [L_] = L1; } //object #declare MOP_Character [M_] = object { #local M1 = .04 + R; #local M_A0 = 34; union { #local MCorner = object { #local MCornerRadius = R * 1.75; intersection { torus {MCornerRadius, R sturm rotate 90 * x} plane {x, 0 inverse} plane {y, 0 inverse rotate M_A0 * z} } //intersection } //object #local M_P0 = ; #local M2 = M_P0.y / sin (radians (90 - M_A0)) * sin (radians (M_A0)); #local M_P1 = ; #local M_L0 = sqrt (M2 * M2 + M_P0.y * M_P0.y); object {VerticalBar} //Left side sphere {, R} cylinder {<0, 1, 0> , R} object {VerticalBar translate (M_P0.x + M2 + M2 + M_P0.x) * x} //Right side sphere {, R} cylinder { , R} sphere {, R} //Center object {MCorner translate } object {MCorner rotate 180 * y translate } sphere {M_P0, R} cylinder {<0, 0, 0> , R rotate (-90 + M_A0) * z translate M_P0} sphere {M_P1, R} cylinder {<0, 0, 0> , R rotate (270 - M_A0) * z translate M_P1} GenericRoundedCorner (, 90 + M_A0, 90 - M_A0, R, CornerRadius) object {RoundedCorner rotate Quadrant4 * z translate <0, 1, 0>} object {RoundedCorner rotate Quadrant3 * z translate } } //union #declare MOP_CharacterWidth [M_] = M_P0.x + M2 + M2 + M_P0.x; } //object #declare MOP_Character [N_] = object { #local N1 = .04 + R; #local N_A0 = 43; union { #local NCorner = object { #local NCornerRadius = R * 1.75; intersection { torus {NCornerRadius, R sturm rotate 90 * x} plane {x, 0 inverse} plane {y, 0 inverse rotate N_A0 * z} } //intersection } //object #local N_P0 = ; #local N_P1Y = NCornerRadius - NCornerRadius * sin (radians (N_A0)); #local N2 = (N_P0.y - N_P1Y) / sin (radians (90 - N_A0)) * sin (radians (N_A0)); #local N_P1X = N_P0.x + N2 + NCornerRadius * cos (radians (N_A0)); #local N_P1 = ; #local N_L0 = sqrt (N2 * N2 + (N_P0.y - N_P1.y) * (N_P0.y - N_P1.y)); object {VerticalBar} //Left side sphere {, R} cylinder {<0, 1, 0> , R} object {VerticalBar translate (N_P1.x + N1) * x} //Right side sphere {, R} cylinder { , R} object {NCorner translate } object {NCorner rotate 180 * x rotate 180 * y translate } sphere {N_P0, R} sphere {, R rotate (-90 + N_A0) * z translate N_P0} cylinder {<0, 0, 0> , R rotate (-90 + N_A0) * z translate N_P0} object {RoundedCorner rotate Quadrant4 * z translate <0, 1, 0>} object {RoundedCorner rotate Quadrant2 * z translate } } //union #declare MOP_CharacterWidth [N_] = N_P1.x + N1; } //object #declare MOP_Character [O_] = object { #local O1 = .15; #local O2 = 1.3; //Width #local O3 = .2; sphere_sweep { b_spline 19 , R , R <0, O1, 0>, R <0, O1 + O3, 0>, R <0, 1 - O1 - O3, 0>, R <0, 1 - O1, 0>, R , R , R , R , R , R , R , R , R , R , R , R , R <0, O1, 0>, R } //sphere_sweep #declare MOP_CharacterWidth [O_] = O2; } //object #declare MOP_Character [P_] = object { #local P1 = .12; #local P2 = 1.13; //Width #local P3 = .2; #local P4 = .42; //Vertical union { object {VerticalBar} sphere {<.2, P4, 0>, R} sphere {<.2, 1, 0>, R} cylinder {<0, 1, 0> <.2, 1, 0>, R} cylinder {<0, P4, 0> <.2, P4, 0>, R} intersection { sphere_sweep { b_spline 13 <-2, 1, 0>, R <-1, 1, 0>, R //Shouldn't be necessary, but seems to minimize a glitch <.5, 1, 0>, R , R , R , R , R , R , R , R , R <.5, P4, 0>, R <-2, P4, 0>, R } //sphere_sweep plane {x, .2 inverse} } //intersection object {RoundedCorner rotate Quadrant4 * z translate <0, 1, 0>} object {RoundedCorner translate <0, P4, 0>} object {RoundedCorner rotate Quadrant4 * z translate <0, P4, 0>} } //union #declare MOP_CharacterWidth [P_] = P2; } //object #declare MOP_Character [Q_] = object { #local Q1 = MOP_CharacterWidth [O_]; //Width #local Q2 = .26; //Outside length of tail #local Q3 = .385; //Inside length of tail #switch (R) //Adjust length of flattened portion #range (0, .06) #local Q4 = .085; #break #range (.06, .0986) #local Q4 = .085 - (R - .06) / (.0986 - .06) * .085; #break #range (.0986, 999) #local Q4 = 0; #break #end //#switch #local Q_A0 = 32; union { difference { object {MOP_Character [O_]} box { } } //difference #local QCornerRadius = .28; #local Q_P0 = ; #local QCorner_Left = object { intersection { torus {QCornerRadius, R sturm rotate 90 * x} plane {x, 0 inverse} plane {y, 0 rotate -45 * z} } //intersection } //object #local QCorner_Right = object { intersection { torus {QCornerRadius, R sturm rotate 90 * x} plane {y, 0} plane {x, 0 inverse rotate 45 * z} } //intersection } //object object {QCorner_Left translate } cylinder { , R} sphere {, R} sphere {, R} object {QCorner_Right translate } #if (Q4 > 0) cylinder { , R} sphere {, R} #end //#if sphere {, R} #local Q_P0_Left = Q_P0 + ; #local Q_P0_Right = Q_P0 + ; cylinder {Q_P0_Left, Q_P0_Right, R} #local QTail = object { union { cylinder {<-Q3, 0, 0> , R} sphere {<-Q3, 0, 0>, R} sphere {, R} } //union } //object #local Q_P1 = <(Q_P0_Left.x + Q_P0_Right.x) / 2, (Q_P0_Left.y + Q_P0_Right.y) / 2, 0>; object {QTail rotate -Q_A0 * z translate Q_P1} GenericRoundedCorner (Q_P1, 45, 180 - Q_A0, R, CornerRadius) GenericRoundedCorner (Q_P1, 45, -Q_A0, R, CornerRadius) GenericRoundedCorner (Q_P1, -135, 180 - Q_A0, R, CornerRadius) GenericRoundedCorner (Q_P1, -135, -Q_A0, R, CornerRadius) } //union #declare MOP_CharacterWidth [Q_] = Q_P1.x + Q2 * cos (radians (Q_A0)); } //object #declare MOP_Character [R_] = object { #local R1 = .12; #local R2 = 1.13; //Top width #local R3 = .2; #local R4 = .42; //Vertical #local R5 = R2 + .05; //Bottom width union { object {VerticalBar} sphere {<.2, R4, 0>, R} sphere {<.2, 1, 0>, R} cylinder {<0, 1, 0> <.2, 1, 0>, R} cylinder {<0, R4, 0> <.2, R4, 0>, R} intersection { sphere_sweep { //Top b_spline 13 <-2, 1, 0>, R <-1, 1, 0>, R //Shouldn't be necessary, but seems to minimize a glitch <.5, 1, 0>, R , R , R , R , R , R , R , R , R <.5, R4, 0>, R <-2, R4, 0>, R } //sphere_sweep plane {x, .2 inverse} } //intersection intersection { sphere_sweep { //Bottom b_spline 9 <-1, R4, 0>, R <-.5, R4, 0>, R //Shouldn't be necessary, but seems to minimize a glitch <.5, R4, 0>, R , R , R , R , R , R , R } //sphere_sweep plane {x, .2 inverse} } //intersection object {RoundedCorner rotate Quadrant4 * z translate <0, 1, 0>} object {RoundedCorner translate <0, R4, 0>} object {RoundedCorner rotate Quadrant4 * z translate <0, R4, 0>} } //union #declare MOP_CharacterWidth [R_] = R5; } //object #declare MOP_Character [S_] = object { #local S1 = .12; #local S2 = 1.13; //Top width #local S3 = .2; #local S4 = .5; //Vertical #local S5 = .15; #local S6 = .22; //Length of ends #local S7 = .025; //Additional bottom width union { difference { sphere_sweep { b_spline 28 <0, 1, 0>, R <0, S5, 0>, R <0, S1 + S3, 0>, R <0, S1, 0>, R , R , R , R , R , R , R , R , R , R , R , R , R <0, S4 + S1, 0>, R <0, S4 + S1 + S3, 0>, R <0, 1 - S1 - S3, 0>, R <0, 1 - S1, 0>, R , R , R , R , R , R , R , R , R } //sphere_sweep box {<-.15, S6, -.15> <.15, S5 + .25, .15>} //Left / Bottom box {<-.075, S6 + .0001, -.075> <.075, S5 + .28, .075>} //Left / Bottom box { } //Right / Top box { } //Right / Top } //difference intersection { //Left / Bottom sphere {<0, 0, 0>, R} plane {y, 0 inverse} translate <.002, S6, 0> } //intersection intersection { //Right / Top sphere {<0, 0, 0>, R} plane {y, 0} translate } //intersection } //union #declare MOP_CharacterWidth [S_] = S2 + S7; } //object #declare MOP_Character [T_] = object { #local T1 = 1.17; //Top bar union { cylinder { , R} sphere {, R} cylinder {<0, 1, 0> , R} sphere {<0, 1, 0>, R} sphere {, R} object {RoundedCorner rotate Quadrant3 * z translate } object {RoundedCorner rotate Quadrant4 * z translate } } //union #declare MOP_CharacterWidth [T_] = T1; } //object #declare MOP_Character [U_] = object { #local U1 = .15; #local U2 = 1.18; //Width #local U3 = .2; sphere_sweep { b_spline 12 , R , R , R , R , R , R , R , R <0, U1, 0>, R <0, U1 + U3, 0>, R <0, 1, 0>, R <0, 1.65, 0>, R } //sphere_sweep #declare MOP_CharacterWidth [U_] = U2; } //object #declare MOP_Character [V_] = object { #local V1 = .565; //Determines angle of sides #local V2 = .9886; //Vertical #local V3 = .14; //Width of bottom flat part #local V4 = .9; #local V5 = .0093; //Fix sphere_sweep { b_spline 8 <-V1, V2, 0>, R <0, 0, 0>, R , R , R , R , R , R , R } //sphere_sweep translate #declare MOP_CharacterWidth [V_] = V5 + V1 + V3 + V1 + V5; } //object #declare MOP_Character [W_] = object { #local W1 = .01 + R; #local W_A0 = 20.5; //Inside bars #local W_A1 = 20.5; //Outside bars union { #local WCorner = object { #local WCornerRadius = R * 1.75; intersection { torus {WCornerRadius, R sturm rotate 90 * x} plane {x, 0 inverse} plane {y, 0 inverse rotate W_A0 * z} } //intersection } //object #local W_P0 = ; #local W2 = W_P0.y / sin (radians (90 - W_A0)) * sin (radians (W_A0)); #local W_P1 = ; #local W_L0 = sqrt (W2 * W2 + W_P0.y * W_P0.y); #local W3 = sin (radians (W_A1)) / sin (radians (90 - W_A1)); sphere {<-W3, 0, 0>, R} //Left side sphere {<0, 1, 0>, R} cylinder {<-W3, 0, 0> <0, 1, 0>, R} sphere {, R} cylinder {<0, 1, 0> , R} //Connector sphere {, R} //Right side sphere {, R} cylinder { , R} sphere {, R} cylinder { , R} //Connector object {WCorner translate } object {WCorner rotate 180 * y translate } sphere {W_P0, R} sphere {W_P1, R} cylinder {<0, 0, 0> , R rotate (-90 + W_A0) * z translate W_P0} //Left center cylinder {<0, 0, 0> , R rotate (270 - W_A0) * z translate W_P1} //Right center sphere {, R} //Center GenericRoundedCorner (, 90 + W_A0, 90 - W_A0, R, CornerRadius) GenericRoundedCorner (<0, 1, 0>, 90 - W_A1 + 180, 0, R, CornerRadius) GenericRoundedCorner (, -90 + W_A1, 180, R, CornerRadius) } //union translate W3 * x rotate 180 * z translate #declare MOP_CharacterWidth [W_] = W3 + W_P0.x + W2 + W2 + W_P0.x + W3; } //object #declare MOP_Character [X_] = object { #local X1 = .53; //Vertical #if (R < .06) #local X3 = 0; //Offset #else #local X3 = .02; //Offset #end //#if #local X_A0 = 45; //Don't change #local X_L0_Bottom = X1 / sin (radians (X_A0)); #local X2 = X_L0_Bottom * sin (radians (90 - X_A0)); #local X_P0 = ; #local X_P1_Left = ; #local X_P1_Right = ; #local X_L0_Top = (1 - X_P1_Left.y) / sin (radians (X_A0)); #local X_L0_Bottom = X_L0_Bottom - X3; union { #local TempX = object { union { #local Bar_Bottom = object { union { sphere {<0, 0, 0>, R} sphere {, R} cylinder {<0, 0, 0> , R} } //union } //object #local Bar_Top = object { union { sphere {<0, 0, 0>, R} sphere {, R} cylinder {<0, 0, 0> , R} } //union } //object object {Bar_Bottom rotate X_A0 * z} //Bottom left object {Bar_Bottom rotate (180 - X_A0) * z translate } //Bottom right object {Bar_Top rotate (180 - X_A0) * z translate X_P1_Left} //Top left object {Bar_Top rotate X_A0 * z translate X_P1_Right} //Top right } //union rotate X_A0 * z } //object object {TempX} #local X_L1 = sqrt (X_P1_Left.x * X_P1_Left.x + X_P1_Left.y * X_P1_Left.y); #local X_A2 = atan (X_P1_Left.y / X_P1_Left.x) + radians (X_A0); #local X_P2 = ; #local X_L2 = sqrt (X_P1_Right.x * X_P1_Right.x + X_P1_Right.y * X_P1_Right.y); #local X_A3 = atan (X_P1_Right.y / X_P1_Right.x) + radians (X_A0); #local X_P3 = ; object {RoundedCorner rotate Quadrant3 * z translate } object {RoundedCorner rotate Quadrant4 * z translate } object {RoundedCorner translate } object {RoundedCorner rotate Quadrant2 * z translate } } //union rotate -X_A0 * z #declare MOP_CharacterWidth [X_] = X2 + X2; } //object #declare MOP_Character [Y_] = object { #local Y1 = .44; //Vertical #local Y3 = 1.2; //Width #local Y4 = Y3 / 2; #local Y_A0 = degrees (atan (Y4 / (1 - Y1))); union { sphere {<0, 0, 0>, R} sphere {<0, Y1, 0>, R} cylinder {<0, 0, 0> <0, Y1, 0>, R} #local Y_L0 = sqrt (Y4 * Y4 + (1 - Y1) * (1 - Y1)); #local Bar = object { union { cylinder {<0, 0, 0> , R} sphere {, R} } //union } //object object {Bar rotate (90 + Y_A0) * z translate <0, Y1, 0>} object {Bar rotate (90 - Y_A0) * z translate <0, Y1, 0>} #local TCornerRadius = CornerRadius * 2; GenericRoundedCorner (<0, Y1, 0>, 90 + Y_A0, 270, R, TCornerRadius) GenericRoundedCorner (<0, Y1, 0>, 90 - Y_A0, 270, R, TCornerRadius) GenericRoundedCorner (<0, Y1, 0>, 90 + Y_A0, 90 - Y_A0, R, CornerRadius) } //union translate Y4 * x #declare MOP_CharacterWidth [Y_] = Y3; } //object #declare MOP_Character [Z_] = object { #local Z1 = 1.17; //Width #local ZCornerRadius = R * 1.3; union { #local Z9 = .024; //Shorten right side of top bar #local Z2 = ZCornerRadius; #local Z3 = ZCornerRadius; #local Z4 = Z1 - Z9 - ZCornerRadius; #local Z5 = 1 - ZCornerRadius; #local Z6 = ZCornerRadius + R; #local Z7 = ZCornerRadius - R; #local Z8 = .03; //Shorten left side of top bar #local Z_P0X = (Z4 * Z6 + Z2 * Z7) / (Z6 + Z7); //Intersection of inner tangents #local Z_P0Y = (Z5 * Z6 + Z3 * Z7) / (Z6 + Z7); #local Z_P1X = (Z6 * Z6 * (Z_P0X - Z2) - Z6 * (Z_P0Y - Z3) * sqrt ((Z_P0X - Z2) * (Z_P0X - Z2) + (Z_P0Y - Z3) * (Z_P0Y - Z3) - Z6 * Z6)) / ((Z_P0X - Z2) * (Z_P0X - Z2) + (Z_P0Y - Z3) * (Z_P0Y - Z3)) + Z2; #local Z_P1Y = (Z6 * Z6 * (Z_P0Y - Z3) + Z6 * (Z_P0X - Z2) * sqrt ((Z_P0X - Z2) * (Z_P0X - Z2) + (Z_P0Y - Z3) * (Z_P0Y - Z3) - Z6 * Z6)) / ((Z_P0X - Z2) * (Z_P0X - Z2) + (Z_P0Y - Z3) * (Z_P0Y - Z3)) + Z3; #local Z_P2 = ; #local Z_A0 = atan (Z_P2.y / Z_P2.x); #local Z_P3 = ; #local Z_A0 = Z_A0 + radians (90); #local Z_P4X = Z4 + Z7 * cos (Z_A0 - radians (90)); #local Z_P4Y = Z5 + Z7 * sin (Z_A0 - radians (90)); #local Z_L0 = sqrt ((Z_P4X - Z_P1X) * (Z_P4X - Z_P1X) + (Z_P4Y - Z_P1Y) * (Z_P4Y - Z_P1Y)); #local ZCorner = object { intersection { torus {ZCornerRadius, R sturm rotate 90 * x} plane {x, 0} plane {x, 0 rotate degrees (Z_A0) * z} } //intersection } //object sphere {, R} sphere {, R} sphere {, R} cylinder { , R} sphere {, R} cylinder { , R} sphere {Z_P3, R} sphere {, R rotate degrees (Z_A0) * z translate Z_P3} cylinder {<0, 0, 0> , R rotate degrees (Z_A0) * z translate Z_P3} object {ZCorner translate } //Bottom object {ZCorner rotate 180 * z translate } //Top } //union #declare MOP_CharacterWidth [Z_] = Z1; } //object #declare MOP_Character [DASH_] = object { #local DASH1 = .5; //Width #local DASH2 = .435; //Vertical, match the "G" union { sphere {<0, DASH2, 0>, R} sphere {, R} cylinder {<0, DASH2, 0> , R} } //union #declare MOP_CharacterWidth [DASH_] = DASH1; } //object #declare MOP_Character [PERIOD_] = object { #local PERIOD1 = R * 1; //Width #local PERIOD2 = PERIOD1 * .4; //Height #local PERIODRadius = R * .075; union { #local PERIODCorner = object { intersection { torus {PERIODRadius, R sturm rotate 90 * x} plane {x, 0} plane {y, 0} } //intersection } //object object {PERIODCorner translate <0, PERIODRadius, 0>} object {PERIODCorner rotate 90 * z translate } object {PERIODCorner rotate 180 * z translate } object {PERIODCorner rotate 270 * z translate <0, PERIOD2, 0>} cylinder {<0, 0, 0> , R} //Bottom cylinder { , R} //Right cylinder {<0, PERIOD2 + PERIODRadius, 0> , R} //Top cylinder {<-PERIODRadius, PERIODRadius, 0> <-PERIODRadius, PERIOD2, 0>, R} //Left cylinder {<0, 0, -R>, <0, 0, R>, PERIODRadius translate <0, PERIODRadius, 0>} cylinder {<0, 0, -R>, <0, 0, R>, PERIODRadius translate } cylinder {<0, 0, -R>, <0, 0, R>, PERIODRadius translate } cylinder {<0, 0, -R>, <0, 0, R>, PERIODRadius translate <0, PERIOD2, 0>} box {<-PERIODRadius, PERIODRadius, -R> } box {<0, 0, -R> } } //union translate PERIODRadius * x #declare MOP_CharacterWidth [PERIOD_] = PERIOD1 + PERIODRadius; } //object #declare MOP_TextObjectHeight = 1 + MOP_FontRadius * 2; #declare LastMOP_FontRadius = MOP_FontRadius; #declare MOP_CharactersValid = yes; #end //#macro CreateMOP_Characters #macro CreateMOP_TextObject (TextLine_, MOP_Gap_, MOP_Space_, MOP_FontRadius_, MOP_ApplyKerning_) #declare MOP_Gap = MOP_Gap_; #declare MOP_Space = MOP_Space_; #declare MOP_FontRadius = MOP_FontRadius_; #declare MOP_ApplyKerning = MOP_ApplyKerning_; #if (MOP_FontRadius != LastMOP_FontRadius) CreateMOP_Characters (MOP_FontRadius) #end //#if #local TextLine = strupr (TextLine_); #local TextLine_ = ""; #for (I, 1, strlen (TextLine)) #local CurrentCharacter = substr (TextLine, I, 1); #if (CurrentCharacter = " " | (CurrentCharacter >= "A" & CurrentCharacter <= "Z") | CurrentCharacter = "-" | CurrentCharacter = ".") #local TextLine_ = concat (TextLine_, CurrentCharacter); #else #debug "\nMOPFont Message: Only letters A - Z, [SPACE], [DASH], and [PERIOD] are supported. A non-supported character was skipped.\n" #end //#if #end //#for #local TextLine = TextLine_; #if (TextLine = "") #error "MOPFont Message: No valid characters." #end //#if #while (substr (TextLine, 1, 1) = " ") //Remove leading spaces #if (strlen (TextLine) > 1) #local TextLine = substr (TextLine, 2, strlen (TextLine) - 1); #else #error "MOPFont Message: No valid characters." #end //#if #end //#while #while (substr (TextLine, strlen (TextLine), 1) = " ") //Remove trailing spaces #local TextLine = substr (TextLine, 1, strlen (TextLine) - 1); #end //#while #local LineCharacterIndex = array [strlen (TextLine)] #local NLineCharacters = 0; #for (I, 1, strlen (TextLine)) #local CurrentCharacter = substr (TextLine, I, 1); #if ((CurrentCharacter >= "A" & CurrentCharacter <= "Z") | CurrentCharacter = "-" | CurrentCharacter = ".") #local CurrentLineCharacterIndex = asc (CurrentCharacter) - 65; #if (CurrentLineCharacterIndex = 45 - 65) #local CurrentLineCharacterIndex = 26; #end //DASH #if (CurrentLineCharacterIndex = 46 - 65) #local CurrentLineCharacterIndex = 27; #end //PERIOD #local LineCharacterIndex [NLineCharacters] = CurrentLineCharacterIndex; #local NLineCharacters = NLineCharacters + 1; #end //#if #end //#for #if (NLineCharacters = 0) #error "MOPFont Message: No valid characters." #end //#if #if (NLineCharacters > 1 & MOP_ApplyKerning) #local CharacterInUse = array [NCharacters] #local Kerning = array [NCharacters] [NCharacters] #for (I, 0, NCharacters - 1) //Initialize kerning flags #local CharacterInUse [I] = no; #for (J, 0, NCharacters - 1) #local Kerning [I] [J] = 0; #end //#for #end //#for #for (I, 0, NLineCharacters - 1) #local CharacterInUse [LineCharacterIndex [I]] = yes; //Flag for character measurement #end //#for #for (I, 0, NLineCharacters - 2) #local Kerning [LineCharacterIndex [I]] [LineCharacterIndex [I + 1]] = 1; //Flag for character-to-character measurement #end //#for #local DefaultKerningDistance = .12; //Default value when characters never touch #local MaximumKerningDistance = .6; #local Range_Lower = 0; //Even though the characters are actually larger, the unique design of these characters guarantees #local Range_Upper = 1; //that the closest points between any two characters will be between y = 0 and y = 1. #local NSteps = 600; //More steps produce more accuracy but take more time. #local Step = (Range_Upper - Range_Lower) / (NSteps - 1); #local SideDistance_Left = array [NCharacters] [NSteps] #local SideDistance_Right = array [NCharacters] [NSteps] #local RayDirection_LeftToRight = x; #local RayDirection_RightToLeft = -x; #for (I, 0, NCharacters - 1) #if (CharacterInUse [I]) #local CurrentShape = object {MOP_Character [I] translate } #local StepCount = 0; #for (CurrentY, Range_Lower, Range_Upper, Step) #local RayStartPoint_LeftSide = <-10, CurrentY, -MOP_FontRadius>; #local RayStartPoint_RightSide = <10, CurrentY, -MOP_FontRadius>; #local IntersectionPoint_LeftSide = trace (CurrentShape, RayStartPoint_LeftSide, RayDirection_LeftToRight); #if (IntersectionPoint_LeftSide.z != 0) //There's something here... #local IntersectionPoint_RightSide = trace (CurrentShape, RayStartPoint_RightSide, RayDirection_RightToLeft); #local SideDistance_Left [I] [StepCount] = IntersectionPoint_LeftSide.x; #local SideDistance_Right [I] [StepCount] = MOP_CharacterWidth [I] + MOP_FontRadius * 2 - IntersectionPoint_RightSide.x; #else #local SideDistance_Left [I] [StepCount] = -1; //Set to -1 if no intersection #local SideDistance_Right [I] [StepCount] = -1; //Set to -1 if no intersection #end //#if #local StepCount = StepCount + 1; #end //#for #end //#if #end //#for #for (I, 0, NCharacters - 1) #for (J, 0, NCharacters - 1) #if (Kerning [I] [J] = 1) //Flagged for measurement #local MinimumDistance = 10; #local StepCount = 0; #for (CurrentY, Range_Lower, Range_Upper, Step) #if (SideDistance_Right [I] [StepCount] != -1 & SideDistance_Left [J] [StepCount] != -1) #local CurrentDistance = SideDistance_Right [I] [StepCount] + SideDistance_Left [J] [StepCount]; #if (CurrentDistance < MinimumDistance) #local MinimumDistance = CurrentDistance; #end //#if #end //#if #local StepCount = StepCount + 1; #end //#for #if (MinimumDistance = 10) //Characters never touch #local Kerning [I] [J] = DefaultKerningDistance; #else #local Kerning [I] [J] = min (MaximumKerningDistance, abs (MinimumDistance)); #end //#if #debug concat ("\nMOPFont Message: Kerning value for characters ", str (I, 0, 0), " and ", str (J, 0, 0), ": ", str (Kerning [I] [J], 0, 3), "\n") #end //#if #end //#for #end //#for #end //#if #declare MOP_TextObject = object { #local CurrentX = 0; #if (NLineCharacters > 1) union { #for (I, 1, strlen (TextLine)) #local AddCharacter = yes; #local CurrentCharacter = asc (substr (TextLine, I, 1)) - 65; #if (CurrentCharacter = 32 - 65) #local CurrentX = CurrentX + MOP_Space; #local AddCharacter = no; #elseif (CurrentCharacter = 45 - 65) #local CurrentCharacter = DASH_; #elseif (CurrentCharacter = 46 - 65) #local CurrentCharacter = PERIOD_; #end //#if #if (AddCharacter) object {MOP_Character [CurrentCharacter] translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [CurrentCharacter] + MOP_FontRadius * 2 + MOP_Gap; #if (I < strlen (TextLine)) #for (J, I + 1, strlen (TextLine)) #local NextCharacter = asc (substr (TextLine, J, 1)) - 65; #if (NextCharacter != 32 - 65) //Use this one #if (NextCharacter = 45 - 65) #local NextCharacter = DASH_; #elseif (NextCharacter = 46 - 65) #local NextCharacter = PERIOD_; #end //#if #break #end //#if #end //#for #if (MOP_ApplyKerning) #local CurrentX = CurrentX - Kerning [CurrentCharacter] [NextCharacter]; #end //#if #end //#if #end //#if #end //#for } //union #else #local CurrentCharacter = asc (TextLine) - 65; #if (CurrentCharacter = 45 - 65) #local CurrentCharacter = DASH_; #elseif (CurrentCharacter = 46 - 65) #local CurrentCharacter = PERIOD_; #end //#if object {MOP_Character [CurrentCharacter] translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [CurrentCharacter] + MOP_FontRadius * 2 + MOP_Gap; #end //#if translate //The lower left corner/back of the text object will be at the origin. } //object #declare MOP_TextObjectWidth = CurrentX - MOP_Gap; #end //#macro CreateMOP_TextObject /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * */ /* * INITIALIZATIONS * */ /* * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #declare A_ = 0; #declare B_ = 1; #declare C_ = 2; #declare D_ = 3; #declare E_ = 4; #declare F_ = 5; #declare G_ = 6; #declare H_ = 7; #declare I_ = 8; #declare J_ = 9; #declare K_ = 10; #declare L_ = 11; #declare M_ = 12; #declare N_ = 13; #declare O_ = 14; #declare P_ = 15; #declare Q_ = 16; #declare R_ = 17; #declare S_ = 18; #declare T_ = 19; #declare U_ = 20; #declare V_ = 21; #declare W_ = 22; #declare X_ = 23; #declare Y_ = 24; #declare Z_ = 25; #declare DASH_ = 26; #declare PERIOD_ = 27; #declare NCharacters = 28; #declare MOP_Character = array [NCharacters]; #declare MOP_CharacterWidth = array [NCharacters]; #declare LastMOP_FontRadius = -1; #ifndef (MOP_Gap) #declare MOP_Gap = .16; #end #ifndef (MOP_Space) #declare MOP_Space = .7; #end #ifndef (MOP_ApplyKerning) #declare MOP_ApplyKerning = yes; #end #ifndef (MOP_CharactersValid) #declare MOP_CharactersValid = no; #end //#ifndef #if (!MOP_CharactersValid) #ifndef (MOP_FontRadius) #declare MOP_FontRadius = .06; #end //#ifndef CreateMOP_Characters (MOP_FontRadius) #end //#if