Hi Bernard,

firstly, thanks for the kind words! I think you're overcomplicating
your problem and the extreme use of comp & partial would not help
making things run v.smoothly (obviously depending on number of
generated points / line segments). Instead I think you should look
into matrix based transformations, which, once constructed, have an
O(1) cost, no matter how complex the transformation. E.g. With
http://thi.ng/geom you can create a matrix, encoding a combined
translation, rotation and scale op like this:

;; assumes [thi.ng/geom "0.0.1173-SNAPSHOT"]
(require
  '[thi.ng.geom.core :as g]
  '[thi.ng.geom.matrix :as mat]
  '[thi.ng.math.core :as m])

;; for 2D: M32 is a 3x2 identity matrix
(def tx (-> mat/M32 (g/translate [10 20]) (g/rotate Math/PI) (g/scale 10)))

;; for 3D: M44 is 4x4 identity matrix
(def tx (-> mat/M44 (g/translate [10 20 30]) (g/rotate-x m/HALF_PI)
(g/scale 10)))

Then to transform a point:
(g/transform-vector tx [x y z])

To reverse the transformation, simply apply the matrix inverse to a
transformed point:
(g/transform-vector (m/invert tx) [x' y' z'])

This approach also makes it trivial to create animations, simply keep
a reference to the untransformed elements, then compute a matrix for
each animation frame, transform & visualize them...

If you just want to tween between a two sets of elements (e.g. the
original and transformed elements), you can use the `mix` protocol
function defined for all vector types (2D/3D) in thi.ng/geom:

(require '[thi.ng.geom.vector :as v])

(defn tween-points
  [src dest t] (map (fn [a b] (m/mix a b t)) src dest))

(tween-points [(v/vec2 0 0) (v/vec2 100 50)] [(v/vec2 100 200) (v/vec2
200 100)] 0.5)
;; ([50.0 100.0] [150.0 75.0])

Hth! K.

On 28 June 2016 at 11:17, bernardH <[email protected]> wrote:
>
> Hi,
>
> Inspired by Karsten Schmidt's amazing work[0], I'm thinking about porting
> some generative
> code from python to Clojure[script].
>
> However, I would like to use the (expected) performance boost (from python
> turtle module) to add some animation effects. I believe my current code is
> quite clean
> and would like to avoid the second-system effect [1]
>
> I currently have some very generic fractal generators taking some geometric
> transforms as arguments.
> Those geometric transforms are composition of curryfied primitive operations
> (rotate, add, zoom), as in
> (def transfo (compose (partial rotate pi) (partial add [0. 1.]) (partial
> zoom (/ 1 3))))
>
> My wish would be to be able to compute smooth animations by "scaling"
> smoothly
> the composite transformations between identity (no transformation) and the
> full
> (original) transformation (if fact I would also use the opposite transforms,
> the
> one that would compose to identity). I would do so by scaling all the
> parameters involved
> with a scaling factor in [0 …1] ([0…-1] for opposite transforms) either by
> multiplication (for "additive" transformations like rotate and add) or by
> exponentiation (for "multiplicative" transformations like zoom).
>
> "Half" of the above "transfo" would thus be :
> (def transfo_half (comp (partial rotate (deep_multiply 0.5 pi)) (partial add
> (deep_multiply 0.5 [0. 1.])) (partial zoom (Math.pow (/ 1 3) 0.5))))
>
> with
>
> (defn deep_f [f x] (if (seq? x) (map deep_f x) (f x)))
>
> (defn deep_multiply [k x] (deep_f (partial * k) x))
>
> to unify meutiplication because for additive functions, some params are
> vectors (for add) while others are scalars (for rotate).
>
> and the opposite of the original full transformation would be :
> (def transfo_inv (comp (partial rotate (deep_multiply -1 pi)) (partial add
> (deep_multiply -1 [0. 1.])) (partial zoom (Math.pow (/ 1 3) -1))))
>
>
> The ideal solution for me would be to be able to write a "scale" function so
> that :
>
> (def transfo_half (scale 0.5 transfo))
> (def transfo_inv (scale -1 transfo))
>
> The scale function could look like
>
> (def scale [k f]
>   (condp is f
>    comp (apply comp (map (partial scale k) (args f)))
>    partial (let[ [ fun bound] (args f)] (if (or (is f add) (is f rotate))
> (partial f (deep_multiply k bound )) (if (is f zoom) (partial f (Math.pow
> bound k)) f)))
>    f)
> )
>
>  But that would require some help from the values returned by comp and
> partial :
> - the ability to identify them as such (above with an "is" function)
> - the ability to access the bound values passed to them as arguments (above
> with an "args" function)
>
> Of course, I would have to shadow clojure.core/comp and clojure.core/partial
> to
> add those functionalities. I suppose I would have to create records and
> protocols. However, I find this a bit cumbersome and thought that there
> might be
> a simpler way to achieve my goal of keeping the transformation generation
> separate from the animation code that must scale those functions.
> Piggiebacking metadata might be easier if more hackish.
>
> Best would be to be able to write a higher order function (or macro) like:
>
> (def comp (with-is-args comp))
> (def partial (with-is-args partial))
>
> Maybe using metadata on the elementary transformation functions (rotate,
> add,
> zoom) to indicate that comp and partial should have specific results so that
> the generic case would not be changed.
>
> But that is getting over my clojure-foo ☹.
> How would you go about it ? I have a hard time to believe I'd be the first
> to want to modify composed and curryfied functions.
>
> Any piece of advice would be greatly appreciated !
>
> Best Regards,
>
> b.
>
> [0]
> https://medium.com/@thi.ng/workshop-report-generative-design-with-clojure-7d6d8ea9a6e8#.w6te331y0
> [1] https://en.wikipedia.org/wiki/Second-system_effect .
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to [email protected]
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> [email protected]
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/d/optout.



-- 
Karsten Schmidt
http://postspectacular.com | http://thi.ng | http://toxiclibs.org

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to