Refactored margin fixpoint computation
This commit is contained in:
parent
ee9f9ffae0
commit
d953a093c7
|
@ -276,3 +276,48 @@
|
|||
|
||||
(define (subdivide-polygon transform vs)
|
||||
(subdivide-lines transform (cons (last vs) vs)))
|
||||
|
||||
;; ===================================================================================================
|
||||
;; Fixpoint margin computation
|
||||
|
||||
;; In calculating margins in 2d-plot-area% and 3d-plot-area%, we have a mutual dependence problem:
|
||||
;; 1. We can't set the margins without knowing where the ticks and axis labels will be drawn.
|
||||
;; 2. We can't determine the tick and label angles (and thus their vertexes) without the margins.
|
||||
|
||||
;; The margins could be solved exactly using algebra and trigonometry, but the solutions wouldn't
|
||||
;; be robust, as small changes to the layout algorithms would invalidate them.
|
||||
|
||||
;; So we use a fixpoint solution: iterate
|
||||
;; 1. Getting tick and label vertexes ('get-vs' below); then
|
||||
;; 2. Calculating new margins by how far off the dc the vertexes would be.
|
||||
|
||||
;; As long as this process is monotone and bounded, the distance off the dc is zero in the limit. In
|
||||
;; practice, only a few iterations drives this distance to less than 1 drawing unit.
|
||||
|
||||
(define (appx= x y) ((abs (- x y)) . < . 1/2))
|
||||
|
||||
(define (margin-fixpoint x-min x-max y-min y-max
|
||||
init-left init-right init-top init-bottom
|
||||
get-vs)
|
||||
(let/ec return
|
||||
(for/fold ([left init-left] [right init-right] [top init-top] [bottom init-bottom]
|
||||
) ([i (in-range 3)])
|
||||
(match-define (list (vector xs ys) ...) (get-vs left right top bottom))
|
||||
|
||||
(define param-x-min (apply min x-min xs))
|
||||
(define param-x-max (apply max (sub1 x-max) xs))
|
||||
(define param-y-min (apply min y-min ys))
|
||||
(define param-y-max (apply max (sub1 y-max) ys))
|
||||
|
||||
(define new-left (+ left (- x-min param-x-min)))
|
||||
(define new-right (- right (- (sub1 x-max) param-x-max)))
|
||||
(define new-top (+ top (- y-min param-y-min)))
|
||||
(define new-bottom (- bottom (- (sub1 y-max) param-y-max)))
|
||||
|
||||
;; Early out: if the margins haven't changed much, another iteration won't change them more
|
||||
;; (hopefully)
|
||||
(when (and (appx= left new-left) (appx= right new-right)
|
||||
(appx= top new-top) (appx= bottom new-bottom))
|
||||
(return new-left new-right new-top new-bottom))
|
||||
|
||||
(values new-left new-right new-top new-bottom))))
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
(define radius (if ticks? (* 1/2 (plot-tick-size)) 0))
|
||||
|
||||
(send area put-alpha alpha)
|
||||
(send area put-major-pen)
|
||||
(send area put-minor-pen)
|
||||
(send area put-line (vector x-min y) (vector x-max y))
|
||||
|
||||
(when ticks?
|
||||
|
@ -56,7 +56,7 @@
|
|||
(define radius (if ticks? (* 1/2 (plot-tick-size)) 0))
|
||||
|
||||
(send area put-alpha alpha)
|
||||
(send area put-major-pen)
|
||||
(send area put-minor-pen)
|
||||
(send area put-line (vector x y-min) (vector x y-max))
|
||||
|
||||
(when ticks?
|
||||
|
@ -148,7 +148,7 @@
|
|||
(define-values (x-min x-max y-min y-max) (send area get-bounds))
|
||||
(define-values (θs r-mins r-maxs) (build-polar-axes num x-min x-max y-min y-max))
|
||||
|
||||
(send area put-major-pen)
|
||||
(send area put-minor-pen)
|
||||
(for ([θ (in-list θs)] [r-min (in-list r-mins)] [r-max (in-list r-maxs)])
|
||||
(send area put-line
|
||||
(vector (* r-min (cos θ)) (* r-min (sin θ)))
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
(define tick-radius (* 1/2 (plot-tick-size)))
|
||||
(define half-tick-radius (* 1/2 tick-radius))
|
||||
|
||||
(define near-dist^2 (sqr(* 3 (plot-line-width))))
|
||||
(define near-dist^2 (sqr (* 3 (plot-line-width))))
|
||||
(define (vnear? v1 v2)
|
||||
((vmag^2 (v- (plot->dc* v1) (plot->dc* v2))) . <= . near-dist^2))
|
||||
|
||||
|
@ -164,14 +164,20 @@
|
|||
(collapse-nearby-ticks (filter (λ (t) (<= y-min (pre-tick-value t) y-max)) ry-far-ticks)
|
||||
(y-tick-near? x-max)))
|
||||
|
||||
(define draw-x-far-tick-labels? (not (and (plot-x-axis?) (equal? x-ticks x-far-ticks))))
|
||||
(define draw-y-far-tick-labels? (not (and (plot-y-axis?) (equal? y-ticks y-far-ticks))))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Tick and tick label parameters
|
||||
;; Tick and label parameters, and fixpoint margin computation
|
||||
|
||||
;; From here through "All parameters" are functions that compute *just the parameters* of ticks
|
||||
;; and labels that will be drawn on the plot. We have to separate computing parameters from
|
||||
;; actually drawing the ticks and labels so we can solve for the plot margins using a fixpoint
|
||||
;; computation. See ../common/draw.rkt for more explanation. (Search for 'margin-fixpoint'.)
|
||||
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; Tick parameters
|
||||
|
||||
(define (x-tick-value->dc x) (plot->dc* (vector x y-min)))
|
||||
(define (y-tick-value->dc y) (plot->dc* (vector x-min y)))
|
||||
|
||||
(define (x-far-tick-value->dc x) (plot->dc* (vector x y-max)))
|
||||
(define (y-far-tick-value->dc y) (plot->dc* (vector x-max y)))
|
||||
|
||||
|
@ -191,9 +197,16 @@
|
|||
|
||||
(define (get-y-far-tick-params)
|
||||
(if (plot-y-far-axis?) (get-tick-params y-far-ticks y-far-tick-value->dc 0) empty))
|
||||
|
||||
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; Tick label parameters
|
||||
|
||||
(define draw-x-far-tick-labels? (not (and (plot-x-axis?) (equal? x-ticks x-far-ticks))))
|
||||
(define draw-y-far-tick-labels? (not (and (plot-y-axis?) (equal? y-ticks y-far-ticks))))
|
||||
|
||||
(define x-tick-label-offset (vector 0 (+ (pen-gap) tick-radius)))
|
||||
(define y-tick-label-offset (vector (- (+ (pen-gap) tick-radius)) 0))
|
||||
|
||||
(define x-far-tick-label-offset (vneg x-tick-label-offset))
|
||||
(define y-far-tick-label-offset (vneg y-tick-label-offset))
|
||||
|
||||
|
@ -213,16 +226,16 @@
|
|||
empty))
|
||||
|
||||
(define (get-x-far-tick-label-params)
|
||||
(if (plot-x-far-axis?)
|
||||
(if (and (plot-x-far-axis?) draw-x-far-tick-labels?)
|
||||
(get-tick-label-params x-far-ticks x-far-tick-label-offset x-far-tick-value->dc 'bottom)
|
||||
empty))
|
||||
|
||||
(define (get-y-far-tick-label-params)
|
||||
(if (plot-y-far-axis?)
|
||||
(if (and (plot-y-far-axis?) draw-y-far-tick-labels?)
|
||||
(get-tick-label-params y-far-ticks y-far-tick-label-offset y-far-tick-value->dc 'left)
|
||||
empty))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; Axis label parameters
|
||||
|
||||
(define (max-tick-offset ts)
|
||||
|
@ -232,6 +245,7 @@
|
|||
|
||||
(define max-x-tick-offset (if (plot-x-axis?) (max-tick-offset x-ticks) 0))
|
||||
(define max-y-tick-offset (if (plot-y-axis?) (max-tick-offset y-ticks) 0))
|
||||
|
||||
(define max-x-far-tick-offset (if (plot-x-far-axis?) (max-tick-offset x-far-ticks) 0))
|
||||
(define max-y-far-tick-offset (if (plot-y-far-axis?) (max-tick-offset y-far-ticks) 0))
|
||||
|
||||
|
@ -244,6 +258,7 @@
|
|||
|
||||
(define max-x-tick-label-height (if (plot-x-axis?) (max-tick-label-height x-ticks) 0))
|
||||
(define max-y-tick-label-width (if (plot-y-axis?) (max-tick-label-width y-ticks) 0))
|
||||
|
||||
(define max-x-far-tick-label-height (if (and (plot-x-far-axis?) draw-x-far-tick-labels?)
|
||||
(max-tick-label-height x-far-ticks)
|
||||
0))
|
||||
|
@ -267,54 +282,40 @@
|
|||
(define offset (vector (+ max-y-far-tick-offset max-y-far-tick-label-width half-char-height) 0))
|
||||
(list (plot-y-far-label) (v+ (view->dc (vector x-max y-mid)) offset) 'top (/ pi 2)))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Fixpoint margin computation
|
||||
|
||||
(define (get-all-tick-label-params)
|
||||
(append (get-x-tick-label-params) (get-y-tick-label-params)
|
||||
(if draw-x-far-tick-labels? (get-x-far-tick-label-params) empty)
|
||||
(if draw-y-far-tick-labels? (get-y-far-tick-label-params) empty)))
|
||||
|
||||
(define (get-all-axis-label-params)
|
||||
(append (if (plot-x-label) (list (get-x-label-params)) empty)
|
||||
(if (plot-y-label) (list (get-y-label-params)) empty)
|
||||
(if (plot-x-far-label) (list (get-x-far-label-params)) empty)
|
||||
(if (plot-y-far-label) (list (get-y-far-label-params)) empty)))
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; All parameters
|
||||
|
||||
(define (get-all-label-params)
|
||||
(cond [(plot-decorations?) (append (get-all-axis-label-params) (get-all-tick-label-params))]
|
||||
[else empty]))
|
||||
(if (plot-decorations?)
|
||||
(append (if (plot-x-label) (list (get-x-label-params)) empty)
|
||||
(if (plot-y-label) (list (get-y-label-params)) empty)
|
||||
(if (plot-x-far-label) (list (get-x-far-label-params)) empty)
|
||||
(if (plot-y-far-label) (list (get-y-far-label-params)) empty)
|
||||
(get-x-tick-label-params)
|
||||
(get-y-tick-label-params)
|
||||
(get-x-far-tick-label-params)
|
||||
(get-y-far-tick-label-params))
|
||||
empty))
|
||||
|
||||
(define (get-all-tick-params)
|
||||
(cond [(plot-decorations?) (append (get-x-tick-params) (get-y-tick-params)
|
||||
(get-x-far-tick-params) (get-y-far-tick-params))]
|
||||
[else empty]))
|
||||
(if (plot-decorations?)
|
||||
(append (get-x-tick-params) (get-y-tick-params)
|
||||
(get-x-far-tick-params) (get-y-far-tick-params))
|
||||
empty))
|
||||
|
||||
(define (new-margins left right top bottom label-params tick-params)
|
||||
(match-define (list (vector label-xs label-ys) ...)
|
||||
(append* (map (λ (params) (send/apply pd get-text-corners params)) label-params)))
|
||||
(match-define (list (vector tick-xs tick-ys) ...)
|
||||
(append* (map (λ (params) (send/apply pd get-tick-endpoints (rest params))) tick-params)))
|
||||
(define xs (append label-xs tick-xs))
|
||||
(define ys (append label-ys tick-ys))
|
||||
|
||||
(define param-x-min (apply min dc-x-min xs))
|
||||
(define param-x-max (apply max (sub1 dc-x-max) xs))
|
||||
(define param-y-min (apply min title-y-min ys))
|
||||
(define param-y-max (apply max (sub1 dc-y-max) ys))
|
||||
|
||||
(values (+ left (- dc-x-min param-x-min))
|
||||
(- right (- (sub1 dc-x-max) param-x-max))
|
||||
(+ top (- title-y-min param-y-min))
|
||||
(- bottom (- (sub1 dc-y-max) param-y-max))))
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; Fixpoint margin computation
|
||||
|
||||
(define (get-param-vs/set-view->dc! left right top bottom)
|
||||
(set! view->dc (make-view->dc left right top bottom))
|
||||
(append (append* (map (λ (params) (send/apply pd get-text-corners params))
|
||||
(get-all-label-params)))
|
||||
(append* (map (λ (params) (send/apply pd get-tick-endpoints (rest params)))
|
||||
(get-all-tick-params)))))
|
||||
|
||||
(define-values (area-x-min right area-y-min bottom)
|
||||
(for/fold ([left 0] [right 0] [top init-top-margin] [bottom 0]) ([i (in-range 5)])
|
||||
(define-values (new-left new-right new-top new-bottom)
|
||||
(new-margins left right top bottom (get-all-label-params) (get-all-tick-params)))
|
||||
(set! view->dc (make-view->dc new-left new-right new-top new-bottom))
|
||||
;(printf "margins: ~v ~v ~v ~v~n" new-left new-right new-top new-bottom)
|
||||
(values new-left new-right new-top new-bottom)))
|
||||
(margin-fixpoint dc-x-min dc-x-max title-y-min dc-y-max 0 0 init-top-margin 0
|
||||
get-param-vs/set-view->dc!))
|
||||
|
||||
(define area-x-max (- dc-x-max right))
|
||||
(define area-y-max (- dc-y-max bottom))
|
||||
|
@ -336,21 +337,25 @@
|
|||
(when (and (plot-decorations?) (plot-title))
|
||||
(send pd draw-text (plot-title) (vector (* 1/2 (+ dc-x-min dc-x-max)) dc-y-min) 'top)))
|
||||
|
||||
(define (draw-borders)
|
||||
(define (draw-axes)
|
||||
(when (plot-decorations?)
|
||||
(put-minor-pen)
|
||||
(when (plot-x-axis?) (send pd draw-line
|
||||
(vector area-x-min area-y-max)
|
||||
(vector area-x-max area-y-max)))
|
||||
(when (plot-x-far-axis?) (send pd draw-line
|
||||
(vector area-x-min area-y-min)
|
||||
(vector area-x-max area-y-min)))
|
||||
(when (plot-y-axis?) (send pd draw-line
|
||||
(vector area-x-min area-y-min)
|
||||
(vector area-x-min area-y-max)))
|
||||
(when (plot-y-far-axis?) (send pd draw-line
|
||||
(vector area-x-max area-y-min)
|
||||
(vector area-x-max area-y-max)))))
|
||||
(send pd set-minor-pen)
|
||||
(when (plot-x-axis?)
|
||||
(send pd draw-line
|
||||
(vector area-x-min area-y-max)
|
||||
(vector area-x-max area-y-max)))
|
||||
(when (plot-x-far-axis?)
|
||||
(send pd draw-line
|
||||
(vector area-x-min area-y-min)
|
||||
(vector area-x-max area-y-min)))
|
||||
(when (plot-y-axis?)
|
||||
(send pd draw-line
|
||||
(vector area-x-min area-y-min)
|
||||
(vector area-x-min area-y-max)))
|
||||
(when (plot-y-far-axis?)
|
||||
(send pd draw-line
|
||||
(vector area-x-max area-y-min)
|
||||
(vector area-x-max area-y-max)))))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Public drawing control (used by plot/dc)
|
||||
|
@ -358,7 +363,7 @@
|
|||
(define/public (start-plot)
|
||||
(send pd reset-drawing-params)
|
||||
(send pd clear)
|
||||
(draw-borders)
|
||||
(draw-axes)
|
||||
(draw-ticks))
|
||||
|
||||
(define/public (start-renderer rx-min rx-max ry-min ry-max)
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
(send pd reset-drawing-params)
|
||||
|
||||
(define char-height (send pd get-char-height))
|
||||
(define half-char-height (* 1/2 char-height))
|
||||
(define char-baseline (send pd get-char-baseline))
|
||||
|
||||
(define clipping? #f)
|
||||
(define clip-x-min x-min)
|
||||
|
@ -160,22 +162,42 @@
|
|||
(define init-top-margin (if (and (plot-decorations?) (plot-title)) (* 3/2 char-height) 0))
|
||||
(set! view->dc (make-view->dc 0 0 init-top-margin 0))
|
||||
|
||||
(define (plot-dir->dc-angle v)
|
||||
(match-define (vector dx dy)
|
||||
(v- (plot->dc/no-axis-trans (v+ v (vector x-mid y-mid z-mid)))
|
||||
(plot->dc/no-axis-trans (vector x-mid y-mid z-mid))))
|
||||
(- (atan2 (- dy) dx)))
|
||||
|
||||
(define (x-axis-angle) (plot-dir->dc-angle #(1 0 0)))
|
||||
(define (y-axis-angle) (plot-dir->dc-angle #(0 1 0)))
|
||||
|
||||
(define (plot-dir->dc-dir v)
|
||||
(vnormalize (v- (plot->dc/no-axis-trans (v+ v (vector x-mid y-mid z-mid)))
|
||||
(plot->dc/no-axis-trans (vector x-mid y-mid z-mid)))))
|
||||
|
||||
(define (x-axis-dir) (plot-dir->dc-dir #(1 0 0)))
|
||||
(define (y-axis-dir) (plot-dir->dc-dir #(0 1 0)))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Tick and label constants
|
||||
|
||||
(define tick-radius (* 1/2 (plot-tick-size)))
|
||||
(define half-tick-radius (* 1/2 tick-radius))
|
||||
|
||||
(define x-axis-y-min? ((cos theta) . >= . 0)) ; #t iff x near labels should be drawn at y-min
|
||||
(define y-axis-x-min? ((sin theta) . >= . 0)) ; #t iff y near labels should be drawn at x-min
|
||||
|
||||
(define x-axis-y (if x-axis-y-min? y-min y-max))
|
||||
(define x-far-axis-y (if x-axis-y-min? y-max y-min))
|
||||
(define y-axis-x (if y-axis-x-min? x-min x-max))
|
||||
(define y-far-axis-x (if y-axis-x-min? x-max x-min))
|
||||
(define z-axis-x (if x-axis-y-min? x-min x-max))
|
||||
(define z-axis-y (if y-axis-x-min? y-max y-min))
|
||||
|
||||
(define x-far-axis-y (if x-axis-y-min? y-max y-min))
|
||||
(define y-far-axis-x (if y-axis-x-min? x-max x-min))
|
||||
(define z-far-axis-x (if x-axis-y-min? x-max x-min))
|
||||
(define z-far-axis-y (if y-axis-x-min? y-min y-max))
|
||||
|
||||
(define near-dist^2 (sqr(* 3 (plot-line-width))))
|
||||
(define near-dist^2 (sqr (* 3 (plot-line-width))))
|
||||
(define (vnear? v1 v2)
|
||||
((vmag^2 (v- (plot->dc* v1) (plot->dc* v2))) . <= . near-dist^2))
|
||||
|
||||
|
@ -211,116 +233,62 @@
|
|||
(collapse-nearby-ticks (filter (λ (t) (<= z-min (pre-tick-value t) z-max)) rz-far-ticks)
|
||||
(z-ticks-near? z-far-axis-x z-far-axis-y)))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Tick and label parameters, and fixpoint margin computation
|
||||
|
||||
;; From here through "All parameters" are functions that compute *just the parameters* of ticks
|
||||
;; and labels that will be drawn on the plot. We have to separate computing parameters from
|
||||
;; actually drawing the ticks and labels so we can solve for the plot margins using a fixpoint
|
||||
;; computation. See ../common/draw.rkt for more explanation. (Search for 'margin-fixpoint'.)
|
||||
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; Tick parameters
|
||||
|
||||
(define (x-tick-value->view x) (plot->view (vector x x-axis-y z-min)))
|
||||
(define (y-tick-value->view y) (plot->view (vector y-axis-x y z-min)))
|
||||
(define (x-tick-value->dc x) (view->dc (x-tick-value->view x)))
|
||||
(define (y-tick-value->dc y) (view->dc (y-tick-value->view y)))
|
||||
(define (z-tick-value->dc z) (plot->dc* (vector z-axis-x z-axis-y z)))
|
||||
|
||||
(define (x-far-tick-value->view x) (plot->view (vector x x-far-axis-y z-min)))
|
||||
(define (y-far-tick-value->view y) (plot->view (vector y-far-axis-x y z-min)))
|
||||
(define (x-far-tick-value->dc x) (view->dc (x-far-tick-value->view x)))
|
||||
(define (y-far-tick-value->dc y) (view->dc (y-far-tick-value->view y)))
|
||||
(define (z-far-tick-value->dc z) (plot->dc* (vector z-far-axis-x z-far-axis-y z)))
|
||||
|
||||
(define (get-tick-params ticks tick-value->dc angle)
|
||||
(for/list ([t (in-list ticks)])
|
||||
(match-define (tick p major? _) t)
|
||||
(list major? (tick-value->dc p) (if major? tick-radius half-tick-radius) angle)))
|
||||
|
||||
(define (get-x-tick-params)
|
||||
(if (plot-x-axis?) (get-tick-params x-ticks x-tick-value->dc (y-axis-angle)) empty))
|
||||
|
||||
(define (get-y-tick-params)
|
||||
(if (plot-y-axis?) (get-tick-params y-ticks y-tick-value->dc (x-axis-angle)) empty))
|
||||
|
||||
(define (get-z-tick-params)
|
||||
(if (plot-z-axis?) (get-tick-params z-ticks z-tick-value->dc 0) empty))
|
||||
|
||||
(define (get-x-far-tick-params)
|
||||
(if (plot-x-far-axis?) (get-tick-params x-far-ticks x-far-tick-value->dc (y-axis-angle)) empty))
|
||||
|
||||
(define (get-y-far-tick-params)
|
||||
(if (plot-y-far-axis?) (get-tick-params y-far-ticks y-far-tick-value->dc (x-axis-angle)) empty))
|
||||
|
||||
(define (get-z-far-tick-params)
|
||||
(if (plot-z-far-axis?) (get-tick-params z-far-ticks z-far-tick-value->dc 0) empty))
|
||||
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; Tick label parameters
|
||||
|
||||
(define draw-x-far-tick-labels? (not (and (plot-x-axis?) (equal? x-ticks x-far-ticks))))
|
||||
(define draw-y-far-tick-labels? (not (and (plot-y-axis?) (equal? y-ticks y-far-ticks))))
|
||||
(define draw-z-far-tick-labels? (not (and (plot-z-axis?) (equal? z-ticks z-far-ticks))))
|
||||
|
||||
(define (max-tick-offset ts)
|
||||
(cond [(empty? ts) 0]
|
||||
[(ormap pre-tick-major? ts) (+ (pen-gap) (* 1/2 (plot-tick-size)))]
|
||||
[else (+ (pen-gap) (* 1/4 (plot-tick-size)))]))
|
||||
|
||||
(define max-x-tick-offset (if (plot-x-axis?) (max-tick-offset x-ticks) 0))
|
||||
(define max-y-tick-offset (if (plot-y-axis?) (max-tick-offset y-ticks) 0))
|
||||
(define max-x-far-tick-offset (if (plot-x-far-axis?) (max-tick-offset x-far-ticks) 0))
|
||||
(define max-y-far-tick-offset (if (plot-y-far-axis?) (max-tick-offset y-far-ticks) 0))
|
||||
|
||||
(define (max-tick-label-height ts)
|
||||
(if (ormap pre-tick-major? ts) char-height 0))
|
||||
|
||||
(define (max-tick-label-width ts)
|
||||
(apply max 0 (for/list ([t (in-list ts)] #:when (pre-tick-major? t))
|
||||
(send pd get-text-width (tick-label t)))))
|
||||
|
||||
(define (max-x-tick-label-diag y-axis-angle)
|
||||
(if (plot-x-axis?)
|
||||
(+ (* (abs (cos y-axis-angle)) (max-tick-label-width x-ticks))
|
||||
(* (abs (sin y-axis-angle)) (max-tick-label-height x-ticks)))
|
||||
0))
|
||||
|
||||
(define (max-y-tick-label-diag x-axis-angle)
|
||||
(if (plot-y-axis?)
|
||||
(+ (* (abs (cos x-axis-angle)) (max-tick-label-width y-ticks))
|
||||
(* (abs (sin x-axis-angle)) (max-tick-label-height y-ticks)))
|
||||
0))
|
||||
|
||||
(define (max-x-far-tick-label-diag y-axis-angle)
|
||||
(if (and (plot-x-far-axis?) draw-x-far-tick-labels?)
|
||||
(+ (* (abs (cos y-axis-angle)) (max-tick-label-width x-far-ticks))
|
||||
(* (abs (sin y-axis-angle)) (max-tick-label-height x-far-ticks)))
|
||||
0))
|
||||
|
||||
(define (max-y-far-tick-label-diag x-axis-angle)
|
||||
(if (and (plot-y-far-axis?) draw-y-far-tick-labels?)
|
||||
(+ (* (abs (cos x-axis-angle)) (max-tick-label-width y-far-ticks))
|
||||
(* (abs (sin x-axis-angle)) (max-tick-label-height y-far-ticks)))
|
||||
0))
|
||||
|
||||
(define (plot-dir->dc-angle v)
|
||||
(match-define (vector dx dy)
|
||||
(v- (plot->dc/no-axis-trans (v+ v (vector x-mid y-mid z-mid)))
|
||||
(plot->dc/no-axis-trans (vector x-mid y-mid z-mid))))
|
||||
(- (atan2 (- dy) dx)))
|
||||
|
||||
(define (axis-dc-angles)
|
||||
(values (plot-dir->dc-angle (vector 1 0 0))
|
||||
(plot-dir->dc-angle (vector 0 1 0))))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Axis label parameters
|
||||
|
||||
(define (get-x-label-params)
|
||||
(define-values (x-axis-angle y-axis-angle) (axis-dc-angles))
|
||||
(define v0 (plot->dc/no-axis-trans (vector x-mid x-axis-y z-min)))
|
||||
(define dist (+ max-x-tick-offset
|
||||
(max-x-tick-label-diag y-axis-angle)
|
||||
(* 1/2 char-height)))
|
||||
(list #t (plot-x-label) (v+ v0 (v* (vector (cos y-axis-angle) (sin y-axis-angle))
|
||||
(if x-axis-y-min? (- dist) dist)))
|
||||
'top (- (if x-axis-y-min? 0 pi) x-axis-angle)))
|
||||
|
||||
(define (get-y-label-params)
|
||||
(define-values (x-axis-angle y-axis-angle) (axis-dc-angles))
|
||||
(define v0 (plot->dc/no-axis-trans (vector y-axis-x y-mid z-min)))
|
||||
(define dist (+ max-y-tick-offset
|
||||
(max-y-tick-label-diag x-axis-angle)
|
||||
(* 1/2 char-height)))
|
||||
(list #t (plot-y-label) (v+ v0 (v* (vector (cos x-axis-angle) (sin x-axis-angle))
|
||||
(if y-axis-x-min? (- dist) dist)))
|
||||
'top (- (if y-axis-x-min? pi 0) y-axis-angle)))
|
||||
|
||||
(define (get-z-label-params)
|
||||
(list #t (plot-z-label) (v+ (plot->dc* (vector z-axis-x z-axis-y z-max))
|
||||
(vector 0 (* -1/2 char-height)))
|
||||
'bottom-left 0))
|
||||
|
||||
(define (get-x-far-label-params)
|
||||
(define-values (x-axis-angle y-axis-angle) (axis-dc-angles))
|
||||
(define v0 (plot->dc/no-axis-trans (vector x-mid x-far-axis-y z-min)))
|
||||
(define dist (+ max-x-far-tick-offset
|
||||
(max-x-far-tick-label-diag y-axis-angle)
|
||||
(* 1/2 char-height)))
|
||||
(list #f (plot-x-far-label) (v+ v0 (v* (vector (cos y-axis-angle) (sin y-axis-angle))
|
||||
(if x-axis-y-min? dist (- dist))))
|
||||
'bottom (- (if x-axis-y-min? 0 pi) x-axis-angle)))
|
||||
|
||||
(define (get-y-far-label-params)
|
||||
(define-values (x-axis-angle y-axis-angle) (axis-dc-angles))
|
||||
(define v0 (plot->dc/no-axis-trans (vector y-far-axis-x y-mid z-min)))
|
||||
(define dist (+ max-y-far-tick-offset
|
||||
(max-y-far-tick-label-diag x-axis-angle)
|
||||
(* 1/2 char-height)))
|
||||
(list #f (plot-y-far-label) (v+ v0 (v* (vector (cos x-axis-angle) (sin x-axis-angle))
|
||||
(if y-axis-x-min? dist (- dist))))
|
||||
'bottom (- (if y-axis-x-min? pi 0) y-axis-angle)))
|
||||
|
||||
(define (get-z-far-label-params)
|
||||
(list #t (plot-z-far-label) (v+ (plot->dc* (vector z-far-axis-x z-far-axis-y z-max))
|
||||
(vector 0 (* -1/2 char-height)))
|
||||
'bottom-right 0))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Tick label parameters
|
||||
(define (sort-ticks ticks tick-value->view)
|
||||
(sort ticks > #:key (λ (t) (vector-ref (tick-value->view (pre-tick-value t)) 2))
|
||||
#:cache-keys? #t))
|
||||
|
||||
(define (opposite-anchor a)
|
||||
(case a
|
||||
|
@ -343,205 +311,212 @@
|
|||
[(c . > . (cos (degrees->radians 157.5))) (if y-axis-x-min? 'top-left 'top-right)]
|
||||
[else (if y-axis-x-min? 'top-left 'top-right)])))
|
||||
|
||||
(define z-tick-label-anchor 'right)
|
||||
|
||||
(define x-far-tick-label-anchor (opposite-anchor x-tick-label-anchor))
|
||||
(define y-far-tick-label-anchor (opposite-anchor y-tick-label-anchor))
|
||||
(define z-far-tick-label-anchor 'left)
|
||||
|
||||
(define (get-tick-label-params ticks tick-value->dc offset-dir anchor)
|
||||
(define dist (+ (pen-gap) tick-radius))
|
||||
(for/list ([t (in-list ticks)] #:when (pre-tick-major? t))
|
||||
(match-define (tick x _ label) t)
|
||||
(list #t label (v+ (tick-value->dc x) (v* offset-dir dist)) anchor)))
|
||||
|
||||
(define (get-x-tick-label-params)
|
||||
(define y-axis-angle (plot-dir->dc-angle (vector 0 1 0)))
|
||||
(define dist (+ (pen-gap) (* 1/2 (plot-tick-size))))
|
||||
(define offset (v* (vector (cos y-axis-angle) (sin y-axis-angle))
|
||||
(if x-axis-y-min? (- dist) dist)))
|
||||
(for/list ([t (in-list x-ticks)] #:when (pre-tick-major? t))
|
||||
(match-define (tick x _ label) t)
|
||||
(list #f label (v+ (plot->dc* (vector x x-axis-y z-min)) offset)
|
||||
x-tick-label-anchor 0)))
|
||||
(if (plot-x-axis?)
|
||||
(let ([offset (if x-axis-y-min? (vneg (y-axis-dir)) (y-axis-dir))])
|
||||
(get-tick-label-params (sort-ticks x-ticks x-tick-value->view)
|
||||
x-tick-value->dc offset x-tick-label-anchor))
|
||||
empty))
|
||||
|
||||
(define (get-y-tick-label-params)
|
||||
(define x-axis-angle (plot-dir->dc-angle (vector 1 0 0)))
|
||||
(define dist (+ (pen-gap) (* 1/2 (plot-tick-size))))
|
||||
(define offset (v* (vector (cos x-axis-angle) (sin x-axis-angle))
|
||||
(if y-axis-x-min? (- dist) dist)))
|
||||
(for/list ([t (in-list y-ticks)] #:when (pre-tick-major? t))
|
||||
(match-define (tick y _ label) t)
|
||||
(list #f label (v+ (plot->dc* (vector y-axis-x y z-min)) offset)
|
||||
y-tick-label-anchor 0)))
|
||||
(if (plot-y-axis?)
|
||||
(let ([offset (if y-axis-x-min? (vneg (x-axis-dir)) (x-axis-dir))])
|
||||
(get-tick-label-params (sort-ticks y-ticks y-tick-value->view)
|
||||
y-tick-value->dc offset y-tick-label-anchor))
|
||||
empty))
|
||||
|
||||
(define (get-z-tick-label-params)
|
||||
(define dist (+ (pen-gap) (* 1/2 (plot-tick-size))))
|
||||
(define offset (vector (- dist) (* 2 (send pd get-char-baseline))))
|
||||
(for/list ([t (in-list z-ticks)] #:when (pre-tick-major? t))
|
||||
(match-define (tick z _ label) t)
|
||||
(list #t label (v+ (plot->dc* (vector z-axis-x z-axis-y z)) offset) 'bottom-right 0)))
|
||||
(if (plot-z-axis?)
|
||||
(get-tick-label-params z-ticks z-tick-value->dc #(-1 0) z-tick-label-anchor)
|
||||
empty))
|
||||
|
||||
(define (get-x-far-tick-label-params)
|
||||
(define y-axis-angle (plot-dir->dc-angle (vector 0 1 0)))
|
||||
(define dist (+ (pen-gap) (* 1/2 (plot-tick-size))))
|
||||
(define offset (v* (vector (cos y-axis-angle) (sin y-axis-angle))
|
||||
(if x-axis-y-min? dist (- dist))))
|
||||
(for/list ([t (in-list x-far-ticks)] #:when (pre-tick-major? t))
|
||||
(match-define (tick x _ label) t)
|
||||
(list #f label (v+ (plot->dc* (vector x x-far-axis-y z-min)) offset)
|
||||
x-far-tick-label-anchor 0)))
|
||||
(if (and (plot-x-far-axis?) draw-x-far-tick-labels?)
|
||||
(let ([offset (if x-axis-y-min? (y-axis-dir) (vneg (y-axis-dir)))])
|
||||
(get-tick-label-params (sort-ticks x-far-ticks x-far-tick-value->view)
|
||||
x-far-tick-value->dc offset x-far-tick-label-anchor))
|
||||
empty))
|
||||
|
||||
(define (get-y-far-tick-label-params)
|
||||
(define x-axis-angle (plot-dir->dc-angle (vector 1 0 0)))
|
||||
(define dist (+ (pen-gap) (* 1/2 (plot-tick-size))))
|
||||
(define offset (v* (vector (cos x-axis-angle) (sin x-axis-angle))
|
||||
(if y-axis-x-min? dist (- dist))))
|
||||
(for/list ([t (in-list y-far-ticks)] #:when (pre-tick-major? t))
|
||||
(match-define (tick y _ label) t)
|
||||
(list #f label (v+ (plot->dc* (vector y-far-axis-x y z-min)) offset)
|
||||
y-far-tick-label-anchor 0)))
|
||||
(if (and (plot-y-far-axis?) draw-y-far-tick-labels?)
|
||||
(let ([offset (if y-axis-x-min? (x-axis-dir) (vneg (x-axis-dir)))])
|
||||
(get-tick-label-params (sort-ticks y-far-ticks y-far-tick-value->view)
|
||||
y-far-tick-value->dc offset y-far-tick-label-anchor))
|
||||
empty))
|
||||
|
||||
(define (get-z-far-tick-label-params)
|
||||
(define dist (+ (pen-gap) (* 1/2 (plot-tick-size))))
|
||||
(define offset (vector dist (* 2 (send pd get-char-baseline))))
|
||||
(for/list ([t (in-list z-far-ticks)] #:when (pre-tick-major? t))
|
||||
(match-define (tick z _ label) t)
|
||||
(list #t label (v+ (plot->dc* (vector z-far-axis-x z-far-axis-y z)) offset)
|
||||
'bottom-left 0)))
|
||||
(if (and (plot-z-far-axis?) draw-z-far-tick-labels?)
|
||||
(get-tick-label-params z-far-ticks z-far-tick-value->dc #(1 0) z-far-tick-label-anchor)
|
||||
empty))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Tick parameters
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; Axis label parameters
|
||||
|
||||
(define (get-x-tick-params)
|
||||
(define radius (* 1/2 (plot-tick-size)))
|
||||
(define angle (plot-dir->dc-angle (vector 0 1 0)))
|
||||
(for/list ([t (in-list x-ticks)])
|
||||
(match-define (tick x major? _) t)
|
||||
(list major? (plot->dc* (vector x x-axis-y z-min))
|
||||
(if major? radius (* 1/2 radius)) angle)))
|
||||
(define (max-tick-offset ts)
|
||||
(cond [(empty? ts) 0]
|
||||
[(ormap pre-tick-major? ts) (+ (pen-gap) tick-radius)]
|
||||
[else (+ (pen-gap) (* 1/4 (plot-tick-size)))]))
|
||||
|
||||
(define (get-y-tick-params)
|
||||
(define radius (* 1/2 (plot-tick-size)))
|
||||
(define angle (plot-dir->dc-angle (vector 1 0 0)))
|
||||
(for/list ([t (in-list y-ticks)])
|
||||
(match-define (tick y major? _) t)
|
||||
(list major? (plot->dc* (vector y-axis-x y z-min))
|
||||
(if major? radius (* 1/2 radius)) angle)))
|
||||
(define max-x-tick-offset (if (plot-x-axis?) (max-tick-offset x-ticks) 0))
|
||||
(define max-y-tick-offset (if (plot-y-axis?) (max-tick-offset y-ticks) 0))
|
||||
|
||||
(define (get-z-tick-params)
|
||||
(define radius (* 1/2 (plot-tick-size)))
|
||||
(for/list ([t (in-list z-ticks)])
|
||||
(match-define (tick z major? _) t)
|
||||
(list major? (plot->dc* (vector z-axis-x z-axis-y z))
|
||||
(if major? radius (* 1/2 radius)) 0)))
|
||||
(define max-x-far-tick-offset (if (plot-x-far-axis?) (max-tick-offset x-far-ticks) 0))
|
||||
(define max-y-far-tick-offset (if (plot-y-far-axis?) (max-tick-offset y-far-ticks) 0))
|
||||
|
||||
(define (get-x-far-tick-params)
|
||||
(define radius (* 1/2 (plot-tick-size)))
|
||||
(define angle (plot-dir->dc-angle (vector 0 1 0)))
|
||||
(for/list ([t (in-list x-ticks)])
|
||||
(match-define (tick x major? _) t)
|
||||
(list major? (plot->dc* (vector x x-far-axis-y z-min))
|
||||
(if major? radius (* 1/2 radius)) angle)))
|
||||
(define (max-tick-label-height ts)
|
||||
(if (ormap pre-tick-major? ts) char-height 0))
|
||||
|
||||
(define (get-y-far-tick-params)
|
||||
(define radius (* 1/2 (plot-tick-size)))
|
||||
(define angle (plot-dir->dc-angle (vector 1 0 0)))
|
||||
(for/list ([t (in-list y-ticks)])
|
||||
(match-define (tick y major? _) t)
|
||||
(list major? (plot->dc* (vector y-far-axis-x y z-min))
|
||||
(if major? radius (* 1/2 radius)) angle)))
|
||||
(define (max-tick-label-width ts)
|
||||
(apply max 0 (for/list ([t (in-list ts)] #:when (pre-tick-major? t))
|
||||
(send pd get-text-width (tick-label t)))))
|
||||
|
||||
(define (get-z-far-tick-params)
|
||||
(define radius (* 1/2 (plot-tick-size)))
|
||||
(for/list ([t (in-list z-ticks)])
|
||||
(match-define (tick z major? _) t)
|
||||
(list major? (plot->dc* (vector z-far-axis-x z-far-axis-y z))
|
||||
(if major? radius (* 1/2 radius)) 0)))
|
||||
(define max-x-tick-label-width (max-tick-label-width x-ticks))
|
||||
(define max-y-tick-label-width (max-tick-label-width y-ticks))
|
||||
(define max-z-tick-label-width (max-tick-label-width z-ticks))
|
||||
(define max-x-tick-label-height (max-tick-label-height x-ticks))
|
||||
(define max-y-tick-label-height (max-tick-label-height y-ticks))
|
||||
(define max-z-tick-label-height (max-tick-label-height z-ticks))
|
||||
|
||||
;; ===============================================================================================
|
||||
(define max-x-far-tick-label-width (max-tick-label-width x-far-ticks))
|
||||
(define max-y-far-tick-label-width (max-tick-label-width y-far-ticks))
|
||||
(define max-z-far-tick-label-width (max-tick-label-width z-far-ticks))
|
||||
(define max-x-far-tick-label-height (max-tick-label-height x-far-ticks))
|
||||
(define max-y-far-tick-label-height (max-tick-label-height y-far-ticks))
|
||||
(define max-z-far-tick-label-height (max-tick-label-height z-far-ticks))
|
||||
|
||||
(define (max-tick-label-diag axis-dc-dir max-tick-label-width max-tick-label-height)
|
||||
(match-define (vector dx dy) axis-dc-dir)
|
||||
(+ (* (abs dx) max-tick-label-width) (* (abs dy) max-tick-label-height)))
|
||||
|
||||
(define (max-x-tick-label-diag)
|
||||
(if (plot-x-axis?)
|
||||
(max-tick-label-diag (y-axis-dir) max-x-tick-label-width max-x-tick-label-height)
|
||||
0))
|
||||
|
||||
(define (max-y-tick-label-diag)
|
||||
(if (plot-y-axis?)
|
||||
(max-tick-label-diag (x-axis-dir) max-y-tick-label-width max-y-tick-label-height)
|
||||
0))
|
||||
|
||||
(define (max-x-far-tick-label-diag)
|
||||
(if (and (plot-x-far-axis?) draw-x-far-tick-labels?)
|
||||
(max-tick-label-diag (y-axis-dir) max-x-far-tick-label-width max-x-far-tick-label-height)
|
||||
0))
|
||||
|
||||
(define (max-y-far-tick-label-diag)
|
||||
(if (and (plot-y-far-axis?) draw-y-far-tick-labels?)
|
||||
(max-tick-label-diag (x-axis-dir) max-y-far-tick-label-width max-y-far-tick-label-height)
|
||||
0))
|
||||
|
||||
(define (get-x-label-params)
|
||||
(define v0 (plot->dc/no-axis-trans (vector x-mid x-axis-y z-min)))
|
||||
(define dist (+ max-x-tick-offset (max-x-tick-label-diag) half-char-height))
|
||||
(list #t (plot-x-label) (v+ v0 (v* (y-axis-dir) (if x-axis-y-min? (- dist) dist)))
|
||||
'top (- (if x-axis-y-min? 0 pi) (x-axis-angle))))
|
||||
|
||||
(define (get-y-label-params)
|
||||
(define v0 (plot->dc/no-axis-trans (vector y-axis-x y-mid z-min)))
|
||||
(define dist (+ max-y-tick-offset (max-y-tick-label-diag) half-char-height))
|
||||
(list #t (plot-y-label) (v+ v0 (v* (x-axis-dir) (if y-axis-x-min? (- dist) dist)))
|
||||
'top (- (if y-axis-x-min? pi 0) (y-axis-angle))))
|
||||
|
||||
(define (get-z-label-params)
|
||||
(list #t (plot-z-label) (v+ (plot->dc* (vector z-axis-x z-axis-y z-max))
|
||||
(vector 0 (- half-char-height)))
|
||||
'bottom-left 0))
|
||||
|
||||
(define (get-x-far-label-params)
|
||||
(define v0 (plot->dc/no-axis-trans (vector x-mid x-far-axis-y z-min)))
|
||||
(define dist (+ max-x-far-tick-offset (max-x-far-tick-label-diag) half-char-height))
|
||||
(list #f (plot-x-far-label) (v+ v0 (v* (y-axis-dir) (if x-axis-y-min? dist (- dist))))
|
||||
'bottom (- (if x-axis-y-min? 0 pi) (x-axis-angle))))
|
||||
|
||||
(define (get-y-far-label-params)
|
||||
(define v0 (plot->dc/no-axis-trans (vector y-far-axis-x y-mid z-min)))
|
||||
(define dist (+ max-y-far-tick-offset (max-y-far-tick-label-diag) half-char-height))
|
||||
(list #f (plot-y-far-label) (v+ v0 (v* (x-axis-dir) (if y-axis-x-min? dist (- dist))))
|
||||
'bottom (- (if y-axis-x-min? pi 0) (y-axis-angle))))
|
||||
|
||||
(define (get-z-far-label-params)
|
||||
(list #t (plot-z-far-label) (v+ (plot->dc* (vector z-far-axis-x z-far-axis-y z-max))
|
||||
(vector 0 (- half-char-height)))
|
||||
'bottom-right 0))
|
||||
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; All parameters
|
||||
|
||||
;; Within each get-back-* or get-front-*, the parameters are ordered (roughly) back-to-front
|
||||
|
||||
(define (get-back-label-params)
|
||||
(if (plot-decorations?)
|
||||
(append (if (plot-x-far-label) (list (get-x-far-label-params)) empty)
|
||||
(if (plot-y-far-label) (list (get-y-far-label-params)) empty)
|
||||
(get-x-far-tick-label-params)
|
||||
(get-y-far-tick-label-params))
|
||||
empty))
|
||||
|
||||
(define (get-front-label-params)
|
||||
(if (plot-decorations?)
|
||||
(append (get-z-tick-label-params)
|
||||
(get-z-far-tick-label-params)
|
||||
(get-x-tick-label-params)
|
||||
(get-y-tick-label-params)
|
||||
(if (plot-x-label) (list (get-x-label-params)) empty)
|
||||
(if (plot-y-label) (list (get-y-label-params)) empty)
|
||||
(if (plot-z-label) (list (get-z-label-params)) empty)
|
||||
(if (plot-z-far-label) (list (get-z-far-label-params)) empty))
|
||||
empty))
|
||||
|
||||
(define (get-back-tick-params)
|
||||
(if (plot-decorations?)
|
||||
(append (if (plot-x-far-axis?) (get-x-far-tick-params) empty)
|
||||
(if (plot-y-far-axis?) (get-y-far-tick-params) empty))
|
||||
empty))
|
||||
|
||||
|
||||
(define (get-front-tick-params)
|
||||
(if (plot-decorations?)
|
||||
(append (if (plot-x-axis?) (get-x-tick-params) empty)
|
||||
(if (plot-y-axis?) (get-y-tick-params) empty)
|
||||
(if (plot-z-axis?) (get-z-tick-params) empty)
|
||||
(if (plot-z-far-axis?) (get-z-far-tick-params) empty))
|
||||
empty))
|
||||
|
||||
(define (get-all-tick-params)
|
||||
(append (get-back-tick-params) (get-front-tick-params)))
|
||||
|
||||
(define (get-all-label-params)
|
||||
(append (get-back-label-params) (get-front-label-params)))
|
||||
|
||||
;; -----------------------------------------------------------------------------------------------
|
||||
;; Fixpoint margin computation
|
||||
|
||||
(define (get-near-label-params)
|
||||
(cond [(plot-decorations?)
|
||||
(append (if (plot-z-label) (list (get-z-label-params)) empty)
|
||||
(if (plot-z-far-label) (list (get-z-far-label-params)) empty)
|
||||
(if (plot-z-axis?) (get-z-tick-label-params) empty)
|
||||
(if (and (plot-z-far-axis?) draw-z-far-tick-labels?)
|
||||
(get-z-far-tick-label-params)
|
||||
empty))]
|
||||
[else empty]))
|
||||
|
||||
(define (get-far-label-params)
|
||||
(cond [(plot-decorations?)
|
||||
;; Ordered back-to-front
|
||||
(append (if (plot-x-far-label) (list (get-x-far-label-params)) empty)
|
||||
(if (plot-y-far-label) (list (get-y-far-label-params)) empty)
|
||||
(if (and (plot-x-far-axis?) draw-x-far-tick-labels?)
|
||||
(get-x-far-tick-label-params)
|
||||
empty)
|
||||
(if (and (plot-y-far-axis?) draw-y-far-tick-labels?)
|
||||
(get-y-far-tick-label-params)
|
||||
empty)
|
||||
(if (plot-x-axis?) (get-x-tick-label-params) empty)
|
||||
(if (plot-y-axis?) (get-y-tick-label-params) empty)
|
||||
(if (plot-x-label) (list (get-x-label-params)) empty)
|
||||
(if (plot-y-label) (list (get-y-label-params)) empty))]
|
||||
[else empty]))
|
||||
|
||||
(define (get-near-tick-params)
|
||||
(cond [(plot-decorations?)
|
||||
(append (if (plot-z-axis?) (get-z-tick-params) empty)
|
||||
(if (plot-z-far-axis?) (get-z-far-tick-params) empty))]
|
||||
[else empty]))
|
||||
|
||||
(define (get-far-tick-params)
|
||||
(cond [(plot-decorations?)
|
||||
(append (if (plot-x-axis?) (get-x-tick-params) empty)
|
||||
(if (plot-y-axis?) (get-y-tick-params) empty)
|
||||
(if (plot-x-far-axis?) (get-x-far-tick-params) empty)
|
||||
(if (plot-y-far-axis?) (get-y-far-tick-params) empty))]
|
||||
[else empty]))
|
||||
|
||||
;; We have a mutual dependence problem:
|
||||
;; 1. We can't set the margins without knowing where the axis labels will be
|
||||
;; 2. We can't determine the axis label angles (and thus their positions) without knowing the
|
||||
;; margins
|
||||
|
||||
;; The margins could be solved exactly using algebra and trigonometry, but the solutions wouldn't
|
||||
;; be robust, as small changes to the layout algorithms would invalidate them.
|
||||
|
||||
;; So we use a fixpoint solution:
|
||||
;; 1. Define 'new-margins', which takes the current margins and info about the current labels,
|
||||
;; and returns margins large enough that the current axis labels would be drawn completely
|
||||
;; on the dc (although at slightly wrong angles)
|
||||
;; 2. Iterate 'new-margins', recalculating the labels every iteration
|
||||
|
||||
;; Because 'new-margins' is monotone and bounded, the amount of axis label drawn off the dc is
|
||||
;; zero in the limit. In practice, only a few iterations achieves less than 1 drawing unit.
|
||||
|
||||
(define (new-margins left right top bottom label-params tick-params)
|
||||
(match-define (list (vector label-xs label-ys) ...)
|
||||
(append* (map (λ (params) (send/apply pd get-text-corners (rest params))) label-params)))
|
||||
(match-define (list (vector tick-xs tick-ys) ...)
|
||||
(append* (map (λ (params) (send/apply pd get-tick-endpoints (rest params))) tick-params)))
|
||||
(define xs (append label-xs tick-xs))
|
||||
(define ys (append label-ys tick-ys))
|
||||
|
||||
(define param-x-min (apply min dc-x-min xs))
|
||||
(define param-x-max (apply max (sub1 dc-x-max) xs))
|
||||
(define param-y-min (apply min dc-y-min ys))
|
||||
(define param-y-max (apply max (sub1 dc-y-max) ys))
|
||||
|
||||
(values (+ left (- dc-x-min param-x-min))
|
||||
(- right (- (sub1 dc-x-max) param-x-max))
|
||||
(+ top (- dc-y-min param-y-min))
|
||||
(- bottom (- (sub1 dc-y-max) param-y-max))))
|
||||
(define (get-param-vs/set-view->dc! left right top bottom)
|
||||
(set! view->dc (make-view->dc left right top bottom))
|
||||
(append (append* (map (λ (params) (send/apply pd get-text-corners (rest params)))
|
||||
(get-all-label-params)))
|
||||
(append* (map (λ (params) (send/apply pd get-tick-endpoints (rest params)))
|
||||
(get-all-tick-params)))))
|
||||
|
||||
(define-values (area-x-min right area-y-min bottom)
|
||||
(for/fold ([left 0] [right 0] [top init-top-margin] [bottom 0]) ([i (in-range 3)])
|
||||
(define-values (new-left new-right new-top new-bottom)
|
||||
(new-margins left right top bottom
|
||||
(append (get-near-label-params) (get-far-label-params))
|
||||
(append (get-near-tick-params) (get-far-tick-params))))
|
||||
(set! view->dc (make-view->dc new-left new-right new-top new-bottom))
|
||||
;(printf "margins: ~v ~v ~v ~v~n" new-left new-right new-top new-bottom)
|
||||
(values new-left new-right new-top new-bottom)))
|
||||
(margin-fixpoint dc-x-min dc-x-max dc-y-min dc-y-max 0 0 init-top-margin 0
|
||||
get-param-vs/set-view->dc!))
|
||||
|
||||
;; ===============================================================================================
|
||||
;; Plot decoration
|
||||
|
||||
|
||||
(define (draw-ticks tick-params)
|
||||
(for ([params (in-list tick-params)])
|
||||
(match-define (list major? v r angle) params)
|
||||
|
@ -552,7 +527,7 @@
|
|||
(for ([params (in-list label-params)])
|
||||
(send/apply pd draw-text (rest params) #:outline? (first params))))
|
||||
|
||||
(define (draw-far-borders)
|
||||
(define (draw-far-axes)
|
||||
(when (plot-decorations?)
|
||||
(send pd set-minor-pen)
|
||||
(when (plot-x-axis?)
|
||||
|
@ -572,7 +547,7 @@
|
|||
(plot->dc/no-axis-trans (vector y-far-axis-x y-min z-min))
|
||||
(plot->dc/no-axis-trans (vector y-far-axis-x y-max z-min))))))
|
||||
|
||||
(define (draw-near-borders)
|
||||
(define (draw-near-axes)
|
||||
(when (plot-decorations?)
|
||||
(send pd set-minor-pen)
|
||||
(when (plot-z-axis?)
|
||||
|
@ -593,7 +568,7 @@
|
|||
|
||||
(define render-list empty)
|
||||
(define (add-shape! shape) (set! render-list (cons shape render-list)))
|
||||
|
||||
|
||||
(define (draw-shapes lst)
|
||||
(for ([s (in-list (depth-sort lst))])
|
||||
(send pd set-alpha (shape-alpha s))
|
||||
|
@ -660,9 +635,9 @@
|
|||
(send pd reset-drawing-params)
|
||||
(send pd clear)
|
||||
(set! render-list empty)
|
||||
(draw-labels (get-far-label-params))
|
||||
(draw-ticks (get-far-tick-params))
|
||||
(draw-far-borders))
|
||||
(draw-labels (get-back-label-params))
|
||||
(draw-ticks (get-back-tick-params))
|
||||
(draw-far-axes))
|
||||
|
||||
(define/public (start-renderer rx-min rx-max ry-min ry-max rz-min rz-max)
|
||||
(send pd reset-drawing-params)
|
||||
|
@ -673,9 +648,9 @@
|
|||
(clip-to-none)
|
||||
(send pd reset-drawing-params)
|
||||
(draw-title)
|
||||
(draw-near-borders)
|
||||
(draw-ticks (get-near-tick-params))
|
||||
(draw-labels (get-near-label-params)))
|
||||
(draw-near-axes)
|
||||
(draw-ticks (get-front-tick-params))
|
||||
(draw-labels (get-front-label-params)))
|
||||
|
||||
(define (draw-angles*)
|
||||
(define angle-str (format " angle = ~a " (number->string (round angle))))
|
||||
|
|
Loading…
Reference in New Issue
Block a user