graphics-utils.lisp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. ;; This software is Copyright (c) cage
  2. ;; cage grants you the rights to distribute
  3. ;; and use this software as governed by the terms
  4. ;; of the Lisp Lesser GNU Public License
  5. ;; (http://opensource.franz.com/preamble.html),
  6. ;; known as the LLGPL
  7. (in-package :cl-pslib)
  8. (defun aabb->rect (coords)
  9. "(upper-left-x upper-left-y bottom-right-x bottom-right-y) to
  10. (upper-left-x upper-left-y w h)"
  11. (let ((x1 (first coords))
  12. (y1 (second coords))
  13. (x2 (third coords))
  14. (y2 (fourth coords)))
  15. (list x1 y1 (- x2 x1) (- y2 y1))))
  16. (defun rect->aabb (coords)
  17. "(upper-left-x upper-left-y w h) to
  18. (upper-left-x upper-left-y bottom-right-x bottom-right-y)"
  19. (let ((x1 (first coords))
  20. (y1 (second coords))
  21. (w (third coords))
  22. (h (fourth coords)))
  23. (list x1 y1 (+ x1 w) (+ y1 h))))
  24. (defun inside-aabb-p (aabb x y)
  25. "t if x y is inside this bounding box
  26. aabb is in the form: (upper-left-x upper-left-y bottom-right-x bottom-right-y)"
  27. (and
  28. (> x (first aabb))
  29. (< x (third aabb))
  30. (> y (second aabb))
  31. (< y (fourth aabb))))
  32. (defun line-eqn(a b &optional (thresh 1e-5))
  33. "Calculate a bidimensional line equation crossing vector a and b.
  34. Return a list containing m q and two flag indicating if the line is
  35. paralle to x or y respectively"
  36. (let ((dy (- (second b) (second a)))
  37. (dx (- (first b) (first a))))
  38. (cond
  39. ((<= 0 dy thresh) ;parallel to x
  40. (list 0 (second b) t nil))
  41. ((<= 0 dx thresh) ; parallel to y
  42. (list 0 0 nil t))
  43. (t
  44. (list (/ dy dx) (- (second a ) (* (/ dy dx) (first a))) nil nil)))))
  45. (defun recursive-bezier (pairs &key (threshold 1))
  46. (labels ((midpoint (pb pe)
  47. (mapcar #'(lambda (x) (/ x 2)) (2d-vector-sum pb pe)))
  48. (eqvec-p (a b) (and (= (first a) (first b))
  49. (= (second a) (second b)))))
  50. (let* ((p1 (first pairs))
  51. (p2 (second pairs))
  52. (p3 (third pairs))
  53. (p4 (fourth pairs))
  54. (p12 (midpoint p1 p2))
  55. (p23 (midpoint p2 p3))
  56. (p34 (midpoint p3 p4))
  57. (p12-23 (midpoint p12 p23))
  58. (p23-34 (midpoint p23 p34))
  59. (res (midpoint p12-23 p23-34)))
  60. (if (>= (2d-vector-magn (2d-vector-diff p1 res)) threshold)
  61. (remove-duplicates
  62. (append (list p1)
  63. (recursive-bezier (list p1 p12 p12-23 res) :threshold threshold)
  64. (list res)
  65. (recursive-bezier (list res p23-34 p34 p4) :threshold threshold)
  66. (list p4))
  67. :test #'eqvec-p)
  68. nil))))
  69. (defmacro funcall-if-not-null (func val)
  70. (if (not (null func))
  71. `(funcall ,func ,val)
  72. val))
  73. (defun 2d-vector-map (v &key (funcx nil) (funcy nil))
  74. "Return a list of x,y values of the vector transformed by funcx and funcy (if not nil) respectively"
  75. (list
  76. (if (not (null funcx))
  77. (funcall-if-not-null funcx (first v))
  78. (funcall-if-not-null nil (first v)))
  79. (if (not (null funcy))
  80. (funcall-if-not-null funcy (second v))
  81. (funcall-if-not-null nil (second v)))))
  82. (defun 2d-vector-list-map (pairs &key (funcx nil) (funcy nil))
  83. "Remap pairs applying funcx and funcy (if not nil) to each component"
  84. (mapcar #'(lambda (v) (2d-vector-map v :funcx funcx :funcy funcy)) pairs))
  85. (defun 2d-vector-list-scale (pairs &optional (ax 1) (ay 1))
  86. "Remap pairs scaling each components by ax and ay"
  87. (mapcar #'(lambda (v) (2d-vector-scale v ax ay)) pairs))
  88. (defun 2d-vector-list-translate (pairs &optional (dx 0) (dy 0))
  89. "translate pairs by dx and dy"
  90. (mapcar #'(lambda (v) (2d-vector-map v
  91. :funcx #'(lambda (x) (+ x dx))
  92. :funcy #'(lambda (y) (+ y dy))))
  93. pairs))
  94. (defun 2d-vector-list-rotate (pairs angle)
  95. (mapcar #'(lambda (v) (2d-vector-rotate v angle)) pairs))
  96. (defun 2d-vector-sum (a b)
  97. (mapcar #'(lambda (x y) (+ x y)) a b))
  98. (defun 2d-vector-diff (a b)
  99. (mapcar #'(lambda (x y) (- x y)) a b))
  100. (defun 2d-vector-dot-product (a b)
  101. (+ (* (first a) (first b)) (* (second a) (second b))))
  102. (defun 2d-vector-cross-product (a b)
  103. (- (* (first a) (second b)) (* (second a) (first b))))
  104. (defun 2d-vector-scale (a amount-x &optional (amount-y amount-x))
  105. (list (* amount-x (first a)) (* amount-y (second a))))
  106. (defun 2d-vector-translate (a amount-x &optional (amount-y amount-x))
  107. (list (+ amount-x (first a)) (+ amount-y (second a))))
  108. (defun 2d-vector-magn (a)
  109. (sqrt (+ (expt (first a) 2) (expt (second a) 2))))
  110. (defun 2d-vector-normalize (a)
  111. (let ((mag (2d-vector-magn a)))
  112. (list (/ (first a) mag) (/ (second a) mag))))
  113. (defun 2d-vector-angle (a b)
  114. (let* ((a-norm (2d-vector-normalize a))
  115. (b-norm (2d-vector-normalize b))
  116. (dot-product (2d-vector-dot-product a-norm b-norm))
  117. (angle (acos dot-product)))
  118. (if (< (2d-vector-cross-product a b) 0)
  119. (- angle)
  120. angle)))
  121. (defun 2d-vector-rotate (a angle)
  122. (list
  123. (- (* (first a) (cos angle)) (* (second a) (sin angle)))
  124. (+ (* (first a) (sin angle)) (* (second a) (cos angle)))))
  125. (defun xy->pair (xs ys)
  126. "Convert (x1 x2 x3...) (y1 y2 y3...) to ((x1 y1) (x2 y2) (x3 y3) ...)"
  127. (mapcar #'(lambda (x y) (list x y)) xs ys))
  128. (defun pair->interleaved-xy (x-y)
  129. "Convert ((x1 y1) (x2 y2) (x3 y3) ...) to (x1 y1 x2 y2 x3 y3 ...)"
  130. (reduce #'append x-y))
  131. (defun xy->interleaved-xy (xs ys &key (modfunc-x nil) (modfunc-y nil))
  132. "Convert (x1 x2 x3...) (y1 y2 y3...) to ( (funcall modfunc-x x1) (funcall modfunc-y y1)...)"
  133. (pair->interleaved-xy (xy->pair (if (not (null modfunc-x))
  134. (mapcar modfunc-x xs)
  135. xs)
  136. (if (not (null modfunc-y))
  137. (mapcar modfunc-y ys)
  138. ys))))
  139. (defun interleaved-xy->pair (xy)
  140. (macrolet ((get-from-list (when-clause list)
  141. `(loop
  142. for i in ,list
  143. for c = 0 then (1+ c)
  144. when (,when-clause c)
  145. collect i)))
  146. (let ((xs (get-from-list evenp xy))
  147. (ys (get-from-list oddp xy)))
  148. (xy->pair xs ys))))