// C O N V E R T -- read SD, create AC (PREPRESS,PRESS) //1/23/80: The bounding box calculation in ConvertAWidth and ConvertAChar // now checks the value of the flag convertThicken, so that non-thickened // rasters are no longer are given a bounding box one unit too tall. //12/13/77: ConvertAChar now puts out ORbit format characters J.Maleson // catalog number ??? //ConvertAWidth(ps,pc,p) // Convert the widths of a single character. // ps -> SplineWidth. Fills up pc -> CharWidth. // p -> Convert structure. // returns true if bitmap for character is large // (only routines which are prepared to deal with spline // output check the conservative return from ConvertAWidth) //ConvertAChar(w,wo,pc,p,FSGet,FSPut) // Converts a single character. p -> Convert structure, // which describes some parameters. // w is window to read splines from; wo window to put // scan-converted characters into. // pc -> CharWidth structure to return goodies. // Returns an error code: // 0 = All OK // 1= not enough core in SCV // 2,3 = SCV errors in splines // 4 = too big to scan convert, try ScaleAChar // 10= Spline description file illegal // 11= Illegal Press font object // 12= Scan convert screwed up -- not even # intersections // 13= Bit intersection out of range // 14= Conversion did not terminate properly. // FSGet,FSPut are routines for getting, releasing storage. //ScaleAChar(w,wo,pc) // Converts a single character into scaled spline representation // w is window to read splines from; wo window to put // scaled splines into. // pc -> CharWidth structure to return goodies. //SetSCVTransform(siz,rotation,incline,resolutionx,resolutiony) // Set up SCV transformation matrix. //Cos(theta,lvsign,lvmag) // Computes the cosine of the angle "theta" (in minutes) and // returns sign (0 if positive, -1 if negative) and magnitude // (0 to #177777) get "ix.dfs" get "scv.dfs" // outgoing procedures external [ ConvertAChar ConvertAWidth ScaleAChar SetSCVTransform Cos ] // outgoing statics external [ @convertThicken @convertOrbitized ] static [ @convertThicken=false @convertOrbitized=false ] // incoming procedures external [ //In SCV package SCVInit SCVBeginObject SCVEndObject SCVMoveToF SCVDrawToF SCVDrawCurve SCVMatrix SCVReadRuns SCVTransformF SCVFlush Floor //Window package WindowSetPosition WindowGetPosition WindowReadBlock WindowWriteBlock WindowRead WindowWrite WindowCopy //Block move, store Zero; SetBlock; MoveBlock //Misc MulDiv MulFull;DivFull DoubleAddV //Floating point FLD;FST;FLDI;FNEG;FAD;FML;FDV FCM;FLDV;FSTDP;FTR ] // incoming statics // internal statics // File-wide structure and manifest declarations. // Procedures let ConvertAWidth(s,c,p) = valof [ // s -> SplineWidth structure of char to compute widths. // c -> CharWidth structure to receive results. // p -> Convert structure that governs how things are done. // Returns true if spline will be needed. let spline=false let pw=lv s>>SplineWidth.WX test pw!0 eq 0 & pw!1 eq -1 then [ //Non existent char c>>CharWidth.H=HNonExCode ] or [ //Transform widths SCVTransformF(lv s>>SplineWidth.WX,lv s>>SplineWidth.WY) FSTDP(8,lv c>>CharWidth.WX) //and save for AC file FSTDP(9,lv c>>CharWidth.WY) //as double-precision //Calculate bounding box. //Warning: the calculation for the bounding box is really not good enough. // This is because the bounding box kept with the SD description is calculated // a little differently than will be the endpoints of the splines when passed // to SCV during conversion. As a result, small round-off errors will occur // (partly because SCVDrawCurve uses ->relative<- numbers!). This can change // 2E-9 into -2E-9, which will cause a different bounding box to be calculated. test p>>Convert.BBGood then [ //Transform bounding box SCVTransformF(lv s>>SplineWidth.XL,lv s>>SplineWidth.YB) FLD(1,8) //Save left edge let yb=Floor(9) //Y bottom SCVTransformF(lv s>>SplineWidth.XR,lv s>>SplineWidth.YT) let yh=Floor(9) //Now swap ybottom and yheight if inverted (will happen if character is rotated). if yb gr yh then [ let t=yb; yb=yh; yh=t ] yh=yh-yb+(convertThicken? 1,0) //And same for x, but (1) check for empty character, and (2) // in scan direction, things are assymetric, because of the kind of // scan conversion we are doing. let xl,xw=nil,nil let sg=FCM(1,8) switchon sg into [ case 0: xl=0; xw=0; yb=0; yh=0 //Character is empty endcase case 1: FLD(2,1);FLD(1,8);FLD(8,2) //Swap -- ac 1 < ac 8 case -1: xl=Floor(1)+1 //Assymetry xw=Floor(8)-xl+1 endcase ] c>>CharWidth.XL=xl c>>CharWidth.YB=yb c>>CharWidth.H=yh c>>CharWidth.W=xw if p>>Convert.SplineOk & SplineNeeded(c,1) then [ c>>CharWidth.H=HSplineCode spline=true ] ] //end of "test BBGood" or //rotated, can't get bounding box, BUT: we can tell if it looks like //splines are needed (since DP WX,WY are computed already) [ if ((lv c>>CharWidth.WX)!0 gr 50)% ((lv c>>CharWidth.WY)!0 gr 50) then spline=true ] ] //end of good character resultis spline ] and ConvertAChar(w,wo,pc,p,FSGet,FSPut) = valof [ //Assume w positioned at spline, wo positioned to receive it. // pc -> CharWidth structure to receive results (bounding box only) // p -> Convert structure that governs how things are done. let originallen=32000 //Generous estimate! if p>>Convert.PressFontPart then originallen=p>>Convert.Len SCVInit(FSGet,FSPut) SCVBeginObject(not p>>Convert.Monotone,p>>Convert.Monotone) let opos=vec 3 //Remember old pos for spline WindowGetPosition(w,opos) WindowGetPosition(wo,opos+2) let stuff=vec 12 let len=originallen [ if len le 0 then break let op=WindowRead(w) switchon op into [ case DSplineFontMoveTo: //MoveTo WindowReadBlock(w,stuff,4) SCVMoveToF(stuff,stuff+2) len=len-5 endcase; case DSplineFontDrawTo: //DrawTo WindowReadBlock(w,stuff,4) SCVDrawToF(stuff,stuff+2) len=len-5 endcase; case DSplineFontDrawCurve: //DrawCurve WindowReadBlock(w,stuff,12) SCVDrawCurve(stuff,stuff+2,stuff+4,stuff+6, stuff+8,stuff+10) len=len-13 endcase; case DSplineFontEndObjects: //End break endcase default: resultis 10 //Illegal file format ] ] repeat let v=vec (size SCV/16) SCVEndObject(v) //Finish off if v>>SCV.Error then [ //Error -- return code SCVFlush(v) resultis v>>SCV.Error ] //Compute offsets (ox,oy), width (ns) and height (nb) let ns,nb=nil,nil let ox=v>>SCV.Smin test ox gr v>>SCV.Smax then [ ox=0;ns=0 ] or ns=v>>SCV.Smax-ox+1 let oy=v>>SCV.Rmin test oy gr v>>SCV.Rmax then [ oy=0;nb=0 ] or nb=v>>SCV.Rmax-oy+(convertThicken? 1,0) if p>>Convert.PressFontPart then [ if len ne 0 then [ SCVFlush(v) resultis 11 ] SCVTransformF(stuff,stuff+2) //Use last MOVETO FSTDP(8,lv pc>>CharWidth.WX) // to compute widths FSTDP(9,lv pc>>CharWidth.WY) ] //Salt away goodies in the structure pc>>CharWidth.XL=ox pc>>CharWidth.YB=oy pc>>CharWidth.W=ns pc>>CharWidth.H=nb //figure out how much space needed: if not enough, use splines unless convertOrbitized do nb=(nb+15)𫙠 let bitsNeeded=vec 1 MulFull(ns,nb,bitsNeeded) DoubleAddV(bitsNeeded,15) //take care of odd bit lengths let sizeNeeded=DivFull(bitsNeeded,16)+1 //add fudge for final tempPBits!1 let pbits=FSGet(sizeNeeded) //Now decide if splines needed. test p>>Convert.SplineOk&((pbits eq 0)%SplineNeeded(pc)) then [ unless pbits eq 0 do FSPut(pbits) WindowSetPosition(w,opos) //Restart SCVFlush(v) //Release any storage resultis 4 //return error, so that caller will call ScaleAChar ] or [ //Can convert OK //The character can be converted into a bit matrix, and stored in // the character definition file as such. let sl=vec 2 test convertOrbitized then [ sl!0=-nb //height sl!1=ns-1 //width WindowWriteBlock(wo,sl,2) ] or [ sl<<FHEAD.hw=nb rshift 4 sl<<FHEAD.ns=ns //Make up font header WindowWrite(wo,sl) ] if sizeNeeded eq 1 then [ FSPut(pbits);resultis 0] //null character let Masks= table [ #177777; #077777; #037777; #017777; #007777; #003777; #001777; #000777; #000377; #000177; #000077; #000037; #000017; #000007; #000003; #000001; #000000 ] let Cycle=table [ #60000;#1401] let CMasks= table [ #177777;#177776;#177774 #177770;#177760;#177740 #177700;#177600;#177400 #177000;#176000;#174000 #170000;#160000;#140000 #100000;0 ] let slbuf=vec 100 //For making up scan lines Zero(slbuf,100) //Prepare to call SCVReadRuns to obtain all runs until the character // exhausts. let hw=(nb+15)/16 let ob=0 let tempPBits=pbits let buf=vec 1000 let sl=v>>SCV.Smin v>>SCV.Send=sl-1 [ v>>SCV.Sbegin=v>>SCV.Send+1 //Move right v>>SCV.Send=v>>SCV.Smax //Optimistic SCVReadRuns(v,buf,1000) let n=v>>SCV.IntCnt if n eq 0 then break //No more intersections let p=v>>SCV.IntPtr for i=1 to n by 2 do [ while sl ne p!0 do //Going to new scan line. [ let leftMask=CMasks!(16-ob) let rightMask=not leftMask for j=0 to hw-1 do [ let w=Cycle(slbuf!j,16-ob) tempPBits!0=(tempPBits!0&(not Masks!ob))+(w&rightMask) tempPBits!1=(tempPBits!1&(Masks!ob))+(w&leftMask) tempPBits=tempPBits+1 ] //end of "for j" ob=ob+nb tempPBits=tempPBits-hw+ob/16 ob=ob Zero(slbuf,hw) sl=sl+1 ] //end of "while sl" if p!2 ne sl then resultis 12 let yb=p!1-oy //Bottom y let yt=p!3-oy+(convertThicken? 1,0) //Top y+1 p=p+4 //Bump to next intersection // Turn on bits from yb to yt-1 (inclusive) if yb ls 0 % yt gr nb then resultis 13 if yt ge yb then //Only show non-zero runs [ let LeftMask=(Masks!(yb)) let RightMask= not (Masks!(yt)) yb=yb rshift 4 let wc=(yt rshift 4)-yb //Word count let w=slbuf+yb //Word address let bw=(@w & (not LeftMask))%(-1 & LeftMask) for i=0 to wc-1 do [ w!i=bw; bw=-1 ] w!wc=(w!wc & (not RightMask))%(bw & RightMask) ] //end of "if yt ge yb" ] //end of "for i" ] repeat //and finish putting out the last line... let leftMask=CMasks!(16-ob) let rightMask=not leftMask for j=0 to hw-1 do [ let w=Cycle(slbuf!j,16-ob) tempPBits!0=(tempPBits!0&(not Masks!ob))+(w&rightMask) tempPBits!1=(tempPBits!1&(Masks!ob))+(w&leftMask) tempPBits=tempPBits+1 ] WindowWriteBlock(wo,pbits,sizeNeeded) //Last line.... FSPut(pbits) if sl ne v>>SCV.Smax then resultis 14 ] //end of doing scan conversion resultis 0 ] //The character will occupy too much space if scan-converted and // saved in a character file as bits. We return an error code, and // the calling program will have the smarts to call ScaleAChar, // which will simply scale the spline definition, // and place it in the character file. In addition, // the CharWidth.H entry is changed to have a special code that // indicates this character is described by splines, and XL and YB // have in them the file position of the spline encoding. and ScaleAChar(w,wo,pc) = valof [ WindowGetPosition(wo,lv pc>>CharWidth.XL) //Save pos in XL,YB pc>>CharWidth.H=HSplineCode let outLen=0 let stuff=vec 13 [ let op=WindowRead(w) stuff!0=op-1 //GAAAAAAA!!! PreObjects uses different codes!!!! switchon op into [ case DSplineFontMoveTo: case DSplineFontDrawTo: WindowReadBlock(w,stuff+1,4) SCVTransformF(stuff+1,stuff+3) stuff!1=FTR(8);stuff!2=FTR(9) WindowWriteBlock(wo,stuff,3) outLen=outLen+3 endcase case DSplineFontDrawCurve: WindowReadBlock(w,stuff+1,12) for p=1 to 12 by 4 do [ SCVTransformF(stuff+p,stuff+p+2) FST(8,stuff+p) FST(9,stuff+p+2) ] WindowWriteBlock(wo,stuff,13) outLen=outLen+13 endcase case DSplineFontNewObject: case DSplineFontEndObjects: break//done ] //end of "switchon op" ] repeat pc>>CharWidth.W=outLen resultis 0 //no errors ] and //Set up the SCV transformation matrix from parameters that are // supplied for converting a font: // siz Size of the font in micas // rotation Rotation of the font in minutes // incline Incline of the font in percent // resx,resy Resolution of the output device // (if not supplied, FPAC's 3&4 assumed set up) SetSCVTransform(siz,rotation,incline,resx,resy; numargs n) be [ FLDI(5,25400) FLDI(1,siz); FLDI(2,siz) if n gr 3 then [ FLDI(3,resx); FLDI(4,resy) ] FML(1,3); FML(2,4) FDV(1,5); FDV(2,5) //x and y scales. test rotation ne 0 then [ //Get sine and cosine GetFloatingCos(rotation,3) GetFloatingCos(rotation-90*60,4) ] or [ FLDI(3,1); FLDI(4,0) ] FLD(5,3); FML(5,1) //m[1,1] FLD(6,4); FML(6,1) //m[1,2] FNEG(4) FLDI(7,incline);FLDI(0,100);FDV(7,0) FML(7,3);FAD(4,7);FML(4,2) //m[2,1] FML(3,2) //m[2,2] SCVMatrix(5,6,4,3) ] and //Return floating cosine in ac. Argument is minutes of arc. GetFloatingCos(min,ac) be [ let v=vec 4 v!1=0 //Exponent v!3=0 //Low mantissa let one=table [ 0;0;#177777;0 ] //Normalization constant Cos(min,v,v+2) // Now normalize the number if v!2 then while ((v!2)𘚠) eq 0 do [ v!2=v!2 lshift 1; v!1=v!1-1 ] FLDV(ac,v) FLDV(0,one) FDV(ac,0) ] and Cos(theta,lvsign,lvmag) be [ //Calculate the cosine of the given angle, and return the // magnitude as a fraction of #177777 (largest number) // Also return sign (0 if positive, -1 if negative) if theta ls 0 then theta=-theta @lvsign=-(((theta+90*60)/(180*60))&1) let d=theta rem 90*60 if ((theta/(90*60))&1) ne 0 then d=90*60-d let min=d rem 60 //Minutes part d=d/60 //Degrees part //Now d in range 0-90 degrees let retrievecos(d,min) =valof [ //0 le d le 45 let cosar=table [ #177777; #177765; #177727; #177645; #177537; #177405; #177227; #177026; #176601; #176330; #176033; #175512; #175146; #174557; #174144; #173505; #173024; #172317; #171567; #171014; #170216; #167376; #166532; #165645; #164735; #164002; #163026; #162030; #161007; #157746; #156662; #155556; #154430; #153262; #152072; #150663; #147432; #146162; #144672; #143362; #142032; #140463; #137075; #135471; #134045; #132405; #130743; //46 degrees because of interpolation ] let a=cosar!d //First answer if min ne 0 then //Must interpolate [ let b=cosar!(d+1) a=a-MulDiv(a-b,min,60) //Careful about signs ] resultis a ] test d gr 45 then [ //Use half-angle formulae if (d&1) ne 0 then min=min+60 //Divide angle by 2 let a=retrievecos(d rshift 1,min rshift 1) a=MulDiv(a,a,#177777) // cos↑2(theta/2) a=a-#100000 // cos↑2 -1/2 @lvmag=a lshift 1 //2 cos↑2 -1 ] or @lvmag=retrievecos(d,min) ] and //Return true if character described by pc>>CharWidth... // will be too big for a scan-converted form. SplineNeeded(pc,boundFactor;numargs na) = valof [ if na eq 1 then boundFactor=10 let nbw=(pc>>CharWidth.H+15)/16 resultis (nbw gr 10*boundFactor) % (nbw*pc>>CharWidth.W gr 200*boundFactor) ]