The Tektronix Circuit Computer scale annotations read both inward (from the center) and outward (from the rim):

It’s surprisingly difficult (for me, anyhow) to see the middle FL Scale as reading upside-down, rather than mirror-image backwards.
This turned into a rewrite of the the read-outward annotation code I used for the vacuum tube reflectors. Eventually the justification and orientation options came out right:

The text baseline sits at the specified radius from the center point, regardless of its orientation, so you must offset the text path by half its height in the proper direction before handing it to the ArcText
function.
The testcase shows the invocation ritual:
ctr = [0mm,0mm];
tp = scale(typeset("Right Inward",TextFont),ScaleTextSize);
tpa = ArcText(tp,ctr,30mm,45deg,TEXT_RIGHT,INWARD);
engrave(tpa,TravelZ,EngraveZ);
tp = scale(typeset("Right Outward",TextFont),ScaleTextSize);
tpa = ArcText(tp,ctr,30mm,45deg,TEXT_RIGHT,OUTWARD);
engrave(tpa,TravelZ,EngraveZ);
tp = scale(typeset("Center Inward",TextFont),ScaleTextSize);
tpa = ArcText(tp,ctr,20mm,45deg,TEXT_CENTERED,INWARD);
engrave(tpa,TravelZ,EngraveZ);
tp = scale(typeset("Center Outward",TextFont),ScaleTextSize);
tpa = ArcText(tp,ctr,20mm,45deg,TEXT_CENTERED,OUTWARD);
engrave(tpa,TravelZ,EngraveZ);
tp = scale(typeset("Left Inward",TextFont),ScaleTextSize);
tpa = ArcText(tp,ctr,10mm,45deg,TEXT_LEFT,INWARD);
engrave(tpa,TravelZ,EngraveZ);
tp = scale(typeset("Left Outward",TextFont),ScaleTextSize);
tpa = ArcText(tp,ctr,10mm,45deg,TEXT_LEFT,OUTWARD);
engrave(tpa,TravelZ,EngraveZ);
goto([0mm,0mm,-]);
move([40mm,40mm,-]);
A utility function to draw scale legends stuffs some of that complexity into a bottle:
function ArcLegend(Text,Radius,Angle,Orient) {
local tp = scale(typeset(Text,TextFont),LegendTextSize);
local tpa = ArcText(tp,[0mm,0mm],Radius,Angle,TEXT_CENTERED,Orient);
feedrate(TextSpeed);
engrave(tpa,TravelZ,EngraveZ);
}
Which means most of the text uses a simpler invocation:
r = Radius + TickMajor + 2*TickGap + LegendTextSize.y;
logval = MinLog + 1.5;
a = offset + logval * Arc;
ArcLegend("nH - nanohenry x10^-9",r,a,INWARD);
logval += 3;
a = offset + logval * Arc;
ArcLegend("μH - microhenry x10^-6",r,a,INWARD);
Arc
determines the angular span of each decade, with positive values going counterclockwise. MinLog
is the logarithm of the scale endpoint, so adding 1.5 puts the text angle one-and-a-half decades from MinLog
and multiplying by Arc
moves it in the right direction. The offset
angle rotates the entire scale with respect to the 0° reference sticking out the X axis over on the right. The top picture has its 0° reference pointing north-northeast.
The GCMC source code as a GitHub Gist:
INWARD = -1; // text and tick alignment (used as integers) | |
OUTWARD = 1; | |
TEXT_LEFT = -1; // text justification | |
TEXT_CENTERED = 0; | |
TEXT_RIGHT = 1; | |
//----- | |
// Bend text around an arc | |
function ArcText(TextPath,CenterPt,Radius,BaseAngle,Justify,Orient) { | |
local pl = TextPath[-1].x; // path length | |
local c = 2*pi()*Radius; | |
local ta = to_deg(360 * pl / c); // subtended angle | |
local ja = (Justify == TEXT_LEFT ? 0deg : // assume OUTWARD | |
(Justify == TEXT_CENTERED) ? -ta / 2 : | |
(Justify == TEXT_RIGHT) ? -ta : | |
0deg); | |
ja = BaseAngle + Orient*ja; | |
local ArcPath = {}; | |
local pt,r,a; | |
foreach(TextPath; pt) { | |
if (!isundef(pt.x) && !isundef(pt.y) && isundef(pt.z)) { // XY motion, no Z | |
r = (Orient == OUTWARD) ? Radius - pt.y : Radius + pt.y; | |
a = Orient * 360deg * (pt.x / c) + ja; | |
ArcPath += {[r*cos(a) + CenterPt.x, r*sin(a) + CenterPt.y,-]}; | |
} | |
elif (isundef(pt.x) && isundef(pt.y) && !isundef(pt.z)) { // no XY, Z up/down | |
ArcPath += {pt}; | |
} | |
else { | |
error("ArcText - Point is not pure XY or pure Z: " + to_string(pt)); | |
} | |
} | |
return ArcPath; | |
} |
GCMC treats variables defined inside a function as local, unless they’re already defined in an enclosing scope, whereupon you overwrite the outer variables. This wasn’t a problem in my earlier programs, but I fired the footgun with nested functions using the same local / temporary variables. Now, I ruthlessly declare truly local variables as local
, except when I don’t, for what seem good reasons at the time.
2 thoughts on “GCMC Text on Arcs: Improved Version”
Comments are closed.