%! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % PostScript $99 XY TABLE FLUTTERWUMPER TOOLKIT % ======================================================== % by Don Lancaster Revised January 13, 1997 % =================================================================== % Copyright c 1997 by Don Lancaster and Synergetics, Box 809, % Thatcher AZ, 85552. (520) 428-4073 www.tinaja.com don@tinaja.com % All commercial rights and all electronic media rights are % *fully* reserved. Linking welcome. Reposting expressly forbidden. % =================================================================== % % SUMMARY: A Flutterwumper is any hackable entity that moves and % either chomps or spits. This is a very powerful set of % preliminary PostScript tools, utilities, readers, test % files, emulators, and demos as required for preliminary % homebrew PIC flutterwumper development. % % Tutorial may be read as textfile. % Acrobat Distiller or GhostScript required for use % % See FLUTWUMP.PDF and POSTFLUT.PDF. % % Copyright c 1994, 1997 by Don Lancaster. All rights reserved. % PIC sourcecode and full consulting services available. % Free help line and additional info: (520) 428-4073. % % ============================================================================ % % Name of textfile: FLUTOOLS.PS % Source: SYNERGETICS % Author: Don Lancaster % Desc: PS $99 XY table flutterwumper toolkit % Date: September 24, 1994 July 14, 1997 % Release: 3.0 % Approx length: 43K % Status: Copyright 1994,1997 by Don Lancaster and Synergetics. % 3860 West First Street, Thatcher, AZ. (520) 428-4073. % All commercial rights and all electronic media rights % fully reserved. Personal use is permitted so long as % this status message stays present and intact. % Basic flutterwumper Infopack $75 VISA/MC. Free help % line and additional info (520) 428-4073. % % Keywords: PostScript, guru, xy, x-y, table, flutterwumper, % vector, raster, driver, utility, tool, tutorial, hack % hardware, software, interface, hack, stepper, Santa, % Claus, PIC, %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This particular utility set has been optimized to work with Acrobat % Distiller or GhostScript on Windows 95. Example data files are % written and read from the A: drive. PS printer-based utilities % using print statements instead of disk writes are equally possible. % PS $99 XY TABLE FLUTTERWUMPER TOOLKIT % ===================================== % by Don Lancster % This toolkit consists of PS-to-step methods for getting from PostScript % to the individual XY steps needed in a $99 flutterwumper, or any other % automated positioning system. % A (usually) serial and extremely low level communication format called % a FLUTFILE is created. A flutfile simply itemizes each and every individual % table step or action as one ASCII character. Thus DRAMATICALLY minimizing % the smarts needed by the flutterwumper itself. % The input to these tools can be largely UNMODIFIED PostScript, generated % by hand or by many applications package. Virtually ALL of the power of % PostScript becomes available for your flutterwumper at near zero cost! % In use, ordinary PostScript code is combined with these routines and % sent to (preferably) Acrobat Distiller or (alternately) GhostScript % running on a host. A flutfile is generated. This file can be sent % out a port to immediately control the flutterwumper or can be kept % for later reuse. Any comm program can be used for an interface. % These routines are easily extended to input or output HPGL or Gerber files. % For most uses, these fancier formats are unnecessary complications. % Several example flutfiles are provided, including a simple box, a circle, % and a typographic character. Along with tolerance plots. % A flutfile reader is included. This can be used to proof or debug % flutfiles, or else to software emulate a hardware flutterwumper project % in development. % The fundamental core problems are to convert fonts into PostScript paths, % convert paths into straight line vectors and then convert those % vectors into individual flutfile steps. % Font path conversion gets done with the -charpath- operator. Curves % in the path get converted to straight line vectors using the -setflat- % and -flattenpath- operators. Paths are enumerated for vector conversion % with the -pathforall- operator. Step conversion uses the code below. % In this version, a vector flutfile system is used, sending commands for % octant moves of north, northwest, west, southwest, south, southeast, east, % and northeast. Note that a flutterwumper that INTERLEAVES x any y stepper % phases offers DRAMATICALLY smoother results, finer resolution, and shorter % file lengths. % All motions with the exception of the !H HOME command are RELATIVE with % respect to the CURRENT flutterwumper tool position. % Code at present is for 2-1/2 D applications, where the Z axis is a % simple up-down or on-off command. These routines are easily extended % for full three axis or higher uses. % While not included here, it is EXTREMELY SIMPLE to add transformations % for non-cartesian (non-XYZ) output devices. Hooks are provided. % These results have not yet been speed optimized. But they already are % much faster than most flutterwumpers, even at lower serial baud rates. % Table lookup (details on request) can offer speed improvements. % The code also provides "very good" but not "outstanding" typography. % On coarser resolution devices, slight retouching may be required, % compared to the simple and direct use of -charpath- shown here. % In any "low res" and "small letter" situation, picking a low res % friendly friendly font (Helvetica or Stone) can help bunches. It % is also possible to "retouch" the results by using the flutfile reader. % or custom hinting code. % Faster matrix transformation methods are also possible, but these % are harder to understand and debug. Plain old algebra is used instead. % //////////// (A) CREATE A POSTSCRIPT DICTIONARY ////////////////// % Since these tools intercept several fundamental PostScript commands, % they are best placed inside a closed dictionary until they are actually % required... /flutdict 100 dict def % define a dictionary flutdict begin % open dictionary for most following routines % ///////////// (B) A TIME DELAY ROUTINE ///////////////////////////// % A brief time delay might be handy for open loop flutterwumper homing, % special comm situations, and such. Here is a simple and obvious one... /stall1 {usertime add 300000 {usertime 1 index sub 0 ge {exit} if} repeat pop} def % Example: For a 600 millisecond delay, use 600 -stall1-. % ////////////// (C) OUTPUT FILE FORMATTER /////////////////////// % Flutterwumper files often consist of long strings of single characters. % This print formatter limits the width of certain printed lines... /linecount 0 def % initial character counter init /maxline 64 def % maximum linewidth /write1 { dup dup length 1 gt exch (\n) eq or {dest exch writestring /linecount 0 store} {dest exch writestring /linecount linecount 1 add store linecount maxline ge {dest (\n) writestring /linecount 0 store}if}ifelse} bind def /writecr1 {write1 (\n) dest exch writestring } def % ////////////// (D) OUTPUT COMMAND REDEFINER /////////////// % These hooks allow you to redefine your flutfile character set. % The ability to ignore everything between a "%" and a carriage % return or linefeed is assumed... % A flutterwumper that can INTERLEAVE X and Y step phases is assumed. % To convert these to degrees, MULTIPLY them by 45... /!E (0) def % step east /!NE (1) def % step northeast /!N (2) def % step north /!NW (3) def % step northwest /!W (4) def % step west /!SW (5) def % step southwest /!S (6) def % step south /!SE (7) def % step southeast /!H (:) def % step to XY home /!U (8) def % pen up command /!D (9) def % pen down command /!B (:) def % initialize job /!Q (:) def % job completed /!X (:) def % breaking debugger /!R {(R?) dup repeatcount 32 sub 1 put} def % repeatproc /repeatcount 4 def % and default /!cr (\n) def % forced carriage return /flutbegin {/lastxmove 0 def /lastymove 0 def /curxpos 0 def /curypos 0 def !B write1 !cr} def % send begin command /fluthome {flutpenup !H write1 !cr} def % home command /penupflag true def % initialize penup /flutpenup {penupflag not {!U write1 % pen up if not up /penupflag true store}if} def /flutpendown {penupflag {!D write1 % pen down if not down /penupflag false store}if} def /flutquit {flutpenup !Q write1 !cr} def % flut quit proc /flutbreak {flutpenup !X write1 !cr} def % flut break debugger /lastxmove 0 def % defaults /lastymove 0 def % //////////// (E) VECTOR OCTANT SELECTOR //////////////////// % Final stack has -x- -y- -angle- {octantproc}. /findoctant { 2 copy exch 2 copy 0 eq exch 0 eq and {pop 0.000001} if atan dup round cvi 45 idiv [{oct0}{oct1}{oct2}{oct3}{oct4}{oct5}{oct6}{oct7}{oct0}] exch get} def % examples: 10 4.7 leaves {oct0} on stack top; -4.7 10 leaves {oct2}. % //////////// (G) OCTANT VECTOR-TO-STEP ALGORITHMS ///////////// % Assume an octant #0 from 0 to +45 degrees. There will ALWAYS be more % X increments than Y in a step approximation. For each X step, % advance X, check the Y position. If half a unit low, also advance Y. % % These can later be speed optimized through table lookups of longer % vectors. They are presented in simple form for clarity here. /curxpos 0 def % running currentpoint for output /curypos 0 def % running currentpoint for output /oct0 { cos 0.5 mul /thresh exch store % calculate threshold 2 copy exch dup 0 eq {0.00001 add} if div % don't divide by zero /slope exch store % find the slope pop abs % don't need y no more? round cvi /#incs exch store % number of x incs 0 % set y increment counter 0 1 #incs 1 sub {/posn exch def % start loop /curxpos curxpos 1 add store % move one right posn 1 add slope mul thresh sub % test vertical position 1 index ge {1 add % y increment advance !NE write1 % command x and y move /curypos curypos 1 add store} % move one up {!E write1} % command x move only ifelse % go east or northeast? } for % for all x increments pop % done with y increment count } bind def % end proc % Each of the remaining octants is slightly different, rotating mirroring or % exchanging x for y... /oct1 {sin 0.5 mul /thresh exch store exch 2 copy exch div /slope exch store pop abs round cvi /#incs exch store 0 0 1 #incs 1 sub {/posn exch def /curypos curypos 1 add store posn 1 add slope mul thresh sub 1 index ge {1 add !NE write1 /curxpos curxpos 1 add store}{!N write1} ifelse } for pop} bind def /oct2 {sin 0.5 mul /thresh exch store exch 2 copy exch div neg /slope exch store pop abs round cvi /#incs exch store 0 0 1 #incs 1 sub {/posn exch def /curypos curypos 1 add store posn 1 add slope mul thresh sub 1 index ge {1 add !NW write1 /curxpos curxpos 1 sub store} {!N write1} ifelse } for pop} bind def /oct3 {cos -0.5 mul /thresh exch store 2 copy exch div neg /slope exch store pop abs round cvi /#incs exch store 0 0 1 #incs 1 sub {/posn exch def /curxpos curxpos 1 sub store posn 1 add slope mul thresh sub 1 index ge {1 add !NW write1 /curypos curypos 1 add store} {!W write1} ifelse } for pop} bind def /oct4 {cos -0.5 mul /thresh exch store 2 copy exch div /slope exch store pop abs round cvi /#incs exch store 0 0 1 #incs 1 sub {/posn exch def /curxpos curxpos 1 sub store posn 1 add slope mul thresh sub 1 index ge {1 add !SW write1 /curypos curypos 1 sub store}{!W write1} ifelse } for pop} bind def /oct5 {sin -0.5 mul /thresh exch store 2 copy div /slope exch store abs round cvi /#incs exch store pop 0 0 1 #incs 1 sub {/posn exch def /curypos curypos 1 sub store posn 1 add slope mul thresh sub 1 index ge {1 add !SW write1 /curxpos curxpos 1 sub store}{!S write1} ifelse } for pop} bind def /oct6 {sin -0.5 mul /thresh exch store 2 copy div neg /slope exch store abs round cvi /#incs exch store pop 0 0 1 #incs 1 sub {/posn exch def /curypos curypos 1 sub store posn 1 add slope mul thresh sub 1 index ge {1 add !SE write1 /curxpos curxpos 1 add store}{!S write1} ifelse } for pop} bind def /oct7 {cos 0.5 mul /thresh exch store 2 copy exch div neg /slope exch store pop abs round cvi /#incs exch store 0 0 1 #incs 1 sub {/posn exch def /curxpos curxpos 1 add store posn 1 add slope mul thresh sub 1 index ge {1 add !SE write1 /curypos curypos 1 sub store}{!E write1} ifelse } for pop} bind def % ////////////// (H) MAIN VECTOR-TO-STEP ALGORITHM ///////////////// % To convert a vector to individual XY steps, the octant is first found, % and then a suitable octant algorithm is used... /vectortostep {findoctant exec !cr write1 } bind def % ///////////// (I) FLATTENPATH CALCULATOR ////////////////////////// % For conversion to vectors, all curves get converted by -flattenpath-. % Too high a value, and output step size suffers. Too low a value and % the computation time get excessive. % Note that -flattenpath- is DEVICE DEPENDENT. A 2X cruder value is % needed at 600 DPI to get the same results at 300 DPI! /inch {72 mul} def % inch converter /flutres 0.01 inch def % DEVICE DEPENDENT output resolution % For small or complex typography, an oversample value of at least 8 % is recommended. This causes a -flattenpath- error of less than 0.25 % flutterwumper steps. Oversamples of 0.4 or less execute faster, but % make straight line approximations that have path errors.. % In general, this is a subtle variable. It does NOT affect the output file % length, but DOES affect computation time SOMEWHAT. The effects are data % dependent, but changes usually occur in large chunks. The average % flutfile line length gives you a clue whether a change has happened. % Leave -oversample- at 8 unless you are after special situations. /oversample 8 def % flat error per output resolution error % A scheme to find resolution of old level I PS code... /findres {save /snap exch def initgraphics matrix currentmatrix dup 0 get dup mul exch 1 get dup mul add sqrt 72 mul cvi snap restore} def /findflat {findres 1 exch div flutres 72 div exch div oversample div} def % /////////////// (J) CO-ORDINATE TRANSFORM AND SCALING /////////// % This does a custom scaling and optional nonlinear co-ordinate transform % from PostScript XY space to flutterwumper axis space. /coordxf {xfxyrelative} def % pick a set of rules % xfxyrelative is the default transform, shifting from absolute PS xy % values to relative flutterwumper values of suitable scale... % microsizing, XY home offsets, and tool diameter allowances are not yet % implemented. They can be added here... /xfxyrelative { curypos flutres mul sub flutres div exch % scale y to output res curxpos flutres mul sub flutres div exch % scale x to output res } def % /////////////// (K) PS PATH TO VECTOR CONVERTER ////////////////// % We will initially assume that ONLY paths ending with the -stroke- % operator OR strings ending with the -show- operator are to be vector % converted. We will also assume the default scale of one point. % At present, clips, fills, images, awidthshows, etc.. are IGNORED. % These features can easily be added as the need arises. % Define output resolution... /inch {72 mul} def /flutres 0.01 inch def % DEVICE DEPENDENT output resolution % Routines needed by -pathforall-... /lastxmove 0 def /lastymove 0 def /curxpos 0 def /curypos 0 def /movetoproc { flutpenup % pen or drill up coordxf % translate to flutter axes vectortostep % generate flutter file curypos flutres mul /lastymove exch store % save device yposn curxpos flutres mul /lastxmove exch store % save device xposn } def /linetoproc { flutpendown % pen or drill down coordxf % translate to flutter axes vectortostep % generate flutter file } def /curvetoproc { % should NOT happen! (Error - No curveto should remain!\n) write1 flush unflattenedcurvetoerror} def /closepathproc {lastxmove lastymove % force lineto linetoproc} def % Intercept PS commands for vector conversion. These MUST be in a dictionary % opened ONLY when generating flutterwumper files! /stroke {findflat setflat flattenpath {movetoproc}{linetoproc}{curvetoproc}{closepathproc} pathforall} def /show {false charpath stroke} def % //////////////// (L) CLOSE FLUTDICT DICTIONARY ////////////// end % place all above definitions into closed dictionary % ////////// (M) GENERATE TEST FILE - SIMPLE RECTANGLE ///////////// % The full flutdict definitions above are needed in the file or run % as a prefile before this code can be run. flutdict begin % open flutterwumper dictionary % Always use "\\" when you mean "\" in a PostScript filename string! /destfilename (C:\\tomj\\projects\\xyzada~1\\XYZ.out) def /inch {512 mul} def /flutres 0.0003 inch def % set DEVICE DEPENDENT output resolution destfilename (w) file % create an output file /dest exch store % A flutfile permits a comment header. Eventually standards similar to % .eps file headers can be used. For now, just say something... % ( % %! flut3.0 Synergetics % % XYZ Adapter test % ) writecr1 flutbegin % initialize flutterwumper fluthome % home flutterwumper to x=0 y=0 % Save as 5.0 compatible .EPS. Set origin to lower left. Set to 100 dpi % resolution. % ============= YOUR POSTSCRIPT SOURCE FILE STARTS HERE =============== % ============= MUST NOT INCLUDE SHOWPAGE, QUIT, ETC... ===============