discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

matrix interpolation

JB
Jordan Brown
Thu, Sep 21, 2017 5:00 PM

[ Mostly this is just me nattering about some stuff I was playing with,
with a minor wish list item tossed in.  I'd be interested in any hints
on how to do this better; I recognize that this is stuff that some of
you probably do in your sleep. ]

I started to play with animation, and it seemed like one of the key
things that would be useful would be to conveniently interpolate between
two (or N) positions or rotations.  That is, I'd like to say:

When $t is 0, the position is [x1,y1,z1].
When $t is 0.5, the position is [x2,y2,z2].
When $t is 1.0, the position is [x3,y3,z3].
... with interpolation for points between.

Hey, lookup( ) does interpolation like that:

t1 = [
    [ 0, 1 ],
    [ 1, 2 ]
];

echo(lookup(0.5, t1));

ECHO: 1.5

Interpolation is just addition, subtraction and multiplication, and
OpenSCAD knows how to do subtraction and multiplication on matrices, right?

p1 = [0,0,0];
p2 = [1,2,3];
p15 = p1 + (p2-p1)*0.5;
echo(p15);

ECHO: [0.5, 1, 1.5]

So lookup( ) should be able to do similar interpolation, right?

t2 = [
    [ 0, [0,0,0] ],
    [ 1, [1,2,3] ]
];

echo(lookup(0.5, t2));

ECHO: undef

:-(

Very minor wish list:  make lookup do this.

I did put together a function that rearranges such a table into three
tables and then uses lookup:

function xyzinterp(v, table) =
    let (x = [for (i = [ 0:len(table)-1 ]) [ table[i][0], table[i][1][0]] ])
    let (y = [for (i = [ 0:len(table)-1 ]) [ table[i][0], table[i][1][1]] ])
    let (z = [for (i = [ 0:len(table)-1 ]) [ table[i][0], table[i][1][2]] ])
        [ lookup(v, x), lookup(v, y), lookup(v,z) ];

(extrapolation to arbitrary dimensionality left as an exercise for the
reader) and using that I built a couple of modules:

module atranslate(table) {
    translate(xyzinterp($t, table)) children();
}

module arotate(table) {
    rotate(xyzinterp($t, table)) children();
}

so that you can give a table of positions/rotations and it'll animate them.

Since animations are loops, it seems likely that a common case would be
to start at one position, move to another position at $t=0.5, and then
return to the original position:

module a2translate(p1, p2) {
    atranslate([[0.05, p1], [0.45, p2], [0.55, p2], [0.95, p1]]) children();
}
module a2rotate(p1, p2) {
    arotate([[0.05, p1], [0.45, p2], [0.55, p2], [0.95, p1]]) children();
}

and using them I took one of my models and combined the "render
assembled" and "render for printing" sequences into one animation
sequence that moved the parts back and forth between the two layouts.

And that's what I've been doing this morning instead of real work :-)

[ Mostly this is just me nattering about some stuff I was playing with, with a minor wish list item tossed in.  I'd be interested in any hints on how to do this better; I recognize that this is stuff that some of you probably do in your sleep. ] I started to play with animation, and it seemed like one of the key things that would be useful would be to conveniently interpolate between two (or N) positions or rotations.  That is, I'd like to say: When $t is 0, the position is [x1,y1,z1]. When $t is 0.5, the position is [x2,y2,z2]. When $t is 1.0, the position is [x3,y3,z3]. ... with interpolation for points between. Hey, lookup( ) does interpolation like that: t1 = [     [ 0, 1 ],     [ 1, 2 ] ]; echo(lookup(0.5, t1)); ECHO: 1.5 Interpolation is just addition, subtraction and multiplication, and OpenSCAD knows how to do subtraction and multiplication on matrices, right? p1 = [0,0,0]; p2 = [1,2,3]; p15 = p1 + (p2-p1)*0.5; echo(p15); ECHO: [0.5, 1, 1.5] So lookup( ) should be able to do similar interpolation, right? t2 = [ [ 0, [0,0,0] ], [ 1, [1,2,3] ] ]; echo(lookup(0.5, t2)); ECHO: undef :-( Very minor wish list:  make lookup do this. I did put together a function that rearranges such a table into three tables and then uses lookup: function xyzinterp(v, table) = let (x = [for (i = [ 0:len(table)-1 ]) [ table[i][0], table[i][1][0]] ]) let (y = [for (i = [ 0:len(table)-1 ]) [ table[i][0], table[i][1][1]] ]) let (z = [for (i = [ 0:len(table)-1 ]) [ table[i][0], table[i][1][2]] ]) [ lookup(v, x), lookup(v, y), lookup(v,z) ]; (extrapolation to arbitrary dimensionality left as an exercise for the reader) and using that I built a couple of modules: module atranslate(table) { translate(xyzinterp($t, table)) children(); } module arotate(table) { rotate(xyzinterp($t, table)) children(); } so that you can give a table of positions/rotations and it'll animate them. Since animations are loops, it seems likely that a common case would be to start at one position, move to another position at $t=0.5, and then return to the original position: module a2translate(p1, p2) { atranslate([[0.05, p1], [0.45, p2], [0.55, p2], [0.95, p1]]) children(); } module a2rotate(p1, p2) { arotate([[0.05, p1], [0.45, p2], [0.55, p2], [0.95, p1]]) children(); } and using them I took one of my models and combined the "render assembled" and "render for printing" sequences into one animation sequence that moved the parts back and forth between the two layouts. And that's what I've been doing this morning instead of real work :-)