The Metapict Weblog
The Metapict Weblog
Jens Axel Søgaard, jensaxel@soegaard.internet
1. Introduction
This weblog options small packages utilizing Metapict to attract figures and pictures.
Write to Jens Axel Søgaard at jensaxel@soegaard.internet with feedback and needs for brand new matters.
2. Arrows
person window which have an (x)-range from -1 and 1 and an (y)-range from -1 to 1.
Given a curve
c
the shape
draw-arrow
is used to attract the curve
and arrow head(s). Let’s outline some curves we are able to flip into arrows.
Right here
(arc C A B)
attracts a round arc from (A) to (B) with heart (C).
> (draw (draw-arrow c1) (draw-arrow c2) (draw-double-arrow c3))
The default is to attract an arrow head on the finish of the curve.
Use
draw-double-arrow
to attract arrow heads at each in the beginning and finish
of the curve.
however let’s display that there are various arrow heads out there.
> (draw (draw-arrow c1 #:head arrow-head #:tail line-head) (draw-arrow c2 #:head harpoon-up #:tail harpoon-down) (draw-arrow c3 #:head hook-head #:tail reverse-hook-head))
Right here “ah” is brief for “arrow head”.
A number of parameters have an effect on the dimensions and form of the default arrow head. An important
is
ahlength
which holds the size of the arrowhead.
> (draw (my-arrow 0.04 c1) (my-arrow 0.08 c2) (my-arrow 0.16 c3))
The unit utilized by
ahlength
is person coordinates. This could at instances
be inconvenient, so you should use
(px x)
to compute how massive (x) pixels
are in person coordinates.
> (draw (my-arrow (px 4) c1) (my-arrow (px 8) c2) (my-arrow (px 16) c3))
Now, let’s look nearer on the default arrow head:
> (ahlength (px 100)) > (draw-arrow (curve (pt 0 0) — (pt 1 0)))
The default worth for the parameter
ahangle
is 45 (levels).
Let’s attempt completely different values for the parameter
ahangle
.
And to make room for a number of arrow heads, we’ll scale back the pict dimension.
> (set-curve-pict-size 100 100) > (ahlength (px 50))
> (define (head angle) (ahangle angle) (draw-arrow (curve (pt 0 0) — (pt 1 0)))) > (beside (head 20) (head 30) (head 40) (head 50) (head 60))
When you’ve got two arrows pointing to the identical level, and you are feeling the
overlap of the 2 arrow heads is 2 massive, think about using a smaller worth
for
ahangle
.
ahflankangle
controls the “flank angle”. The default is 10 (levels).
> (ahangle 45)
> (define (head angle) (ahflankangle angle) (draw-arrow (curve (pt 0 0) — (pt 1 0)))) > (beside (head 5) (head 10) (head 15) (head 20) (head 25))
ahtailcurvature
controls the “tail curvature”. The default is 2.
> (ahflankangle 10)
> (define (head curvature) (ahtailcurvature curvature) (draw-arrow (curve (pt 0 0) — (pt 1 0)))) > (beside (head 2) (head 4) (head 8) (head 16) (head 32))
ahratio
controls the dimensions of the indentation
relative to the size of the arrow head. The default worth is 0.9.
> (ahtailcurvature 2)
> (define (head ratio) (ahratio ratio) (draw-arrow (curve (pt 0 0) — (pt 1 0)))) > (beside (head 1) (head 0.9) (head 0.8) (head 0.7) (head 0.6))
> (ahflankangle 0) > (ahtailcurvature 0) > (ahratio 1) > (draw-arrow (curve (pt 0 0) — (pt 1 0)))
Let’s set our parameters again to the default:
> (ahlength (px 4)) > (ahangle 45) > (ahflankangle 10) > (ahtailcurvature 2) > (ahratio 0.89) > (draw-arrow (curve (pt 0 0) — (pt 1 0)))
In the event you want particular values for a couple of arrows, then move the settings as key phrase arguments.
> (draw (draw-arrow c1 #:size (px 8)) (draw-arrow c2 #:length-ratio 1) (draw-double-arrow c3 #:head-angle 30))
> (ahlength (px 8))
> (draw (draw-arrow c1 #:colour “purple”) (draw-arrow c2 #:fill-head #f) (draw-arrow c3 #:stem-color “blue” #:head-color “cyan” #:head-outline-color “darkgreen”))
3. Common polygons
On this instance we’ll see a number of methods of drawing common polygons.
metapict
and setting the “curve pict dimension”.
When a curve is drawn by
, the curve is drawn on a pict with this dimension.
Let’s draw a bit of take a look at curve to see this.
> (draw (level “purple” (pt -1 0)) (level “violet” (pt 1 1)) (level “blue” (pt 0 -1)) (curve (pt -1 0) — (pt 1 1) — (pt 0 -1)))
We see that the default person coordinates has an (x)-range
[text{from } x_text{min}=-1 text{ to } x_text{max}=1, ]and an (y)-range given by
[text{from } y_text{min}=-1 text{ to } y_text{max}=1. ]We’ll keep on with this default window for now.
> (draw (color “grey” (draw (circle 1))) (curve (pt 1 0) — (pt (cosd 120) (sind 120)) — (pt (cosd 240) (sind 240)) — cycle))
Right here
(cosd d)
and
(sind d)
computes the cosine and sine respectively to (d) levels.
(pt@d r θ)
will return the purpose (P) that {that a} distance (r) from
the origo (O(0,0)) and the angle between the (x)-axis and (P) will probably be (θ) levels.
The
d
in
stands for levels.
Utilizing this operate, we are able to write our instance as:
> (draw (color “grey” (draw (circle 1))) (curve (pt@d 1 0) — (pt@d 1 120) — (pt@d 1 240) — cycle))
Similarly we are able to draw an everyday polygon with (n=4) sides:
> (draw (color “grey” (draw (circle 1))) (curve (pt@d 1 0) — (pt@d 1 90) — (pt@d 1 180) — (pt@d 1 270) — cycle))
We start to see a sample. The factors on the common polygon
with (n) sides could be computed like this:
> (define (regular-points n) (def d (/ 360 n)) (for/list ([i n]) (pt@d 1 (* i d))))
With a purpose to draw the polygon, we have to add the trail connector
between every level – and append
.
Since
is a macro, we are able to’t apply
to our path description,
einstead we use the operate model named
curve*
.
> (require racket/listing)
> (define (common n) (def ps (regular-points n)) (def path (append (add-between ps —) (list — cycle))) (curve* path))
And we are able to now draw an everyday polygon with (n=6) sides:
> (draw (common 6))
4. Venn Diagrams
On this part we’re drawing Venn diagrams.
Let’s start by drawing two circles with radius 5.
> (def r 5) > (def s (/ r 1.8)) > (def c1 (circle (pt (– s) 0) r)) > (def c2 (circle (pt s 0) r)) > (draw c1 c2)
Now let’s decide some good colours:
The decision
(color-med f color1 color2)
interpolates between the 2 colours.
Let’s additionally decide a font:
> (def font (make-similar-font (new-font) #:dimension 15 #:face “Arial”))
We at the moment are able to deal with the issue of filling the within of each circles.
The operate
is used to fill a curve. The pen is used for outlines
and the comb is used for areas. Setting
will fill
the within with a strong colour.
The rule used to find out whether or not a degree (P) is within the inside:
Given a degree (P), contemplate a ray from (P) in direction of infinity.
For every intersection between the ray and the curve(s),
decide whether or not the curve crosses right-to-left or left-to-right.
Every right-to-left crossing counts as +1 and every left-to-right crossing as -1.
If the whole sum of the counts are non-zero, then the purpose will probably be stuffed.
c2
(the second circle) the factors
in intersection of the 2 disks could have a zero sum – in order that they gained’t be stuffed.
to reverse the orientation of a curve.
We need to fill the a part of
c1
that lies outdoors
c2
with purple.
Now an excessive amount of is stuffed. If we clip out the left half, we have now what we’d like.
We introduce two rectangles
and
.
clips the a part of the pict that’s contained in the curve.
Observe that we might have used
and
for the clipping as a substitute.
> (draw (clipped left (brushcolor purple (fill c1 (rev c2)))) (clipped right (brushcolor blue (fill (rev c1) c2))) c1 c2)
If we fill your entire determine with magenta first, after which draw these two components
on prime, we get:
> (draw (brushcolor magazine (fill c1 c2)) (clipped left (brushcolor purple (fill c1 (rev c2)))) (clipped right (brushcolor blue (fill (rev c1) c2))) c1 c2)
Let’s finish the instance by including labels to the determine.
> (text-color “white” (with-font font (draw (brushcolor magazine (fill c1 c2)) (clipped left (brushcolor purple (fill c1 (rev c2)))) (clipped right (brushcolor blue (fill (rev c1) c2))) c1 c2 (label-cnt “A” (pt (– r) 0)) (label-cnt “B” (pt r 0)) (label-cnt “A ∩ B” (pt 0 0)))))
Let’s try to the identical with three circles.
> (require metapict racket/listing) > (set-curve-pict-size 35 35) > (def x 10) > (def -x (– x)) > (curve-pict-window (window -x x -x x)) > (def purple (color-med 0.2 “purple” “white”)) > (def blue (color-med 0.2 “blue” “white”)) > (def inexperienced (color-med 0.2 “inexperienced” “white”)) > (def grey (color+ (color* 0.33 purple) (color+ (color* 0.33 inexperienced) (color* 0.33 blue)))) > (def magazine (color-med 0.5 “purple” “blue”)) > (def rg (color-med 0.5 “purple” “inexperienced”)) > (def bg (color-med 0.5 “blue” “inexperienced”)) > (def r 5) > (def s (/ r 1.8)) > (def c1 (circle (pt (– s) 0) r)) > (def c2 (circle (pt s 0) r)) > (def c3 (circle (pt 0 (* -1 r)) r)) > (def rev curve-reverse) > (def r1 (rev c1)) > (def r2 (rev c2)) > (def r3 (rev c3))
> (define diagrams (for*/list ([Mag (list mag “white”)] [Rg (list rg “white”)] [Bg (list bg “white”)] [Red (list red “white”)] [Blue (list blue “white”)] [Green (list green “white”)] [Gray (list gray “white”)]) (draw (clipped c1 (clipped c2 (brushcolor Magazine (fill c1 c2)))) (clipped c1 (clipped c3 (brushcolor Rg (fill c1 c3)))) (clipped c2 (clipped c3 (brushcolor Bg (fill c2 c3)))) (clipped c1 (brushcolor Purple (fill c1 r2 r3))) (clipped c2 (brushcolor Blue (fill c2 r1 r3))) (clipped c3 (brushcolor Inexperienced (fill c3 r1 r2))) (clipped c1 (clipped c2 (clipped c3 (brushcolor Grey (fill c1))))) c1 c2 c3)))
> (define (rows xs) (if (empty? xs) ‘() (cons (take xs 16) (rows (drop xs 16))))) > (apply beside (apply map above (rows diagrams)))
5. Easy Block Diagrams – Passes in Racket
in Racket and switch it right into a block diagram.
[begin{align}
textrm{Source} & xrightarrow{texttt{read}} textrm{Syntax Object} \
& xrightarrow{texttt{expand}} textrm{Syntax Object} \
& xrightarrow{texttt{compile}} textrm{Compiled Expression}\
& xrightarrow{texttt{eval}}
end{align} ]
Let’s make a 800 by 100 image and set the person coordinates of the window
to an (x)-range from 0 to 800 and the (y)-range from -50 to 50.
With this selection we are able to use (y=0) for heart place of our nodes.
We’ll want nodes for “Supply”, “Syntax Object”, “Syntax Object” and “Compiled Expression”.
> (def n1 (rectangle-node “Supply” #:at (pt 100 0))) > (def n2 (rectangle-node “Syntax Object” #:at (pt 200 0))) > (def n3 (rectangle-node “Syntax Object” #:at (pt 300 0))) > (def n4 (rectangle-node “Compiled Expression” #:at (pt 400 0))) > (draw n1 n2 n3 n4)
You need to use
#:beneath
,
#:above
,
#:right-of
and
#:left-of
to put nodes.
This doesn’t look too good – the nodes are drawn on prime of one another.
As a substitute of manually putting all nodes, let’s simply place the primary node
and place the following nodes relative to the node at its left.
> (def n1 (rectangle-node “Supply” #:at (pt 100 0))) > (def n2 (rectangle-node “Syntax Object” #:right-of n1)) > (def n3 (rectangle-node “Syntax Object” #:right-of n2)) > (def n4 (rectangle-node “Compiled Expression” #:right-of n3)) > (draw n1 n2 n3 n4)
Higher, however we’d like far between neighbouring nodes.
> (current-neighbour-distance 70) > (def n1 (rectangle-node “Supply” #:at (pt 100 0))) > (def n2 (rectangle-node “Syntax Object” #:right-of n1)) > (def n3 (rectangle-node “Syntax Object” #:right-of n2)) > (def n4 (rectangle-node “Compiled Expression” #:right-of n3)) > (draw n1 n2 n3 n4)
As default the oblong path of a rectangle node is drawn with no
separation between the trail and its contents. This seems to be cramped, when
the contents is a textual content, so we have to enhance the interior separation.
This may be carried out with
#:inner-separation quantity
when the
node is created. Nonetheless we have to set this for all out nodes,
so as a substitute we set the parameter
current-inner-separation
.
> (current-neighbour-distance 70) > (current-inner-separation 3) > (def n1 (rectangle-node “Supply” #:at (pt 50 0))) > (def n2 (rectangle-node “Syntax Object” #:right-of n1)) > (def n3 (rectangle-node “Syntax Object” #:right-of n2)) > (def n4 (rectangle-node “Compiled Expression” #:right-of n3)) > (draw n1 n2 n3 n4)
It’s now time so as to add edges between the nodes.
> (def e1 (edge n1 n2 #:label “learn”)) > (def e2 (edge n2 n3 #:label “increase”)) > (def e3 (edge n3 n4 #:label “compile”))
> (draw n1 n2 n3 n4 e1 e2 e3)
To set set the label hole dimension for a single edge, you should use
the key phrase arguement
#:label-gap
.
We see a minimum of two issues: the arrow head dimension is so small,
we are able to’t see it – and the labels are positioned on prime of the sides.
The primary drawback is mounted by setting setting the arrow head
size with
ahlength
. The second drawback is that
the default hole dimension between labels and edges are too small,
so we set the parameter
current-label-gap
.
> (ahlength (px 4)) > (current-label-gap (px 4)) > (def e1 (edge n1 n2 #:label “learn”)) > (def e2 (edge n2 n3 #:label “increase”)) > (def e3 (edge n3 n4 #:label “compile”))
> (draw n1 n2 n3 n4 e1 e2 e3)
The astute reader has seen, that we’re lacking the final edge.
The final edge wants an finish node, so we make an “invisible” node
(a textual content node that reveals the empty string).
> (def n5 (text-node “” #:right-of n4)) > (def e4 (edge n4 n5 #:label “eval”))
> (draw n1 n2 n3 n4 e1 e2 e3 e4)
The complete instance is:
> (require metapict) > (set-curve-pict-size 800 50) > (curve-pict-window (window 0 800 -25 25)) > (ahlength (px 4)) > (current-label-gap (px 4)) > (current-neighbour-distance 70) > (current-inner-separation 3) > (def n1 (rectangle-node “Supply” #:at (pt 50 0))) > (def n2 (rectangle-node “Syntax Object” #:right-of n1)) > (def n3 (rectangle-node “Syntax Object” #:right-of n2)) > (def n4 (rectangle-node “Compiled Expression” #:right-of n3)) > (def n5 (text-node “” #:right-of n4)) > (def e1 (edge n1 n2 #:label “learn”)) > (def e2 (edge n2 n3 #:label “increase”)) > (def e3 (edge n3 n4 #:label “compile”)) > (def e4 (edge n4 n5 #:label “eval”))
> (draw n1 n2 n3 n4 e1 e2 e3 e4)
2
ahflankangle
2
ahlength
2
ahratio
2
ahtailcurvature
2
arrow-head
2
Arrows
2
block diagram
5
brushcolor
4
circle
4
clipped
4
color-med
4
cosd
3
curve*
3
curve-reverse
4
diagram, block
5
diagram, Venn
4
draw-arrow
2
draw-double-arrow
2
edge
5
fill
4
harpoon-down
2
harpoon-up
2
hook-head
2
line-head
2
make-similar-font
4
new-font
4
node
5
polygon, common
3
pt@d
3
common polygon
3
reverse-hook-head
2
set-curve-pict-size
2
sind
3
Venn diagram
4