PasteRack.org
Paste # 39958
2019-08-14 16:46:58

Fork as a new paste.

Paste viewed 419 times.


Embed:

EEF

#lang racket/base

(require plot
         racket/match
         racket/file
         math)

(module+ test (require rackunit))
(define (^ b [e 2])(expt b e))

;--------------------------------------------
;ribbon coordinates
;--------------------------------------------
(define R 100)
(define P  90)
(define π (angle -1))
(define 2π (* 2 π))

(define (xyz->ribbon x y z)
  (define ϕ0 (atan y x))
  (define n0 (/ (- z (* P (/ ϕ0 2π))) P))
  (define n (round n0))
  (define ϕ (+ ϕ0 (* n 2π)))
  (define t (- z (* P (/ ϕ 2π))))
  (define d (- (sqrt (+ (* x x) (* y y))) R))
;(println (list ϕ0 n0 n ϕ t d))
  (list ϕ t d))
(module+ test
  (check-within (xyz->ribbon 100 0 0) '(0 0 0) 1e-15)
  (check-within (xyz->ribbon  90 0 0) '(0 0 -10) 1e-15)
  (check-within (xyz->ribbon 110 0 0) '(0 0 10) 1e-15)
  
  (check-within (xyz->ribbon 100 0  4) '(0 4 0) 1e-15)
  (check-within (xyz->ribbon 100 0 -4) '(0 -4 0) 1e-15)
  (check-within (xyz->ribbon 100 0 (/ P  3)) (list 0 (/ P  3) 0) 1e-15)
  (check-within (xyz->ribbon 100 0 (/ P -3)) (list 0 (/ P -3) 0) 1e-15)

  (check-within (xyz->ribbon -100 0 (/ P 2)) (list π 0 0) 1e-15)
  (check-within (xyz->ribbon -100 0 (+ (/ P 2)(/ P  3))) (list π (/ P  3) 0) 1e-14)
  (check-within (xyz->ribbon -100 0 (+ (/ P 2)(/ P -3))) (list π (/ P -3) 0) 1e-14)

  (check-within (xyz->ribbon 100   0 P) (list 2π 0 0) 1e-15)
  (check-within (xyz->ribbon   0 100 (/ P 4)) (list (/ π 2) 0 0) 1e-15)
  (check-within (xyz->ribbon   0  90 (/ P 4)) (list (/ π 2) 0 -10) 1e-15)
  (check-within (xyz->ribbon 100 100 (* P (+ 2 1/8))) (list (+ (* (+ 2 1/8) 2π)) 0 (* 100 (- (sqrt 2) 1))) 1e-13)
  )

(define (ribbon->xyz ϕ t d)
  (list (* (+ R d) (cos ϕ))
        (* (+ R d) (sin ϕ))
        (+ (* P (/ ϕ 2π)) t)))
(module+ test
  (let ([x (* (random) 100)]
        [y (* (random) 100)]
        [z (* (random) 100)])
    (check-within (apply ribbon->xyz (xyz->ribbon x y z)) (list x y z) 1e-10)))

;--------------------------------------------
;egg-face (in cilinder coordinates)
;--------------------------------------------
(define (skull θ z)
  (define Z0 10)(define Z1 290)
  (define C0 90)(define C1 -10)
  (define C (+ (* (/ (- C0 C1)(expt (- Z1 Z0) 2))(expt (- Z1 z) 2)) C1))
  (define A/B0 .2)
  (define A/B (+ 1 (* A/B0 (/ (- Z0 z)(- Z0 Z1)))))
  (define R0 130)
  (define R (* R0 (sqrt (/ (* 4 (- z Z0)(- Z1 z)) (^ (- Z1 Z0))))))

  (define a (+ (^ (cos θ))(^ (* A/B (sin θ)))))
  (define b (* -2 C (cos θ)))
  (define c (- (^ C)(^ (* R A/B))))
  (define D (sqrt (+ (^ b) (* -4 a c))))

  (and (<= Z0 z Z1)
       (real? D)
       (max (/ (- (- b) D) 2 a)(/ (+ (- b) D) 2 a))))
(define (neck θ z)
  (define Z0  0)(define Z1 90)
  (define R0 80)(define R1 70)
  (and (<= Z0 z Z1)
       (- R0 (* (- R0 R1)(* 4 (/ (- z Z0) (- Z1 Z0)) (- 1 (/ (- z Z0) (- Z1 Z0))))))))
(define (nose θ z)
  (define Z0  120)(define Z1 200)(define Z2 480)
  (define θ0 .15)
  (define R0 140)(define R1 180)
  (and (<= Z0 z Z1)
       (<= (- θ0) θ (+ θ0))
       (* (- 1 (/ (-  z Z0)
                  (- Z2 Z0)))
          (+ R0 (* (- R1 R0)
                   (let ([θ* (/ (+ θ θ0) 2 θ0)])(* 4 θ* (- 1 θ*))))))))
(define (lips θ z)
  (define Z0  70)(define Z1 110)
  (define θ0 .4)
  (define R0 150)(define R1 170)
  (define Z/2 (/ (+ Z0 Z1) 2))
  (and (<= Z0 z Z1)
       (<= (- θ0) θ (+ θ0))
       (+ R0 (* (- R1 R0)
                (if (< z Z/2)
                    (let ([z* (/ (- z Z0)(- Z/2 Z0))])( * -2.25 z* (- z* 4/3)))
                    (let ([z* (/ (- z Z/2)(- Z1 Z/2))])(* -2.25 (+ z* 1/3) (- z* 1))))
                (let ([θ* (/ (+ θ θ0) 2 θ0)])(* 4 θ* (- 1 θ*)))))))
(define (eyes θ z)
  (define Z0 170)(define Z1 190)
  (define θ0 .15)(define θ1 .35)
  (define R0 140)(define R1 150)
 (and (<= Z0 z Z1)
      (<= θ0 (abs θ) θ1)
      (+ R0 (* (- R1 R0)
               (let ([z* (/ (- z Z0)(- Z1 Z0))])(* 4 z* (- 1 z*)))
               (let ([θ* (/ (- (abs θ) θ0)(- θ1 θ0))])(* 4 θ* (- 1 θ*)))))))
(define (eyebrow θ z)
  (define Z0 195)(define Z1 205)
  (define θ0 .55)
  (define R0 130)(define R1 145)
  (and (<= Z0 z Z1)
       (<= (- θ0) θ (+ θ0))
       (+ R0 (* (- R1 R0)
                (let ([z* (/ (- z Z0)(- Z1 Z0))])(* 4 z* (- 1 z*)))
                (let ([θ* (/ (+ θ θ0) 2 θ0)])(* 4 θ* (- 1 θ*)))))))
(define (ears1 θ z)
  (define Z0 110)(define Z1 200)
  (define θ0 (* .35 (sqrt (/ (* 4 (- z Z0)(- Z1 z)) (^ (- Z1 Z0))))))
  (define R0 140)
  (and (<= Z0 z Z1)
       (<= (- (/ π 2) θ0) (abs θ) (+ (/ π 2) θ0))
       R0))
(define (ears2 θ z)
  (define Z0 190)(define Z1 295)
  (define θ0 .1)
  (and (<= Z0 z Z1)
       (<= (- (/ π 2) θ0) (abs θ) (+ (/ π 2) θ0))
       (+ (or (skull θ z) 0) 10)))
;combine
(define (face θ z)
  (apply
   max
   (filter
    values
    (list
     (skull θ z) (neck θ z) (nose θ z) (lips θ z)
     (eyes θ z)  (eyebrow θ z)
     (ears1 θ z) (ears2 θ z)
     0))))

;--------------------------------------------
;some plot functions to show the face
;--------------------------------------------
(module+ main
  (define (ribonFct f
                    #:ϕ-min [ϕ-min -inf.0]
                    #:ϕ-max [ϕ-max +inf.0]
                    #:t-min [t-min -inf.0]
                    #:t-max [t-max +inf.0])
    (λ (x y z)
      (match-define (list ϕ t d0) (xyz->ribbon x y z))
      (if (and (<= ϕ-min ϕ ϕ-max)
               (<= t-min t t-max))
          (- d0 (f ϕ t))
          +inf.0)))
  (define (memo-parapoint f u0 u1 v0 v1 file #:nr [nr 10000])
    (define memo (if (file-exists? file) (file->list file read) '()))
    (define len (length memo))
    (append
     memo
     (for*/list ([i (in-range (max 0 (- nr len)))]
                 [u (in-value (+ u0 (* (- u1 u0) (random))))]
                 [v (in-value (+ v0 (* (- v1 v0) (random))))]
                 [xyz (in-value (with-handlers ([exn:fail? (λ (e) #f)])(f u v)))]
                 #:when xyz)
       (call-with-output-file file (λ (out) (writeln xyz out)) #:exists 'append)
       xyz)))
  (define (parapoint f u0 u1 v0 v1 #:nr [nr 10000] #:memo-it [file #f])
    (if file
        (memo-parapoint f u0 u1 v0 v1 file #:nr nr)
        (for*/list ([i (in-range nr)]
                [u (in-value (+ u0 (* (- u1 u0) (random))))]
                [v (in-value (+ v0 (* (- v1 v0) (random))))]
                [xyz (in-value (with-handlers ([exn:fail? (λ (e) #f)])(f u v)))]
                #:when xyz)
      xyz)))
  )

#;(module+ main
  (plot3d
   (list
    (points3d (parapoint (λ (θ z) (define r (skull    θ z)) (list (* r (cos θ))(* r (sin θ)) z)) (- π)  π  10 290) #:size 1 #:color 'brown)
    (points3d (parapoint (λ (θ z) (define r (neck     θ z)) (list (* r (cos θ))(* r (sin θ)) z)) (- π)  π   0  90) #:size 1 #:color 'green)
    (points3d (parapoint (λ (θ z) (define r (nose     θ z)) (list (* r (cos θ))(* r (sin θ)) z))  -.2  .2 120 200) #:size 1 #:color 'red)
    (points3d (parapoint (λ (θ z) (define r (lips     θ z)) (list (* r (cos θ))(* r (sin θ)) z))  -.4  .4  70 110) #:size 1 #:color 'yellow)
    (points3d (parapoint (λ (θ z) (define r (eyes     θ z)) (list (* r (cos θ))(* r (sin θ)) z))  -.4  .4 170 190) #:size 1 #:color 'blue)
    (points3d (parapoint (λ (θ z) (define r (eyebrow  θ z)) (list (* r (cos θ))(* r (sin θ)) z)) (- π)  π 195 205) #:size 1 #:color 'blue)
    (points3d (parapoint (λ (θ z) (define r (ears1    θ z)) (list (* r (cos θ))(* r (sin θ)) z)) (- π)  π 100 210) #:size 1 #:color 'gray)
    (points3d (parapoint (λ (θ z) (define r (ears2    θ z)) (list (* r (cos θ))(* r (sin θ)) z)) (- π)  π 195 300) #:size 1 #:color 'gray))
          #:width 800
          #:height 800
          #:angle 197
          #:altitude 7))

;--------------------------------------------
;result: EEF (escher-egg-face)
;--------------------------------------------
(module+ main
  (plot3d
   (points3d
    (parapoint
     (λ (θ z) (define r (face θ z))
       (match-define (list x y _)(list (* r (cos θ))(* r (sin θ)) z))
       (match-define (list ϕ t d)(xyz->ribbon x y z))
       (if (< (abs t) 10) (list x y z) #f))
     (- π)  π  0 300
     #:nr 30000)
    #:size 1)
   #:x-min -300 #:x-max 300
   #:y-min -300 #:y-max 300
   #:z-min    0 #:z-max 600
   #:width 800
   #:height 800
   #:angle 197
   #:altitude 7))
(module+ main
  (parameterize ([plot-decorations? #f])
    (plot3d
     (parametric-surface3d
      (λ (ϕ t)
        (match-define (list x y z)(ribbon->xyz ϕ t 0))
        (ribbon->xyz ϕ t (- (face (atan y x) z) R)))
      0   (* (/ 290 P) 2π) #:s-samples 1500
      -7 +40 #:t-samples 30
      #:color "navajowhite"
      #:line-color "navajowhite")
     #:x-min -300 #:x-max 300
     #:y-min -300 #:y-max 300
     #:z-min    0 #:z-max 600
     #:width 800
     #:height 800
     #:angle 210
     #:altitude 10)))