geometry.scm 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. (library (geometry (0 0 1))
  2. (export point
  3. make-point
  4. get-point-label
  5. get-point-coords
  6. get-point-coord
  7. vector->point
  8. make-element-wise-vector-operation
  9. vec+vec
  10. vec*vec
  11. make-arbitrary-arity-vector-operation
  12. vector+
  13. vector*
  14. vector-dot-product
  15. vector-scalar-product
  16. vec*sca
  17. vector-cross-product
  18. vector-magnitude
  19. vectors-perpendicular?
  20. vectors-angle-between
  21. counter-clockwise?
  22. clockwise?
  23. colinear?
  24. counter-clockwise-function
  25. ccw)
  26. (import
  27. (except (rnrs base)
  28. error
  29. vector-map)
  30. (only (guile) lambda* λ error)
  31. ;; structs
  32. (srfi srfi-9)
  33. (srfi srfi-9 gnu)
  34. ;; fold and list operations
  35. (srfi srfi-1)
  36. ;; vector operations
  37. (srfi srfi-43)))
  38. (define-immutable-record-type <point>
  39. ;; define constructor
  40. (point label coords)
  41. ;; define predicate
  42. point?
  43. ;; define accessors and functional setters
  44. (label get-point-label set-point-label)
  45. (coords get-point-coords set-point-coords))
  46. (define make-point
  47. (lambda* (coords #:key (label #f))
  48. (cond
  49. [(vector? coords)
  50. (cond
  51. [label (point label coords)]
  52. [else (point 'unlabeled coords)])]
  53. [(list? coords)
  54. (cond
  55. [label (point label (list->vector coords))]
  56. [else (point 'unlabeled (list->vector coords))])]
  57. [else
  58. (error "coordinates are supposed to be given as a list or vector")])))
  59. (define get-point-coord
  60. (λ (a-point coord-ind)
  61. (vector-ref (get-point-coords a-point) coord-ind)))
  62. (define vector->point
  63. (lambda* (vec #:key (label #f))
  64. (cond
  65. [label
  66. (point label vec)]
  67. [else
  68. (point 'unlabeled vec)])))
  69. (define make-element-wise-vector-operation
  70. (lambda (elem-wise-op)
  71. ;; Return a vector operation, which works element-wise
  72. ;; with 2 vectors to create a new vector.
  73. (lambda (v1 v2)
  74. (let ([len1 (vector-length v1)]
  75. [len2 (vector-length v2)])
  76. (cond
  77. [(= len1 len2)
  78. (let ([res-vec (make-vector len1)])
  79. (let iter ([ind 0])
  80. (cond
  81. [(< ind len1)
  82. ;; Update the vector in-place.
  83. (vector-set! res-vec
  84. ind
  85. ;; Make use of the element-wise
  86. ;; operation.
  87. (elem-wise-op (vector-ref v1 ind)
  88. (vector-ref v2 ind)))
  89. (iter (+ ind 1))]
  90. [else
  91. res-vec])))]
  92. [else
  93. (error "vectors do not have same length")])))))
  94. (define vec+vec
  95. (make-element-wise-vector-operation +))
  96. (define vec*vec
  97. (make-element-wise-vector-operation *))
  98. (define make-arbitrary-arity-vector-operation
  99. (lambda (elem-wise-vec-op op-neutral-elem)
  100. ;; Return a procedure, which takes an arbitrary number
  101. ;; of arguments and works through them using the given
  102. ;; element-wise vector operation.
  103. (lambda (vec1 vec2 . rest-vecs)
  104. (fold elem-wise-vec-op
  105. (make-vector (vector-length vec1) op-neutral-elem)
  106. (cons vec1
  107. (cons vec2
  108. rest-vecs))))))
  109. (define vector+
  110. (make-arbitrary-arity-vector-operation vec+vec 0))
  111. (define vector*
  112. (make-arbitrary-arity-vector-operation vec*vec 1))
  113. (define vector-dot-product
  114. (lambda (v1 v2)
  115. (vector-fold (lambda (ind acc elem1 elem2)
  116. (+ acc (* elem1 elem2)))
  117. 0
  118. v1 v2)))
  119. ;; alias
  120. (define vector-scalar-product
  121. vector-dot-product)
  122. (define vec*sca
  123. (lambda (vec sca)
  124. (vector-map (λ (ind elem) (* elem sca))
  125. vec)))
  126. (define vector-cross-product
  127. (lambda (v1 v2)
  128. (let ([len1 (vector-length v1)]
  129. [len2 (vector-length v2)])
  130. (cond
  131. ;; The cross product is only defined for 3
  132. ;; dimensions.
  133. [(= len1 len2 3)
  134. (let ([a1 (vector-ref v1 0)]
  135. [a2 (vector-ref v1 1)]
  136. [a3 (vector-ref v1 2)]
  137. [b1 (vector-ref v2 0)]
  138. [b2 (vector-ref v2 1)]
  139. [b3 (vector-ref v2 2)])
  140. (vector (- (* a2 b3) (* a3 b2))
  141. (- (* a3 b1) (* a1 b3))
  142. (- (* a1 b2) (* a2 b1))))]
  143. [else
  144. (error "one of the vectors does not have correct dimensions for cross product")]))))
  145. (define vector-magnitude
  146. (λ (vec)
  147. (sqrt
  148. (vector-fold
  149. (λ (ind acc elem)
  150. (+ acc (* elem elem)))
  151. 0
  152. vec))))
  153. (define vectors-perpendicular?
  154. (λ (v1 v2)
  155. (= (vector-dot-product v1 v2) 0)))
  156. (define vectors-angle-between
  157. (λ (v1 v2)
  158. (/ (vector-dot-product v1 v2)
  159. (* (vector-magnitude v1)
  160. (vector-magnitude v2)))))
  161. (define counter-clockwise?
  162. (λ (a b c)
  163. (let ([dx1 (- (get-point-coord b 0)
  164. (get-point-coord a 0))]
  165. [dx2 (- (get-point-coord c 0)
  166. (get-point-coord a 0))]
  167. [dy1 (- (get-point-coord b 1)
  168. (get-point-coord a 1))]
  169. [dy2 (- (get-point-coord c 1)
  170. (get-point-coord a 1))])
  171. (cond
  172. [(> (* dx1 dy2) (* dy1 dx2)) #t]
  173. [else #f]))))
  174. (define clockwise?
  175. (λ (a b c)
  176. (let ([dx1 (- (get-point-coord b 0)
  177. (get-point-coord a 0))]
  178. [dx2 (- (get-point-coord c 0)
  179. (get-point-coord a 0))]
  180. [dy1 (- (get-point-coord b 1)
  181. (get-point-coord a 1))]
  182. [dy2 (- (get-point-coord c 1)
  183. (get-point-coord a 1))])
  184. (cond
  185. [(< (* dx1 dy2) (* dy1 dx2)) #t]
  186. [else #f]))))
  187. (define colinear?
  188. (λ (a b c)
  189. (let ([dx1 (- (get-point-coord b 0)
  190. (get-point-coord a 0))]
  191. [dx2 (- (get-point-coord c 0)
  192. (get-point-coord a 0))]
  193. [dy1 (- (get-point-coord b 1)
  194. (get-point-coord a 1))]
  195. [dy2 (- (get-point-coord c 1)
  196. (get-point-coord a 1))])
  197. (cond
  198. [(= (* dx1 dy2) (* dy1 dx2)) #t]
  199. [else #f]))))
  200. (define counter-clockwise-function
  201. (λ (a b c)
  202. "Return a positive number, if the angle of ab to bc is counter clockwise, a
  203. negative number, if the angle is clockwise and 0 if the points are colinear (on
  204. the same line)."
  205. (let ([dx1 (- (get-point-coord b 0)
  206. (get-point-coord a 0))]
  207. [dx2 (- (get-point-coord c 0)
  208. (get-point-coord a 0))]
  209. [dy1 (- (get-point-coord b 1)
  210. (get-point-coord a 1))]
  211. [dy2 (- (get-point-coord c 1)
  212. (get-point-coord a 1))])
  213. (cond
  214. [(> (* dx1 dy2) (* dy1 dx2)) 1]
  215. [(< (* dx1 dy2) (* dy1 dx2)) -1]
  216. [else 0]))))
  217. (define ccw counter-clockwise-function)