[racket] Crowdsourcing Pict3D's design

From: Neil Toronto (neil.toronto at gmail.com)
Date: Mon Mar 9 17:58:00 EDT 2015

Sure! You could assemble it yourself out of triangles and quads. :)

OK, maybe that's not "good". It's a fun problem, though, so I gave it a 
shot. I've attached my solution. The `parametric-cylinder` function 
accepts a function that takes a "time" parameter `t` and returns four 
values: the center of the cylinder at time `t`, the first derivative of 
the function from `t` to center, the second derivative, and a radius. It 
should work on any parametric function that doesn't have any collinear 
segments.

You probably want something like the `helix` example.

An easier-to-use solution would probably derive the first and second 
derivatives from samples of the center position.

Neil ⊥

On 03/09/2015 03:37 PM, Alexander D. Knauth wrote:
> Is there a good way to draw a smooth curved cylinder?
>
> On Mar 8, 2015, at 10:53 PM, Neil Toronto <neil.toronto at gmail.com> wrote:
>
>> Pict3D is finally ready for public consumption. You can install the package either in DrRacket using "File -> Install Package..." or from the command line using
>>
>>     raco pkg install pict3d
>>
>> The GitHub page is here:
>>
>>     https://github.com/ntoronto/pict3d
>>
>> All features are documented. The API is stable. I've verified that it runs on Racket 6.1.1 and the current development version. There are reports of it working on at least two Windows systems, two Mac OS X systems, and two Linux systems. It might not eat your graphics card.
>>
>> Current features:
>>
>> * Works in untyped and Typed Racket
>>
>> * Spheres, rectangles, triangles and quads with per-vertex attributes
>>
>> * A system of groups and affine (arbitrary parallel-line-preserving)
>>    transformations for sticking Pict3Ds together
>>
>> * Ray-against-scene and line-against-scene collision detection
>>
>> * Render targets: an interactive debugging view in DrRacket's REPL,
>>    `pict3d->bitmap` and `pict3d-canvas%`
>>
>> * big-bang3d (currently without networking)
>>
>> ------------------
>>
>> Now we get to crowdsourcing.
>>
>> I've reached the limits of what I can do without working on Pict3D full-time. In particular, I don't know whether the API is awkward or actually quite nice for the uses it'll be put to. I've drawn on some personal game design and coding experience, but that only goes so far.
>>
>> This is where you come in.
>>
>> If you've ever had the slightest hankering to do some real 3D but avoided it because of the pain that usually goes with it, try Pict3D. (If it fails to work, please submit a bug report on the GitHub page.) Got a visualization project? Try Pict3D. Want to make a game? Try Pict3D's version of Big Bang. Want to just fool around in 3D space for a bit? Try Pict3D, and report back on how it goes.
>>
>> Anything is fair game for criticism, praise or suggestions: groups and pinning, distinguishing direction and position vectors, presence or lack of shapes you need, how to allow shader programming, file formats that would be nice to import models from, information that would be nice to have in the interactive debugging view, how to add texturing to the API, and even the tone of the documentation.
>>
>> I'm looking forward to your reports, all my little minions. Wait, did I say that out loud?
>>
>> Neil ⊥
>> ____________________
>> Racket Users list:
>> http://lists.racket-lang.org/users
>

-------------- next part --------------
#lang typed/racket

(require pict3d
         math/flonum)

(: parametric-cylinder (-> (-> Flonum (Values Pos Dir Dir Real))
                           Real
                           Real
                           [#:segments Nonnegative-Integer]
                           [#:samples Nonnegative-Integer]
                           [#:inside? Boolean]
                           Pict3D))
(define (parametric-cylinder f tmin tmax #:segments [m 32] #:samples [n 32] #:inside? [inside? #f])
  (define tstep (/ (- (fl tmax) (fl tmin)) (fl n)))
  (define θstep (/ (* 2 pi) (fl m)))
  
  ;; Compute all the verices first
  (define vss
    ;; For each sample...
    (for/list : (Listof (Listof Vertex)) ([i  (in-range (+ n 1))])
      (define t (+ tmin (* tstep (fl i))))
      (define-values (v dv ddv r) (f t))
      ;; Derive local coordinate axes from derivative and second derivative
      (define dz (dir-normalize dv))
      (cond
        [(not dz)  (error 'bent-cylinder "zero derivative at t = ~v~n" t)]
        [else
         (define dy (dir-normalize (dir-cross dz ddv)))
         (cond
           [(not dy)  (error 'bent-cylinder "zero or coincident second derivative at t = ~v~n" t)]
           [else
            (define dx (dir-cross dy dz))
            ;; Assemble the transformation to local coordinates
            (define tr (cols->affine dx dy dz origin))
            ;; For each angle...
            (for/list : (Listof Vertex) ([j  (in-range (+ m 1))])
              (define θ (* θstep (fl j)))
              (let* (;; Compute the direction to the vertex on the unit circle
                     [d  (dir (* (cos θ) r) (* (sin θ) r) 0)]
                     ;; Transform into local coordinates
                     [d  (transform-dir d tr)])
                (vertex (pos+ v d) #:normal d)))])])))
  
  (freeze
   (combine
    ;; Cylinder part
    (for/list : (Listof (Listof Pict3D)) ([vs0  (in-list vss)]
                                          [vs1  (in-list (rest vss))])
      (for/list : (Listof Pict3D) ([v00  (in-list vs0)]
                                   [v01  (in-list (rest vs0))]
                                   [v10  (in-list vs1)]
                                   [v11  (in-list (rest vs1))])
        (quad v00 v01 v11 v10 #:back? inside?)))
    ;; "Bottom" (tmin) cap
    (for/list : (Listof Pict3D) ([v0  (in-list (first vss))]
                                 [v1  (in-list (rest (first vss)))])
      (define-values (v2 dv _2 _3) (f (fl tmin)))
      (triangle (vertex v2 #:normal dv)
                (vertex (vertex-pos v1) #:normal dv)
                (vertex (vertex-pos v0) #:normal dv)
                #:back? inside?))
    ;; "Top" (tmax) cap
    (for/list : (Listof Pict3D) ([v0  (in-list (last vss))]
                                 [v1  (in-list (rest (last vss)))])
      (define-values (v2 dv _2 _3) (f (fl tmax)))
      (triangle (vertex (vertex-pos v0) #:normal dv)
                (vertex (vertex-pos v1) #:normal dv)
                (vertex v2 #:normal dv)
                #:back? inside?)))))

(: square (-> Flonum (Values Pos Dir Dir Real)))
(define (square t)
  (values (pos t (sqr t) 0)
          (dir 1 (* 2 t) 0)
          (dir 0 2 0)
          (+ 0.25 (* 0.25 (abs (sin (* t 4)))))))

(: helix (-> Flonum (Values Pos Dir Dir Real)))
(define (helix t)
  (values (pos (cos t) (sin t) (/ t (* 2 pi)))
          (dir (- (sin t)) (cos t) (/ 1 (* 2 pi)))
          (dir (- (cos t)) (- (sin t)) 0)
          1/2))

(parametric-cylinder square -1 1 #:inside? #t)
(with-color (rgba "lightblue")
  (parametric-cylinder helix 0 (* 8 pi) #:segments 32 #:samples 128))

Posted on the users mailing list.