/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * */ /* * 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 called "MOP_TextObject" 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. //In general, 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. I haven't tested the digits and symbols //extensively. I did notice the "$" fails somewhere between .075 and .08. A value of .06 best matches the //font on the Master of Puppets album cover. //Note that the rounded nature of this font is especially suited to metallic and/or shiny, reflective //textures. //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 MeasureCharacter (CharacterIndex_, Shape_, Range_Lower_, Range_Upper_, NSteps_) #local I = CharacterIndex_; #local Shape = Shape_; #local Range_Lower = Range_Lower_; #local Range_Upper = Range_Upper_; #local NSteps = NSteps_; #local Step = (Range_Upper - Range_Lower) / (NSteps - 1); #local RayDirection_LeftToRight = x; #local RayDirection_RightToLeft = -x; #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 (Shape, RayStartPoint_LeftSide, RayDirection_LeftToRight); #if (IntersectionPoint_LeftSide.z != 0) //There's something here... #local IntersectionPoint_RightSide = trace (Shape, RayStartPoint_RightSide, RayDirection_RightToLeft); #declare SideDistance_Left [I] [StepCount] = IntersectionPoint_LeftSide.x; #declare SideDistance_Right [I] [StepCount] = MOP_CharacterWidth [I] - IntersectionPoint_RightSide.x + MOP_FontRadius * 2; //"+ MOP_FontRadius * 2" is unique to this project #else #declare SideDistance_Left [I] [StepCount] = -1; //Set to -1 if no intersection #declare SideDistance_Right [I] [StepCount] = -1; //Set to -1 if no intersection #declare CharacterFullVertical [I] = no; #end //#if #local StepCount = StepCount + 1; #end //#for #end //#macro MeasureCharacter #macro MeasureCharacterToCharacter (CharacterIndex0_, CharacterIndex1_, Range_Lower_, Range_Upper_, NSteps_) #local I = CharacterIndex0_; #local J = CharacterIndex1_; #local Range_Lower = Range_Lower_; #local Range_Upper = Range_Upper_; #local NSteps = NSteps_; #local Step = (Range_Upper - Range_Lower) / (NSteps - 1); #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 -1; #else abs (MinimumDistance); #end //#if #end //#macro MeasureCharacterToCharacter #macro IntersectionPoint (Point0_, Angle0_, Point1_, Angle1_) #local P0 = Point0_; //Local copies must be used because parameters #local A0 = Angle0_; //are passed by reference. #local P1 = Point1_; #local A1 = Angle1_; #local A0 = mod (A0, 360); #local A1 = mod (A1, 360); #if (P0.x = P1.x & P0.y = P1.y) #if (A0 = A1) #error "No unique intersection point exists." #else #declare IntersectionPoint = P0; #break #end //#if #end //#if #if (A1 - A0 = 0 | A1 - A0 = 180) #error "No unique intersection point exists." #end #if (P1.x < P0.x) #local TPoint = P1; #local TAngle = A1; #local P1 = P0; #local A1 = A0; #local P0 = TPoint; #local A0 = TAngle; #end //#if #local XOffset = P0.x; #local YOffset = P0.y; #local P0 = <0, 0, 0>; #local P1 = P1 - ; #if (P1.x = 0) #if (P1.y > 0) #local Theta = 90; #else #local Theta = 270; #end //#if #else #local Theta = degrees (atan (P1.y / P1.x)); #end //#if #local R2 = sqrt (P1.x * P1.x + P1.y * P1.y); #local A0 = A0 - Theta; #local A1 = A1 - Theta; #local P1 = ; #local A1 = 180 - A1; #local A3 = 180 - A0 - A1; #local R1 = R2 * sin (radians (A1)) / sin (radians (A3)); #local A0 = A0 + Theta; ; #end //#macro IntersectionPoint #macro RightAngleCornerFiller (Quadrant_, P0_) #local Quadrant = Quadrant_; #local P0 = P0_; 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 rotate (Quadrant * 90) * z translate P0 } //object #end //#macro RightAngleCornerFiller #macro ArbitraryAngleCornerFiller (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 ArbitraryAngleCornerFiller #macro ArbitraryRoundCorner (CornerRadius_, R_, A0_, Spin_, MirrorHorizontally_) #local CornerRadius = CornerRadius_; #local R = R_; #local A0 = A0_; #local Spin = Spin_; #local MirrorHorizontally = MirrorHorizontally_; object { intersection { torus {CornerRadius, R sturm rotate 90 * x} plane {x, 0} plane {y, 0 rotate A0 * z} } //intersection rotate Spin * z #if (MirrorHorizontally) rotate 180 * y #end //#if } //object #end //#macro ArbitraryRoundCorner #macro ArbitraryHorizontalBar (X0_, X1_, Y0_, R_) #local X0 = X0_; #local X1 = X1_; #local Y0 = Y0_; #local R = R_; union { sphere {, R} sphere {, R} cylinder { , R} } //union #end //#macro ArbitraryHorizontalBar #macro CreateMOP_Characters (MOP_FontRadius) #local R = MOP_FontRadius; #local CornerRadius = R * 1.25; #local QUADRANT1 = 0; #local QUADRANT2 = 1; #local QUADRANT3 = 2; #local QUADRANT4 = 3; #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 = R / 3; //Width of top flat part #local A2 = .24; //Vertical #local A_A0 = 59; union { #local ACornerRadius = R * 1.75; #local ACorner = ArbitraryRoundCorner (ACornerRadius, R, 90 - A_A0, 180, yes) #local A_P0 = ; #local A_L0 = (1 - ACornerRadius + A_P0.y) / sin (radians (A_A0)); #local A_P1 = ; #local A_P2 = A_P1 + ; #local A_P3 = A_P2 + ; #local A_P4 = ; #local A_P5 = ; #local A_L1 = A2 / sin (radians (A_A0)); #local A_P6 = ; #local A_P7 = ; object {ACorner translate A_P1 - A_P0} object {ACorner rotate 180 * y translate A_P1 - A_P0 + } sphere {<0, 0, 0>, R} sphere {A_P1, R} sphere {A_P2, R} sphere {A_P3, R} sphere {A_P4, R} sphere {A_P5, R} cylinder {<0, 0, 0> A_P1, R} cylinder {A_P2 A_P3, R} cylinder {A_P4 A_P5, R} cylinder {A_P6 A_P7, R} #local TCornerRadius = CornerRadius * 2; ArbitraryAngleCornerFiller (A_P6, A_A0, 0, R, CornerRadius) ArbitraryAngleCornerFiller (A_P6, A_A0 + 180, 0, R, TCornerRadius) ArbitraryAngleCornerFiller (A_P7, 180 - A_A0, 180, R, CornerRadius) ArbitraryAngleCornerFiller (A_P7, -A_A0, 180, R, TCornerRadius) } //union #declare MOP_CharacterWidth [A_] = A_P5.x; } //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} intersection { sphere_sweep { //Top b_spline 12 <-3, 1, 0>, R <0, 1, 0>, R , R , R , R , R , R , R , R , R <0, B4, 0>, R <-3, B4, 0>, R } //sphere_sweep plane {x, 0 inverse} } //intersection intersection { sphere_sweep { //Bottom b_spline 12 <-3, B4, 0>, R <0, B4, 0>, R , R , R , R , R , R , R , R , R <0, 0, 0>, R <-3, 0, 0>, R } //sphere_sweep plane {x, 0 inverse} } //intersection RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) RightAngleCornerFiller (QUADRANT1, <0, B4, 0>) RightAngleCornerFiller (QUADRANT4, <0, B4, 0>) RightAngleCornerFiller (QUADRANT1, <0, 0, 0>) } //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} intersection { sphere_sweep { b_spline 12 <-3, 1, 0>, R <0, 1, 0>, R , R , R , R , R , R , R , R , R <0, 0, 0>, R <-3, 0, 0>, R } //sphere_sweep plane {x, 0 inverse} } //intersection RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) RightAngleCornerFiller (QUADRANT1, <0, 0, 0>) } //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} sphere {, R} cylinder {<0, 0, 0> , R} sphere {, R} cylinder {<0, E3, 0> , R} sphere {, R} cylinder {<0, 1, 0> , R} RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) RightAngleCornerFiller (QUADRANT1, <0, E3, 0>) RightAngleCornerFiller (QUADRANT4, <0, E3, 0>) RightAngleCornerFiller (QUADRANT1, <0, 0, 0>) } //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} sphere {, R} cylinder {<0, F3, 0> , R} sphere {, R} cylinder {<0, 1, 0> , R} RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) RightAngleCornerFiller (QUADRANT1, <0, F3, 0>) RightAngleCornerFiller (QUADRANT4, <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 ArbitraryHorizontalBar (G5, G2, G4, R) RightAngleCornerFiller (QUADRANT3, ) } //union #declare MOP_CharacterWidth [G_] = G2; } //object #declare MOP_Character [H_] = object { #local H1 = 1.13; //Width #local H2 = .52; //Vertical union { object {VerticalBar} object {VerticalBar translate H1 * x} cylinder {<0, H2, 0> , R} RightAngleCornerFiller (QUADRANT1, <0, H2, 0>) RightAngleCornerFiller (QUADRANT4, <0, H2, 0>) RightAngleCornerFiller (QUADRANT2, ) RightAngleCornerFiller (QUADRANT3, ) } //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 union { intersection { 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 plane {y, 1} } //intersection sphere {, R} } //union #declare MOP_CharacterWidth [J_] = J2; } //object #declare MOP_Character [K_] = object { #local K1 = .29; //Width of horizontal bar #local K2 = .52; //Vertical #switch (R) //Adjust length of rounded corner #range (0, .0845) #local K4 = 6.5; #break #range (.0845, .1) #local K4 = 6.5 - (R - .0845) / (.1 - .0845) * 1.8; #break #range (.1, 999) #local K4 = 3; #break #end //#switch #local K_A0 = 30; union { object {VerticalBar} sphere {, R} cylinder {<0, K2, 0> , 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 * K4; ArbitraryAngleCornerFiller (, 180, K_A0, R, TCornerRadius) ArbitraryAngleCornerFiller (, 180, -K_A0, R, TCornerRadius) ArbitraryAngleCornerFiller (, K_A0, -K_A0, R, CornerRadius) RightAngleCornerFiller (QUADRANT4, <0, K2, 0>) RightAngleCornerFiller (QUADRANT1, <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} sphere {, R} cylinder {<0, 0, 0> , R} RightAngleCornerFiller (QUADRANT1, <0, 0, 0>) } //union #declare MOP_CharacterWidth [L_] = L1; } //object #declare MOP_Character [M_] = object { #local M1 = .04 + R; #local M_A0 = 34; union { #local MCornerRadius = R * 1.75; #local MCorner = ArbitraryRoundCorner (MCornerRadius, R, M_A0, 180, no) #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} ArbitraryAngleCornerFiller (, 90 + M_A0, 90 - M_A0, R, CornerRadius) RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) RightAngleCornerFiller (QUADRANT3, ) } //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 NCornerRadius = R * 1.75; #local NCorner = ArbitraryRoundCorner (NCornerRadius, R, N_A0, 180, no) #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} RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) RightAngleCornerFiller (QUADRANT2, ) } //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} intersection { sphere_sweep { b_spline 12 <-3, 1, 0>, R <0, 1, 0>, R , R , R , R , R , R , R , R , R <0, P4, 0>, R <-3, P4, 0>, R } //sphere_sweep plane {x, 0 inverse} } //intersection RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) RightAngleCornerFiller (QUADRANT1, <0, P4, 0>) RightAngleCornerFiller (QUADRANT4, <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 = ArbitraryRoundCorner (QCornerRadius, R, 45, 0, yes) #local QCorner_Right = ArbitraryRoundCorner (QCornerRadius, R, 45, 90, no) 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} ArbitraryAngleCornerFiller (Q_P1, 45, 180 - Q_A0, R, CornerRadius) ArbitraryAngleCornerFiller (Q_P1, 45, -Q_A0, R, CornerRadius) ArbitraryAngleCornerFiller (Q_P1, -135, 180 - Q_A0, R, CornerRadius) ArbitraryAngleCornerFiller (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} intersection { sphere_sweep { //Top b_spline 12 <-3, 1, 0>, R <0, 1, 0>, R , R , R , R , R , R , R , R , R <0, R4, 0>, R <-3, R4, 0>, R } //sphere_sweep plane {x, 0 inverse} } //intersection union { intersection { sphere_sweep { //Bottom b_spline 8 <-3, R4, 0>, R <0, R4, 0>, R , R , R , R , R , R , R } //sphere_sweep plane {x, 0 inverse} plane {y, 0 inverse} } //intersection sphere {, R} } //union RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) RightAngleCornerFiller (QUADRANT1, <0, R4, 0>) RightAngleCornerFiller (QUADRANT4, <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 { sphere {, R} cylinder { , R} ArbitraryHorizontalBar (0, T1, 1, R) RightAngleCornerFiller (QUADRANT3, ) RightAngleCornerFiller (QUADRANT4, ) } //union #declare MOP_CharacterWidth [T_] = T1; } //object #declare MOP_Character [U_] = object { #local U1 = .15; #local U2 = 1.18; //Width #local U3 = .2; union { intersection { 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, 2, 0>, R } //sphere_sweep plane {y, 1} } //intersection sphere {<0, 1, 0>, R} sphere {, R} } //union #declare MOP_CharacterWidth [U_] = U2; } //object #declare MOP_Character [V_] = object { #local V1 = R / 3; //Width of top flat part #local V_A0 = 61; union { #local VCornerRadius = R * 1.75; #local VCorner = ArbitraryRoundCorner (VCornerRadius, R, 90 - V_A0, 180, yes) #local V_P0 = ; #local A_L0 = (1 - VCornerRadius + V_P0.y) / sin (radians (V_A0)); #local V_P1 = ; #local V_P2 = V_P1 + ; #local V_P3 = V_P2 + ; #local V_P4 = ; #local V_P5 = ; object {VCorner translate V_P1 - V_P0} object {VCorner rotate 180 * y translate V_P1 - V_P0 + } sphere {<0, 0, 0>, R} sphere {V_P1, R} sphere {V_P2, R} sphere {V_P3, R} sphere {V_P4, R} sphere {V_P5, R} cylinder {<0, 0, 0> V_P1, R} cylinder {V_P2 V_P3, R} cylinder {V_P4 V_P5, R} } //union rotate 180 * x translate 1 * y #declare MOP_CharacterWidth [V_] = V_P5.x; } //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 WCornerRadius = R * 1.75; #local WCorner = ArbitraryRoundCorner (WCornerRadius, R, W_A0, 180, no) #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 cylinder {<-W3, 0, 0> <0, 1, 0>, R} ArbitraryHorizontalBar (0, W1, 1, R) //Connector sphere {, R} //Right side cylinder { , R} ArbitraryHorizontalBar (W_P0.x + W2 + W2 + W_P0.x - W1, W_P0.x + W2 + W2 + W_P0.x, 1, R) 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 ArbitraryAngleCornerFiller (, 90 + W_A0, 90 - W_A0, R, CornerRadius) ArbitraryAngleCornerFiller (<0, 1, 0>, 90 - W_A1 + 180, 0, R, CornerRadius) ArbitraryAngleCornerFiller (, -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 = .56; //Vertical #local X2 = .05; //Top vertical offset #local X3 = .1 / R + .05; //CornerRadius multiplier #local X_A0 = 44; #local X_L0_Bottom = X1 / sin (radians (X_A0)); #local X_L0_Top = (1 - (X1 - X2)) / sin (radians (X_A0)); #local X_P0 = ; #local X_P4 = X_P0 - <0, X2, 0>; #local X_P1 = ; #local X_P2 = ; #local X_P3 = ; #local X_P5 = IntersectionPoint (<0, 0, 0>, X_A0, X_P2, -X_A0) #local X_P6 = IntersectionPoint (X_P1, 180 - X_A0, X_P3, X_A0) union { sphere {<0, 0, 0>, R} //Bottom left intersection { cylinder {<0, 0, 0> X_P0, R} plane {y, 0 rotate -X_A0 * z translate X_P4} } //intersection sphere {X_P1, R} //Bottom right intersection { cylinder {X_P1 X_P0, R} plane {y, 0 rotate X_A0 * z translate X_P4} } //intersection sphere {X_P2, R} //Top left intersection { cylinder {X_P2 X_P4, R} plane {y, 0 inverse rotate X_A0 * z translate X_P0} } //intersection sphere {X_P3, R} //Top right intersection { cylinder {X_P3 X_P4, R} plane {y, 0 inverse rotate -X_A0 * z translate X_P0} } //intersection #local TCornerRadius = CornerRadius * X3; ArbitraryAngleCornerFiller (X_P0, 180 + X_A0, -X_A0, R, TCornerRadius) //Bottom ArbitraryAngleCornerFiller (X_P4, 180 - X_A0, X_A0, R, TCornerRadius) //Top ArbitraryAngleCornerFiller (X_P5, 180 - X_A0, 180 + X_A0, R, TCornerRadius) //Left ArbitraryAngleCornerFiller (X_P6, X_A0, -X_A0, R, TCornerRadius) //Right } //union #declare MOP_CharacterWidth [X_] = X_P1.x; } //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; ArbitraryAngleCornerFiller (<0, Y1, 0>, 90 + Y_A0, 270, R, TCornerRadius) ArbitraryAngleCornerFiller (<0, Y1, 0>, 90 - Y_A0, 270, R, TCornerRadius) ArbitraryAngleCornerFiller (<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 = .04 + R; #local Z2 = 1.15; //Width #local Z3 = .03; //Shorten top left #local Z4 = .02; //Shorten top right #local ZCornerRadius = R * 1.75; #local Z_P2 = ; #local Z_P3 = ; #local Z_P4 = (Z_P2 + Z_P3) / 2; #local Z5 = Z_P4.x - Z_P2.x; #local Z6 = Z_P4.y - Z_P2.y; #local Z_L0 = sqrt (Z5 * Z5 + Z6 * Z6); #local Z_A1 = degrees (asin (ZCornerRadius / Z_L0)); #local Z_A2 = degrees (atan ((Z_P3.y - Z_P2.y) / (Z_P3.x - Z_P2.x))); #local Z_A0 = Z_A2 - Z_A1; #local Z_P0 = ; #local Z_P1 = ; union { #local ZCorner = ArbitraryRoundCorner (ZCornerRadius, R, 180 - Z_A0, 270, yes) ArbitraryHorizontalBar (0, Z2 + Z4, 0, R) //Bottom bar ArbitraryHorizontalBar (Z3, Z2, 1, R) //Top bar #local CornerAssembly = object { union { object {ZCorner translate Z1 * y} sphere {<-ZCornerRadius, Z1, 0>, R} cylinder {<-ZCornerRadius, 0, 0> <-ZCornerRadius, Z1, 0>, R} } //union translate ZCornerRadius * x } //object object {CornerAssembly} //Bottom object {CornerAssembly rotate 180 * z translate } //Top sphere {Z_P0, R} sphere {Z_P1, R} cylinder {Z_P0 Z_P1, R} RightAngleCornerFiller (QUADRANT1, <0, 0, 0>) RightAngleCornerFiller (QUADRANT3, ) } //union #declare MOP_CharacterWidth [Z_] = Z2 + Z4; } //object #declare MOP_Character [DIGIT0_] = object { #local V1 = .13; #local V2 = 1.16; //Width #local V3 = .18; #union { sphere_sweep { b_spline 19 , R , R <0, V1, 0>, R <0, V1 + V3, 0>, R <0, 1 - V1 - V3, 0>, R <0, 1 - V1, 0>, R , R , R , R , R , R , R , R , R , R , R , R , R <0, V1, 0>, R } //sphere_sweep #local Dot = object { #local PERIOD1 = R * 2; //Width #local PERIOD2 = PERIOD1 * .8; //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 translate } //object object {Dot} } //union #declare MOP_CharacterWidth [DIGIT0_] = V2; } //object #declare MOP_Character [DIGIT1_] = object { #local V1 = .04 + R; #local A0 = 51.5; #local L0 = .45; union { #local DigitCornerRadius = R * 1.75; #local DigitCorner = ArbitraryRoundCorner (DigitCornerRadius, R, A0, 180, no) #local P0 = <-V1 - DigitCornerRadius * cos (radians (A0)), 1 - DigitCornerRadius + DigitCornerRadius * sin (radians (A0)), 0>; #local P1 = P0 + ; object {VerticalBar} sphere {<-V1, 1, 0>, R} cylinder {<0, 1, 0> <-V1, 1, 0>, R} object {DigitCorner rotate 180 * y translate <-V1, 1 - DigitCornerRadius, 0>} sphere {P0, R} sphere {P1, R} cylinder {<0, 0, 0> , R rotate (270 - A0) * z translate P0} RightAngleCornerFiller (QUADRANT3, <0, 1, 0>) } //union translate abs (P1.x) * x #declare MOP_CharacterWidth [DIGIT1_] = abs (P1.x); } //object #declare MOP_Character [DIGIT2_] = object { #local V1 = .1; #local V2 = .01; //Offset top #local V3 = .12; #local V4 = .5; //Controls length of top vertical #local V5 = 1.14; //Width #local L0 = .36; #local L1 = 1.12; //Determines width of top portion #local A0 = 5; #local P0 = <0, L0, 0>; #local P1 = P0 + ; union { intersection { sphere_sweep { b_spline 20 <0, -1, 0>, R <0, 0, 0>, R , R , R P0 + , R P0 + <(V1 + V3) * cos (radians (A0)), (V1 + V3) * sin (radians (A0)), 0>, R P1 - <(V1 + V3) * cos (radians (A0)), (V1 + V3) * sin (radians (A0)), 0>, R P1 - , R P1 + <0, V1, 0>, R P1 + <0, V1 + V3, 0>, R , R , R , R , R , R , R , R , R , R , R } //sphere_sweep plane {y, 0 inverse} } //intersection ArbitraryHorizontalBar (0, V5, 0, R) RightAngleCornerFiller (QUADRANT1, <0, 0, 0>) } //union #declare MOP_CharacterWidth [DIGIT2_] = V5; } //object #declare MOP_Character [DIGIT3_] = object { #local V1 = .1; #local V2 = 1.12; //Top width #local V3 = .2; #local V4 = .51; //Vertical #local V5 = V2 + .02; //Bottom width #local V6 = .01; //Top offset #local V7 = -.2; //Controls length of middle bar #local V8 = .23; //Length of verticals union { union { difference { sphere_sweep { //Top b_spline 15 , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R } //sphere_sweep box {<-R - .1, 0, -R - .1> } } //difference intersection { sphere {, R} plane {y, 1 - V8} } //intersection } //union union { difference { sphere_sweep { //Bottom b_spline 15 <0, V1 + V3 + .01, 0>, R <0, V1 + V3, 0>, R <0, V1, 0>, R , R , R , R , R , R , R , R , R , R , R , R , R } //sphere_sweep box {<-R - .1, V8, -R - .1> } } //difference intersection { sphere {<.00044, V8, 0>, R} plane {y, V8 inverse} } //intersection } //union } //union #declare MOP_CharacterWidth [DIGIT3_] = V5; } //object #declare MOP_Character [DIGIT4_] = object { #local V1 = .04 + R; #local V2 = 1.05; //Width of lower bar #local A0 = 52; #local L0 = .94; union { #local DigitCornerRadius = R * 1.75; #local DigitCorner0 = ArbitraryRoundCorner (DigitCornerRadius, R, A0, 180, yes) #local DigitCorner1 = ArbitraryRoundCorner (DigitCornerRadius, R, 90 - A0, 270, no) #local P0 = <-V1 - DigitCornerRadius * cos (radians (A0)), 1 - DigitCornerRadius + DigitCornerRadius * sin (radians (A0)), 0>; #local P1 = P0 + ; #local P2 = ; #local P3 = + P1 - P2; object {VerticalBar} sphere {<-V1, 1, 0>, R} cylinder {<-V1, 1, 0> <0, 1, 0>, R} object {DigitCorner0 translate <-V1, 1 - DigitCornerRadius, 0>} #local BottomAssembly = object { union { object {DigitCorner1} sphere {<-DigitCornerRadius, 0, 0>, R} cylinder {<-DigitCornerRadius, -V1, 0> <-DigitCornerRadius, 0, 0>, R} ArbitraryHorizontalBar (-DigitCornerRadius, V2, -V1, R) RightAngleCornerFiller (QUADRANT1, <-DigitCornerRadius, -V1, 0>) } //union } //object object {BottomAssembly translate P1 - P2} sphere {P0, R} sphere {P3, R} cylinder {P3 P0, R} RightAngleCornerFiller (QUADRANT3, <0, 1, 0>) RightAngleCornerFiller (QUADRANT1, <0, P1.y - P2.y - V1, 0>) RightAngleCornerFiller (QUADRANT2, <0, P1.y - P2.y - V1, 0>) RightAngleCornerFiller (QUADRANT3, <0, P1.y - P2.y - V1, 0>) RightAngleCornerFiller (QUADRANT4, <0, P1.y - P2.y - V1, 0>) } //union translate -(P1.x - P2.x - DigitCornerRadius) * x #declare MOP_CharacterWidth [DIGIT4_] = V2 + DigitCornerRadius; } //object #declare MOP_Character [DIGIT5_] = object { #local V1 = .12; #local V2 = .22; //Corner radius #local V3 = .2; #local V4 = .64; //Vertical #local V5 = 1.14; //Width #local V6 = .02; //Top left offset #local V7 = V5 - .05; //Top right offset #local V8 = .23; //Length of bottom vertical #local V9 = .11; //Y component of corner #local V10 = V4 - V9; //Vertical offset #local A0 = degrees (asin ((V2 - V9) / V2)); #local V11 = sqrt (V2 * V2 - (V2 - V9) * (V2 - V9)); union { ArbitraryHorizontalBar (V6, V7, 1, R) sphere {, R} cylinder { , R} #local DigitCorner = object { #local DigitCornerRadius = V2; intersection { torus {DigitCornerRadius, R sturm rotate 90 * x} plane {x, 0} plane {y, 0 inverse rotate -A0 * z} } //intersection } //object object {DigitCorner translate } sphere {, R} union { difference { sphere_sweep { b_spline 15 <0, V1 + V3 + .01, 0>, R <0, V1 + V3, 0>, R <0, V1, 0>, R , R , R , R , R , R , R , R , R , R , R <0, V4, 0>, R <-1, V4, 0>, R } //sphere_sweep box {<-R - .1, V8, -R - .1> } } //difference intersection { sphere {<.00155, V8, 0>, R} plane {y, V8 inverse} } //intersection } //union RightAngleCornerFiller (QUADRANT4, ) } //union #declare MOP_CharacterWidth [DIGIT5_] = V5; } //object #declare MOP_Character [DIGIT7_] = object { #local V1 = .04 + R; #local V2 = 1.16; //Width #local A0 = 25.5; union { ArbitraryHorizontalBar (0, V2, 1, R) sphere {, R} cylinder { , R} #local DigitCornerRadius = R * 1.75; #local DigitCorner = ArbitraryRoundCorner (DigitCornerRadius, R, 90 - A0, 90, no) #local P0 = ; #local P1 = ; object {DigitCorner translate } sphere {P0, R} sphere {P1, R} cylinder {P0, P1, R} RightAngleCornerFiller (QUADRANT3, ) } //union #declare MOP_CharacterWidth [DIGIT7_] = V2; } //object #declare MOP_Character [DIGIT8_] = object { #local V1 = .1; #local V2 = 1.12; //Width #local V3 = .2; #local V4 = .52; //Vertical #local V5 = .045; //Top offset sphere_sweep { b_spline 35 , R , R <0, V1, 0>, R <0, V1 + V3, 0>, R <0, V4 - V1 - V3, 0>, R <0, V4 - V1, 0>, R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R <0, V1, 0>, R } //sphere_sweep #declare MOP_CharacterWidth [DIGIT8_] = V2; } //object #declare MOP_Character [DIGIT9_] = object { #local V1 = .12; #local V2 = 1.1; //Width #local V3 = .2; #local V4 = .45; //Vertical #local V5 = .01; //Bottom offset #local V8 = .23; //Length of verticals union { difference { sphere_sweep { b_spline 26 , R , R , R , R , R , R , R , R , R , R , R , R , R , R , R <0, 1 - V1, 0>, R <0, 1 - V1 - V3, 0>, R <0, V4 + V1 + V3, 0>, R <0, V4 + V1, 0>, R , R , R , R , R , R , R , R } //sphere_sweep box { } } //difference intersection { sphere {, R} plane {y, V8 inverse} } //intersection } //union #declare MOP_CharacterWidth [DIGIT9_] = V2; } //object #declare MOP_Character [DIGIT6_] = object { object {MOP_Character [DIGIT9_] translate -MOP_CharacterWidth [DIGIT9_] * x rotate 180 * z translate 1 * y} #declare MOP_CharacterWidth [DIGIT6_] = MOP_CharacterWidth [DIGIT9_]; } //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_Character [COMMA_] = object { #local PERIOD1 = R * 1; //Width #local PERIOD2 = PERIOD1 * .4; //Height #local PERIODRadius = R * .075; #local V1 = R * 1.1; #local A0 = 30; #local CommaTail = object { #local CommaTailRadius = R; union { intersection { torus {CommaTailRadius, R sturm rotate 90 * x} plane {x, 0 rotate A0 * z inverse} plane {y, 0} } //intersection sphere {, R} } //union } //object #local CommaTail = object { union { sphere {, R} cylinder { , R} object {CommaTail translate -V1 * y} } //union } //object union { object {MOP_Character [PERIOD_]} object {CommaTail translate PERIODRadius * x} } //union #declare MOP_CharacterWidth [COMMA_] = MOP_CharacterWidth [PERIOD_]; } //object #declare MOP_Character [COLON_] = object { #local V1 = .6; union { object {MOP_Character [PERIOD_]} object {MOP_Character [PERIOD_] translate V1 * y} } //union #declare MOP_CharacterWidth [COLON_] = MOP_CharacterWidth [PERIOD_]; } //object #declare MOP_Character [SEMICOLON_] = object { #local V1 = .6; union { object {MOP_Character [COMMA_]} object {MOP_Character [PERIOD_] translate V1 * y} } //union #declare MOP_CharacterWidth [SEMICOLON_] = MOP_CharacterWidth [PERIOD_]; } //object #declare MOP_Character [APOSTROPHE_] = object { #local PERIOD1 = R * 1; //Width #local PERIOD2 = PERIOD1 * .4; //Height #local PERIODRadius = R * .075; MOP_Character [COMMA_] translate (1 - PERIOD2 - PERIODRadius) * y #declare MOP_CharacterWidth [APOSTROPHE_] = MOP_CharacterWidth [COMMA_]; } //object #declare MOP_Character [QUOTELeft_] = object { #local PERIOD1 = R * 1; //Width #local PERIOD2 = PERIOD1 * .4; //Height #local PERIODRadius = R * .075; #local V1 = .035; #local V2 = R * sin (radians (270 + 30)) - R * 1.1; //Y offset union { object {MOP_Character [COMMA_] translate (-PERIOD2 - PERIODRadius) * y rotate 180 * z translate } object {MOP_Character [COMMA_] translate (-PERIOD2 - PERIODRadius) * y rotate 180 * z translate } } //union translate (1 - PERIOD2 - PERIODRadius) * y #declare MOP_CharacterWidth [QUOTELeft_] = MOP_CharacterWidth [COMMA_] + R * 3 + V1; } //object #declare MOP_Character [QUOTERight_] = object { #local V1 = .035; union { object {MOP_Character [APOSTROPHE_]} object {MOP_Character [APOSTROPHE_] translate (MOP_CharacterWidth [COMMA_] + R * 2 + V1) * x} } //union #declare MOP_CharacterWidth [QUOTERight_] = MOP_CharacterWidth [COMMA_] + R * 3 + V1; } //object #declare MOP_Character [EXCLAMATION_] = object { #local V1 = .292; #local V2 = MOP_CharacterWidth [PERIOD_] / 2; union { object {MOP_Character [PERIOD_]} sphere {, R} sphere {, R} cylinder { , R} } //union #declare MOP_CharacterWidth [EXCLAMATION_] = MOP_CharacterWidth [PERIOD_]; } //object #declare MOP_Character [QUESTION_] = object { #local V1 = .06; #local V2 = .03; #local V1B = .1; #local V1C = .04; #local V3 = .12; #local V3B = .2; #local V3C = .08; #local V4 = -.4; #local V5 = .25; #local A0 = 12; #local L0 = .53; #local P0 = <0, .44, 0>; #local P1 = P0 + ; union { sphere_sweep { b_spline 20 <0, P0.y - V1C - V3C - V2 - .01, 0>, R <0, P0.y - V1C - V3C - V2, 0>, R <0, P0.y - V1C - V3C, 0>, R <0, P0.y - V1C, 0>, R P0 + , R P0 + <(V1 + V3) * cos (radians (A0)), (V1 + V3) * sin (radians (A0)), 0>, R P1 - <(V1 + V3) * cos (radians (A0)), (V1 + V3) * sin (radians (A0)), 0>, R P1 - , R , R , R , R , R , R , R , R , R , R , R , R , R } //sphere_sweep object {MOP_Character [PERIOD_] translate (-MOP_CharacterWidth [PERIOD_] / 2) * x} } //union translate -V4 * x #declare MOP_CharacterWidth [QUESTION_] = P1.x - V4; } //object #declare MOP_Character [SLASH_] = object { #local V1 = .51; //Width union { sphere {<0, 0, 0>, R} sphere {, R} cylinder {<0, 0, 0> , R} } //union #declare MOP_CharacterWidth [SLASH_] = V1; } //object #declare MOP_Character [DASH_] = object { #local DASH1 = .6; //Width #local DASH2 = .435; //Vertical, match the "G" ArbitraryHorizontalBar (0, DASH1, DASH2, R) #declare MOP_CharacterWidth [DASH_] = DASH1; } //object #declare MOP_Character [PLUS_] = object { #local V1 = .67; //Width #local V2 = .435; //Vertical, match the "G" union { #local Bar = object {ArbitraryHorizontalBar (0, V1, 0, R)} object {Bar translate V2 * y} object {Bar translate (-V1 / 2) * x rotate 90 * z translate } RightAngleCornerFiller (QUADRANT1, ) RightAngleCornerFiller (QUADRANT2, ) RightAngleCornerFiller (QUADRANT3, ) RightAngleCornerFiller (QUADRANT4, ) } //union #declare MOP_CharacterWidth [PLUS_] = V1; } //object #declare MOP_Character [EQUALS_] = object { #local V1 = .67; //Width #local V2 = .435; //Vertical, match the "G" #local V3 = .16; //Spacing union { #local Bar = object {ArbitraryHorizontalBar (0, V1, 0, R)} object {Bar translate (V2 - V3) * y} object {Bar translate (V2 + V3) * y} } //union #declare MOP_CharacterWidth [EQUALS_] = V1; } //object #declare MOP_Character [DOLLAR_] = object { #local S1 = .08; #local S2 = .96; //Top width #local S3 = .13; #local S4 = .43; //Vertical #local S5 = .15; #local S6 = .22; //Length of ends #local S7 = .025; //Additional bottom width #local S8 = .07; //Top and bottom spacing #local S9 = .49; //Center bar x union { difference { sphere_sweep { b_spline 28 <0, 1 - S8, 0>, R <0, S8 + S5, 0>, R <0, S8 + S1 + S3, 0>, R <0, S8 + S1, 0>, R , R , R , R , R , R , R , R , R , R , R , R , R <0, S8 + S4 + S1, 0>, R <0, S8 + S4 + S1 + S3, 0>, R <0, 1 - S8 - S1 - S3, 0>, R <0, 1 - S8 - 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 <.001, S6, 0> } //intersection intersection { //Right / Top sphere {<0, 0, 0>, R} plane {y, 0} translate } //intersection sphere {, R} sphere {, R} cylinder { , R} #local CornerAssembly = object { union { RightAngleCornerFiller (QUADRANT1, <0, 0, 0>) RightAngleCornerFiller (QUADRANT2, <0, 0, 0>) RightAngleCornerFiller (QUADRANT3, <0, 0, 0>) RightAngleCornerFiller (QUADRANT4, <0, 0, 0>) } //union } //object object {CornerAssembly translate } object {CornerAssembly translate } object {CornerAssembly translate } } //union #declare MOP_CharacterWidth [DOLLAR_] = S2 + S7; } //object #declare MOP_Character [PARENTHESISLeft_] = object { #local V1 = .1; #local V2 = .3; //Width #local V3 = .24; sphere_sweep { b_spline 10 , R , R , R <0, V1, 0>, R <0, V1 + V3, 0>, R <0, 1 - V1 - V3, 0>, R <0, 1 - V1, 0>, R , R , R , R } //sphere_sweep #declare MOP_CharacterWidth [PARENTHESISLeft_] = V2 - .007; } //object #declare MOP_Character [PARENTHESISRight_] = object { MOP_Character [PARENTHESISLeft_] translate -MOP_CharacterWidth [PARENTHESISLeft_] * x rotate 180 * y #declare MOP_CharacterWidth [PARENTHESISRight_] = MOP_CharacterWidth [PARENTHESISLeft_]; } //object #declare MOP_Character [SQUAREBRACKETLeft_] = object { #local V1 = .28; union { ArbitraryHorizontalBar (0, V1, 0, R) ArbitraryHorizontalBar (0, V1, 1, R) cylinder {<0, 0, 0> <0, 1, 0>, R} RightAngleCornerFiller (QUADRANT1, <0, 0, 0>) RightAngleCornerFiller (QUADRANT4, <0, 1, 0>) } //union #declare MOP_CharacterWidth [SQUAREBRACKETLeft_] = V1; } //object #declare MOP_Character [SQUAREBRACKETRight_] = object { MOP_Character [SQUAREBRACKETLeft_] translate -MOP_CharacterWidth [SQUAREBRACKETLeft_] * x rotate 180 * y #declare MOP_CharacterWidth [SQUAREBRACKETRight_] = MOP_CharacterWidth [SQUAREBRACKETLeft_]; } //object #declare MOP_Character [ANGLEBRACKETLeft_] = object { #local V1 = .435; //Vertical, match the "G" #local L0 = .74; #local A0 = 24; #local P0 = ; union { sphere {<0, P0.y, 0>, R} sphere {, R} sphere {, R} cylinder {<0, P0.y, 0> , R} cylinder {<0, P0.y, 0> , R} ArbitraryAngleCornerFiller (<0, P0.y, 0>, A0, 360 - A0, R, CornerRadius) } //union translate (V1 - P0.y) * y #declare MOP_CharacterWidth [ANGLEBRACKETLeft_] = P0.x; } //object #declare MOP_Character [ANGLEBRACKETRight_] = object { MOP_Character [ANGLEBRACKETLeft_] translate -MOP_CharacterWidth [ANGLEBRACKETLeft_] * x rotate 180 * y #declare MOP_CharacterWidth [ANGLEBRACKETRight_] = MOP_CharacterWidth [ANGLEBRACKETLeft_]; } //object #declare MOP_Character [PERCENT_] = object { #local V1 = .07; #local V2 = .7; //Width of circle #local V3 = .15; #local V4 = .61; //Height of circle #local V5 = .34; //Width of slash #local V6 = .74; union { #local Circle = object { sphere_sweep { b_spline 19 , R , R <0, V1, 0>, R <0, V1 + V3, 0>, R <0, V4 - V1 - V3, 0>, R <0, V4 - V1, 0>, R , R , R , R , R , R , R , R , R , R , R , R , R <0, V1, 0>, R } //sphere_sweep } //object #local Slash = object { union { sphere {<0, 0, 0>, R} sphere {, R} cylinder {<0, 0, 0> , R} } //union } //object object {Circle translate (1 - V4) * y} object {Circle translate (V6 + V5 + V6 - V2) * x} object {Slash translate V6 * x} } //union #declare MOP_CharacterWidth [PERCENT_] = V6 + V5 + V6; } //object #declare MOP_Character [NUMBER_] = object { #local A0 = 82.5; #local L0 = 1 / sin (radians (A0)); #local V1 = .165; //Polar distance from vertical center for crossbars #local V2 = .5; //Distance apart for diagonal bars #local V3 = .09 + R; //Distance horizontal bars extend past diagonal bars #local P0 = ; #local P1 = P0 - ; #local P2 = P0 + ; #local P3 = P1 + ; #local P4 = P2 + ; union { #local DiagonalBar = object { union { sphere {<0, 0, 0>, R} sphere {, R} cylinder {<0, 0, 0> , R} } //union rotate A0 * z } //object #local HorizontalBar = object {ArbitraryHorizontalBar (0, V3 + V2 + V3, 0, R)} object {DiagonalBar} object {DiagonalBar translate V2 * x} object {HorizontalBar translate P1 - } object {HorizontalBar translate P2 - } #local CornerAssembly = object { union { ArbitraryAngleCornerFiller (<0, 0, 0>, 0, A0, R, CornerRadius) ArbitraryAngleCornerFiller (<0, 0, 0>, 0, A0 + 180, R, CornerRadius) ArbitraryAngleCornerFiller (<0, 0, 0>, 180, A0, R, CornerRadius) ArbitraryAngleCornerFiller (<0, 0, 0>, 180, A0 + 180, R, CornerRadius) } //union } //object object {CornerAssembly translate P1} object {CornerAssembly translate P2} object {CornerAssembly translate P3} object {CornerAssembly translate P4} } //union translate (-P1.x + V3) * x #declare MOP_CharacterWidth [NUMBER_] = -P1.x + V3 + P4.x + V3; } //object #declare MOP_Character [ASTERISK_] = object { #local L0 = R + .22; #local V1 = L0 * sin (radians (60)); #local CenterRadius = sin (radians (60)) * R / sin (radians (30)) - R * 1.25; difference { union { #local Bar = object { union { sphere {, R} cylinder {<0, 0, 0> , R} } //union } //object sphere {<0, 0, 0>, R} #for (I, 0, 5) object {Bar rotate (I * 60) * z} ArbitraryAngleCornerFiller (<0, 0, 0>, I * 60, (I + 1) * 60, R, CornerRadius) #end //#for } //union #local Cutout = object { difference { cylinder {<0, 0, -R - .1> <0, 0, 0>, CenterRadius + R} torus {CenterRadius + R, R sturm rotate 90 * x} } //difference } //object object {Cutout} object {Cutout rotate 180 * x} cylinder {<0, 0, -R - .1> <0, 0, R + .1>, CenterRadius} } //difference translate #declare MOP_CharacterWidth [ASTERISK_] = L0 * 2; } //object #declare MOP_Character [UNFINISHED_] = object { #local V1 = .02; //Eye radius #local V2 = .1; //Eye height #local V3 = .06; //Eye spacing #local V4 = .08; //Eye y offset #local V5 = .32; //Mouth radius #local V6 = .3; //Mouth y offset #local A0 = 70; union { torus {.5, R sturm rotate 90 * x} #local Mouth = object { union { intersection { torus {V5, R sturm rotate 90 * x} plane {x, 0 inverse rotate -A0 * z} plane {x, 0 rotate A0 * z} } //intersection sphere {, R} sphere {, R} } //union translate (V5 - V6) * y } //object object {Mouth} #local Eye = object { union { intersection { torus {V1, R sturm rotate 90 * x} plane {y, 0} } //intersection intersection { torus {V1, R sturm rotate 90 * x translate V2 * y} plane {y, V2 inverse} } //intersection sphere {<-V1, 0, 0>, R} sphere {<-V1, V2, 0>, R} sphere {, R} sphere {, R} cylinder {<-V1, 0, 0> <-V1, V2, 0>, R} cylinder { , R} cylinder {<0, 0, -R> <0, 0, R>, V1} cylinder {<0, V2, -R> <0, V2, R>, V1} box {<-V1, 0, -R> } } //union } //object object {Eye translate <-V1 - R - V3 / 2, V4, 0>} object {Eye translate } } //union translate <.5, .5, 0> #declare MOP_CharacterWidth [UNFINISHED_] = 1; } //object /* //Example... #declare MOP_Character [a_] = object { #local TempCharacter = object {text {ttf "SportsCenter.ttf" "a" 1, 0}} #local TempCharacter = object {TempCharacter translate -min_extent (TempCharacter).x * x} TempCharacter #local S = 1/.724; scale translate -min_extent (TempCharacter).y * y translate <-R, -R, -R> #declare MOP_CharacterWidth [a_] = max_extent (TempCharacter).x + R * 2; } //object */ #declare MOP_TextObjectHeight = 1 + MOP_FontRadius * 2; #declare LastMOP_FontRadius = MOP_FontRadius; #declare MOP_CharactersValid = yes; #end //#macro CreateMOP_Characters #macro TextToIndex (Character) #switch (asc (Character)) #case (asc (" ")) #local IndexValue = SPACE_; #break #case (asc ("\"")) #local IndexValue = QUOTE_; #break #range (asc ("A"), asc ("Z")) #local IndexValue = asc (Character) - asc ("A"); #break #range (asc ("a"), asc ("z")) #local IndexValue = UNFINISHED_; #break #range (asc ("0"), asc ("9")) #local IndexValue = asc (Character) - asc ("0") + 26; #break #case (asc (".")) #local IndexValue = PERIOD_; #break #case (asc (",")) #local IndexValue = COMMA_; #break #case (asc (":")) #local IndexValue = COLON_; #break #case (asc (";")) #local IndexValue = SEMICOLON_; #break #case (asc ("'")) #local IndexValue = APOSTROPHE_; #break #case (asc ("!")) #local IndexValue = EXCLAMATION_; #break #case (asc ("?")) #local IndexValue = QUESTION_; #break #case (asc ("/")) #local IndexValue = SLASH_; #break #case (asc ("-")) #local IndexValue = DASH_; #break #case (asc ("+")) #local IndexValue = PLUS_; #break #case (asc ("=")) #local IndexValue = EQUALS_; #break #case (asc ("$")) #local IndexValue = DOLLAR_; #break #case (asc ("(")) #local IndexValue = PARENTHESISLeft_; #break #case (asc (")")) #local IndexValue = PARENTHESISRight_; #break #case (asc ("[")) #local IndexValue = SQUAREBRACKETLeft_; #break #case (asc ("]")) #local IndexValue = SQUAREBRACKETRight_; #break #case (asc ("<")) #local IndexValue = ANGLEBRACKETLeft_; #break #case (asc (">")) #local IndexValue = ANGLEBRACKETRight_; #break #case (asc ("%")) #local IndexValue = PERCENT_; #break #case (asc ("#")) #local IndexValue = NUMBER_; #break #case (asc ("*")) #local IndexValue = ASTERISK_; #break #else //Undefined character #local IndexValue = -1; #break #end //#switch IndexValue #end //#macro TextToIndex #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 <= 0) #error "MOPFont Message: MOP_FontRadius must be > 0." #end //#if #if (MOP_FontRadius != LastMOP_FontRadius) CreateMOP_Characters (MOP_FontRadius) #end //#if #local TextLine = TextLine_; #local TextLine_ = ""; #for (I, 1, strlen (TextLine)) #local CurrentCharacter = substr (TextLine, I, 1); #if (TextToIndex (CurrentCharacter) != -1) #local TextLine_ = concat (TextLine_, CurrentCharacter); #else #debug "\nMOPFont Message: 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; #local NextQuote = QUOTELeft_; #for (I, 1, strlen (TextLine)) #local CurrentLineCharacterIndex = TextToIndex (substr (TextLine, I, 1)); #if (CurrentLineCharacterIndex != SPACE_) #if (CurrentLineCharacterIndex = QUOTE_) #switch (NextQuote) #case (QUOTELeft_) #local CurrentLineCharacterIndex = QUOTELeft_; #local NextQuote = QUOTERight_; #break #case (QUOTERight_) #local CurrentLineCharacterIndex = QUOTERight_; #local NextQuote = QUOTELeft_; #break #end //#switch #end //#if #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 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 CharacterInUse = array [NDefinedCharacters] #declare CharacterFullVertical = array [NDefinedCharacters] #local Kerning = array [NDefinedCharacters] [NDefinedCharacters] #declare SideDistance_Left = array [NDefinedCharacters] [NSteps] #declare SideDistance_Right = array [NDefinedCharacters] [NSteps] #local CharacterIndex_Save = array [NLineCharacters] #local CurrentX_Save = array [NLineCharacters] #for (I, 0, NDefinedCharacters - 1) //Initialize kerning flags #local CharacterInUse [I] = no; #declare CharacterFullVertical [I] = yes; #for (J, 0, NDefinedCharacters - 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, NDefinedCharacters - 1) #if (CharacterInUse [I]) MeasureCharacter (I, object {MOP_Character [I] translate }, Range_Lower, Range_Upper, NSteps) #end //#if #end //#for #for (I, 1, NLineCharacters - 1) #local Kerning [LineCharacterIndex [I - 1]] [LineCharacterIndex [I]] = -1; //Flag for character-to-character measurement #if (I >= 2) #if (!CharacterFullVertical [LineCharacterIndex [I - 1]]) #local Kerning [LineCharacterIndex [I - 2]] [LineCharacterIndex [I]] = -1; #end //#if #end //#if #end //#for #for (I, 0, NDefinedCharacters - 1) #for (J, 0, NDefinedCharacters - 1) #if (Kerning [I] [J] = -1) //Flagged for measurement #local CurrentKerningValue = MeasureCharacterToCharacter (I, J, Range_Lower, Range_Upper, NSteps) #if (CurrentKerningValue = -1) //Characters never touch #local Kerning [I] [J] = DefaultKerningDistance; #else #local Kerning [I] [J] = min (CurrentKerningValue, MaximumKerningDistance); #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 NextQuote = QUOTELeft_; #local CurrentX = 0; #local MaximumX = 0; #local NVisibleCharacters = 0; #if (NLineCharacters > 1) union { #for (I, 1, strlen (TextLine)) #local CurrentCharacterIndex = TextToIndex (substr (TextLine, I, 1)); #if (CurrentCharacterIndex = SPACE_) #local CurrentX = CurrentX + MOP_Space; #else #if (CurrentCharacterIndex = QUOTE_) #switch (NextQuote) #case (QUOTELeft_) #local CurrentCharacterIndex = QUOTELeft_; #local NextQuote = QUOTERight_; #break #case (QUOTERight_) #local CurrentCharacterIndex = QUOTERight_; #local NextQuote = QUOTELeft_; #break #end //#switch #end //#if #if (MOP_ApplyKerning) #if (NVisibleCharacters >= 2) #if (!CharacterFullVertical [CharacterIndex_Save [NVisibleCharacters - 1]]) #local CurrentX2 = CurrentX_Save [NVisibleCharacters - 2] + MOP_CharacterWidth [CharacterIndex_Save [NVisibleCharacters - 2]] + MOP_FontRadius * 2 + MOP_Gap; #local CurrentX2 = CurrentX2 - Kerning [CharacterIndex_Save [NVisibleCharacters - 2]] [CurrentCharacterIndex]; #local CurrentX = max (CurrentX, CurrentX2); #end //#if #end //#if #local CharacterIndex_Save [NVisibleCharacters] = CurrentCharacterIndex; //Contains correct quote indices #local CurrentX_Save [NVisibleCharacters] = CurrentX; #local NVisibleCharacters = NVisibleCharacters + 1; #end //#if object {MOP_Character [CurrentCharacterIndex] translate CurrentX * x} #local CurrentX = CurrentX + MOP_CharacterWidth [CurrentCharacterIndex] + MOP_FontRadius * 2 + MOP_Gap; #local MaximumX = max (CurrentX, MaximumX); #if (MOP_ApplyKerning) #if (I < strlen (TextLine)) #for (J, I + 1, strlen (TextLine)) #local NextCharacterIndex = TextToIndex (substr (TextLine, J, 1)); #if (NextCharacterIndex != SPACE_) //Use this one #if (NextCharacterIndex = QUOTE_) #switch (NextQuote) #case (QUOTELeft_) #local NextCharacterIndex = QUOTELeft_; #break #case (QUOTERight_) #local NextCharacterIndex = QUOTERight_; #break #end //#switch #end //#if #break #end //#if #end //#for #local CurrentX = CurrentX - Kerning [CurrentCharacterIndex] [NextCharacterIndex]; #local CurrentX = max (CurrentX, 0); //Allow for ".T" (for example) - the "T" would be moved to x < 0 #end //#if #end //#if #end //#if #end //#for } //union #else #local CurrentCharacterIndex = TextToIndex (TextLine); #if (CurrentCharacterIndex = QUOTE_) #local CurrentCharacterIndex = NextQuote; #end //#if object {MOP_Character [CurrentCharacterIndex]} #local MaximumX = MOP_CharacterWidth [CurrentCharacterIndex] + 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 = MaximumX - MOP_Gap; #end //#macro CreateMOP_TextObject /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * */ /* * INITIALIZATIONS * */ /* * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #declare SPACE_ = 999; #declare QUOTE_ = 998; #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 DIGIT0_ = 26; #declare DIGIT1_ = 27; #declare DIGIT2_ = 28; #declare DIGIT3_ = 29; #declare DIGIT4_ = 30; #declare DIGIT5_ = 31; #declare DIGIT6_ = 32; #declare DIGIT7_ = 33; #declare DIGIT8_ = 34; #declare DIGIT9_ = 35; #declare PERIOD_ = 36; #declare COMMA_ = 37; #declare COLON_ = 38; #declare SEMICOLON_ = 39; #declare APOSTROPHE_ = 40; #declare QUOTELeft_ = 41; #declare QUOTERight_ = 42; #declare EXCLAMATION_ = 43; #declare QUESTION_ = 44; #declare SLASH_ = 45; #declare DASH_ = 46; #declare PLUS_ = 47; #declare EQUALS_ = 48; #declare DOLLAR_ = 49; #declare PARENTHESISLeft_ = 50; #declare PARENTHESISRight_ = 51; #declare SQUAREBRACKETLeft_ = 52; #declare SQUAREBRACKETRight_ = 53; #declare ANGLEBRACKETLeft_ = 54; #declare ANGLEBRACKETRight_ = 55; #declare PERCENT_ = 56; #declare NUMBER_ = 57; #declare ASTERISK_ = 58; #declare UNFINISHED_ = 59; //#declare a_ = 60; //Not used #declare NDefinedCharacters = 60; #declare MOP_Character = array [NDefinedCharacters]; #declare MOP_CharacterWidth = array [NDefinedCharacters]; #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 #declare LastMOP_FontRadius = -1; #if (!MOP_CharactersValid) #ifndef (MOP_FontRadius) #declare MOP_FontRadius = .06; #end //#ifndef CreateMOP_Characters (MOP_FontRadius) #end //#if