Skip to content

Commit 4415b2d

Browse files
bdeketpbpfalex-hhh
authored
add arrows and arrows3d renderers (#67)
The `arrows` and `arrows3d` renderers allow drawing connected arrows, specified either as a list of points or as a point + magnitude vector, with both 2D and 3D variants available. Two new parameters are introduced for controlling the arrow head length and opening angle. Co-authored-by: pbpf <[email protected]> Co-authored-by: Alex Harsanyi <[email protected]>
1 parent 18d8eca commit 4415b2d

26 files changed

+586
-36
lines changed

plot-doc/plot/scribblings/params.scrbl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ Used as default keyword arguments of @racket[point-label], @racket[function-labe
268268
@racket[inverse-label], @racket[parametric-label], @racket[polar-label] and @racket[point-label3d].
269269
}
270270

271-
@section{Vector Fields}
271+
@section{Vector Fields & Arrows}
272272

273273
@deftogether[((defparam vector-field-samples n exact-positive-integer? #:value 20)
274274
(defparam vector-field3d-samples n exact-positive-integer? #:value 9))]{
@@ -283,6 +283,22 @@ The default number of samples @racket[vector-field] and @racket[vector-field3d]
283283
The default pen color, pen width, pen style, scaling factor, and opacity used by
284284
@racket[vector-field] and @racket[vector-field3d].
285285
}
286+
@deftogether[((defparam arrows-color color plot-color/c #:value 1)
287+
(defparam arrows-line-width width (>=/c 0) #:value 2/3)
288+
(defparam arrows-line-style style plot-pen-style/c #:value 'solid)
289+
(defparam arrows-alpha alpha (real-in 0 1) #:value 1))]{
290+
The default pen color, pen width, pen style, and opacity used by
291+
@racket[arrows] and @racket[arrows3d].
292+
@history[#:added "7.9"]
293+
}
294+
295+
@deftogether[((defparam arrow-head-size-or-scale size (or/c (>=/c 0) (list/c '= (>=/c 0))) #:value 2/5)
296+
(defparam arrow-head-angle alpha (>=/c 0) #:value (/ pi 6)))]{
297+
The default size and angle of the arrow head in @racket[vector-field], @racket[vector-field3d], @racket[arrows] and @racket[arrows3d].
298+
When the @racket[arrow-head-size-or-scale] is a number, it is interpreted as a proportion of the arrow length , and will be bigger for longer arrows. When it is in the form @racket[(list '= size)], it is interpreted as the size of the arrow head in drawing units (pixels).
299+
@history[#:added "7.9"]
300+
}
301+
286302

287303
@section{Error Bars}
288304

plot-doc/plot/scribblings/renderer2d.scrbl

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,14 @@ If @(racket scale) is a real number, arrow lengths are multiplied by @(racket sc
145145
If @(racket 'auto), the scale is calculated in a way that keeps arrows from overlapping.
146146
If @(racket 'normalized), each arrow is made the same length: the maximum length that would have been allowed by @(racket 'auto).
147147

148+
The shape of the arrow-head can be controlled with @racket[arrow-head-size-or-scale] and @racket[arrow-head-angle].
149+
148150
An example of automatic scaling:
149151
@interaction[#:eval plot-eval
150152
(plot (vector-field (λ (x y) (vector (+ x y) (- x y)))
151153
-2 2 -2 2))]
152154

153-
@history[#:changed "7.9" "Added support for pictures for #:label"]
155+
@history[#:changed "7.9" "Added support for pictures for #:label and controlling the arrowhead"]
154156
}
155157

156158
@defproc[(error-bars
@@ -346,6 +348,40 @@ For example, to plot an estimated density of the triangle distribution:
346348
@history[#:changed "7.9" "Added support for pictures for #:label"]
347349
}
348350

351+
352+
@defproc[(arrows [vs (or/c (listof (sequence/c #:min-count 2 real?))
353+
(vectorof (vector/c (sequence/c #:min-count 2 real?)
354+
(sequence/c #:min-count 2 real?))))]
355+
[#:x-min x-min (or/c rational? #f) #f] [#:x-max x-max (or/c rational? #f) #f]
356+
[#:y-min y-min (or/c rational? #f) #f] [#:y-max y-max (or/c rational? #f) #f]
357+
[#:color color plot-color/c (arrows-color)]
358+
[#:width width (>=/c 0) (arrows-line-width)]
359+
[#:style style plot-pen-style/c (arrows-line-style)]
360+
[#:alpha alpha (real-in 0 1) (arrows-alpha)]
361+
[#:arrow-head-size-or-scale size (or/c (list/c '= (>=/c 0)) (>=/c 0)) (arrow-head-size-or-scale)]
362+
[#:arrow-head-angle angle (>=/c 0) (arrow-head-angle)]
363+
[#:label label (or/c string? pict? #f) #f]
364+
) renderer2d?]{
365+
Returns a renderer which draws arrows. Arrows can be specified either as sequences of 2D points,
366+
in this case they will be drawn as connected arrows between each two adjacent points,
367+
or they can be specified as an origin point and a rectangular magnitude vector, in which case each arrow
368+
is drawn individually. See example below.
369+
370+
In @racket[vs] list and vector are interchangeable. Arrow-heads are only drawn when the endpoint is inside the drawing area.
371+
@interaction[#:eval plot-eval
372+
(plot (list
373+
(arrows
374+
`((0 0) (2 1) (3 3) (0 0))
375+
#:arrow-head-size-or-scale '(= 20)
376+
#:arrow-head-angle .2
377+
#:color 6 #:label "a+b+c=0")
378+
(arrows
379+
`(((2 0) (0 1)) ((3 0) (-1 1)))
380+
#:arrow-head-size-or-scale .2
381+
#:color 2 #:label "d")))]
382+
@history[#:added "7.9"]
383+
}
384+
349385
@defproc[(hrule [y real?]
350386
[x-min (or/c rational? #f) #f] [x-max (or/c rational? #f) #f]
351387
[#:color color plot-color/c (line-color)]

plot-doc/plot/scribblings/renderer3d.scrbl

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ See @secref["renderer2d-function-arguments"] for a detailed example.
2121
@section{3D Point Renderers}
2222

2323
@defproc[(points3d
24-
[vs (sequence/c (sequence/c #:min-count 3 real?))]
24+
[vs (sequence/c (sequence/c #:min-count 3 real?))]
2525
[#:x-min x-min (or/c rational? #f) #f] [#:x-max x-max (or/c rational? #f) #f]
2626
[#:y-min y-min (or/c rational? #f) #f] [#:y-max y-max (or/c rational? #f) #f]
2727
[#:z-min z-min (or/c rational? #f) #f] [#:z-max z-max (or/c rational? #f) #f]
@@ -86,7 +86,7 @@ The arguments are interpreted identically to the corresponding arguments to @rac
8686
(plot3d (vector-field3d (λ (x y z) (vector x z y))
8787
-2 2 -2 2 -2 2))]
8888

89-
@history[#:changed "7.9" "Added support for pictures for #:label"]
89+
@history[#:changed "7.9" "Added support for pictures for #:label and controlling the arrowhead"]
9090
}
9191

9292
@section{3D Line Renderers}
@@ -131,6 +131,28 @@ Returns a renderer that plots a vector-valued function of time. For example,
131131
@history[#:changed "7.9" "Added support for pictures for #:label"]
132132
}
133133

134+
@defproc[(arrows3d
135+
[vs (or/c (listof (sequence/c #:min-count 3 real?))
136+
(vectorof (vector/c (sequence/c #:min-count 3 real?)
137+
(sequence/c #:min-count 3 real?))))]
138+
[#:x-min x-min (or/c rational? #f) #f] [#:x-max x-max (or/c rational? #f) #f]
139+
[#:y-min y-min (or/c rational? #f) #f] [#:y-max y-max (or/c rational? #f) #f]
140+
[#:z-min z-min (or/c rational? #f) #f] [#:z-max z-max (or/c rational? #f) #f]
141+
[#:color color plot-color/c (arrows-color)]
142+
[#:width width (>=/c 0) (arrows-line-width)]
143+
[#:style style plot-pen-style/c (arrows-line-style)]
144+
[#:alpha alpha (real-in 0 1) (arrows-alpha)]
145+
[#:arrow-head-size-or-scale size (or/c (list/c '= (>=/c 0)) (>=/c 0)) (arrow-head-size-or-scale)]
146+
[#:arrow-head-angle angle (>=/c 0) (arrow-head-angle)]
147+
[#:label label (or/c string? pict? #f) #f]
148+
) renderer3d?]{
149+
Returns a renderer that draws arrows. The arguments and arrow-head parameters are interpreted identically as in @racket[arrows].
150+
@interaction[#:eval plot-eval
151+
(plot3d (arrows3d `((0 0 0) (1 1 1) (2 2 2) (3 2 1)))
152+
#:altitude 25)]
153+
@history[#:added "7.9"]
154+
}
155+
134156
@section{3D Surface Renderers}
135157

136158
@defproc[(surface3d

plot-lib/plot/no-gui.rkt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
(provide
5656
color-field)
5757

58+
(require "private/plot2d/arrows.rkt")
59+
(provide
60+
arrows)
61+
5862
(require "private/plot2d/line.rkt")
5963
(provide
6064
lines
@@ -134,6 +138,10 @@
134138
contours3d
135139
contour-intervals3d)
136140

141+
(require "private/plot3d/arrows.rkt")
142+
(provide
143+
arrows3d)
144+
137145
(require "private/plot3d/line.rkt")
138146
(provide
139147
lines3d

plot-lib/plot/private/common/parameter-groups.rkt

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
(module untyped-defs racket/base
44
(require "parameters.rkt"
55
"parameter-group.rkt")
6-
6+
77
(provide (all-defined-out))
8-
8+
99
(define-parameter-group plot-axes?
1010
(plot-x-axis? plot-x-far-axis?
1111
plot-y-axis? plot-y-far-axis?
1212
plot-z-axis? plot-z-far-axis?))
13-
13+
1414
(define-parameter-group plot-tick-labels
1515
(plot-x-tick-labels?
1616
plot-x-tick-label-anchor
@@ -24,7 +24,7 @@
2424
plot-y-far-tick-labels?
2525
plot-y-far-tick-label-anchor
2626
plot-y-far-tick-label-angle))
27-
27+
2828
(define-parameter-group plot-appearance
2929
(plot-width
3030
plot-height
@@ -38,29 +38,31 @@
3838
plot-decorations?
3939
plot-animating?
4040
plot-pen-color-map
41-
plot-brush-color-map))
42-
41+
plot-brush-color-map
42+
arrow-head-size-or-scale
43+
arrow-head-angle))
44+
4345
(define-parameter-group plot3d-appearance
4446
(plot3d-samples
4547
plot3d-angle
4648
plot3d-altitude
4749
plot3d-ambient-light
4850
plot3d-diffuse-light?
4951
plot3d-specular-light?))
50-
52+
5153
(define-parameter-group plot-output
5254
(plot-new-window? plot-jpeg-quality plot-ps/pdf-interactive? plot-ps-setup))
53-
55+
5456
(define-parameter-group plot-labels
5557
(plot-title
5658
plot-x-label plot-y-label plot-z-label
5759
plot-x-far-label plot-y-far-label plot-z-far-label))
58-
60+
5961
(define-parameter-group plot-x-axis (plot-x-transform plot-x-ticks plot-x-far-ticks))
6062
(define-parameter-group plot-y-axis (plot-y-transform plot-y-ticks plot-y-far-ticks))
6163
(define-parameter-group plot-z-axis (plot-z-transform plot-z-ticks plot-z-far-ticks))
6264
(define-parameter-group plot-axes (plot-x-axis plot-y-axis plot-z-axis plot-d-ticks plot-r-ticks))
63-
65+
6466
(define-parameter-group plot-parameters
6567
(plot-appearance
6668
plot3d-appearance
@@ -77,11 +79,12 @@
7779
"types.rkt"
7880
"axis-transform.rkt"
7981
"ticks.rkt")
80-
82+
8183
(provide Plot-Parameters)
82-
84+
8385
(deftype Plot-Parameters
8486
(List
87+
;; plot-appearance
8588
(List
8689
Positive-Integer
8790
Positive-Integer
@@ -104,8 +107,12 @@
104107
Boolean
105108
Boolean
106109
(U Symbol #f)
107-
(U Symbol #f))
110+
(U Symbol #f)
111+
(U (List '= Nonnegative-Real) Nonnegative-Real)
112+
Nonnegative-Real)
113+
;;plot3d-appearance
108114
(List Positive-Integer Real Real Nonnegative-Real Boolean Boolean)
115+
;;plot-labels
109116
(List
110117
(U False String pict)
111118
(U False String pict)
@@ -114,14 +121,16 @@
114121
(U False String pict)
115122
(U False String pict)
116123
(U False String pict))
124+
;;plot-output
117125
(List Boolean Nonnegative-Integer Boolean (Instance PS-Setup%))
126+
;;plot-axes
118127
(List
119128
(List Axis-Transform ticks ticks)
120129
(List Axis-Transform ticks ticks)
121130
(List Axis-Transform ticks ticks)
122131
ticks
123132
ticks)))
124-
133+
125134
(define (test) (ann (plot-parameters) Plot-Parameters)))
126135

127136
(require 'untyped-defs

plot-lib/plot/private/common/parameters.rkt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,16 @@
212212
(defparam2 vector-field-alpha Real Nonnegative-Real 1 (unit-ivl 'vector-field-alpha))
213213
(defparam vector-field3d-samples Positive-Integer 9)
214214

215+
;;arrow
216+
217+
(defparam arrows-color Plot-Color 1)
218+
(defparam2 arrows-line-width Real Nonnegative-Real 2/3
219+
(nonnegative-rational 'arrows-line-width))
220+
(defparam arrows-line-style Plot-Pen-Style 'solid)
221+
(defparam2 arrows-alpha Real Nonnegative-Real 1 (unit-ivl 'arrows-alpha))
222+
(defparam arrow-head-size-or-scale (U Nonnegative-Real (List '= Nonnegative-Real)) 2/5)
223+
(defparam arrow-head-angle Nonnegative-Real 0.5235987755982988);=pi/6=30°
224+
215225
;; Error bars
216226

217227
(defparam2 error-bar-width Real Nonnegative-Real 6 (nonnegative-rational 'error-bar-width))

plot-lib/plot/private/common/plot-device.rkt

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,21 @@
306306
(define/public (set-text-foreground color)
307307
(send dc set-text-foreground (color->color% (->pen-color color))))
308308

309+
310+
;; -----------------------------------------------------------------------------------------------
311+
;; Arrows
312+
313+
(: pd-arrow-head-size-or-scale (U (List '= Nonnegative-Real) Nonnegative-Real))
314+
(: pd-arrow-head-angle Nonnegative-Real)
315+
(define pd-arrow-head-size-or-scale (arrow-head-size-or-scale))
316+
(define pd-arrow-head-angle (arrow-head-angle))
317+
318+
;; Sets the arrow-head shape (for draw-arrow)
319+
(define/public (set-arrow-head size-or-scale angle)
320+
(set! pd-arrow-head-size-or-scale size-or-scale)
321+
(set! pd-arrow-head-angle angle))
322+
323+
309324
;; -----------------------------------------------------------------------------------------------
310325
;; Clipping
311326

@@ -410,12 +425,15 @@
410425
(define dy (- y2 y1))
411426
(define angle (if (and (zero? dy) (zero? dx)) 0 (atan dy dx)))
412427
(define dist (sqrt (+ (sqr dx) (sqr dy))))
413-
(define head-r (* 2/5 dist))
414-
(define head-angle (* 1/6 pi))
415-
(define dx1 (* (cos (+ angle head-angle)) head-r))
416-
(define dy1 (* (sin (+ angle head-angle)) head-r))
417-
(define dx2 (* (cos (- angle head-angle)) head-r))
418-
(define dy2 (* (sin (- angle head-angle)) head-r))
428+
(define head-r
429+
(let ([size-or-scale pd-arrow-head-size-or-scale])
430+
(if (list? size-or-scale)
431+
(cadr size-or-scale)
432+
(* size-or-scale dist))))
433+
(define dx1 (* (cos (+ angle pd-arrow-head-angle)) head-r))
434+
(define dy1 (* (sin (+ angle pd-arrow-head-angle)) head-r))
435+
(define dx2 (* (cos (- angle pd-arrow-head-angle)) head-r))
436+
(define dy2 (* (sin (- angle pd-arrow-head-angle)) head-r))
419437
(send dc draw-line x1 y1 x2 y2)
420438
(send dc draw-line x2 y2 (- x2 dx1) (- y2 dy1))
421439
(send dc draw-line x2 y2 (- x2 dx2) (- y2 dy2))))

plot-lib/plot/private/common/types.rkt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
(deftype Plot-Color
2828
(U Integer Color))
2929

30-
(deftype Color-Map (Vectorof (List Byte Byte Byte)))
30+
(deftype Color-Map (Vectorof (List Byte Byte Byte)))
3131

3232
(deftype Plot-Pen-Style-Sym
3333
(U 'transparent 'solid 'dot 'long-dash
@@ -84,8 +84,8 @@
8484
(deftype Contour-Levels (U 'auto Positive-Integer (Listof Real)))
8585

8686
(define-type Image-File-Format
87-
(U 'png 'jpeg
88-
'xbm 'xpm 'bmp
87+
(U 'png 'jpeg
88+
'xbm 'xpm 'bmp
8989
'ps 'pdf 'svg))
9090

9191
(deftype Legend-Draw-Proc (-> (Instance Plot-Device%) Real Real Void))
@@ -116,6 +116,7 @@
116116
[get-text-extent (-> (U String pict) (Values Exact-Rational Exact-Rational Exact-Rational Exact-Rational))]
117117
[get-text-width (-> (U String pict) Exact-Rational)]
118118
[set-text-foreground (-> Plot-Color Void)]
119+
[set-arrow-head (-> (U (List '= Nonnegative-Real) Nonnegative-Real) Nonnegative-Real Void)]
119120
[set-clipping-rect (-> Rect Void)]
120121
[clear-clipping-rect (-> Void)]
121122
[clear (-> Void)]

0 commit comments

Comments
 (0)