Skip to content

Commit ec39e09

Browse files
committed
Add syntactic sugar to (lispkit draw). Adapt demo program.
1 parent 778aec8 commit ec39e09

File tree

5 files changed

+180
-46
lines changed

5 files changed

+180
-46
lines changed

Sources/LispKit/Primitives/DrawingLibrary.swift

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ public final class DrawingLibrary: NativeLibrary {
101101

102102
/// Dependencies of the library.
103103
public override func dependencies() {
104+
self.`import`(from: ["lispkit", "core"], "define-syntax", "syntax-rules")
105+
self.`import`(from: ["lispkit", "control"], "let")
106+
self.`import`(from: ["lispkit", "dynamic"], "parameterize")
104107
self.`import`(from: ["lispkit", "system"], "current-directory")
105108
}
106109

@@ -180,11 +183,61 @@ public final class DrawingLibrary: NativeLibrary {
180183
self.define(Procedure("font", font))
181184
self.define(Procedure("font-name", fontName))
182185
self.define(Procedure("font-size", fontSize))
186+
self.define(Procedure("point?", isPoint))
183187
self.define(Procedure("point", point))
188+
self.define(Procedure("point-x", pointX))
189+
self.define(Procedure("point-y", pointY))
190+
self.define(Procedure("size?", isSize))
184191
self.define(Procedure("size", size))
192+
self.define(Procedure("size-width", sizeWidth))
193+
self.define(Procedure("size-height", sizeHeight))
194+
self.define(Procedure("rect?", isRect))
185195
self.define(Procedure("rect", rect))
186196
self.define(Procedure("rect-point", rectPoint))
187197
self.define(Procedure("rect-size", rectSize))
198+
self.define(Procedure("rect-x", rectX))
199+
self.define(Procedure("rect-y", rectY))
200+
self.define(Procedure("rect-width", rectWidth))
201+
self.define(Procedure("rect-height", rectHeight))
202+
203+
// Syntax definitions
204+
self.define("drawing", via: """
205+
(define-syntax drawing
206+
(syntax-rules ()
207+
((_ body ...)
208+
(let ((d (make-drawing)))
209+
(parameterize ((current-drawing d)) body ...)
210+
d))))
211+
""")
212+
self.define("with-drawing", via: """
213+
(define-syntax with-drawing
214+
(syntax-rules ()
215+
((_ d body ...)
216+
(parameterize ((current-drawing d)) body ...))))
217+
""")
218+
self.define("transform", via: """
219+
(define-syntax transform
220+
(syntax-rules ()
221+
((_ tf body ...)
222+
(let ((t tf))
223+
(enable-transformation t)
224+
body ...
225+
(disable-transformation t)))))
226+
""")
227+
self.define("shape", via: """
228+
(define-syntax shape
229+
(syntax-rules ()
230+
((_ body ...)
231+
(let ((s (make-shape)))
232+
(parameterize ((current-shape s)) body ...)
233+
s))))
234+
""")
235+
self.define("with-shape", via: """
236+
(define-syntax with-shape
237+
(syntax-rules ()
238+
((_ s body ...)
239+
(parameterize ((current-shape s)) body ...))))
240+
""")
188241
}
189242

190243
public override func initializations() {
@@ -1045,18 +1098,67 @@ public final class DrawingLibrary: NativeLibrary {
10451098

10461099
// Fonts/points/sizes/rects
10471100

1101+
private func isPoint(expr: Expr) throws -> Expr {
1102+
guard case .pair(.flonum(_), .flonum(_)) = expr else {
1103+
return .false
1104+
}
1105+
return .true
1106+
}
1107+
10481108
private func point(xc: Expr, yc: Expr) throws -> Expr {
10491109
let x = try xc.asDouble(coerce: true)
10501110
let y = try yc.asDouble(coerce: true)
10511111
return .pair(.flonum(x), .flonum(y))
10521112
}
10531113

1114+
private func pointX(expr: Expr) throws -> Expr {
1115+
guard case .pair(.flonum(let x), .flonum(_)) = expr else {
1116+
throw RuntimeError.eval(.invalidPoint, expr)
1117+
}
1118+
return .flonum(x)
1119+
}
1120+
1121+
private func pointY(expr: Expr) throws -> Expr {
1122+
guard case .pair(.flonum(_), .flonum(let y)) = expr else {
1123+
throw RuntimeError.eval(.invalidPoint, expr)
1124+
}
1125+
return .flonum(y)
1126+
}
1127+
1128+
private func isSize(expr: Expr) throws -> Expr {
1129+
guard case .pair(.flonum(_), .flonum(_)) = expr else {
1130+
return .false
1131+
}
1132+
return .true
1133+
}
1134+
10541135
private func size(wc: Expr, hc: Expr) throws -> Expr {
10551136
let w = try wc.asDouble(coerce: true)
10561137
let h = try hc.asDouble(coerce: true)
10571138
return .pair(.flonum(w), .flonum(h))
10581139
}
10591140

1141+
private func sizeWidth(expr: Expr) throws -> Expr {
1142+
guard case .pair(.flonum(let w), .flonum(_)) = expr else {
1143+
throw RuntimeError.eval(.invalidSize, expr)
1144+
}
1145+
return .flonum(w)
1146+
}
1147+
1148+
private func sizeHeight(expr: Expr) throws -> Expr {
1149+
guard case .pair(.flonum(_), .flonum(let h)) = expr else {
1150+
throw RuntimeError.eval(.invalidSize, expr)
1151+
}
1152+
return .flonum(h)
1153+
}
1154+
1155+
private func isRect(expr: Expr) throws -> Expr {
1156+
guard case .pair(.pair(.flonum(_), .flonum(_)), .pair(.flonum(_), .flonum(_))) = expr else {
1157+
return .false
1158+
}
1159+
return .true
1160+
}
1161+
10601162
private func rect(fst: Expr, snd: Expr, thrd: Expr?, fth: Expr?) throws -> Expr {
10611163
if let width = thrd {
10621164
let x = try fst.asDouble(coerce: true)
@@ -1089,6 +1191,20 @@ public final class DrawingLibrary: NativeLibrary {
10891191
return point
10901192
}
10911193

1194+
private func rectX(expr: Expr) throws -> Expr {
1195+
guard case .pair(.pair(.flonum(let x), .flonum(_)), .pair(.flonum(_), .flonum(_))) = expr else {
1196+
throw RuntimeError.eval(.invalidRect, expr)
1197+
}
1198+
return .flonum(x)
1199+
}
1200+
1201+
private func rectY(expr: Expr) throws -> Expr {
1202+
guard case .pair(.pair(.flonum(_), .flonum(let y)), .pair(.flonum(_), .flonum(_))) = expr else {
1203+
throw RuntimeError.eval(.invalidRect, expr)
1204+
}
1205+
return .flonum(y)
1206+
}
1207+
10921208
private func rectSize(expr: Expr) throws -> Expr {
10931209
guard case .pair(.pair(.flonum(_), .flonum(_)), let size) = expr else {
10941210
throw RuntimeError.eval(.invalidRect, expr)
@@ -1099,6 +1215,20 @@ public final class DrawingLibrary: NativeLibrary {
10991215
return size
11001216
}
11011217

1218+
private func rectWidth(expr: Expr) throws -> Expr {
1219+
guard case .pair(.pair(.flonum(_), .flonum(_)), .pair(.flonum(let w), .flonum(_))) = expr else {
1220+
throw RuntimeError.eval(.invalidRect, expr)
1221+
}
1222+
return .flonum(w)
1223+
}
1224+
1225+
private func rectHeight(expr: Expr) throws -> Expr {
1226+
guard case .pair(.pair(.flonum(_), .flonum(_)), .pair(.flonum(_), .flonum(let h))) = expr else {
1227+
throw RuntimeError.eval(.invalidRect, expr)
1228+
}
1229+
return .flonum(h)
1230+
}
1231+
11021232
private func isFont(expr: Expr) -> Expr {
11031233
if case .object(let obj) = expr, obj is ImmutableBox<NSFont> {
11041234
return .true

Sources/LispKit/Resources/Examples/AvlTrees.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
;;; either express or implied. See the License for the specific language governing permissions
2929
;;; and limitations under the License.
3030

31+
3132
(define-library (avl-tree)
3233

3334
(export make-avl-tree

Sources/LispKit/Resources/Examples/Coroutines.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
;;;
1717
;;; Author: Matt Might ([email protected])
1818

19+
1920
(import (srfi 31))
2021

2122
; *thread-queue* : list[continuation]

Sources/LispKit/Resources/Examples/HTTP.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
;;; either express or implied. See the License for the specific language governing permissions
2929
;;; and limitations under the License.
3030

31+
3132
(define (http-get-header url)
3233
(let-values (((header _) (http-get url)))
3334
header))
Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
;;; Plot graphs into a PDF file
22
;;;
3-
;;; This is a demo of library (lispkit draw). Function `plot` draws a function over
4-
;;; a given range using a number of interpolation points into a given rectangle.
5-
;;; It is used a number of times in function `plot-demo-page` which explains how to
6-
;;; compose drawings and save them in a PDF file.
3+
;;; This is a demo of library (lispkit draw). Function `plot` draws a graph for a
4+
;;; function for a given range using a number of interpolation points into a given
5+
;;; rectangle. `plot` is used a number of times in function `plot-demo-page` which
6+
;;; explains how to compose drawings and save them in a PDF file.
77
;;;
88
;;; Usage: (plot-demo-page "graph-demo.pdf")
99
;;;
@@ -24,58 +24,59 @@
2424
(import (lispkit draw))
2525

2626
;; Plots a function `f` over range `[xmin; xmax]` using `n` interpolation points
27-
;; within rectangle `rect`. Prints `label` at the bottom of the graph.
27+
;; within rectangle `rect`. Prints `label` at the bottom of the graph. Returns the result
28+
;; as a drawing object.
2829
(define (plot f xmin xmax n rect label)
2930
(let* ((dx (/ (- xmax xmin) n))
3031
(xs (tabulate (fx1+ n) (lambda (i) (+ xmin (* i dx)))))
3132
(ys (map f xs))
3233
(ymin (apply min ys))
3334
(ymax (apply max ys))
34-
(xfac (/ (car (rect-size rect)) (- xmax xmin)))
35-
(yfac (/ (cdr (rect-size rect)) (- ymax ymin)))
35+
(xfac (/ (rect-width rect) (- xmax xmin)))
36+
(yfac (/ (rect-height rect) (- ymax ymin)))
3637
(ps (map (lambda (x y) (point (* xfac (- x xmin)) (* yfac (- y ymin)))) xs ys))
37-
(shift (translate (car (rect-point rect)) (cdr (rect-point rect))))
38-
(d (make-drawing)))
39-
; Interpolate the points and flip the shape
40-
(define s (flip-shape (interpolate ps)))
41-
; Draw a bounding box
42-
(define box (shape-bounds s))
43-
(draw (rectangular (rect-point rect) (rect-size rect)) 0.5 d)
44-
; Draw the graph and coordinate axis
45-
(enable-transformation shift d)
46-
(if (and (<= xmin 0.0) (>= xmax 0.0))
47-
(draw (polygon (point (* xfac (- xmin)) 0)
48-
(point (* xfac (- xmin)) (cdr (rect-size rect)))) 0.3 d))
49-
(if (and (<= ymin 0.0) (>= ymax 0.0))
50-
(draw (polygon (point 0 (+ (cdr (rect-size rect)) (* yfac ymin)))
51-
(point (car (rect-size rect)) (+ (cdr (rect-size rect)) (* yfac ymin))))
52-
0.3 d))
53-
(set-color (make-color 0.0 0.0 1.0 1.0) d)
54-
(draw s 1.0 d)
55-
; Draw interpolation points
56-
(set-color (make-color 0.0 0.0 0.0) d)
57-
(set-fill-color (make-color 0.0 0.0 0.0) d)
58-
(for-each (lambda (p) (fill (flip-shape (arc p 1 0) box) d)) ps)
59-
; Draw the label
60-
(draw-text label
61-
(point 30 (- (cdr (rect-size rect)) 12))
62-
(font "Times-Italic" 7)
63-
(make-color 0.3 0.3 0.3) d)
64-
(disable-transformation shift d)
65-
d))
38+
(graph (flip-shape (interpolate ps))))
39+
(drawing
40+
; Draw a bounding box
41+
(draw (rectangular (rect-point rect) (rect-size rect)) 0.5)
42+
; Move rest of drawing into the bounding box
43+
(transform (translate (rect-x rect) (rect-y rect))
44+
; Draw the coordinate axis
45+
(make-color 0.3 0.3 0.3)
46+
(if (and (<= xmin 0.0) (>= xmax 0.0))
47+
(draw (line (point (* xfac (- xmin)) 0)
48+
(point (* xfac (- xmin)) (rect-height rect))) 0.3))
49+
(if (and (<= ymin 0.0) (>= ymax 0.0))
50+
(draw (line (point 0 (+ (rect-height rect) (* yfac ymin)))
51+
(point (rect-width rect) (+ (rect-height rect) (* yfac ymin)))) 0.3))
52+
; Draw flipped interpolation shape
53+
(set-color (make-color 0 0 1))
54+
(draw graph)
55+
; Draw interpolation points
56+
(set-color (make-color 0 0 0))
57+
(set-fill-color (make-color 0 0 0))
58+
(for-each (lambda (p) (fill (flip-shape (circle p 1) (shape-bounds graph)))) ps)
59+
; Draw the label
60+
(draw-text label
61+
(point 30 (- (rect-height rect) 12))
62+
(font "Times-Italic" 7)
63+
(make-color 0.3 0.3 0.3))))))
6664

6765
;; Creates a demo page consisting of a header and four graphs
6866
(define (plot-demo-page path)
6967
; Create a new drawing
70-
(define page (make-drawing))
71-
; Draw a header in font "Helvetica" of size 8
72-
(draw-text "Demo of library (lispkit draw)"
73-
(point 160 8) (font "Helvetica" 8) (make-color 0.0 0.0 0.0) page)
74-
; Plot four graphs
75-
(draw-drawing (plot sin -1 6.3 50 (rect 10 30 200 100) "sin(x)") page)
76-
(draw-drawing (plot cos -1 6.3 50 (rect 220 30 200 100) "cos(x)") page)
77-
(draw-drawing (plot (lambda (x) (* (sin (* x 2)) (cos (/ x 4))))
78-
-1 6.3 50 (rect 10 140 200 100) "sin(x*2)*cos(x/4)") page)
79-
(draw-drawing (plot (lambda (x) (/ (* x x) 40)) -1 6.3 50 (rect 220 140 200 100) "x*x/40") page)
68+
(define page
69+
(drawing
70+
; Draw a header in font "Helvetica-Bold" of size 8
71+
(draw-text "Demo of library (lispkit draw)"
72+
(point 160 8)
73+
(font "Helvetica-Bold" 8)
74+
(make-color 0 0 0))
75+
; Plot four graphs
76+
(draw-drawing (plot sin -1 6.3 50 (rect 10 30 200 100) "sin(x)"))
77+
(draw-drawing (plot cos -1 6.3 50 (rect 220 30 200 100) "cos(x)"))
78+
(draw-drawing (plot (lambda (x) (* (sin (* x 2)) (cos (/ x 4))))
79+
-1 6.3 50 (rect 10 140 200 100) "sin(x*2)*cos(x/4)"))
80+
(draw-drawing (plot (lambda (x) (/ (* x x) 40)) -1 6.3 50 (rect 220 140 200 100) "x*x/40"))))
8081
; Save drawing in a PDF file
8182
(save-drawing page path (size 430 250)))

0 commit comments

Comments
 (0)