PasteRack.org
Paste # 75790
2015-03-26 10:38:41

Fork as a new paste.

Paste viewed 329 times.


Embed:

  1. ;this is geometric_functions.rkt
  2.  
  3. ;(require "structs.rkt")
  4.  
  5. (provide in-between?
  6.          point-in-rect?
  7.          biggest
  8.          smallest
  9.          reasonable-equal?
  10.          intersect?
  11.          arc-intersect?
  12.          line-intersect?)
  13.  
  14. ;; geometric functions
  15. (define (point-in-rect? x y xs ys xb yb)
  16.   (and (> x xs) (< x xb) (> y ys) (< y yb)))
  17.  
  18. ;; auxilliary functions
  19. (define (best fn lst)
  20.   (unless (empty? lst)
  21.     (let ((wins (car lst)))
  22.       (for/list ([i (cdr lst)])
  23.         (when (fn i wins)
  24.           (set! wins i)))
  25.       wins)))
  26.  
  27. (define (biggest lst)
  28.   (best > lst))
  29.  
  30. (define (smallest lst)
  31.   (best < lst))
  32.  
  33. ;; this is used to check the equality of two numbers to a set decimal point
  34. ;; 0.009 -> accuracy up to 2 decimal point.
  35. ;; 0.09 -> accuracy up to 1 decimal point.
  36. ;; 0.9 -> integer test.
  37. ;; test up to 3 decimal points.
  38. (define (reasonable-equal? x y)
  39.   (<= (abs (- x y)) 0.000009))
  40.  
  41. (define (in-between? test-num num-1 num-2)
  42.   (or (and (> num-1 test-num) (< num-2 test-num))
  43.       (and (> num-2 test-num) (< num-1 test-num))))
  44.  
  45. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  46. ;; DXF specific routines ;;
  47. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  48.  
  49. ;; pass intersect? the start and end point of select box and the struct-list
  50. ;; it will traverse the struct-list to see if any elements
  51. (define (intersect? x1 y1 x2 y2 struct-lst)
  52.   (let ((big-x (biggest (list x1 x2)))
  53.         (big-y (biggest (list y1 y2)))
  54.         (small-x (smallest (list x1 x2)))
  55.         (small-y (smallest (list y1 y2))))
  56.     (for/list ([i struct-lst])
  57.       ;calculate intersections for visible
  58.       (when (dxf-entity-visible i)
  59.         (when (dxf-line? i)
  60.           (if (line-intersect? i small-x small-y big-x big-y)
  61.               (set-dxf-entity-selected! i #t)
  62.               (set-dxf-entity-selected! i #f)))
  63.         (when (dxf-arc? i)
  64.           (if (arc-intersect? i small-x small-y big-x big-y)
  65.               (set-dxf-entity-selected! i #t)
  66.               (set-dxf-entity-selected! i #f)))
  67.         (when (dxf-point? i)
  68.           (if (point-in-rect? (dxf-point-x i) (dxf-point-y i) small-x small-y big-x big-y)
  69.               (set-dxf-entity-selected! i #t)
  70.               (set-dxf-entity-selected! i #f)))))))
  71.  
  72. ;; these 3 functions calculate the x and y coordinates for arc points
  73. (define (arc-point-x circle-x degree radius)
  74.   (let ((adjusted (localize-degree degree)))
  75.     (cond ((or (= degree 90) (= degree 270)) circle-x)
  76.           ((= degree 180) (- circle-x radius))
  77.           ((or (= degree 360) (= degree 0)) (+ circle-x radius))
  78.           ((in-between? degree 0 90)    (+ circle-x (* radius (cos (degrees->radians adjusted)))))
  79.           ((in-between? degree 90 180)  (- circle-x (* radius (sin (degrees->radians adjusted)))))
  80.           ((in-between? degree 180 270) (- circle-x (* radius (cos (degrees->radians adjusted)))))
  81.           ((in-between? degree 270 360) (+ circle-x (* radius (sin (degrees->radians adjusted)))))
  82.           (else (display "error")))))
  83. (define (arc-point-y circle-y degree radius)
  84.   (let ((adjusted (localize-degree degree)))
  85.     (cond ((or (= degree 0) (= degree 360) (= degree 180)) circle-y)
  86.           ((= degree 90) (+ circle-y radius))
  87.           ((= degree 270) (- circle-y radius))
  88.           ((in-between? degree 0 90)    (+ circle-y (* radius (sin (degrees->radians adjusted)))))
  89.           ((in-between? degree 90 180)  (+ circle-y (* radius (cos (degrees->radians adjusted)))))
  90.           ((in-between? degree 180 270) (- circle-y (* radius (sin (degrees->radians adjusted)))))
  91.           ((in-between? degree 270 360) (- circle-y (* radius (cos (degrees->radians adjusted)))))
  92.           (else (display "error")))))
  93. (define (localize-degree degree)
  94.   (cond ((in-between? degree 0 90) degree)
  95.         ((in-between? degree 90 180) (- degree 90))
  96.         ((in-between? degree 180 270) (- degree 180))
  97.         ((in-between? degree 270 360) (- degree 270))))
  98.  
  99. ;; 1) check for the trivial case - the arc point is inside the select box
  100. ;; 2) imagine the 4 lines of the select box as an infinite line, do they intersect the circle of the arc?
  101. ;; 2.1) if they do, are they in the select box's actual length/width?
  102. ;; 2.2) if they are, does it intersect the arc?
  103. ;; 2.3.1) arc intersection is checked by comparing the points where the lines intersect the circle.
  104. ;; 2.3.2) imagine a line from arc point 1 to arc point 2 as a "dividing line", to differentiate points intersecting the circle on the "right" or "wrong" side of the arc
  105. ;; 2.3.3) calculate the mid-point of the arc to determine the "right" side of the arc.
  106. ;; 2.3.4) imagine a line that goes through the mid-point of the arc and is parallel to the "dividing line" (hence they have the same slope).
  107. ;; 2.3.5) is the y-intercept bigger or smaller than the y-intercept of the dividing line? use that as a barometer for any point intersecting the circle.
  108. ;; 2.3.6) if the line formed with the intersecting point falls on the right side of the "dividing line" together with the line formed with the mid-point line, then there is an intersection.
  109. (define (arc-intersect? dxf-arc-struct xs ys xb yb)
  110.   (let* ((radius (dxf-arc-radius dxf-arc-struct))
  111.          (circle-x (dxf-arc-x dxf-arc-struct))
  112.          (circle-y (dxf-arc-y dxf-arc-struct))
  113.          (start (dxf-arc-start dxf-arc-struct))
  114.          (end (dxf-arc-end dxf-arc-struct))
  115.          (angle-difference (if (> end start) (- end start) (+ (- 360 start) end)))
  116.          (half-angle (if (> end start) (/ (+ start end) 2) (if (< 360 (+ 180 (/ (+ start end) 2))) (- (+ 180 (/ (+ start end) 2)) 360) (+ 180 (/ (+ start end) 2)))))
  117.          (radius (dxf-arc-radius dxf-arc-struct))
  118.          (arc-x1 (arc-point-x circle-x start radius))
  119.          (arc-y1 (arc-point-y circle-y start radius))
  120.          (arc-x2 (arc-point-x circle-x end radius))
  121.          (arc-y2 (arc-point-y circle-y end radius))
  122.          ;we calculate the middle arc-point to determine which is the right side
  123.          (half-x (arc-point-x circle-x half-angle radius))
  124.          (half-y (arc-point-y circle-y half-angle radius)))
  125.     (define (right-side-y? x y)
  126.       (let* ((dividing-line-slope       (/ (- arc-y2 arc-y1) (- arc-x2 arc-x1)))
  127.              (dividing-line-yintercept  (- arc-y1 (* dividing-line-slope arc-x1)))
  128.              (right-yintercept          (- half-y (* dividing-line-slope half-x)))
  129.              (right-value-test          (> right-yintercept dividing-line-yintercept))
  130.              (point-yintercept          (- y (* dividing-line-slope x)))
  131.              (point-test                (> point-yintercept dividing-line-yintercept)))
  132.         (eq? right-value-test point-test)))
  133.     (define (line-intersect-arc? x1 y1 x2 y2)
  134.       ;return the point where line intersects arc. intersection of a y line with a circle, 2 possible x values
  135.       (define (yline-intersect-circle? y)
  136.         (let ((result1 (+ circle-x (sqrt (- (expt radius 2) (expt (- y circle-y) 2)))))
  137.               (result2 (- circle-x (sqrt (- (expt radius 2) (expt (- y circle-y) 2))))))
  138.           (if (real? result1)
  139.               (cond ((and (in-between? result1 xs xb) (in-between? result2 xs xb))
  140.                      (list (list result1 y) (list result2 y)))
  141.                     ((in-between? result1 xs xb)
  142.                      (list (list result1 y)))
  143.                     ((in-between? result2 xs xb)
  144.                      (list (list result2 y)))
  145.                     (else #f))
  146.               #f)))
  147.       ;return the point where line intersects arc. intersection of a x line with a circle, 2 possible y values
  148.       (define (xline-intersect-circle? x)
  149.         (let ((result1 (+ circle-y (sqrt (- (expt radius 2) (expt (- x circle-x) 2)))))
  150.               (result2 (- circle-y (sqrt (- (expt radius 2) (expt (- x circle-x) 2))))))
  151.           (if (real? result1)
  152.               (cond ((and (in-between? result1 ys yb) (in-between? result2 ys yb))
  153.                      (list (list x result1) (list x result2)))
  154.                     ((in-between? result1 ys yb)
  155.                      (list (list x result1)))
  156.                     ((in-between? result2 ys yb)
  157.                      (list (list x result2)))
  158.                     (else #f))
  159.               #f)))
  160.       (if (= x1 x2)
  161.           ((lambda (x) (if (eq? x #f) #f (ormap (lambda (a) (apply right-side-y? a)) x))) (xline-intersect-circle? x1))    ;is a x line, find y values
  162.           ((lambda (x) (if (eq? x #f) #f (ormap (lambda (a) (apply right-side-y? a)) x))) (yline-intersect-circle? y1))))  ;is a y line, find x values
  163.     (cond ((or (point-in-rect? arc-x1 arc-y1 xs ys xb yb) (point-in-rect? arc-x2 arc-y2 xs ys xb yb)) #t)
  164.           ((or (line-intersect-arc? xs ys xs yb)
  165.                (line-intersect-arc? xs yb xb yb)
  166.                (line-intersect-arc? xb yb xb ys)
  167.                (line-intersect-arc? xb ys xs ys)) #t)
  168.           (else #f))))
  169.  
  170. ;; divide the complete 2d space into 9 boxes
  171. ;; cohen-sutherland algorithm to detect line-rectangle intersection. separate 2d area into 9 rectangles where 0 represents the selected area
  172. ;; region numbers are bit->decimal
  173. ;; 9   1   5                1001   0001   0101
  174. ;; 8   0   4      --->      1000   0000   0100
  175. ;; 10  2   6                1010   0010   0110
  176. (define (line-intersect? dxf-line-struct xs ys xb yb)
  177.   (let ((lx1 (dxf-line-x1 dxf-line-struct))
  178.         (ly1 (dxf-line-y1 dxf-line-struct))
  179.         (lx2 (dxf-line-x2 dxf-line-struct))
  180.         (ly2 (dxf-line-y2 dxf-line-struct)))
  181.     (define (compute-outcode x y)
  182.       (let ((inside 0))
  183.         (cond ((< x xs)
  184.                (set! inside (bitwise-ior inside 1)))
  185.               ((> x xb)
  186.                (set! inside (bitwise-ior inside 2))))
  187.         (cond ((< y ys)
  188.                (set! inside (bitwise-ior inside 4)))
  189.               ((> y yb)
  190.                (set! inside (bitwise-ior inside 8))))
  191.         inside))
  192.     ;return #t if intersect
  193.     (define (trivial-accept? region1 region2)
  194.       (or (not (bitwise-ior region1 region2))
  195.           (= region1 0)
  196.           (= region2 0)
  197.           (and (= region1 1) (= region2 2))
  198.           (and (= region1 2) (= region2 1))
  199.           (and (= region1 4) (= region2 8))
  200.           (and (= region1 8) (= region2 4))))
  201.     ;return #t if does not intersect
  202.     (define (trivial-reject? region1 region2)
  203.       (not (= (bitwise-and region1 region2) 0)))
  204.     ;clip until no more ambiguous cases
  205.     (define (clip-until region1 region2 tries)
  206.       (cond ((= tries 0) #f)
  207.             ((trivial-reject? region1 region2) #f)
  208.             ((trivial-accept? region1 region2) #t)
  209.             (else (apply clip-until (append (do-clip region1 region2) (list (- tries 1)))))))
  210.     (define (do-clip region1 region2)
  211.       (define (not0 num)
  212.         (if (= num 0) #f #t))
  213.       (let* ((new-x 0)
  214.              (new-y 0)
  215.              (slope (/ (- ly2 ly1) (- lx2 lx1)))
  216.              (y-intercept (- ly2 (* slope lx2))))
  217.         ;apply the formula y = y1 + slope * (x - x1), x = x1 + (y - y1) / slope
  218.         (cond ((not0 (bitwise-and 8 region2))
  219.                (set! new-x (/ (- yb y-intercept) slope))
  220.                (set! new-y yb))
  221.               ((not0 (bitwise-and 4 region2))
  222.                (set! new-x (/ (- ys y-intercept) slope))
  223.                (set! new-y ys))
  224.               ((not0 (bitwise-and 2 region2))
  225.                (set! new-x xb)
  226.                (set! new-y (+ (* slope xb) y-intercept)))
  227.               ((not0 (bitwise-and 1 region2))
  228.                (set! new-x xs)
  229.                (set! new-y (+ (* slope xs) y-intercept))))
  230.         (set! lx2 new-x)
  231.         (set! ly2 new-y)
  232.         (set! region2 (compute-outcode lx2 ly2)))
  233.       (list region1 region2))
  234.     (let* ((region1 (compute-outcode lx1 ly1))
  235.            (region2 (compute-outcode lx2 ly2)))
  236.       (clip-until region1 region2 4))))

=>