Now make-flomap* and effects functions accept (U (Vectorof Real) FlVector) for color instead of just FlVector
New vector-of-component functions: unsafe-flomap-ref*, flomap-ref*, flomap-bilinear-ref*, build-flomap*, inline-build-flomap*; REPL interaction with -ref* is a bit weird - still need to make flvectors print nicely Bilinear ref and scaling fix on top and left borders (bad/missing special cases); Clarified flomap-bilinear-ref docs on extent of interpolated nonzero rectangle Various doc fixes
This commit is contained in:
parent
4ad700021b
commit
91579f2a6e
|
@ -31,8 +31,7 @@
|
|||
(match-define (flomap _ 4 w h) argb-fm)
|
||||
(match-define (flomap _ 1 zw zh) z-fm)
|
||||
(unless (and (= w zw) (= h zh))
|
||||
(error 'deep-flomap
|
||||
"expected flomaps of equal dimension; given dimensions ~e×~e and ~e×~e" w h zw zh))
|
||||
(error 'deep-flomap "expected same-size flomaps; given sizes ~e×~e and ~e×~e" w h zw zh))
|
||||
(values argb-fm z-fm)))
|
||||
|
||||
(: flomap->deep-flomap (flomap -> deep-flomap))
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
flomap-shadow flomap-shadowed
|
||||
flomap-whirl-morph)
|
||||
|
||||
(: colorize-alpha (flomap FlVector -> flomap))
|
||||
(: colorize-alpha (flomap (U (Vectorof Real) FlVector) -> flomap))
|
||||
(define (colorize-alpha fm vs)
|
||||
(match-define (flomap _ 1 w h) fm)
|
||||
(flomap-append-components fm (fm* fm (make-flomap* w h vs))))
|
||||
|
||||
(: flomap-shadow (case-> (flomap Real -> flomap)
|
||||
(flomap Real (Option FlVector) -> flomap)))
|
||||
(flomap Real (Option (U (Vectorof Real) FlVector)) -> flomap)))
|
||||
(define flomap-shadow
|
||||
(case-lambda
|
||||
[(fm σ) (flomap-shadow fm σ #f)]
|
||||
|
@ -27,18 +27,18 @@
|
|||
(match-define (flomap _ c w h) fm)
|
||||
(cond [(c . = . 0) fm]
|
||||
[else (define alpha-fm (flomap-ref-component fm 0))
|
||||
(define color-vs (if (flvector? color) color (make-flvector (- c 1) 0.0)))
|
||||
(define color-vs (if color color (make-flvector (- c 1) 0.0)))
|
||||
(colorize-alpha (flomap-blur alpha-fm σ) color-vs)])]))
|
||||
|
||||
(: flomap-shadowed (case-> (flomap Real -> flomap)
|
||||
(flomap Real (Option FlVector) -> flomap)))
|
||||
(flomap Real (Option (U (Vectorof Real) FlVector)) -> flomap)))
|
||||
(define flomap-shadowed
|
||||
(case-lambda
|
||||
[(fm σ) (flomap-shadowed fm σ #f)]
|
||||
[(fm σ c) (flomap-cc-superimpose (flomap-shadow fm σ c) fm)]))
|
||||
|
||||
(: flomap-outline (case-> (flomap Real -> flomap)
|
||||
(flomap Real (Option FlVector) -> flomap)))
|
||||
(flomap Real (Option (U (Vectorof Real) FlVector)) -> flomap)))
|
||||
(define flomap-outline
|
||||
(case-lambda
|
||||
[(fm amt) (flomap-outline fm amt #f)]
|
||||
|
@ -57,11 +57,11 @@
|
|||
(define alpha-fm (flomap-ref-component fm 0))
|
||||
(define new-alpha-fm (fmmax 0.0 (fmmin 1.0 (fm/ (fm- (flomap-blur alpha-fm σ) v-min)
|
||||
(- v-max v-min)))))
|
||||
(define color-vs (if (flvector? color) color (make-flvector (- c 1) 0.0)))
|
||||
(define color-vs (if color color (make-flvector (- c 1) 0.0)))
|
||||
(colorize-alpha new-alpha-fm color-vs))]))
|
||||
|
||||
(: flomap-outlined (case-> (flomap Real -> flomap)
|
||||
(flomap Real (Option FlVector) -> flomap)))
|
||||
(flomap Real (Option (U (Vectorof Real) FlVector)) -> flomap)))
|
||||
(define flomap-outlined
|
||||
(case-lambda
|
||||
[(fm amt) (flomap-outlined fm amt #f)]
|
||||
|
|
|
@ -164,9 +164,9 @@
|
|||
[else (let ([height (abs height)])
|
||||
(flomap-scale*-y fm (abs (exact->inexact (/ height h))) height))]))
|
||||
|
||||
;; standard deviation of an unscaled box filter (i.e. f([-1/2,1/2]) = {1}, zero elsewhere)
|
||||
;; variance of an unscaled box filter (i.e. f([-1/2,1/2]) = {1}, zero elsewhere)
|
||||
(define box-filter-variance (/ 1.0 12.0))
|
||||
;; standard deviation of an unscaled triangle filter (simulates effect of linear interpolation)
|
||||
;; variance of an unscaled triangle filter (simulates effect of linear interpolation)
|
||||
(define triangle-filter-variance (/ 1.0 24.0))
|
||||
|
||||
;; calculates the standard deviation of downscaling blur, assuming linear interpolation will be
|
||||
|
@ -175,7 +175,7 @@
|
|||
(define (stddev-for-scale scale)
|
||||
(define var (- (/ box-filter-variance (sqr scale))
|
||||
triangle-filter-variance))
|
||||
(abs (flsqrt (max 0.0 var))))
|
||||
(flsqrt (max 0.0 var)))
|
||||
|
||||
(: flomap-scale*-x (flomap Flonum Exact-Nonnegative-Integer -> flomap))
|
||||
(define (flomap-scale*-x fm scale width)
|
||||
|
@ -196,17 +196,18 @@
|
|||
(: flomap-scale*-x/linear (flomap Flonum Exact-Nonnegative-Integer -> flomap))
|
||||
(define (flomap-scale*-x/linear fm s new-w)
|
||||
(match-define (flomap vs c w h) fm)
|
||||
(define w-1 (fx- w 1))
|
||||
(define w-1 (unsafe-fx+ w -1))
|
||||
(inline-build-flomap
|
||||
c new-w h
|
||||
(λ (k new-x y _i)
|
||||
(define scaled-x (- (/ (+ (fx->fl new-x) 0.5) s) 0.5))
|
||||
(define floor-scaled-x (floor scaled-x))
|
||||
(define x0 (fl->fx floor-scaled-x))
|
||||
(cond [(or (x0 . fx< . 0) (x0 . fx>= . w)) 0.0]
|
||||
(cond [(or (x0 . fx< . -1) (x0 . fx>= . w)) 0.0]
|
||||
[else
|
||||
(define i0 (coords->index c w k x0 y))
|
||||
(define v0 (flvector-ref vs i0))
|
||||
(define v0 (cond [(x0 . fx= . -1) 0.0]
|
||||
[else (flvector-ref vs i0)]))
|
||||
(define v1 (cond [(x0 . fx= . w-1) 0.0]
|
||||
[else (flvector-ref vs (unsafe-fx+ i0 c))]))
|
||||
(fl-convex-combination v0 v1 (- scaled-x floor-scaled-x))]))))
|
||||
|
@ -214,7 +215,7 @@
|
|||
(: flomap-scale*-y/linear (flomap Flonum Exact-Nonnegative-Integer -> flomap))
|
||||
(define (flomap-scale*-y/linear fm s new-h)
|
||||
(match-define (flomap vs c w h) fm)
|
||||
(define h-1 (fx- h 1))
|
||||
(define h-1 (unsafe-fx+ h -1))
|
||||
(define cw (* c w))
|
||||
(inline-build-flomap
|
||||
c w new-h
|
||||
|
@ -222,10 +223,11 @@
|
|||
(define scaled-y (- (/ (+ (fx->fl new-y) 0.5) s) 0.5))
|
||||
(define floor-scaled-y (floor scaled-y))
|
||||
(define y0 (fl->fx floor-scaled-y))
|
||||
(cond [(or (y0 . fx< . 0) (y0 . fx>= . h)) 0.0]
|
||||
(cond [(or (y0 . fx< . -1) (y0 . fx>= . h)) 0.0]
|
||||
[else
|
||||
(define i0 (coords->index c w k x y0))
|
||||
(define v0 (flvector-ref vs i0))
|
||||
(define v0 (cond [(y0 . fx= . -1) 0.0]
|
||||
[else (flvector-ref vs i0)]))
|
||||
(define v1 (cond [(y0 . fx= . h-1) 0.0]
|
||||
[else (flvector-ref vs (unsafe-fx+ i0 cw))]))
|
||||
(fl-convex-combination v0 v1 (- scaled-y floor-scaled-y))]))))
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
|
||||
(provide flomap flomap? flomap-values flomap-components flomap-width flomap-height
|
||||
;; Accessors
|
||||
flomap-size unsafe-flomap-ref flomap-ref flomap-bilinear-ref coords->index
|
||||
flomap-size coords->index
|
||||
unsafe-flomap-ref flomap-ref flomap-bilinear-ref
|
||||
unsafe-flomap-ref* flomap-ref* flomap-bilinear-ref*
|
||||
;; Basic constructors
|
||||
make-flomap make-flomap* build-flomap inline-build-flomap
|
||||
make-flomap build-flomap inline-build-flomap
|
||||
make-flomap* build-flomap* inline-build-flomap*
|
||||
flomap-ref-component flomap-take-components flomap-drop-components flomap-append-components)
|
||||
|
||||
(struct: flomap ([values : FlVector] [components : Integer] [width : Integer] [height : Integer])
|
||||
|
@ -43,6 +46,19 @@
|
|||
(unsafe-flvector-ref vs (coords->index c w k x y))]
|
||||
[else 0.0]))
|
||||
|
||||
(: unsafe-flomap-ref* (FlVector Integer Integer Integer Integer Integer -> FlVector))
|
||||
(define (unsafe-flomap-ref* vs c w h x y)
|
||||
(cond [(and (x . fx>= . 0) (x . fx< . w)
|
||||
(y . fx>= . 0) (y . fx< . h))
|
||||
(define i (coords->index c w 0 x y))
|
||||
(define point-vs (make-flvector c))
|
||||
(let: loop : Void ([k : Nonnegative-Fixnum 0])
|
||||
(when (k . < . c)
|
||||
(unsafe-flvector-set! point-vs k (unsafe-flvector-ref vs (unsafe-fx+ i k)))
|
||||
(loop (unsafe-fx+ k 1))))
|
||||
point-vs]
|
||||
[else (make-flvector c 0.0)]))
|
||||
|
||||
(: flomap-ref (flomap Integer Integer Integer -> Flonum))
|
||||
(define (flomap-ref fm k x y)
|
||||
(match-define (flomap vs c w h) fm)
|
||||
|
@ -50,6 +66,11 @@
|
|||
(raise-type-error 'flomap-ref (format "nonnegative fixnum < ~e" c) k))
|
||||
(unsafe-flomap-ref vs c w h k x y))
|
||||
|
||||
(: flomap-ref* (flomap Integer Integer -> FlVector))
|
||||
(define (flomap-ref* fm x y)
|
||||
(match-define (flomap vs c w h) fm)
|
||||
(unsafe-flomap-ref* vs c w h x y))
|
||||
|
||||
) ; begin-encourage-inline
|
||||
|
||||
(: flomap-bilinear-ref (flomap Integer Real Real -> Flonum))
|
||||
|
@ -58,14 +79,14 @@
|
|||
(cond [(and (k . >= . 0) (k . < . c))
|
||||
(let ([x (- (exact->inexact x) 0.5)]
|
||||
[y (- (exact->inexact y) 0.5)])
|
||||
(cond [(and (x . > . -0.5) (x . < . (+ 0.5 (->fl w)))
|
||||
(y . > . -0.5) (y . < . (+ 0.5 (->fl h))))
|
||||
(cond [(and (x . > . -1.0) (x . < . (->fl w))
|
||||
(y . > . -1.0) (y . < . (->fl h)))
|
||||
(define floor-x (floor x))
|
||||
(define floor-y (floor y))
|
||||
(define x0 (fl->fx floor-x))
|
||||
(define y0 (fl->fx floor-y))
|
||||
(define x1 (fx+ x0 1))
|
||||
(define y1 (fx+ y0 1))
|
||||
(define x1 (unsafe-fx+ x0 1))
|
||||
(define y1 (unsafe-fx+ y0 1))
|
||||
(define v00 (unsafe-flomap-ref vs c w h k x0 y0))
|
||||
(define v10 (unsafe-flomap-ref vs c w h k x1 y0))
|
||||
(define v01 (unsafe-flomap-ref vs c w h k x0 y1))
|
||||
|
@ -78,6 +99,40 @@
|
|||
[else
|
||||
(raise-type-error 'flomap-bilinear-ref (format "nonnegative fixnum < ~e" c) 1 fm k x y)]))
|
||||
|
||||
(: flomap-bilinear-ref* (flomap Real Real -> FlVector))
|
||||
(define (flomap-bilinear-ref* fm x y)
|
||||
(match-define (flomap vs c w h) fm)
|
||||
(let ([x (- (exact->inexact x) 0.5)]
|
||||
[y (- (exact->inexact y) 0.5)])
|
||||
(cond [(and (x . > . -1.0) (x . < . (->fl w))
|
||||
(y . > . -1.0) (y . < . (->fl h)))
|
||||
(define floor-x (floor x))
|
||||
(define floor-y (floor y))
|
||||
(define x0 (fl->fx floor-x))
|
||||
(define y0 (fl->fx floor-y))
|
||||
(define x1 (unsafe-fx+ x0 1))
|
||||
(define y1 (unsafe-fx+ y0 1))
|
||||
(define vs00 (unsafe-flomap-ref* vs c w h x0 y0))
|
||||
(define vs10 (unsafe-flomap-ref* vs c w h x1 y0))
|
||||
(define vs01 (unsafe-flomap-ref* vs c w h x0 y1))
|
||||
(define vs11 (unsafe-flomap-ref* vs c w h x1 y1))
|
||||
(define xα (- x floor-x))
|
||||
(define yα (- y floor-y))
|
||||
(define point-vs (make-flvector c))
|
||||
(let: loop : FlVector ([k : Nonnegative-Fixnum 0])
|
||||
(cond [(k . < . c)
|
||||
(define v00 (unsafe-flvector-ref vs00 k))
|
||||
(define v10 (unsafe-flvector-ref vs10 k))
|
||||
(define v01 (unsafe-flvector-ref vs01 k))
|
||||
(define v11 (unsafe-flvector-ref vs11 k))
|
||||
(define v (fl-convex-combination (fl-convex-combination v00 v10 xα)
|
||||
(fl-convex-combination v01 v11 xα)
|
||||
yα))
|
||||
(unsafe-flvector-set! point-vs k v)
|
||||
(loop (unsafe-fx+ k 1))]
|
||||
[else point-vs]))]
|
||||
[else (make-flvector c 0.0)])))
|
||||
|
||||
;; ===================================================================================================
|
||||
;; Construction and conversion
|
||||
|
||||
|
@ -98,7 +153,8 @@
|
|||
[w : Integer width]
|
||||
[h : Integer height])
|
||||
(with-asserts ([c nonnegative-fixnum?] [w nonnegative-fixnum?] [h nonnegative-fixnum?])
|
||||
(define vs (make-flvector (* c w h)))
|
||||
(define fm (make-flomap c w h))
|
||||
(define vs (flomap-values fm))
|
||||
(let: y-loop : flomap ([y : Nonnegative-Fixnum 0] [i : Nonnegative-Fixnum 0])
|
||||
(cond
|
||||
[(y . fx< . h)
|
||||
|
@ -111,19 +167,63 @@
|
|||
(k-loop (unsafe-fx+ k 1) (unsafe-fx+ i 1))]
|
||||
[else (x-loop (unsafe-fx+ x 1) i)]))]
|
||||
[else (y-loop (unsafe-fx+ y 1) i)]))]
|
||||
[else (flomap vs c w h)])))))
|
||||
[else fm])))))
|
||||
|
||||
(: build-flomap (Integer Integer Integer
|
||||
(Nonnegative-Fixnum Nonnegative-Fixnum Nonnegative-Fixnum
|
||||
Nonnegative-Fixnum -> Real)
|
||||
(Nonnegative-Fixnum Nonnegative-Fixnum Nonnegative-Fixnum -> Real)
|
||||
-> flomap))
|
||||
(define (build-flomap components width height fun)
|
||||
(inline-build-flomap components width height (λ (k x y i) (exact->inexact (fun k x y i)))))
|
||||
(define (build-flomap c w h f)
|
||||
(inline-build-flomap c w h (λ (k x y i) (exact->inexact (f k x y)))))
|
||||
|
||||
(: make-flomap* (Integer Integer FlVector -> flomap))
|
||||
#;
|
||||
(: inline-build-flomap* (Integer Integer Integer
|
||||
(Nonnegative-Fixnum Nonnegative-Fixnum Nonnegative-Fixnum
|
||||
-> FlVector)
|
||||
-> flomap))
|
||||
(define-syntax-rule (inline-build-flomap* components width height f)
|
||||
(let: ([c : Integer components]
|
||||
[w : Integer width]
|
||||
[h : Integer height])
|
||||
(with-asserts ([c nonnegative-fixnum?] [w nonnegative-fixnum?] [h nonnegative-fixnum?])
|
||||
(define fm (make-flomap c w h))
|
||||
(define vs (flomap-values fm))
|
||||
(let: y-loop : flomap ([y : Nonnegative-Fixnum 0] [i : Nonnegative-Fixnum 0])
|
||||
(cond
|
||||
[(y . fx< . h)
|
||||
(let: x-loop : flomap ([x : Nonnegative-Fixnum 0] [i : Nonnegative-Fixnum i])
|
||||
(cond
|
||||
[(x . fx< . w)
|
||||
(define: point-vs : FlVector (f x y i))
|
||||
(cond
|
||||
[(fx= (flvector-length point-vs) c)
|
||||
(let: k-loop : flomap ([k : Nonnegative-Fixnum 0] [i : Nonnegative-Fixnum i])
|
||||
(cond
|
||||
[(k . fx< . c) (unsafe-flvector-set! vs i (unsafe-flvector-ref point-vs k))
|
||||
(k-loop (unsafe-fx+ k 1) (unsafe-fx+ i 1))]
|
||||
[else (x-loop (unsafe-fx+ x 1) i)]))]
|
||||
[else (raise-type-error 'inline-build-flomap* (format "length-~e FlVector" c)
|
||||
point-vs)])]
|
||||
[else (y-loop (unsafe-fx+ y 1) i)]))]
|
||||
[else fm])))))
|
||||
|
||||
(: make-flomap* (Integer Integer (U (Vectorof Real) FlVector) -> flomap))
|
||||
(define (make-flomap* w h vs)
|
||||
(define c (flvector-length vs))
|
||||
(inline-build-flomap c w h (λ (k _x _y _i) (unsafe-flvector-ref vs k))))
|
||||
(let ([vs (->flvector vs)])
|
||||
(define c (flvector-length vs))
|
||||
(inline-build-flomap* c w h (λ (_x _y _i) vs))))
|
||||
|
||||
(: build-flomap* (Integer Integer Integer
|
||||
(Nonnegative-Fixnum Nonnegative-Fixnum -> (U (Vectorof Real) FlVector))
|
||||
-> flomap))
|
||||
(define (build-flomap* c w h f)
|
||||
(inline-build-flomap*
|
||||
c w h
|
||||
(λ (x y i)
|
||||
(define point-vs0 (f x y))
|
||||
(define point-vs1 (->flvector point-vs0))
|
||||
(cond [(fx= (flvector-length point-vs1) c) point-vs1]
|
||||
[else (raise-type-error 'build-flomap* (format "length-~e Vector or FlVector" c)
|
||||
point-vs0)]))))
|
||||
|
||||
(: flomap-ref-component (flomap Integer -> flomap))
|
||||
(define (flomap-ref-component fm k)
|
||||
|
@ -155,8 +255,7 @@
|
|||
(match-define (flomap vs1 d1 w1 h1) fm1)
|
||||
(match-define (flomap vs2 d2 w2 h2) fm2)
|
||||
(unless (and (= w1 w2) (= h1 h2))
|
||||
(error 'flomap-append-components
|
||||
"expected flomaps with equal dimension; given dimensions ~e×~e and ~e×~e"
|
||||
(error 'flomap-append-components "expected same-size flomaps; given sizes ~e×~e and ~e×~e"
|
||||
w1 h1 w2 h2))
|
||||
(inline-build-flomap (fx+ d1 d2) w1 h1
|
||||
(λ (k x y _i)
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
[flvector-set! old:flvector-set!])
|
||||
(except-in racket/fixnum fl->fx fx->fl) ; these two functions are untyped
|
||||
racket/math
|
||||
(only-in racket/unsafe/ops unsafe-flvector-set! unsafe-fx+)
|
||||
(only-in racket/unsafe/ops
|
||||
unsafe-flvector-set! unsafe-flvector-ref
|
||||
unsafe-vector-set! unsafe-vector-ref
|
||||
unsafe-fx+)
|
||||
racket/performance-hint)
|
||||
|
||||
(provide (all-defined-out)
|
||||
|
@ -35,8 +38,31 @@
|
|||
(loop (unsafe-fx+ i 1))]
|
||||
[else vs])))))
|
||||
|
||||
(: flvector->vector (FlVector -> (Vectorof Flonum)))
|
||||
(define (flvector->vector vs)
|
||||
(define n (flvector-length vs))
|
||||
(define new-vs (make-vector n 0.0))
|
||||
(let: loop : (Vectorof Flonum) ([k : Nonnegative-Fixnum 0])
|
||||
(cond [(k . < . n) (unsafe-vector-set! new-vs k (unsafe-flvector-ref vs k))
|
||||
(loop (unsafe-fx+ k 1))]
|
||||
[else new-vs])))
|
||||
|
||||
(: real-vector->flvector ((Vectorof Real) -> FlVector))
|
||||
(define (real-vector->flvector vs)
|
||||
(define n (vector-length vs))
|
||||
(define new-vs (make-flvector n 0.0))
|
||||
(let: loop : FlVector ([k : Nonnegative-Fixnum 0])
|
||||
(cond [(k . < . n) (unsafe-flvector-set! new-vs k (exact->inexact (unsafe-vector-ref vs k)))
|
||||
(loop (unsafe-fx+ k 1))]
|
||||
[else new-vs])))
|
||||
|
||||
(begin-encourage-inline
|
||||
|
||||
(: ->flvector ((U (Vectorof Real) FlVector) -> FlVector))
|
||||
(define (->flvector vs)
|
||||
(cond [(flvector? vs) vs]
|
||||
[else (real-vector->flvector vs)]))
|
||||
|
||||
(: fx->fl (Fixnum -> Flonum))
|
||||
(define fx->fl ->fl)
|
||||
|
||||
|
|
|
@ -29,19 +29,19 @@ The following flomap @racket[fm] is used in various examples:
|
|||
@interaction[#:eval flomap-eval
|
||||
(define fm
|
||||
(draw-flomap
|
||||
(λ (bm-dc)
|
||||
(send bm-dc set-alpha 0)
|
||||
(send bm-dc set-background "black")
|
||||
(send bm-dc clear)
|
||||
(send bm-dc set-alpha 1/3)
|
||||
(send bm-dc translate 2 2)
|
||||
(send bm-dc set-pen "black" 4 'long-dash)
|
||||
(send bm-dc set-brush "red" 'solid)
|
||||
(send bm-dc draw-ellipse 0 0 192 192)
|
||||
(send bm-dc set-brush "green" 'solid)
|
||||
(send bm-dc draw-ellipse 64 0 192 192)
|
||||
(send bm-dc set-brush "blue" 'solid)
|
||||
(send bm-dc draw-ellipse 32 44 192 192))
|
||||
(λ (fm-dc)
|
||||
(send fm-dc set-alpha 0)
|
||||
(send fm-dc set-background "black")
|
||||
(send fm-dc clear)
|
||||
(send fm-dc set-alpha 1/3)
|
||||
(send fm-dc translate 2 2)
|
||||
(send fm-dc set-pen "black" 4 'long-dash)
|
||||
(send fm-dc set-brush "red" 'solid)
|
||||
(send fm-dc draw-ellipse 0 0 192 192)
|
||||
(send fm-dc set-brush "green" 'solid)
|
||||
(send fm-dc draw-ellipse 64 0 192 192)
|
||||
(send fm-dc set-brush "blue" 'solid)
|
||||
(send fm-dc draw-ellipse 32 44 192 192))
|
||||
260 240))
|
||||
(flomap->bitmap fm)]
|
||||
It is typical to use @racket[flomap->bitmap] to visualize a flomap at the REPL.
|
||||
|
@ -68,7 +68,7 @@ There are three main reasons to use flomaps:
|
|||
@item{@bold{Range.}
|
||||
A floating-point value can also represent about 4.6 quintillion distinct intensities above saturation (@racket[1.0]).
|
||||
If distinguishing oversaturated values is important, flomaps have the range for it.
|
||||
Further, floating-point images are (approximately) closed under pointwise arithmetic.
|
||||
Further, floating-point images are closed under pointwise arithmetic (up to floating-point error).
|
||||
}
|
||||
@item{@bold{Speed.}
|
||||
The @racketmodname[images/flomap] module benefits greatly from Typed Racket's type-directed optimizations.
|
||||
|
@ -76,7 +76,7 @@ There are three main reasons to use flomaps:
|
|||
}
|
||||
)
|
||||
For these reasons, other parts of the @racket[images] library use flomaps internally, to represent and operate on
|
||||
ARGB and RGB images, light maps, shadow maps, height maps, and normal maps.
|
||||
RGB and ARGB images, light maps, shadow maps, height maps, and normal maps.
|
||||
|
||||
@subsection[#:tag "flomap:conceptual"]{Conceptual Model}
|
||||
|
||||
|
@ -88,23 +88,24 @@ The following example creates a 10×10 bitmap with RGB components, and indexes i
|
|||
It also attempts to index component @racket[3], which doesn't exist.
|
||||
Note that @racket[flomap-ref] accepts its coordinate arguments in a standard order: @racket[k] @racket[x] @racket[y] (with @racket[k] for @bold{k}omponent).
|
||||
@interaction[#:eval flomap-eval
|
||||
(define magenta-fm (make-flomap* 10 10 (flvector 1.0 0.0 1.0)))
|
||||
(define magenta-fm (make-flomap* 10 10 #(0.5 0.0 1.0)))
|
||||
(flomap->bitmap magenta-fm)
|
||||
(flomap-ref magenta-fm 0 0 0)
|
||||
(flomap-ref magenta-fm 0 -1 0)
|
||||
(flomap-ref magenta-fm 0 0 1000)
|
||||
(flomap-ref* magenta-fm 0 0)
|
||||
(flomap-ref* magenta-fm -1 0)
|
||||
(flomap-ref* magenta-fm 0 1000)
|
||||
(flomap-ref magenta-fm 3 0 0)]
|
||||
|
||||
Many flomap functions, such as @racket[flomap-bilinear-ref], treat their arguments as if every @italic{real} @racket[x] @racket[y] coordinate has values.
|
||||
In all such cases, known nonzero values are at half-integer coordinates and others are interpolated.
|
||||
|
||||
@examples[#:eval flomap-eval
|
||||
(flomap-bilinear-ref magenta-fm 0 0.5 0.5)
|
||||
(flomap-bilinear-ref magenta-fm 0 0.25 0.25)
|
||||
(flomap-bilinear-ref magenta-fm 0 0.0 0.0)]
|
||||
(flomap-bilinear-ref* magenta-fm 0.5 0.5)
|
||||
(flomap-bilinear-ref* magenta-fm 0.25 0.25)
|
||||
(flomap-bilinear-ref* magenta-fm 0.0 0.0)
|
||||
(flomap-bilinear-ref* magenta-fm -0.25 -0.25)]
|
||||
|
||||
This conceptual model allows us to treat flomaps as if they were multi-valued functions on @racket[Real]×@racket[Real].
|
||||
For example, we might plot the red component of an icon:
|
||||
For example, we might plot the red component of an ARGB icon:
|
||||
@interaction[#:eval flomap-eval
|
||||
(require images/icons/misc plot)
|
||||
(define icon-fm (bomb-flomap "azure" "orange" 48))
|
||||
|
@ -112,7 +113,7 @@ For example, we might plot the red component of an icon:
|
|||
(define-values (icon-width icon-height) (flomap-size icon-fm))
|
||||
(plot3d-bitmap (contour-intervals3d
|
||||
(λ (x y) (flomap-bilinear-ref icon-fm 1 x y))
|
||||
0 icon-width 0 icon-height))]
|
||||
-0.5 (+ 0.5 icon-width) -0.5 (+ 0.5 icon-height)))]
|
||||
Notice that the plot's maximum height is above saturation (@racket[1.0]).
|
||||
The tallest peak corresponds to the specular highlight (the shiny part) on the bomb.
|
||||
Specular highlights are one case where it is important to operate on oversaturated values without truncating them---until it is time to display the image.
|
||||
|
@ -143,10 +144,10 @@ As an example of the last point, consider blur.
|
|||
The following example creates an alpha-multiplied flomap using @racket[draw-flomap].
|
||||
It blurs the flomap using a general-purpose (i.e. non-alpha-aware) blur function, then converts the flomap to non-alpha-multiplied and does the same.
|
||||
@interaction[#:eval flomap-eval
|
||||
(define circle-fm (draw-flomap (λ (dc)
|
||||
(send dc set-pen "black" 1 'transparent)
|
||||
(send dc set-brush "green" 'solid)
|
||||
(send dc draw-ellipse 10 10 30 30))
|
||||
(define circle-fm (draw-flomap (λ (fm-dc)
|
||||
(send fm-dc set-pen "black" 1 'transparent)
|
||||
(send fm-dc set-brush "green" 'solid)
|
||||
(send fm-dc draw-ellipse 10 10 30 30))
|
||||
50 50))
|
||||
(flomap->bitmap circle-fm)
|
||||
(flomap->bitmap (flomap-blur circle-fm 4 4))
|
||||
|
@ -239,10 +240,17 @@ Returns the width and height of @racket[fm] as nonnegative fixnums.
|
|||
|
||||
@defproc[(flomap-ref [fm flomap] [k Integer] [x Integer] [y Integer]) Float]{
|
||||
Returns @racket[fm]'s value at @racket[k] @racket[x] @racket[y].
|
||||
|
||||
|
||||
If @racket[x] or @racket[y] is out of bounds, this function returns @racket[0.0].
|
||||
If @racket[k] is out of bounds, it raises an error.
|
||||
See @secref{flomap:conceptual} to read about why.
|
||||
The @secref{flomap:conceptual} section explains why @racket[k] is treated differently.
|
||||
}
|
||||
|
||||
@defproc[(flomap-ref* [fm flomap] [x Integer] [y Integer]) FlVector]{
|
||||
Returns @racket[fm]'s component values at @racket[x] @racket[y] as an flvector.
|
||||
|
||||
If @racket[x] or @racket[y] is out of bounds, this function returns an flvector filled with @racket[0.0].
|
||||
It always returns an flvector of length @racket[(flomap-components fm)].
|
||||
}
|
||||
|
||||
@defproc[(flomap-bilinear-ref [fm flomap] [k Integer] [x Real] [y Real]) Float]{
|
||||
|
@ -252,9 +260,14 @@ Like all other @racket[flomap] functions that operate on real-valued coordinates
|
|||
Mathematically, if @racket[x] = @racket[(+ i 0.5)] and @racket[y] = @racket[(+ j 0.5)] for any integers @racket[i] and @racket[j],
|
||||
then @racket[(flomap-bilinear-ref fm k x y)] = @racket[(flomap-ref fm k i j)].
|
||||
|
||||
If @racket[x] or @racket[y] is out of bounds, this function returns @racket[0.0].
|
||||
Suppose @racket[fm] is size @racket[w]×@racket[h].
|
||||
If @racket[x] ≤ @racket[-0.5] or @racket[x] ≥ @racket[(+ w 0.5)], this function returns @racket[0.0]; similarly for @racket[y] and @racket[h].
|
||||
If @racket[k] is out of bounds, it raises an error.
|
||||
See @secref{flomap:conceptual} to read about why.
|
||||
The @secref{flomap:conceptual} section explains why @racket[k] is treated differently.
|
||||
}
|
||||
|
||||
@defproc[(flomap-bilinear-ref* [fm flomap] [x Real] [y Real]) FlVector]{
|
||||
Like @racket[flomap-bilinear-ref], but returns an flvector containing estimates of all the components at @racket[x] @racket[y].
|
||||
}
|
||||
|
||||
@defproc[(flomap-min-value [fm flomap]) Float]
|
||||
|
@ -291,6 +304,12 @@ This function is used by some library functions, such as @racket[flomap-bilinear
|
|||
From untyped code, applying this function is likely no faster than applying @racket[flomap-ref], because of extra contract checks.
|
||||
}
|
||||
|
||||
@defproc[(unsafe-flomap-ref* [vs FlVector]
|
||||
[c Integer] [w Integer] [h Integer]
|
||||
[x Integer] [y Integer]) FlVector]{
|
||||
Like @racket[unsafe-flomap-ref], but returns an flvector containing all the component values at @racket[x] @racket[y].
|
||||
}
|
||||
|
||||
|
||||
@; ===================================================================================================
|
||||
|
||||
|
@ -316,6 +335,8 @@ See @secref{flomap:opacity} for a discussion of opacity (alpha) representation.
|
|||
|
||||
A zero-size @racket[fm] is padded by one point in any zero direction before conversion.
|
||||
For example, if @racket[fm] is size 0×1, the result of @racket[(flomap->bitmap fm)] is size 1×1.
|
||||
|
||||
Values are clamped to between @racket[0.0] and @racket[1.0] before conversion.
|
||||
}
|
||||
|
||||
@defproc[(bitmap->flomap [bm Any]) flomap]{
|
||||
|
@ -327,52 +348,68 @@ The argument type is imprecise because Typed Racket does not support the object
|
|||
|
||||
@defproc[(make-flomap [c Integer] [w Integer] [h Integer] [v Real 0.0]) flomap]{
|
||||
Returns a @racket[w]×@racket[h] flomap with @racket[c] components, with every value initialized to @racket[v].
|
||||
Analogous to @racket[make-vector].
|
||||
|
||||
To create flomaps filled with a solid color, use @racket[make-flomap*].
|
||||
}
|
||||
|
||||
@defproc[(make-flomap* [w Integer] [h Integer] [vs FlVector]) flomap]{
|
||||
Returns a @racket[w]×@racket[h] flomap with @racket[(flvector-length vs)] color components, with each known point initialized using the values in @racket[vs].
|
||||
@defproc[(make-flomap* [w Integer] [h Integer] [vs (U (Vectorof Real) FlVector)]) flomap]{
|
||||
Returns a @racket[w]×@racket[h] flomap with each point's components initialized using the values in @racket[vs].
|
||||
Analogous to @racket[make-vector].
|
||||
|
||||
The following two examples create magenta bitmaps with an alpha channel:
|
||||
The following two examples create an RGB and an ARGB flomap:
|
||||
@interaction[#:eval flomap-eval
|
||||
(flomap->bitmap (make-flomap* 100 100 (flvector 1.0 1.0 0.0 1.0)))
|
||||
(flomap->bitmap (make-flomap* 100 100 (flvector 0.5 0.5 0.0 0.5)))]
|
||||
(flomap->bitmap (make-flomap* 100 100 #(0.5 0.0 1.0)))
|
||||
(flomap->bitmap (make-flomap* 100 100 #(0.5 0.25 0.0 0.5)))]
|
||||
See @secref{flomap:opacity} for a discussion of opacity (alpha) representation.
|
||||
}
|
||||
|
||||
@defproc[(build-flomap [c Integer] [w Integer] [h Integer]
|
||||
[f (Nonnegative-Fixnum Nonnegative-Fixnum Nonnegative-Fixnum
|
||||
Nonnegative-Fixnum -> Real)]) flomap]{
|
||||
[f (Nonnegative-Fixnum Nonnegative-Fixnum Nonnegative-Fixnum -> Real)]) flomap]{
|
||||
Returns a @racket[w]×@racket[h] flomap with @racket[c] color components, with values defined by @racket[f].
|
||||
Analogous to @racket[build-vector].
|
||||
|
||||
The function @racket[f] receives three arguments @racket[k] @racket[x] @racket[y]: the color component and two positional coordinates.
|
||||
|
||||
The function @racket[f] receives four arguments @racket[k] @racket[x] @racket[y] @racket[i]: the color component, two positional coordinates, and a precalculated index into the flomap's @racketid[values] vector.
|
||||
@examples[#:eval flomap-eval
|
||||
(flomap->bitmap
|
||||
(build-flomap 1 100 100
|
||||
(λ (k x y i) (/ (+ x y) 200))))
|
||||
(λ (k x y) (/ (+ x y) 200))))
|
||||
(define sine-fm
|
||||
(build-flomap
|
||||
1 100 100
|
||||
(λ (k x y i)
|
||||
(λ (k x y)
|
||||
(* 1/2 (+ 1 (sin (sqrt (+ (sqr (- x 50))
|
||||
(sqr (- y 50))))))))))
|
||||
(flomap->bitmap sine-fm)]
|
||||
|
||||
To build a flomap from a function that returns vectors, see @racket[build-flomap*].
|
||||
}
|
||||
|
||||
@defform[(inline-build-flomap c w h f)]{
|
||||
A macro version of @racket[build-flomap].
|
||||
The function or macro @racket[f] must return a @racket[Float], not a @racket[Real] as the @racket[f] argument to @racket[build-flomap] can.
|
||||
@defproc[(build-flomap* [c Integer] [w Integer] [h Integer]
|
||||
[f (Nonnegative-Fixnum Nonnegative-Fixnum -> (U (Vectorof Real) FlVector))]) flomap]{
|
||||
Returns a @racket[w]×@racket[h] flomap with @racket[c] color components.
|
||||
Its values are defined by @racket[f], which returns vectors of point components.
|
||||
The vectors returned by @racket[f] must be length @racket[c].
|
||||
|
||||
Using @racket[inline-build-flomap] instead of @racket[build-flomap] often ensures that @racket[f] is inlined, and therefore floats remain unboxed.
|
||||
Many library functions use @racket[inline-build-flomap] internally for speed, notably @racket[fm+] and the other pointwise arithmetic operators.
|
||||
Analogous to @racket[build-vector].
|
||||
|
||||
@bold{This is not available in untyped Racket.}
|
||||
@examples[#:eval flomap-eval
|
||||
(flomap->bitmap
|
||||
(build-flomap* 4 100 100
|
||||
(λ (x y)
|
||||
(vector (/ (+ x y) 200)
|
||||
(/ (+ (- 100 x) y) 200)
|
||||
(/ (+ (- 100 x) (- 100 y)) 200)
|
||||
(/ (+ x (- 100 y)) 200)))))
|
||||
|
||||
(build-flomap* 4 100 100
|
||||
(λ (x y) (vector (/ (+ x y) 200))))]
|
||||
}
|
||||
|
||||
@defproc[(draw-flomap [draw (Any -> Any)] [w Integer] [h Integer]) flomap]{
|
||||
Returns a @racket[w]×@racket[h] bitmap drawn by @racket[draw].
|
||||
Think of it as the flomap version of @racketmodname[slideshow]'s @racket[dc].
|
||||
Analogous to @racketmodname[slideshow]'s @racket[dc].
|
||||
|
||||
The @racket[draw] function should accept a @racket[dc<%>] instance and use its drawing methods to draw on an underlying bitmap.
|
||||
The bitmap is converted to a flomap using @racket[bitmap->flomap] and returned.
|
||||
|
@ -395,6 +432,41 @@ You should not generally have to use these functions, because @racket[bitmap->fl
|
|||
See @secref{flomap:opacity} for a discussion of opacity (alpha) representation.
|
||||
}
|
||||
|
||||
@defform[(inline-build-flomap c w h f)
|
||||
#:contracts ([c Integer]
|
||||
[w Integer]
|
||||
[h Integer]
|
||||
[f (Nonnegative-Fixnum Nonnegative-Fixnum Nonnegative-Fixnum
|
||||
Nonnegative-Fixnum -> Float)])]{
|
||||
A macro version of @racket[build-flomap].
|
||||
|
||||
There are three differences between the function @racket[f] passed to @racket[build-flomap] and the @racket[f] passed to @racket[inline-build-flomap].
|
||||
First, the @racket[f] passed to @racket[inline-build-flomap] can be a macro.
|
||||
Second, it receives arguments @racket[k] @racket[x] @racket[y] @racket[i], where @racket[i] is a precalculated index into the result's @racketid[values].
|
||||
Third, it must return a @racket[Float].
|
||||
|
||||
Using @racket[inline-build-flomap] instead of @racket[build-flomap] often ensures that @racket[f] is inlined, and therefore floats remain unboxed.
|
||||
Many library functions use @racket[inline-build-flomap] internally for speed, notably @racket[fm+] and the other pointwise arithmetic operators.
|
||||
|
||||
@bold{This is not available in untyped Racket.}
|
||||
}
|
||||
|
||||
@defform[(inline-build-flomap* c w h f)
|
||||
#:contracts ([c Integer]
|
||||
[w Integer]
|
||||
[h Integer]
|
||||
[f (Nonnegative-Fixnum Nonnegative-Fixnum
|
||||
Nonnegative-Fixnum -> FlVector)])]{
|
||||
A macro version of @racket[build-flomap*].
|
||||
|
||||
There are three differences between the function @racket[f] passed to @racket[build-flomap*] and the @racket[f] passed to @racket[inline-build-flomap*].
|
||||
First, the @racket[f] passed to @racket[inline-build-flomap*] can be a macro.
|
||||
Second, it receives arguments @racket[x] @racket[y] @racket[i], where @racket[i] is a precalculated index into the result's @racketid[values].
|
||||
Third, it must return a @racket[FlVector].
|
||||
|
||||
@bold{This is not available in untyped Racket.}
|
||||
}
|
||||
|
||||
|
||||
@; ===================================================================================================
|
||||
|
||||
|
@ -466,23 +538,14 @@ For example, to estimate the local gradient magnitude at each point in a flomap:
|
|||
Lifts a unary floating-point function to operate pointwise on flomaps.
|
||||
}
|
||||
|
||||
@defform[(inline-flomap-lift f)]{
|
||||
A macro version of @racket[flomap-lift].
|
||||
The function or macro @racket[f] must return a @racket[Float], not a @racket[Real] as the @racket[f] argument to @racket[flomap-lift] can.
|
||||
|
||||
Using @racket[inline-flomap-lift] instead of @racket[flomap-lift] often ensures that @racket[f] is inlined, and therefore floats remain unboxed.
|
||||
|
||||
@bold{This is not available in untyped Racket.}
|
||||
}
|
||||
|
||||
@defproc[(flomap-normalize [fm flomap]) flomap]{
|
||||
Returns a flomap like @racket[fm], but with values linearly rescaled to be between @racket[0.0] and @racket[1.0] inclusive.
|
||||
@examples[#:eval flomap-eval
|
||||
(define gray-fm
|
||||
(build-flomap 1 100 100 (λ (k x y i) (+ 0.375 (/ (+ x y) 800)))))
|
||||
(build-flomap 1 100 100 (λ (k x y) (+ 0.375 (/ (+ x y) 800)))))
|
||||
(flomap->bitmap gray-fm)
|
||||
(flomap->bitmap (flomap-normalize gray-fm))]
|
||||
Besides increasing contrast, you could use this function to debug a rendering pipeline that produces overbright intermediate flomaps.
|
||||
Besides increasing contrast, you could use this function to visualize oversaturated flomaps, or visualize flomaps that don't correspond directly to displayed images, such as height maps and normal maps.
|
||||
}
|
||||
|
||||
@defproc[(fm+ [fm1 (U Real flomap)] [fm2 (U Real flomap)]) flomap]
|
||||
|
@ -504,7 +567,7 @@ Binary operations accept the following argument combinations, in either order:
|
|||
Any other argument combination will raise a type error.
|
||||
|
||||
@examples[#:eval flomap-eval
|
||||
(define fm1 (build-flomap 1 260 240 (λ (k x y i) (/ (+ x y) 500))))
|
||||
(define fm1 (build-flomap 1 260 240 (λ (k x y) (/ (+ x y) 500))))
|
||||
(define fm2 (fm- 1.0 fm1))
|
||||
(flomap->bitmap fm1)
|
||||
(flomap->bitmap fm2)
|
||||
|
@ -526,7 +589,16 @@ Because @racket[fm] is an alpha-multiplied flomap (see @secref{flomap:opacity}),
|
|||
Lifts a binary floating-point function to operate pointwise on flomaps, allowing the same argument combinations as @racket[fm+] and others.
|
||||
}
|
||||
|
||||
@defform[(inline-flomap-lift2 f)]{
|
||||
@defform[(inline-flomap-lift f) #:contracts ([f (Float -> Float)])]{
|
||||
A macro version of @racket[flomap-lift].
|
||||
The function or macro @racket[f] must return a @racket[Float], not a @racket[Real] as the @racket[f] argument to @racket[flomap-lift] can.
|
||||
|
||||
Using @racket[inline-flomap-lift] instead of @racket[flomap-lift] often ensures that @racket[f] is inlined, and therefore floats remain unboxed.
|
||||
|
||||
@bold{This is not available in untyped Racket.}
|
||||
}
|
||||
|
||||
@defform[(inline-flomap-lift2 f) #:contracts ([f (Float Float -> Float)])]{
|
||||
A macro version of @racket[flomap-lift2].
|
||||
The function or macro @racket[f] must return a @racket[Float], not a @racket[Real] as the @racket[f] argument to @racket[flomap-lift2] can.
|
||||
|
||||
|
@ -550,10 +622,10 @@ These return, per-component, estimates of the local @italic{x}- and @italic{y}-d
|
|||
Equivalent to @racket[(values (flomap-gradient-x fm) (flomap-gradient-y fm))].
|
||||
|
||||
@examples[#:eval flomap-eval
|
||||
(let-values ([(dx-fm dy-fm) (flomap-gradient
|
||||
(flomap-drop-components fm 1))])
|
||||
(values (flomap->bitmap (fm* 0.5 (fm+ 1.0 dx-fm)))
|
||||
(flomap->bitmap (fm* 0.5 (fm+ 1.0 dy-fm)))))]
|
||||
(define-values (dx-fm dy-fm)
|
||||
(flomap-gradient (flomap-drop-components fm 1)))
|
||||
(values (flomap->bitmap (fm* 0.5 (fm+ 1.0 dx-fm)))
|
||||
(flomap->bitmap (fm* 0.5 (fm+ 1.0 dy-fm))))]
|
||||
}
|
||||
|
||||
@defproc[(flomap-gradient-normal [fm flomap]) flomap]{
|
||||
|
@ -561,7 +633,8 @@ Given a one-component flomap, returns a @racket[3]-component flomap containing e
|
|||
In other words, @racket[flomap-normal] converts height maps to normal maps.
|
||||
@examples[#:eval flomap-eval
|
||||
(flomap->bitmap sine-fm)
|
||||
(flomap->bitmap (flomap-gradient-normal sine-fm))]
|
||||
(flomap->bitmap (flomap-gradient-normal sine-fm))
|
||||
(flomap-gradient-normal fm)]
|
||||
}
|
||||
|
||||
|
||||
|
@ -595,7 +668,7 @@ Like @racket[flomap-gaussian-blur-x], but per-column instead of per-row.
|
|||
|
||||
@defproc[(flomap-box-blur [fm flomap] [x-radius Real] [y-radius Real x-radius]) flomap]{
|
||||
Returns @racket[fm] convolved, per-component, with a box kernel with radii @racket[x-radius] and @racket[y-radius].
|
||||
The radii are of the largest ellipse that would fit in the box.
|
||||
The radii are of the largest axis-aligned ellipse that would fit in the box.
|
||||
@examples[#:eval flomap-eval
|
||||
(flomap->bitmap (flomap-box-blur (flomap-inset fm 4) 4))
|
||||
(flomap->bitmap (flomap-box-blur (flomap-inset fm 4 1) 4 1))]
|
||||
|
@ -662,8 +735,8 @@ This function cannot return a larger flomap.
|
|||
|
||||
@examples[#:eval flomap-eval
|
||||
(define small-circle-fm
|
||||
(draw-flomap (λ (dc)
|
||||
(send dc draw-ellipse 20 20 10 10))
|
||||
(draw-flomap (λ (fm-dc)
|
||||
(send fm-dc draw-ellipse 20 20 10 10))
|
||||
100 100))
|
||||
(flomap->bitmap small-circle-fm)
|
||||
(flomap->bitmap (flomap-trim small-circle-fm))]
|
||||
|
@ -741,11 +814,11 @@ The result is expanded as necessary.
|
|||
@examples[#:eval flomap-eval
|
||||
(flomap-pin fm -10 -10 sine-fm)
|
||||
(define circle-fm
|
||||
(draw-flomap (λ (the-dc)
|
||||
(send the-dc set-pen "black" 4 'short-dash)
|
||||
(send the-dc set-brush "yellow" 'solid)
|
||||
(send the-dc set-alpha 1/2)
|
||||
(send the-dc draw-ellipse 2 2 124 124))
|
||||
(draw-flomap (λ (fm-dc)
|
||||
(send fm-dc set-pen "black" 4 'short-dash)
|
||||
(send fm-dc set-brush "yellow" 'solid)
|
||||
(send fm-dc set-alpha 1/2)
|
||||
(send fm-dc draw-ellipse 2 2 124 124))
|
||||
128 128))
|
||||
(flomap->bitmap (flomap-pin fm 0 0 circle-fm 64 64))
|
||||
(flomap->bitmap (flomap-pin sine-fm 50 0 sine-fm))]
|
||||
|
@ -795,9 +868,10 @@ See @racket[flomap-pin] and @racket[flomap-pin*] for implementation details.
|
|||
@defproc[(flomap-hc-append [fm0 flomap] [fm flomap] ...) flomap]
|
||||
@defproc[(flomap-hb-append [fm0 flomap] [fm flomap] ...) flomap]{
|
||||
These create a new flomap by spatially appending the flomaps in the argument list.
|
||||
The two-letter abbreviation determines direction (@racket[v] or @racket[h]) and alignment (@racket[l], @racket[c], @racket[r], or @racket[t], @racket[c], @racket[b]).
|
||||
The two-letter abbreviation determines direction (@racketid[v] or @racketid[h]) and alignment (@racketid[l], @racketid[c], @racketid[r], or @racketid[t], @racketid[c], @racketid[b]).
|
||||
@examples[#:eval flomap-eval
|
||||
(flomap->bitmap (flomap-ht-append circle-fm fm circle-fm))]
|
||||
(flomap->bitmap (flomap-ht-append circle-fm fm
|
||||
(flomap-scale circle-fm 1/2)))]
|
||||
See @racket[flomap-pin] and @racket[flomap-pin*] for implementation details.
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user