Jeff Epler's blog2022-11-07T01:35:00ZPhotos, electronics, cnc, and moreJeff Eplerjepler@unpythonic.netLocal coordinate systems in OpenSCAD2022-11-07T01:35:00Z2022-11-07T01:35:00Zhttps://emergent.unpythonic.net/01667784900
<img src="https://media.unpythonic.net/emergent-files/01667784900/pxy-medium.jpg">
<p>Here's a small snippet for setting a local coordinate system. You need to know
the location to treat as origin as well as the direction vectors to treat
as X and Y.
<p><pre>
// Take a position vector (p) and 3 direction vectors (uvw)
// and create a transformation matrix. The origin is transformed to p,
// and xyz point along uvw.
// Normally, the caller will ensure that uvw are orthogonal unit vectors
function puvw(p, u, v, w) = [
[u[0], v[0], w[0], p[0]],
[u[1], v[1], w[1], p[1]],
[u[2], v[2], w[2], p[2]]];
// Take a position vector (p) and 2 direction vectors (uv) which should be
// orthogonal but need not be unit vectors. Calculate the unit vectors as well
// as the third vector and return the resulting matrix
function puv(p, u, v) =
let(nu = u / norm(u), nv = v / norm(v), nw = cross(nu, nv))
puvw(p, nu, nv, nw);
// Operate in a local coordinate system where the origin is the point p,
// x points along u, y points along v, and z points along the normal vector
// to uv. x and y should be orthogonal but need not be unit vectors.
module puv(p, u, v) {
multmatrix(puv(p, u, v)) children();
}
</pre>
<p>For instance, suppose you want to lay out some feature relative to a cone 100mm
in diameter and 500mm tall. It's convenient to set the origin to the
intersection of the cone base with the +x axis, +x be the direction from the
base of the cone to the tip, +y be the direction tangential to the cone, and +z
be the direction 'out' from the cone. You might invoke puv like so (corr is a factor to make the flats of the faceted cone exactly touch the 100mm diameter circle):
<pre>
effen = 16; // 16, 32, 64, ...
corr = 1 / cos(180/effen);
for(i=[0:45:360]) rotate(i)
puv([100,0,0], [-100, 0, 500], [0, -1, 0])
linear_extrude(height=1)
square([25, 4], center=true);
%rotate(45/4) cylinder(d1=200*corr, d2=0, h=500, $fn=effen);
</pre>