Hi Karsten,

Thank you for taking the time to walk me through some of the goodies that 
await me in thi.ng !

I do agree that matrix multiplications are the way to go for efficiently 
applying a bunch of geometric transformations on a number of points.
Actually, I intended to do it when the nb of transforms n more points that 
would be displayed i.e. when going 3D. I assumed that for 2D lines, the svg 
display would dwarf the transformations computation (aside : any way to 
assess this assumption ? I know nothing of profiling Clojurescript in a 
browser).

I also look forward to use your mix function to compute animations for 2d 
polygon games (a reimplementation of a game engine à la 
[[https://en.wikipedia.org/wiki/Another_World_%2528video_game%2529][Another 
World]] ).

However, for the task at hand, I want to decompose the transforms just the 
way I composed them to make apparent the composition itself. This is for a 
class when I want to teach programming as composing (a sort of intro to the 
spirit of functional programming, even if in Python because of the 
curriculum). The kind of result I wanted to achieve can be seen in 
https://scientific-coder.github.io/fractals/resources/public/fractals.html 
(I took model on your 
https://github.com/thi-ng/demos/blob/master/geom/src/physics_demos/strands.cljs,
 
hoping you would not mind).

In order to do that in a generic way (i.e. working on any kind of 
transformations composition), I have to work on the "AST" of the composite 
transformations, and walk it to adjust the parameters according to the step 
(I could/should also walk the "AST" to "compile it to matrix multiplication.
The thing is that I already have the "AST" as the composition of partial 
applications of the functions ( e.g. 
https://github.com/scientific-coder/fractals/blob/master/src/animations_2d/fractals.cljs#L128
 
) and I can easily walk (e.g. with multimethods 
https://github.com/scientific-coder/fractals/blob/master/src/animations_2d/fractals.cljs#L150
 
) if it  exposes the data the it has to hold anyway. The cleanest way might 
be to use a "real" DSL (like you do with your L-system interpreter in 
https://gist.github.com/postspectacular/47d62cc0386452fe3f9f0465c1fb1b73#file-lsys-clj
 
), but I think that better extensibility/interoperability would have been 
achieved with a standard access to partial, comp, juxt & al. attributes. 
Even python, not really the weapon of choice for functional programming, 
gives access to the bound arguments of partial ( 
https://docs.python.org/3/library/functools.html#partial-objects ).

Anyway, thanks again for the amazing thi.ng libraries, I'm having great fun 
with it, and intend to use them a lot .(Now, if only I found a way to have 
clojurescript code create/update svg / Webgl in my 
[[https://github.com/yjwen/org-reveal][org-reveal]] slides… )

I look forward to hooking students to generative programming thanks to you 
☺!

Best Regards,

bernard


On Tuesday, June 28, 2016 at 4:09:07 PM UTC+2, Karsten Schmidt wrote:
>
> 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 <un.compte....@gmail.com <javascript:>> 
> 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 clo...@googlegroups.com 
> <javascript:> 
> > Note that posts from new members are moderated - please be patient with 
> your 
> > first post. 
> > To unsubscribe from this group, send email to 
> > clojure+u...@googlegroups.com <javascript:> 
> > 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 clojure+u...@googlegroups.com <javascript:>. 
> > 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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
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 clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to