File: plot-element.rkt

package info (click to toggle)
racket 7.2%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 125,432 kB
  • sloc: ansic: 258,980; pascal: 59,975; sh: 33,650; asm: 13,558; lisp: 7,124; makefile: 3,329; cpp: 2,889; exp: 499; python: 274; xml: 11
file content (145 lines) | stat: -rw-r--r-- 7,265 bytes parent folder | download | duplicates (8)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#lang typed/racket/base

(require racket/list racket/match
         "type-doc.rkt"
         "math.rkt"
         "ticks.rkt"
         ;"contract.rkt"
         "parameters.rkt"
         "sample.rkt")

(provide (all-defined-out))

(deftype Bounds-Fun (-> Rect Rect))
(deftype Ticks-Fun (-> Rect (Listof (Listof tick))))

(struct plot-element ([bounds-rect : (U #f Rect)]
                      [bounds-fun : (U #f Bounds-Fun)]
                      [ticks-fun : (U #f Ticks-Fun)])
  #:transparent)

;; ===================================================================================================
;; Common field values

(defthing default-ticks-fun Ticks-Fun
  (λ (r)
    (cond
      [(rect-known? r)
       (match r
         [(vector (ivl xa xb) (ivl ya yb))
          (list (ticks-generate (plot-x-ticks) (assert xa values) (assert xb values))
                (ticks-generate (plot-x-far-ticks) (assert xa values) (assert xb values))
                (ticks-generate (plot-y-ticks) (assert ya values) (assert yb values))
                (ticks-generate (plot-y-far-ticks) (assert ya values) (assert yb values)))]
         [(vector (ivl xa xb) (ivl ya yb) (ivl za zb))
          (list (ticks-generate (plot-x-ticks) (assert xa values) (assert xb values))
                (ticks-generate (plot-x-far-ticks) (assert xa values) (assert xb values))
                (ticks-generate (plot-y-ticks) (assert ya values) (assert yb values))
                (ticks-generate (plot-y-far-ticks) (assert ya values) (assert yb values))
                (ticks-generate (plot-z-ticks) (assert za values) (assert zb values))
                (ticks-generate (plot-z-far-ticks) (assert za values) (assert zb values)))]
         [_  (raise-argument-error 'default-ticks-fun "vector of length 2 or 3" r)])]
      [else
       (raise-argument-error 'default-ticks-fun "rect-known?" r)])))

(:: function-bounds-fun (-> Sampler Natural Bounds-Fun))
(define ((function-bounds-fun f samples) r)
  (match-define (vector xi yi) r)
  (cond [(ivl-known? xi)
         (match-define (sample xs ys y-min y-max) (f xi samples))
         (vector xi (ivl y-min y-max))]
        [else  r]))

(:: inverse-bounds-fun (-> Sampler Natural Bounds-Fun))
(define ((inverse-bounds-fun f samples) r)
  (match-define (vector xi yi) r)
  (cond [(ivl-known? yi)
         (match-define (sample ys xs x-min x-max) (f yi samples))
         (vector (ivl x-min x-max) yi)]
        [else  r]))

(:: function-interval-bounds-fun (-> Sampler Sampler Natural Bounds-Fun))
(define ((function-interval-bounds-fun f1 f2 samples) r)
  (rect-join ((function-bounds-fun f1 samples) r)
             ((function-bounds-fun f2 samples) r)))

(:: inverse-interval-bounds-fun (-> Sampler Sampler Natural Bounds-Fun))
(define ((inverse-interval-bounds-fun f1 f2 samples) r)
  (rect-join ((inverse-bounds-fun f1 samples) r)
             ((inverse-bounds-fun f2 samples) r)))

(:: surface3d-bounds-fun (-> 2D-Sampler Natural Bounds-Fun))
(define ((surface3d-bounds-fun f samples) r)
  (match-define (vector xi yi zi) r)
  (cond [(and (ivl-known? xi) (ivl-known? yi))
         (match-define (2d-sample xs ys zss z-min z-max) (f (vector xi yi) (vector samples samples)))
         (vector xi yi (ivl z-min z-max))]
        [else  r]))

;; ===================================================================================================
;; Fixpoint computation of bounding rectangles

;; The reasoning in the following comments is in terms of a lattice comprised of rectangles,
;; rect-meet and rect-join. Think of rect-meet like a set intersection; rect-join like a set union.

(: bounds-fixpoint (->* [(Listof plot-element) Rect] [Natural] Rect))
;; Attempts to comptute a fixpoint of, roughly, the bounds functions for the given plot elements.
;; More precisely, starting with the given plot bounds, it attempts to compute a fixpoint of
;; (apply-bounds* elems), overridden at every iteration by the plot bounds (if given). Because a
;; fixpoint doesn't always exist, or only exists in the limit, it stops after max-iters.
(define (bounds-fixpoint elems given-bounds-rect [max-iters 4])
  (let/ec break : Rect
    ;; Shortcut eval: if the plot bounds are all given, the code below just returns them anyway
    (when (rect-known? given-bounds-rect) (break given-bounds-rect))
    ;; A list of elements' known bounds rects
    (define elem-bounds-rects
      (for*/list : (Listof Rect) ([elem  (in-list elems)]
                                  [r  (in-value (plot-element-bounds-rect elem))]
                                  #:when r)
        r))
    ;; The minimum bounding rectangle
    (define min-bounds-rect
      (cond [(empty? elem-bounds-rects)  given-bounds-rect]
            [else  (rect-join given-bounds-rect
                              (rect-meet given-bounds-rect
                                         (apply rect-join elem-bounds-rects)))]))
    ;; Objective: find the fixpoint of F starting at min-bounds-rect
    (define F (λ ([bounds-rect : Rect])
                (rect-meet given-bounds-rect (apply-bounds* elems bounds-rect))))
    ;; Iterate joint bounds to (hopefully) a fixpoint
    (define-values (bounds-rect area delta-area)
      (for/fold ([bounds-rect : Rect  min-bounds-rect]
                 [area : (U #f Real)  (rect-area min-bounds-rect)]
                 [delta-area : (U #f Real)  #f]
                 ) ([n  (in-range max-iters)])
        ;(printf "bounds-rect = ~v~n" bounds-rect)
        ;; Get new bounds from the elements' bounds functions
        (define new-bounds-rect (F bounds-rect))
        (define new-area (rect-area new-bounds-rect))
        (define new-delta-area (and area new-area (- new-area area)))
        (cond
          ;; Shortcut eval: if the bounds haven't changed, we have a fixpoint
          [(equal? bounds-rect new-bounds-rect)  (break bounds-rect)]
          ;; If the area grew more this iteration than last, it may not converge, so stop now
          [(and delta-area new-delta-area (new-delta-area . > . delta-area))  (break bounds-rect)]
          ;; All good - one more iteration
          [else  (values new-bounds-rect new-area new-delta-area)])))
    bounds-rect))

(: apply-bounds* (-> (Listof plot-element) Rect Rect))
;; Applies the bounds functions of multiple plot elements, in parallel, and returns the smallest
;; bounds containing all the new bounds. This function is monotone and increasing regardless of
;; whether any element's bounds function is. If iterating it is bounded, a fixpoint exists.
(define (apply-bounds* elems bounds-rect)
  (apply rect-join bounds-rect (for/list : (Listof Rect) ([elem  (in-list elems)])
                                 (apply-bounds elem bounds-rect))))

(: apply-bounds (-> plot-element Rect Rect))
;; Applies the plot element's bounds function. Asks this question: If these are your allowed bounds,
;; what bounds will you try to use?
(define (apply-bounds elem bounds-rect)
  (match-define (plot-element elem-bounds-rect elem-bounds-fun _) elem)
  ;(printf "elem-bounds-rect = ~v~n" elem-bounds-rect)
  (let* ([bounds-rect  (if elem-bounds-fun (elem-bounds-fun bounds-rect) bounds-rect)]
         [bounds-rect  (if elem-bounds-rect (rect-join elem-bounds-rect bounds-rect) bounds-rect)])
    bounds-rect))