(module (s9fes char-canvas shape oval) (;export ; circle-octant-point generate-circle-octant ; circle-octant-plotter circle-octant-visitor ; generate-virtual-circle-octant virtual-circle-octant-visitor) (import scheme utf8) (import (chicken base)) (import (chicken fixnum)) (import (chicken type)) (import (s9fes char-canvas)) (include-relative "s9fes.char-canvas.types") (define-type circle-octant-plotter (canvas fixnum fixnum fixnum fixnum -> boolean)) (define-type circle-octant-visitor (canvas fixnum fixnum -> boolean)) (: circle-octant-point (fixnum fixnum fixnum fixnum fixnum -> fixnum fixnum)) (: circle-octant-plotter (#!optional (or char plotter-configuration) -> circle-octant-plotter)) (: circle-octant-visitor (fixnum fixnum circle-octant-plotter -> circle-octant-visitor)) (: generate-circle-octant (canvas fixnum circle-octant-visitor -> void)) (: virtual-circle-octant-visitor (integer integer circle-octant-plotter -> circle-octant-visitor)) (: generate-virtual-circle-octant (canvas integer circle-octant-visitor #!optional boolean -> void)) ;; #; (define (slope x y) ;preserve sign! watch for -0.0 (if (not (zero? x)) (/ y x) ;then can divide ;else vertical, horizontal (cond ((zero? y) (* x y)) ((negative? y) -inf.0) (else +inf.0))) ) ;; ; 0 : x0 + x , y0 + y ; 1 : x0 + y , y0 + x ; 2 : x0 - y , y0 + x ; 3 : x0 - x , y0 + y ; 4 : x0 - x , y0 - y ; 5 : x0 - y , y0 - x ; 6 : x0 + y , y0 - x ; 7 : x0 + x , y0 - y ;FIXME generate-circle-octant produces octant 1! (define (octant-order-patch loc ot) (case ot ((0) 1) ((1) 0) ((2) 3) ((3) 2) ((4) 5) ((5) 4) ((6) 7) ((7) 6) (else (error loc "unknown octant" ot))) ) (define (circle-octant-point ot x0 y0 x y) (case (octant-order-patch 'circle-octant-point ot) ((0) (values (fx+ x0 x) (fx+ y0 y))) ((1) (values (fx+ x0 y) (fx+ y0 x))) ((2) (values (fx- x0 y) (fx+ y0 x))) ((3) (values (fx- x0 x) (fx+ y0 y))) ((4) (values (fx- x0 x) (fx- y0 y))) ((5) (values (fx- x0 y) (fx- y0 x))) ((6) (values (fx+ x0 y) (fx- y0 x))) ((7) (values (fx+ x0 x) (fx- y0 y))) (else (error 'circle-octant-point "unknown octant" ot))) ) ;https://iq.opengenus.org/bresenhams-circle-drawing-algorithm/ (define (generate-circle-octant cv r visit) ;produces octant 1 (let loop ((x 0) (y r) (d (fx- 3 (fx* r 2)))) (unless (fx< y x) (when (visit cv x y) (let ((x (fx+ x 1))) (if (fx> d 0) (loop x (fx- y 1) (fx+ d (fx+ (fx* 4 (fx- x y)) 10))) (loop x y (fx+ d (fx+ (fx* 4 x) 6))) ) ) ) ) ) ) ;FIXME should cv & center be closed-over here or by visit? (define ((circle-octant-visitor x0 y0 plotter) cv x y) (plotter cv x0 y0 x y) ) (define (circle-octant-plotter #!optional (cfg (current-plotter-char))) (let ((cfg (validate-plotter-configuration 'circle-octant-plotter cfg 8 #f))) (lambda (cv x0 y0 x y) (let loop ((rem cfg) (ot 0)) (or (null? rem) (let ((c (car rem))) (when c (let-values (((xr yr) (circle-octant-point ot x0 y0 x y))) (canvas-draw cv xr yr c) ) ) (loop (cdr rem) (fx+ ot 1)) ) ) ) ) ) ) ;; (define (generate-virtual-circle-octant cv r visit #!optional (avg? #f)) (let-values (((rx ry) (canvas-physical cv r r))) (let ((rp (if avg? (fx/ (fx+ rx ry) 2) ry))) (assert (fx< 0 ry) 'generate-virtual-circle-octant "radius is too small" r) (generate-circle-octant cv ry visit) ) ) ) (define (virtual-circle-octant-visitor x0 y0 plotter) ;need a canvas to do the conversion, so pend until available (let ((visit (the (or false circle-octant-visitor) #f))) (lambda (cv x y) (unless visit (set! visit (let-values (((x0 y0) (canvas-physical cv x0 y0))) (circle-octant-visitor x0 y0 plotter))) ) (visit cv x y) ) ) ) ) ;module (s9fes char-canvas shape oval)