bevis@EE.ECN.PURDUE.EDU (Jeff Bevis) (02/04/90)
In article <17807@rpp386.cactus.org>, woody@rpp386.cactus.org (Woodrow Baker) writes: >In article <9001290016.AA23487@en.ecn.purdue.edu>, bevis@EE.ECN.PURDUE.EDU (Jeff Bevis) writes: >> I need to create postscript files for use in generating PC board artwork. >> Unfortunately, I don't know postscript (yet), and the local libraries' books >> are out... Soo... I hope some kind soul out there might help me. I need > >Don Lancaster, 602-428-4073 has a rather complete schematic drawing package >already coded up in Postscript. I think the price is fairly reasonable, and >can save you an imense amount of work. >I have never been sucessful getting 'r' to work from within readnews >Cheers >Woody Thanks to you, and everyone else who replied... I have seen Lancaster's stuff and it seems OK. However, I decided to go with the brute-force method of getting things done. I bought the famed "red and blue" books and started writing my own layout software for the Amiga computer. I've already got the program up and running thanks to the Amiga's graphic-oriented programming environment... The postscript stuff looks to be pretty do-able, but I haven't yet gotten the knack of passing arguments to procedures. Example: I want to creat a 'donut' pad on the pcb image; I call the 'donut' procedure by placing the x,y of the donut on the stack, followed by the outer radius (black filled circle) and then the inner radius (white filled circle, concentric with first).... x y rout rin donut You see, I need to know the (x,y) coord twice; first for the large black circle, and second for the inner white one (the hole). How should I construct the donut procedure to avoid having to save all the arguments in variables? Is that my only hope? Here's more code: /black {0 setgray} def /white {1 setgray} def /donut { /rad1 exch def % puke-O /rad2 exch def % save all the arguments /yval exch def % in variables /xval exch def black xval yval rad2 0 360 arc fill % draw black circle white xval yval rad1 0 360 arc fill % then white one on top } def First of all, is this legitimate? Will it work? (haven't tried yet...) How would the guru's out there optimize/improve it? Thanks again. With help, I may actually be learning this. :-) ------------------------------------------------------------------------------- Jeff Bevis Purdue Univeristy School of Electrical Engineering bevis@en.ecn.purdue.edu Give me Amiga or nothing at all.
woody@rpp386.cactus.org (Woodrow Baker) (02/05/90)
In article <9002040147.AA16999@en.ecn.purdue.edu>, bevis@EE.ECN.PURDUE.EDU (Jeff Bevis) writes: > arguments in variables? Is that my only hope? Here's more code: > > /black {0 setgray} def > /white {1 setgray} def > > /donut > { /rad1 exch def % puke-O > /rad2 exch def % save all the arguments > /yval exch def % in variables > /xval exch def > > black xval yval rad2 0 360 arc fill % draw black circle > white xval yval rad1 0 360 arc fill % then white one on top > } def > My personal bias on this, is that the above is the way to do it. I nearly always like to put things in variables. There is another philosophy that says, leave them on the stack, but to me it is more difficult to debug that way. You could do it several ways, for example, you could rotat the stack until x is on the top, dup it, rotate it until y is on the top dup it, then rotate the top elements of the stack to get x y rad2 x y rad1 then do 0 360 arc... I assume that you have defined black and white to set the appropriate gray shades as needed... I don't have my red book handy, so am not going to take the time to write the stack rotations and duplications, but you can work that out. As always, it is a trade-off between time, codespace and variable space usage. It might be more eff. codewise to save into variables, but slower execution wise. Cheers Woody p.s. You should also get the GREEN book. It has a LOT of things to say about this and other topics. It really is a philosophy book about programming. Glenn did an excellent job on it. However, I don't recommend following his brace style, as it is a bit hard to read. Line up your opening and closing braces verticaly, like you would in 'C' (or should) and like the BEGIN/END in Pascal. It is much easier to follow stuff{ asdfasdfasdff asdfasdfsadf } def ^^^^^^^^^^^^^^^^^^NONO. stuff { asdfasdfasfd asdfasdfffdadsf } def ^^^^^^^^^^^^^^^^^^^Much easier to see. You are started on the right format.
pihlaja@cs.Helsinki.FI (Markku Pihlaja) (02/08/90)
Jeff (bevis@EE.ECN.PURDUE.EDU) in article 2630: > How should I construct the donut procedure to avoid having to save all the > arguments in variables? Is that my only hope? Woody (woody@rpp386.cactus.org) in article 2643: > There is another philosophy >that says, leave them on the stack, but to me it is more difficult to debug >that way. ... >I don't have my red book handy, so am not going to take the time to write >the stack rotations and duplications, but you can work that out. I've got mine handy, and since you definitely get more time-efficient code by not using variables, I'll work it out here. /donut { % Stack when calling: x y rin rout 0 setgray 3 index % x y rin rout x 3 index % x y rin rout x y 3 -1 roll % x y rin x y rout 0 360 arc fill % x y rin 1 setgray % x y rin 0 360 arc fill % - 0 setgray } bind def % Sorry, Woody, but I prefer the Glenn-style indentations There are two points to look at here. A lot of time is `wasted' when you have to load a value from a dictionary (that's what happens when the interpreter encounters a token like `rad1'). Having 3 stack operations instead of 12 dictionary operations is no doubt more effective. Note also the `bind def' at the end. From the Red Book: `For each element of proc that is an executable name, bind looks up the name in the context of the current dictionary stack (as if by load). If the name is found and its value is an operator object, bind replaces the name by the operator in proc.' I.e. instead of executing `setgray' or `index' or `roll', which means first loading the actual operator object from systemdict or wherever it's defined and only after that executing it, bind replaces the names by the operators already when defining the procedure. And if I've got it right, in the example this means as much as 10 dictionary operations less than without bind. Correct me if I'm wrong. I agree with Woody, using variables usually does make the code more readable. But if Jeff happens to need dillions of donuts drawn on one page, then it is definitely better to use only stack manipulations instead of variables. Markku ====================================== ======================= Markku Pihlaja Please tell me if my University of Helsinki, Finland English is not perfect. pihlaja@cs.helsinki.fi I'm a perfectionist. ====================================== =======================
batcheldern@hannah.enet.dec.com (Ned Batchelder) (02/10/90)
I recommend reading the Green Book, not to be indoctrinated into one particular method of writing procedures, but to get exposed to other ideas on the matter. Here's another way to do it: % rin rout x y `donut' -- /donut { gsave translate 0 setgray 0 0 3 -1 roll 0 360 arc fill 1 setgray 0 0 3 -1 roll 0 360 arc fill grestore } bind def Here, we use the x and y to translate the origin so that the pad is centered at 0,0. This reduces the amount of stack manipulation. I can't say whether it is more efficient this way, but I wouldn't be surprised. Notice that I also rearranged the arguments to reduce stack manipulations. If you look on page 75 of the Red Book (at least my edition), there is a figure explaining the non-zero winding rule that gives an idea: % rin rout x y `donut' -- /donut { gsave translate 0 0 3 -1 roll 0 360 arc 0 0 3 -1 roll 0 360 arcn fill grestore } bind def This avoids all of the setgray's, and makes a real donut, in that things will show through the "hole". It also does only one "fill", which will will help on the speed. A point about "local" variables: They're not local. If your program gets more complex, with procedures invoking other procedures, and each saves arguments in variables, you may find yourself having to worry about name clashes. All of the variables get stored in the same dictionary (unless you use a separate dict for each proc, another headache). This is also a huge hassle if you want to write recursive procedures, as you then need a separate dictionary for each invocation of the same procedure. And finally, if you use variables in your procedure, and bind the procedure, you can get into a lot of trouble when being included into other PostScript. Another topic for a longer posting. I recommend that you learn how to write procedures so that they need a minimum of stack manipulation, and then avoid the variables. Your code will be shorter and faster. Ned Batchelder, Digital Equipment Corp., BatchelderN@Hannah.enet.DEC.com Disclaimer: all of the code in this posting was typed off the top of my head, but the ideas are valid.
woody@rpp386.cactus.org (Woodrow Baker) (02/11/90)
In article <8260@shlump.nac.dec.com>, batcheldern@hannah.enet.dec.com (Ned Batchelder) writes: > I recommend reading the Green Book, not to be indoctrinated into one > particular method of writing procedures, but to get exposed to other > ideas on the matter. code deleted> > Notice that I also rearranged the arguments to reduce stack manipulations. > This is a very good general technique for reducing time and complexity. > If you look on page 75 of the Red Book (at least my edition), there is a > figure explaining the non-zero winding rule that gives an idea: > > % rin rout x y `donut' -- > > /donut { > gsave > translate > 0 0 3 -1 roll 0 360 arc > 0 0 3 -1 roll 0 360 arcn > fill > grestore > } bind def > > This avoids all of the setgray's, and makes a real donut, in that things > will show through the "hole". It also does only one "fill", which will > will help on the speed. > A point about "local" variables: They're not local. If your program gets > more complex, with procedures invoking other procedures, and each saves > arguments in variables, you may find yourself having to worry about name > clashes. All of the variables get stored in the same dictionary (unless > you use a separate dict for each proc, another headache). This is also a > huge hassle if you want to write recursive procedures, as you then need > a separate dictionary for each invocation of the same procedure. Boy, isn't that the truth! One of the reasons that I avoid recursion like the plague. Recursion also total obscures what is going on. Even in 'C'. You might, if you are going to try recursion, try creating dynamic dictionaries by creating a new dictionary name and copying the old one into it before executing the recurse. I'm not even sure that would work, but you can do it, as far as I know. I've never tried it. I don't think I want to. I would be inclined to simulate my own stack..... t E > And finally, if you use variables in your procedure, and bind the > procedure, you can get into a lot of trouble when being included into > other PostScript. Another topic for a longer posting. > > I recommend that you learn how to write procedures so that they need a > minimum of stack manipulation, and then avoid the variables. Your code > will be shorter and faster. Verily, Verily, hear ye! It might be less maintainable, but definitly shorter and faster. m Cheers> Woody
rodgers@csc.wcc.govt.nz (02/12/90)
I'm surprised no-one suggested a fat line doughnut. How about this
(totally untried) procedure:
% stack when calling: x y rin rout
/donut { %def
gsave
1 index % x y rin rout rin
sub % x y rin thickness
dup setlinewidth
2 div add % x y rcentre
0 360 % x y rcentre 0 360
3 -1 roll % x y 0 360 rcentre
arc stroke
grestore
} bind def
Unfortunately I don't have my red book handy so I'm not sure if this
is even close to right but I'm sure someone will delight in telling me
if it's not. Has anyone got enough time and enthusiasm to muck
about with usertime to see how all these donuts compare? Woody???? I
would really be interested to know how fills compare with strokes in a
case like this. My experience with fills has been that they are
really slow.
--
Mark Rodgers Computer Services Section
rodgers@csc.wcc.govt.nz Wellington City Council
Telephone (04) 733-130 P.O. Box 2199, Wellington, New Zealand