I want to make my patern to be in many colors. I mean I want my DoLine to make each time line with simmilar but not the same colour. So I did
/red 0.41 def
/green 0.1 def
/blue 0.21 def
/incRed {/red red 0.01 add} def
/incGreen {/green green 0.03 add} def
/incBlue {/blue blue 0.05 add} def
and my DoLine
/DoLine
{
incRed
incGreen
incBlue
red green blue setrgbcolor
rotation rotate
0 linelen rlineto
currentpoint stroke
translate 0 0 moveto
} def
But it output my patern in only one colour which is set as
/red 0.41 def
/green 0.1 def
/blue 0.21 def
Is there something I missed? Here is my all code if u need it
%!
/Helvetica findfont 8 scalefont setfont
/ang1 -141 def
/ang2 {-2 ang1 mul} def
/linelen 36 def
/depth 0 def
/down {/depth depth 1 add def} def
/up {/depth depth 1 sub def} def
/red 0.41 def
/green 0.1 def
/blue 0.21 def
/incRed {/red red 0.01 add} def
/incGreen {/green green 0.03 add} def
/incBlue {/blue blue 0.05 add} def
/CrownPos
{
/x 300 def
/y 300 def
x y moveto
} def
/DoLine
{
incRed
incGreen
incBlue
red green blue setrgbcolor
rotation rotate
0 linelen rlineto
currentpoint stroke
translate 0 0 moveto
} def
/Print
{
gsave
.62 .62 scale
2 setlinewidth
down DoLine
depth 8 le
{
ang1 rotate Print
ang2 rotate Print
} if
up
grestore
} def
/Crown
{
/rotation 0 def
CrownPos Print
stroke
/rotation 270 def
CrownPos Print
stroke
/rotation 90 def
CrownPos Print
stroke
} def
Crown
600 600 translate
180 rotate Crown
showpage
Two problems with these color increment routines: 1) they didn't set the new value back into the variable (i.e. missing a def) and 2) they increment too quickly, reaching white way too soon. Try these reworked versions instead:
/incRed { /red red 0.0001 add def } def
/incGreen { /green green 0.0003 add def } def
/incBlue { /blue blue 0.0005 add def } def
Related
Does anyone have example code in gnuplot for a pie chart? I can't find any great example with a simple graph and the text around it and in it with the % signs that shows easily how much each part has of the circle.
Some example data:
Management frames 4596
Control frames 70173
Data frames 40347
TCP packets 36864
HTTP packets 525
ICMP packets 47
Total frames 115116
Updated:
After some years, I came again across this post, and I thought the code looked pretty messy. Therefore an attempt to improve and clean it up.
The following code is a bit different from the link I referenced above.
instead of a predefined color sequence or number codes in a separate list, the colors of the sections are given in the datablock (or datafile) next to the item/number by the names of predefined colors in gnuplot (see also https://stackoverflow.com/a/55736522/7295599). Because palette is used you can enter either colorname or hex-code, e.g. magenta or 0xff00ff.
the labels are aligned left or right depending on their position relative to 0.
you can choose the starting angle by PieStart and "rotation"-direction by PieDirection of the pie-chart
you can add individual radial and angular offsets for segments and labels
as you can see, there is no need for the total sum in the raw data. The total sum will be calculated automatically.
the reason why I define various functions f(n) which actually do not depend on n is to get the current values of other variables (at the time of calling the function) instead of passing a lot of parameters to the functions.
I hope you can adapt this code to your needs.
Code: (works with gnuplot>=5.0.0)
### pie-chart with labels with gnuplot
reset session
set size square
set angle degrees
set border 0
unset colorbox
unset tics
unset key
$Data <<EOD
# label value color SRoff SAoff LRoff LAoff
"Alpha" 85843 red 0 0 0 0
"Beta" 44000 green 0.2 45 0.2 0
"Gamma" 25399 blue 0 0 0 0
"Delta" 18451 magenta 0 0 0 0
"Epsilon" 12344 yellow 0 0 0 0
"Zeta" 11999 cyan 0 0 0 0
"Eta" 9000 orange 0 0 0 0
"Theta" 8500 0xb0f060 0 0 0.03 0
"Iota" 4711 dark-violet 0 0 0.12 0
EOD
colLabel = 1 # label
colValue = 2 # segment value
colColor = 3 # segment color, either color name or 0xRRGGBB value
colSegRoff = 4 # radial segment offset
colSegAoff = 5 # angular segment offset
colLabRoff = 6 # radial label offset
colLabAoff = 7 # angular label offset
# define a palette from colornames of the datafile/datablock in column colColor
set table $Dummy
myPalette = ''
plot $Data u (myPalette = myPalette.(myPalette eq '' ? '' : ', ').sprintf('%d "%s"',$0,strcol(colColor)),$0) with table
myPalette = '('.myPalette.')'
unset table
set palette defined #myPalette
stats $Data u colValue nooutput # get total sum from column colValue
TotalSum = STATS_sum
set xrange[-1.5:1.5]
set yrange[-1.5:1.5]
PieStart = 90 # 0 = 3 o'clock, 90 = 12 o'clock
PieDirection = -1 # -1 clockwise, 1 counterclockwise
Radius = 1.0
RadiusLabelOff = 0.05 # default radial label offset
SegPosX(n) = column(colSegRoff)*cos((a2+a1+column(colSegAoff))*0.5)
SegPosY(n) = column(colSegRoff)*sin((a2+a1+column(colSegAoff))*0.5)
LabPosX(n) = (Radius+RadiusLabelOff+column(colLabRoff))*cos((a2+a1+column(colLabAoff))*0.5)
LabPosY(n) = (Radius+RadiusLabelOff+column(colLabRoff))*sin((a2+a1+column(colLabAoff))*0.5)
a1=a2=PieStart
getAngles(n) = (a1=a2, a2=a2+sgn(PieDirection)*column(colValue)/TotalSum*360)
getLabel(n) = sprintf("%s %.1f%%", strcol(colLabel), column(colValue)/TotalSum*100)
set multiplot layout 2,1
plot $Data u (getAngles(0), SegPosX(0)):(SegPosY(0)):(Radius):(PieDirection<0?a2:a1):(PieDirection<0?a1:a2):($0) \
with circles fs solid 1.0 lc palette notitle,\
'' u ( getAngles(0), Align=LabPosX(0)):(LabPosY(0)): (Align>0? getLabel(0) : '') with labels font ",10" left, \
'' u ( getAngles(0), Align=LabPosX(0)):(LabPosY(0)): (Align<0? getLabel(0) : '') with labels font ",10" right
PieDirection = +1
a1=a2=PieStart
replot
unset multiplot
### end of code
Result:
I have a Red container rotated by -13 degrees, inside this container there is a Pink Square also rotated by -13 degrees.
Using only these informations below I'm trying to find the pink square transform relative to the origin (top,left) (0,0)
The relative transform coordinate is how much I need to translate inside the parent. And the bounding box is just the size with rotation included (it's the black box on the screenshot)
Pink Square
size before rotation
height : 398
width : 398
size after rotation
height : 477
width : 477
Bounding box
x : 179
y : 230
Relative transform to parent
x : 0
y : 49
Rotation
-13 deg
Red Container
size before rotation
height : 632
width : 447
size after rotation
height : 716
width : 577
Bounding box
x : 179
y : 182.28
Relative transform to parent
x : 279
y : 182
Rotation
-13 deg
Here is what I tried to do
yCoordinate = pink.relativeTransform.y + redContainer.boundingBox.y
xCoordinate = pink.relativeTransform.x + redContainer.boundingBox.x
I managed to get the yCoordinate right but I can't get the x coordinate also I'm worried that this will works for all angles
If you represent the transforms as matrices, you will get the answer pretty easily (note that I will use the word transform to denote the entire transformation, including rotations, and not just the offset vector). Btw, your image shows a rotation in positive direction (in a mathematical sense), so I will assume that it is actually +13°.
To get the transformation matrix for a rotation of angle phi and offset vector (tx, ty), we can employ the following form:
/ cos(phi) -sin(phi) tx \
T = | sin(phi) cos(phi) ty |
\ 0 0 1 /
Hence, the transformation of the red rectangle with respect to the origin would be:
/ 0.974 -0.225 279 \
TRed = | 0.225 0.974 182 |
\ 0 0 1 /
The transformation of the pink square with respect to the red rectangle would be (no rotation relative to parent, just a translation):
/ 1 0 0 \
TPink = | 0 1 49 |
\ 0 0 1 /
To get the transformation of the pink square with respect to the origin, we just multiply the two matrices:
/ 0.974 0.225 267.977 \
TRed * TPink = | 0.225 0.974 229.744 |
\ 0 0 1 /
We can see that the first part is the same rotation as in TRed, i.e., a rotation by 13°. The translation (which is the vector you are looking for) is (267.977, 229.744).
In general, this translation vector is:
/ cos(phi) * tPinkX - sin(phi) * tPinkY + tRedX \
\ sin(phi) * tPinkX + cos(phi) * tPinkY + tRedY /
Can you tell me an easy way to draw graph(2+x, sin(x), cos(x+3)/3.....) in PS format?
For example, I want to draw f(x) = 2+x, with the following values:
Table of values:
Value of X = -5 | -4 | -3 | -2 | -1 | -0 | 1 .....
Value of Y = -3 | -2 | -1 | 0 | 1 | 2 | 3 .....
How to draw this graph? Draw lineto, draw polygon or use curve command?
What do you think is the best solution?
There are a number of different ways you can do this. If you have a set of coordinates to plot, you can put them in an array, and draw the points while iterating through the array.
/XValues [ -5 -4 -3 -2 -1 0 1 ] def % eg. XValues 0 get ==> -5
/YValues [ -3 -2 -1 0 1 2 3 ] def % YValues 0 get ==> -3
XValues 0 get YValues 0 get % X[0] Y[0]
moveto % move to first point
1 1 XValues length 1 sub { % i push integer i = 1 .. length(XValues)-1 on each iteration
XValues % i XVal push X array
1 index % i XVal i copy i from stack
get % i x get ith X value from array
YValues % i x YVal
2 index % i x YVal i i is 1 position deeper now, so 2 index instead of 1
get % i x y
lineto % i line to next point
pop % discard index variable
} for
Now, of course in Postscript the origin is at the bottom left corner by default, and 72 points make an inch. So these values (-5, -4, -2, etc) are not even going to be visible. So you usually want to start by translating to the center of where you want to draw the graph.
/Center { 300 400 } def % roughly the middle of US letter-size paper
Center translate
Then you want to scale the coordinate system so the graph features are visible. Scalefactor = DesiredSize / ExistingSize.
You could scan the dataset to find the existing size.
/Xmin 1000000 def % really high
/Xmax -1000000 def % really low
XValues { % x forall pushes each X value
dup Xmin lt { % x lower than Xmin?
dup /Xmin exch def % x set Xmin
} if % x
dup Xmax gt { % x higher than Xmax?
/Xmax exch def % set Xmax
}{ % x else (lower than Xmax)
pop % discard X value
} ifelse
} forall
/Datasize Xmax Xmin sub def % X size is (Xmax-Xmin)
6 72 mul DataSize div % scalefactor 6*72/(Xmax-Xmin)
dup % scalefactor scalefactor use same scaling for x and y
scale
But there's a snag when you're doing line-drawing. The width of the lines you draw also depend upon the current coordinate space, so if you scale up the space by a large factor, your lines will become undesirably wide. You can either unscale back to the normal space after you describe the path but before you call stroke. Or, fix the linewidth at the same time you scale.
Since we know how much we've increased the line width (it's the same scaling factor), we can adjust the linewidth graphics parameter in the inverse direction.
1 % push 1 for division
6 72 mul DataSize div % 1 scalefactor 6*72/(Xmax-Xmin)
dup dup % 1 scalefactor scalefactor scalefactor
scale % 1 scalefactor
div % 1/scalefactor
currentlinewidth mul setlinewidth % adjust line width
Now, since this is a graph of a function, we don't actually need the tables of values. We can calculate values on the fly by evaluating the function.
/func { 3 add cos 3 div } def % f(x) = cos(3+x)/3 define function y=f(x)
/Xini -5 def % named loop control parameters
/Xfin 1 def
/Xstep 1 def
Xini dup dup func moveto % moveto first point
Xstep add Xstep Xfin { % x
dup % x x
func % x f(x)
lineto % line to next point
} for
stroke
Finally, if you can take the derivative of the function (create a function which calculates the slope of the original function at each point), then you can use my answer over on TeX.SE to draw the graph with many curve segments instead of lines.
I have a data-set that consist of edges and colors, and I want to plot them on a web-like manner, with lines and circles such as the picture below, and possibly with cluster coloring.
The data is organized like this:
point1a_x point1a_y color
point1b_x point1b_y color
point2a_x point2a_y color
point2b_x point2b_y color
(...)
point2n_x point2n_y color
point2n_x point2n_y color
How would I go about doing it on gnuplot?
Okay, so I figured it out myself and I'll leave the details here to help anyone with the same questions.
Single color graph with labels on the nodes:
This will generate a graph much like the one on the question, with lines connecting circles with labels inside.
plot 'edges.dat' u 1:2 with lines lc rgb "black" lw 2 notitle,\
'edges.dat' u 1:2:(0.6) with circles fill solid lc rgb "black" notitle,\
'edges.dat' using 1:2:($0) with labels tc rgb "white" offset (0,0) font 'Arial Bold' notitle
With little changes it can exaclty match the one on the question picture.
plot 'edges.dat' u 1:2 with lines lc rgb "black" lw 2 notitle,\
'edges.dat' u 1:2:(0.8) with circles linecolor rgb "white" lw 2 fill solid border lc lt 0 notitle, \
'edges.dat' using 1:2:($0) with labels offset (0,0) font 'Arial Bold' notitle
Cluster-colored graph:
unset colorbox
set palette model RGB defined ( 0 0 0 0 , 1 1 0 0 , 2 1 0.9 0, 3 0 1 0, 4 0 1 1 , 5 0 0 1 , 6 1 0 1 )
plot 'edges.dat' u 1:2:3 with lines lc palette notitle,\
'edges.dat' u 1:2:(0.15):3 with circles fill solid palette notitle
The data used on all plots follow this structure:
21.53 9.55 0
24.26 7.92 0
5.63 3.23 1
2.65 1.77 1
5.63 3.23 0
4.27 7.04 0
(...)
The accepted answer didn't quite work out for me. Here is how I had to change it:
The format of the input file
# A vertex has 3 fields: x coordinate, y coordnate and the label
# An edge consists of two points in consecutive lines
# There must be one or more blank lines between each edge.
21.53 9.55 A
24.26 7.92 B
5.63 3.23 C
2.65 1.77 D
5.63 3.23 C
4.27 7.04 E
#...
The big difference compared to the other answer is that the labels belong to vertices, not edges.
Also note that I changed the labels to letters instead of numbers. Labels can be any string and this makes it clearer that they are not sequential indexes in the example.
The plotting command
plot \
'edges.dat' using 1:2 with lines lc rgb "black" lw 2 notitle,\
'edges.dat' using 1:2:(0.6) with circles fill solid lc rgb "black" notitle,\
'edges.dat' using 1:2:3 with labels tc rgb "white" offset (0,0) font 'Arial Bold' notitle
Big change here is that now when plotting the labels we plot the 3rd field instead of the $0 field, which is a sequential number.
I came across this question and thought the data input can be made more user-friendly. In case you need to change x,y coordinates of a certain point you probably don't want to search through all connectors and change the coordinates everywhere accordingly. So, instead the example below is working with node IDs and connecting lines between two IDs.
The x,y coordinates and colors are stored in a string and the function strstrt() is used to create a lookup. The script below is a starting point and can be expanded, e.g. dashed lines, different point shapes, string labels, etc.
The datafile looks like this:
first block: IDs with x,y coordinates and color
second block, separated by two(!) blank lines: IDs to be connected and color of the line.
Data: SO20406346.dat
# ID x y PointColor
1 2.0 8.0 0xffaaaa
2 6.0 9.0 0xaaffaa
3 9.0 6.0 0xaaaaff
4 5.0 5.0 0xffaaff
5 6.0 2.0 0xffffaa
6 1.0 1.0 0xaaffff
73 9.2 1.3 0xcccccc
A 8.0 8.0 0xcccccc
XY 2.0 4.0 0xcccccc
# ID1 ID2 LineColor
1 4 0x0000ff
2 4 0x000000
3 4 0x00ff00
4 4 0x000000
5 4 0x000000
6 5 0xff0000
73 3 0xcccccc
73 4 0xcccccc
73 5 0xcccccc
A 2 0xcccccc
A 3 0xcccccc
XY 1 0xcccccc
XY 4 0xcccccc
XY 6 0xcccccc
Edit: changed to work with string "IDs" as well.
Script: (works for gnuplot>=4.6.0, March 2012)
### plot a node graph
reset
FILE = "SO20406346.dat"
IdIdxs = XYs = ' '
stats FILE u (IdIdxs=IdIdxs.sprintf("%s:%d ",strcol(1),$0), \
XYs=XYs.sprintf("%g %g ",$2,$3)) index 0 nooutput
Px(i) = real(word(XYs,2*i+1))
Py(i) = real(word(XYs,2*i+2))
getIdx(col) = (c0=strstrt(IdIdxs,sprintf(" %s:",strcol(col))), \
c1=strstrt(IdIdxs[c0+1:],' ')+c0, \
s0=IdIdxs[c0:c1], c2=strstrt(s0,':'), int(s0[c2+1:]))
set size ratio 1
set key noautotitle
set offsets 0.25,0.25,0.25,0.25
plot FILE index 1 u (idx0=getIdx(1),x0=Px(idx0)):(y0=Py(idx0)): \
(idx1=getIdx(2),Px(idx1)-x0):(Py(idx1)-y0):3 w vec lw 2 lc rgb var nohead, \
'' index 0 u 2:3:4 w p pt 7 ps 6 lc rgb var, \
'' index 0 u 2:3 w p pt 6 ps 6 lc rgb "black", \
'' index 0 u 2:3:1 w labels
### end of script
Result:
First of all, I would like to tell You, I have really limited time.
So i would appricate every help with that task.
I have to draw a regular polygon with every diagonal.
( attached file: http://s30.postimg.org/5m6cvd7u9/polygon_with_all_diagonal.png )
Could someone help me with this?
Edit:
Please check scource code:
300 200 translate
/S 28 def
S S scale
4 S div setlinewidth
1 setlinecap
1 setlinejoin
/n 5 def
/r 5 def
newpath
r 0 moveto
1 1 n 1 sub
{
/i exch def
360 n div i mul cos r mul
360 n div i mul sin r mul lineto
} for
closepath
stroke
Thats all what i could do, i have no more idea, how to draw the diagonals.
Cutting and pasting from my other graph drawing routines I get something like this (there is a bit of redundant code but that's because one may want to make the adjacency list on your own):
% routines
/ngon{ [ exch 360 exch div
0 exch 359.9 {
[ exch dup cos 40 mul exch sin 40 mul ]
} for
]
} def
/fmtrx {[ 0 1 4 3 roll 1 sub { [ 1 1 4 3 roll {pop 1} for ] } for ]} def
/drawnodelist { % nodes drawnodelist
{
newpath aload pop 2.5 0 360 arc closepath fill
} forall
} def
/drawedges { % adjacency_matrix nodes drawedges
/drawnodes exch def
dup
/drawlist exch def
/row 0 def
{
/col 0 def
{
pop
drawlist row get col get 1 eq
{
newpath
drawnodes row get aload pop moveto
drawnodes col get aload pop lineto stroke
} if
/col col 1 add def
} forall
/row row 1 add def
} forall
} def
/drawngon {
dup /polygon exch ngon def
polygon drawnodelist % remove this line if you do not want dots
fmtrx polygon drawedges
} def
% call routines
90 rotate
6 drawngon
Here is a sample of different connected polygons produced:
Here is my take:
/n 7 def % number of sides
/R 100 def % radius of circumscribed circle
R 2 mul dup translate
/A 360 n div def
% point given index
/P {
A mul dup
cos R mul
exch
sin R mul
} bind def
0 1 n 1 sub {
dup P 3 2 roll
1 add 1 n 1 sub {
P moveto 2 copy lineto stroke
} for
pop pop
} for
showpage
Arguably a more fitting description of the problem is that you are trying to draw a fully connected graph.
The [Wikipedia-entry on PostScript][http://en.wikipedia.org/wiki/PostScript#Units_of_length] reveals a simple procedure that can be used to solve your problem:
For example, in order to draw a vertical line of 4 cm length, it is
sufficient to type:
0 0 moveto
0 113.385827 lineto stroke
Observe that the above sample can be easily adapted to draw any line; that is, it does not necessarily have to be a vertical line. Now, for each vertex of your polygon draw a line to every other vertex.
Knowing that the polar coordinates of the vertices of a n-polygon will be (rad,i(2π/n)) for i=0..n-1, you can generate the postscript code to describe a polygon path from another language, like C.
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void emitpoly (double x, double y, int n, double r, int up) {
int i;
double a;
printf("%f %f moveto\n", x+r*cos(up?M_PI/2.0:0.0), y+r*sin(up?M_PI/2.0:0.0));
for(i=1; i<n; i++){
a=(double)i*(2*M_PI)/n;
if (up) a += M_PI/2.0;
printf("%f %f lineto\n", x+r*cos(a), y+r*sin(a));
}
printf("stroke\n");
}
void emitpolyweb (double x, double y, int n, double r, int up) {
int i,j;
double a,b;
for(i=0; i<n; i++){
a=(double)i*(2*M_PI)/n;
if (up) a += M_PI/2.0;
printf("%f %f moveto\n", x+r*cos(a), y+r*sin(a));
for(j=0; j<n; j++){
b=(double)j*(2*M_PI)/n;
if (up) b += M_PI/2.0;
printf("%f %f lineto\n", x+r*cos(b), y+r*sin(b));
printf("closepath\n");
}
}
printf("stroke\n");
}
int main(int argc, char**argv) {
int up = 0, n = 3;
double x = 0.0, y = 0.0, r = 1.0;
if (argc>1) x = strtod(argv[1],NULL); // set x from 1st arg, if present
if (argc>2) y = strtod(argv[2],NULL); // set y from 2nd arg, if present
if (argc>3) n = strtol(argv[3],NULL,10); // set n from 3rd arg, if present
if (argc>4) r = strtod(argv[4],NULL); // set r from 4th arg, if present
if (argc>5) up = strcmp(argv[5],"up") == 0; // rotate 90-degrees if 5th arg is "up"
//emitpoly(x,y,n,r,up);
emitpolyweb(x,y,n,r,up);
printf("showpage\n");
return 0;
}
I came up with some results in this area while playing with venn diagrams, and further in geodesic flowers.
This code implements the polygon as a control structure which takes a radius and a repeat count (number of polygon points) and calls the user-defined procedure at each point (by scaling and rotating the CTM). So it's a loop, that makes the user point (1,0) map to successive points of the polygon for each iteration. Using this function, the figure itself is fairly simple. Being a control structure, it is not limited to drawing polygons but can also be used to position smaller drawings at the vertices of a polygon, or even to generate an array of vertex points.
Note also, that this code doesn't have to call sin or cos, because that is handled by rotating the coordinate system. The big trick here is using the scanner to produce an optimized loop body (procedure array).
After placing the init incr max control values on the stack for the for loop, it performs ({...}) token pop exch pop bind end exec which dynamically creates a procedure and executes the call to for. token called (successfully) on a string will yield several values on the stack: an empty string, the scanned-token itself (a ps object of the appropriate type), and the Boolean true. So the pop exch pop just trims the Boolean and the empty string. bind then replaces operator names with the operators themselves, so we perform fewer hash-lookups during the loop. Then end removes our temporary dictionary, before execing the procedure.
This works because all of the variables have been directly substituted by the token operator since they are written as //immediate-names and the temporary dictionary is available on the dict stack when token does this. Removing the dict makes this a true control structure that will not interfere with the meaning of any names used by the user-proc, even if it uses names like s, p, and m.
The generated procedure body {{//s setmatrix rotate //p exec} for //m setmatrix} has the user proc embedded //p and two matrices, //s a matrix pre-scaled by the rad argument and //m a matrix to restore at the end. The for loop body {//s setmatrix rotate //p exec} receives an angle argument as part of the loop control. It resets the CTM to our scaled, oriented matrix //s setmatrix, then rotates by the argument angle rotate, then executes the user-proc //p exec.
%rad n {proc} atpoly -
%call proc having rotated+scaled
%so (1,0) is each vertex of rad-radius n-polygon
/atpoly {
4 dict begin /p exch def /n exch def % rad
/m matrix currentmatrix def
dup scale
/s matrix currentmatrix def
0 360 n div 359.9 %0 dAng maxAng %{}for
({
{
//s setmatrix
rotate
//p exec
} for
//m setmatrix
}) token pop exch pop %instantiate code template
bind
end exec % run loop without dictionary
} bind def
300 400 translate
/rad 100 def
/n 9 def
rad n {
1 0 moveto
1 n {
1 0 lineto
closepath
} atpoly
} atpoly
stroke
To use atpoly, we have to translate to the desired center-point. Then the pseudo-code is:
for each point in poly
moveto point
for each point in poly
lineto point
line back to last moveto point (closepath)
stroke
The are at least two ways to draw just the polygon with atpoly. You can add a redundant moveto at the beginning and use lineto in the proc, or you can use a procedure which does moveto the first time and redefines itself to do lineto thereafter. Here's a variant of the script part that shows both ways, and the interconnected poly.
/rad 100 def
/n 9 def
gsave
400 200 translate
rad n {
1 0 moveto
1 n {
1 0 lineto
closepath
} atpoly
} atpoly
stroke
grestore
gsave
200 200 translate
rad 0 moveto
rad n {
1 0 lineto
} atpoly
closepath stroke
grestore
gsave
200 400 translate
/action { moveto /action { lineto } def } def
rad n {
1 0 action
} atpoly
closepath stroke
grestore
output:
I suppose these blocks could be wrapped up as procedures. These still require the atpoly function from above.
/drawpoly { % rad n x y
gsave
translate
1 index 0 moveto
{
1 0 lineto
} atpoly
closepath stroke
grestore
} def
% rad and n are needed in the outer call to atpoly,
% then n is needed for each iteration.
% To avoid adding a dictionary, duplicate n n-times.
% Once for each iteration.
/drawpolyweb { % rad n x y
gsave
translate % rad n
dup % rad n n
{ dup } repeat % rad n^(n+1)
1 add % rad n^n n+1
-1 roll % n^n rad
%pstack() =
1 index % n^n rad n
{
1 0 moveto % n^(n-i)
1 exch % n^(n-i-1) 1 n
{
1 0 lineto
closepath
} atpoly
} atpoly
stroke
grestore
} def
Then the usage becomes simpler:
%rad n x y
100 9 300 200 drawpoly
100 9 300 500 drawpolyweb