-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathline.rkt
131 lines (117 loc) · 4.08 KB
/
line.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#lang racket
;;; File:
;;; line.rkt
;;; Summary:
;;; A variety of procedures for working with lines.
;;; Author:
;;; Samuel A. Rebelsky
(require racket/generic)
(require lang/posn)
(require "sstruct.rkt")
(require "cloneable.rkt")
(permit-cloneable)
(permit-done)
(require "type-predicates.rkt")
(require "point.rkt")
(provide (all-defined-out))
; +----------------------+-------------------------------------------
; | Lines (mathematical) |
; +----------------------+
; ax + b
(struct line (slope y-intercept)
#:transparent
#:guard
(lambda (slope y-intercept type-name)
(param-check! line 1 real? slope)
(param-check! line 2 real? y-intercept)
(values slope y-intercept)))
;;; (line-apply line x) -> real?
;;; line : line?
;;; x : real?
;;; Apply a line function to an x value, thereby giving the
;;; y value.
(define line-apply
(lambda (line x)
(+ (* (line-slope line) x)
(line-y-intercept line))))
;;; (line-between pt1 pt2) -> (or line? real?)
;;; pt1 : point?
;;; pt2 : point?
;;; Compute the function of the line between pt1 and pt2. Returns
;;; the x intercept for vertical lines
(define line-between
(lambda (pt1 pt2)
(let ([hoff (- (pt-x pt2) (pt-x pt1))]
[voff (- (pt-y pt2) (pt-y pt1))])
(if (zero? hoff)
(pt-x pt1)
(let* ([slope (/ voff hoff)]
[y-intercept (- (pt-y pt1) (* slope (pt-x pt1)))])
(line slope y-intercept))))))
;;; (offset-line l distance updown) -> line?
;;; l : (any-of line? real?)
;;; distance : non-negative-real?
;;; updown : one of 'up or 'down
;;; Offset the line up or down so that the distance between the two lines
;;; is distance.
(define offset-line
(lambda (l distance updown)
; (println (list 'offset-line line distance updown))
(let* ([mult (if (equal? updown 'up) -1 1)]
[a (line-slope l)]
[b (line-y-intercept l)])
; Note: Computation is going from ax + 0 to ax + c
(if (zero? a)
(line a (+ b (* mult distance)))
(let* ([inverse (/ -1 a)]
[x (/ distance (sqrt (+ 1 (sqr inverse))))]
[c (* x (+ inverse (- a)))])
(line a (+ b (* mult (abs c)))))))))
(define offset-line-old
(lambda (l distance updown)
(println (list 'offset-line line distance updown))
(let* ([mult (if (equal? updown 'up) -1 1)]
[slope (line-slope l)])
(if (zero? slope)
(line slope (+ (line-y-intercept l) (* mult distance)))
(let* ([inverse (/ -1 slope)]
[hoff (sqrt (/ (sqr distance)
(+ 1 (sqr inverse))))]
[voff (abs (* inverse hoff))])
(line slope
(+ (line-apply l hoff)
(* mult (abs voff)))))))))
;;; (intersection line1 line2) -> (any-of pt? false?)
;;; line1 : (any-of line? real?)
;;; line2 : (any-of line? real?)
;;; Find the point of intersection between `line1` and `line2`. Returns
;;; `#f` if they don't intersect. Lines represented as reals are vertical
;;; and the real number is the x intercept.
(define intersection
(lambda (line1 line2)
(cond
[(and (real? line1) (real? line2))
#f]
[(real? line1)
(pt line1 (line-apply line2 line1))]
[(real? line2)
(pt line2 (line-apply line1 line2))]
[(equal? (line-slope line1) (line-slope line2))
#f]
[else
(let ([x (/ (- (line-y-intercept line2) (line-y-intercept line1))
(- (line-slope line1) (line-slope line2)))])
(pt x (line-apply line1 x)))])))
;;; (intersections lines) -> (list-of pt?)
;;; lines : (list-of (any-of line? real?))
;;; Find the intersections between successive lines. If two lines are
;;; parallel, skips that intersection.
(define intersections
(lambda (lines)
(let kernel ([remaining (append lines (list (car lines)))])
(if (null? (cdr remaining))
null
(let ([point (intersection (car remaining) (cadr remaining))])
(if point
(cons point (kernel (cdr remaining)))
(kernel (cdr remaining))))))))