Would it work so that you could all instances of: (pin (combine pict1 (basis 'b1 (point-at v1 v2))) ‘(b1) (combine pict2 (basis ‘b2 (point-at v3 v4))) ‘(b2)) Could be replaced with: (combine pict1 (transform pict2 (my-point-at v1 v2 v3 v4))) I tried doing that with my game, and nothing weird happened, but am I missing something?
And if it does work like that, then would it make sense for you to extend point-at so that when it takes 4 arguments it does this? Or should it be a separate function? Or, would it make sense to provide a function like this? (define (from-to t1 t2) ; It would probably need a better name, but I think it could be very useful and intuitive (affine-compose t2 (affine-inverse t1))) So then my-point-at could be defined as (define (my-point-at v1 v2 v3 v4) (from-to (point-at v1 v2) (point-at v3 v4))) And instances of (pin (combine pict1 (basis ‘b1 t1)) ‘(b1) (combine pict2 (basis ‘b2 t2)) ‘(b2)) could be replaced with (combine pict1 (transform pict2 (from-to t2 t1))) Would that make sense? On Mar 16, 2015, at 7:12 AM, Neil Toronto <neil.toro...@gmail.com> wrote: > It should work fine for what you want to do with it. (It's exactly what I > thought of when I read your spec for it.) The only possible thing that can go > wrong with affine transformations is unwanted shear [1], and `point-at` never > produces a transformation that shears. Aside from the z-axis stretch, it's > all rigid. > > If you want to control *rotation* around the v1-v2 and v3-v4 axes, you'll > need to add a couple of arguments corresponding to the #:up and #:angle > arguments of `point-at`. I don't know how you'd pass those along to the two > `point-at` calls or how they'd interact. That doesn't mean something > reasonable is impossible, though. > > To understand `point-at` better, run the following program and play with the > #:up and #:angle arguments. Most of the code retesselates the vertices of an > octahedron to try to get a uniform distribution of directions. The important > stuff is at the end. > > > #lang racket > > (require pict3d) > > (define (retesselate dvs) > (match-define (list dv0 dv1 dv2) dvs) > (define dv01 (dir-normalize (dir-scale (dir+ dv0 dv1) 0.5))) > (define dv12 (dir-normalize (dir-scale (dir+ dv1 dv2) 0.5))) > (define dv20 (dir-normalize (dir-scale (dir+ dv2 dv0) 0.5))) > (list (list dv0 dv01 dv20) > (list dv1 dv12 dv01) > (list dv2 dv20 dv12) > (list dv01 dv12 dv20))) > > (define octahedron-dirs > (list (list +x +y +z) > (list +y -x +z) > (list -x -y +z) > (list -y +x +z) > (list +y +x -z) > (list -x +y -z) > (list -y -x -z) > (list +x -y -z))) > > (define dvs > (remove-duplicates > (append* > (for/fold ([dvss octahedron-dirs]) ([_ (in-range 3)]) > (append* (map retesselate dvss)))))) > > (combine > (for/list ([dv (in-list dvs)]) > (basis 'camera (point-at (pos+ origin dv 2) origin > #:up +z #:angle 0)))) > > > With the default #:up +z, there's a singularity at +z and another at -z, > where `point-at` isn't smooth. (Generally, with #:angle 0, the red x axes > point to their counterclockwise neighbors. At a pole, the only > counterclockwise neighbor is the pole itself.) Using #:up +x, the > singularities are at +x and -x. There's nothing we can do about this: we're > looking straight down the barrel of the Hairy Ball Theorem [2]. The > `point-at` function must have at least one cowlick. > > All this complexity comes from trying to make a rigid transformation that's > in some way reasonable when specified using only 5 degrees of freedom: a > position and a normalized direction. The result is mostly intuitive, and > works well enough. > > Neil ⊥ > > [1] http://en.wikipedia.org/wiki/Shear_mapping > [2] http://en.wikipedia.org/wiki/Hairy_ball_theorem > > On 03/15/2015 07:38 PM, Alexander D. Knauth wrote: >> Does the attached file look like a good implementation of my-point-at, or >> would it do things I wouldn’t expect for things not on the line between the >> two points, or ? I’m asking because I don’t think I completely understand >> point-at and what it does. >> >> >> >> >> On Mar 15, 2015, at 6:29 PM, Alexander D. Knauth <alexan...@knauth.org> >> wrote: >> >>> Thanks! >>> >>> Actually, now that I think about it something like this would be really >>> helpful, and probably make more sense: >>> Maybe a version of point-at that would let you specify which pos’s should >>> match up where? >>> >>> (my-point-at v1 v2 v3 v4 #:normalize? #f) ; maps v1 to v3 and v2 to v4 >>> (my-point-at (pos 0 0 0) (pos 1 0 0) v1 v2 #:normalize? #f) ; maps the >>> origin to v1, and (pos 1 0 0) to v2. >>> (my-point-at (pos 0 0 0) (pos 0 0 1) v1 v2) ; equivalent to (point-at v1 >>> v2) >>> (my-point-at v1 dv1 v2 dv2) ; equivalent to (my-point-at v1 (pos+ v1 dv1) >>> v2 (pos+ v2 dv2)) >>> >>> On Mar 15, 2015, at 5:58 PM, Neil Toronto <neil.toro...@gmail.com> wrote: >>> >>>> I'd generate a few different kinds of segments and then transform them >>>> into place. Don't use `rotate` for that, though - there's an easier way. >>>> >>>> Transforming a shape is pretty fast. Here's an insane example, using many >>>> more segments for a cylinder than you'd normally ever need: >>>> >>>> >>>> #lang racket >>>> >>>> (require pict3d) >>>> >>>> (define v1 (pos 1 1 1)) >>>> (define v2 (pos 2 3 2)) >>>> (define cyl >>>> (time >>>> (with-color (rgba "lightblue") >>>> ;; WOO 65536 TRIANGLES YEAH >>>> (move-z (cylinder origin (dir 1/4 1/4 1/2) #:segments 16384) >>>> 1/2)))) >>>> >>>> (define pict >>>> (time >>>> (combine (sphere v1 0.2) >>>> (sphere v2 0.2) >>>> (transform cyl (point-at v1 v2 #:normalize? #f))))) >>>> >>>> (time (pict3d->bitmap pict)) >>>> (time (pict3d->bitmap pict)) >>>> >>>> >>>> On my computer, creating `cyl` takes 5 seconds. Transforming it takes no >>>> measurable time. Rendering it the first time takes 1.5 seconds, and >>>> rendering it the second time takes 11 milliseconds. (Cylinders are frozen, >>>> so they'll always render faster the second time.) >>>> >>>> To stretch the cylinder between two points, the program >>>> >>>> 1. Creates the cylinder so that its bottom is at the origin and its >>>> top is at (pos 0 0 1). >>>> >>>> 2. Uses `point-at` without normalization to move the origin to `v1` and >>>> move (pos 0 0 1) to `v2`. >>>> >>>> Based on this and your other feedback, I think Pict3D needs >>>> >>>> * A `rotate-around` function that rotates a shape around a given point >>>> (with the default being the center of its bounding box). >>>> >>>> * A note in the docs for `rotate` et al that explain they rotate around >>>> the origin. >>>> >>>> * A "How Do I" section that includes things like the above example. >>>> >>>> * Notes in the docs about performance characteristics of different >>>> functions (e.g. that `cylinder` and `cone` return frozen Pict3Ds, and >>>> what that means you can expect from them). >>>> >>>> I expect performance characteristics to change, though, so that last one >>>> might be late coming. >>>> >>>> Neil ⊥ >>>> >>> >>> >>> ____________________ >>> Racket Users list: >>> http://lists.racket-lang.org/users >> > ____________________ Racket Users list: http://lists.racket-lang.org/users