mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
libgeometry: simplify rframes
i got rid of redundant code, and added routines to get the xform matrix out of an rframe, so it can be stored and used separately or as part of a composition of xforms. also replaced the big example in the man page for more concise, useful ones.
This commit is contained in:
parent
33572bd895
commit
9bbbc13ce2
3 changed files with 99 additions and 207 deletions
|
@ -124,6 +124,8 @@ Quaternion slerp(Quaternion, Quaternion, double);
|
||||||
Point3 qrotate(Point3, Point3, double);
|
Point3 qrotate(Point3, Point3, double);
|
||||||
|
|
||||||
/* RFrame */
|
/* RFrame */
|
||||||
|
void rframematrix(Matrix, RFrame);
|
||||||
|
void rframematrix3(Matrix3, RFrame3);
|
||||||
Point2 rframexform(Point2, RFrame);
|
Point2 rframexform(Point2, RFrame);
|
||||||
Point3 rframexform3(Point3, RFrame3);
|
Point3 rframexform3(Point3, RFrame3);
|
||||||
Point2 invrframexform(Point2, RFrame);
|
Point2 invrframexform(Point2, RFrame);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.TH GEOMETRY 2
|
.TH GEOMETRY 2
|
||||||
.SH NAME
|
.SH NAME
|
||||||
Flerp, fberp, fclamp, Pt2, Vec2, addpt2, subpt2, mulpt2, divpt2, lerp2, berp2, dotvec2, vec2len, normvec2, edgeptcmp, ptinpoly, Pt3, Vec3, addpt3, subpt3, mulpt3, divpt3, lerp3, berp3, dotvec3, crossvec3, vec3len, normvec3, identity, addm, subm, mulm, smulm, transposem, detm, tracem, minorm, cofactorm, adjm, invm, xform, identity3, addm3, subm3, mulm3, smulm3, transposem3, detm3, tracem3, minorm3, cofactorm3, adjm3, invm3, xform3, Quat, Quatvec, addq, subq, mulq, smulq, sdivq, dotq, invq, qlen, normq, slerp, qrotate, rframexform, rframexform3, invrframexform, invrframexform3, centroid, barycoords, centroid3, vfmt, Vfmt, GEOMfmtinstall \- computational geometry library
|
Flerp, fberp, fclamp, Pt2, Vec2, addpt2, subpt2, mulpt2, divpt2, lerp2, berp2, dotvec2, vec2len, normvec2, edgeptcmp, ptinpoly, Pt3, Vec3, addpt3, subpt3, mulpt3, divpt3, lerp3, berp3, dotvec3, crossvec3, vec3len, normvec3, identity, addm, subm, mulm, smulm, transposem, detm, tracem, minorm, cofactorm, adjm, invm, xform, identity3, addm3, subm3, mulm3, smulm3, transposem3, detm3, tracem3, minorm3, cofactorm3, adjm3, invm3, xform3, Quat, Quatvec, addq, subq, mulq, smulq, sdivq, dotq, invq, qlen, normq, slerp, qrotate, rframematrix, rframematrix3, rframexform, rframexform3, invrframexform, invrframexform3, centroid, barycoords, centroid3, vfmt, Vfmt, GEOMfmtinstall \- computational geometry library
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.de PB
|
.de PB
|
||||||
.PP
|
.PP
|
||||||
|
@ -135,6 +135,8 @@ Quaternion slerp(Quaternion q, Quaternion r, double t);
|
||||||
Point3 qrotate(Point3 p, Point3 axis, double θ);
|
Point3 qrotate(Point3 p, Point3 axis, double θ);
|
||||||
.PB
|
.PB
|
||||||
/* RFrame */
|
/* RFrame */
|
||||||
|
void rframematrix(Matrix, RFrame);
|
||||||
|
void rframematrix3(Matrix3, RFrame3);
|
||||||
Point2 rframexform(Point2 p, RFrame rf);
|
Point2 rframexform(Point2 p, RFrame rf);
|
||||||
Point3 rframexform3(Point3 p, RFrame3 rf);
|
Point3 rframexform3(Point3 p, RFrame3 rf);
|
||||||
Point2 invrframexform(Point2 p, RFrame rf);
|
Point2 invrframexform(Point2 p, RFrame rf);
|
||||||
|
@ -615,7 +617,7 @@ by
|
||||||
.I θ
|
.I θ
|
||||||
radians.
|
radians.
|
||||||
.SS Frames of reference
|
.SS Frames of reference
|
||||||
A frame of reference in a
|
A frame of reference (or rframe) in a
|
||||||
.IR n -dimensional
|
.IR n -dimensional
|
||||||
space is made out of n+1 points, one being the origin
|
space is made out of n+1 points, one being the origin
|
||||||
.IR p ,
|
.IR p ,
|
||||||
|
@ -623,33 +625,33 @@ and the remaining being the
|
||||||
basis vectors
|
basis vectors
|
||||||
.I b1,⋯,bn
|
.I b1,⋯,bn
|
||||||
that define the metric within that frame.
|
that define the metric within that frame.
|
||||||
.PP
|
|
||||||
The origin point and the bases are all defined in terms of an origin
|
|
||||||
frame of reference O. Applying a forward transformation
|
|
||||||
.RI ( rframexform
|
|
||||||
and
|
|
||||||
.IR rframexform3 )
|
|
||||||
to a point relative to O will result in a point relative to the new frame.
|
|
||||||
Applying an inverse transformation
|
|
||||||
.RI ( invrframexform
|
|
||||||
and
|
|
||||||
.IR invrframexform3 )
|
|
||||||
to that same point—now defined in terms of the new frame—will bring it back to O.
|
|
||||||
.TP
|
.TP
|
||||||
Name
|
Name
|
||||||
Description
|
Description
|
||||||
.TP
|
.TP
|
||||||
|
.B rframematrix(\fIm\fP,\fIrf\fP)
|
||||||
|
Initializes
|
||||||
|
.I m
|
||||||
|
as an rframe transformation matrix based on
|
||||||
|
.IR rf .
|
||||||
|
.TP
|
||||||
|
.B rframematrix3(\fIm\fP,\fIrf\fP)
|
||||||
|
Initializes
|
||||||
|
.I m
|
||||||
|
as an rframe transformation matrix based on
|
||||||
|
.IR rf .
|
||||||
|
.TP
|
||||||
.B rframexform(\fIp\fP,\fIrf\fP)
|
.B rframexform(\fIp\fP,\fIrf\fP)
|
||||||
Transforms the point
|
Transforms the point
|
||||||
.IR p ,
|
.IR p ,
|
||||||
relative to some origin frame of reference O, into the frame of reference
|
relative to some origin frame of reference O, into the rframe
|
||||||
.IR rf .
|
.IR rf .
|
||||||
It then returns the new 2D point.
|
It then returns the new 2D point.
|
||||||
.TP
|
.TP
|
||||||
.B rframexform3(\fIp\fP,\fIrf\fP)
|
.B rframexform3(\fIp\fP,\fIrf\fP)
|
||||||
Transforms the point
|
Transforms the point
|
||||||
.IR p ,
|
.IR p ,
|
||||||
relative to some origin frame of reference O, into the frame of reference
|
relative to some origin frame of reference O, into the rframe
|
||||||
.IR rf .
|
.IR rf .
|
||||||
It then returns the new 3D point.
|
It then returns the new 3D point.
|
||||||
.TP
|
.TP
|
||||||
|
@ -658,7 +660,7 @@ Transforms the point
|
||||||
.IR p ,
|
.IR p ,
|
||||||
relative to
|
relative to
|
||||||
.IR rf ,
|
.IR rf ,
|
||||||
into a point relative to the origin frame of reference O.
|
into a point relative to the origin rframe O.
|
||||||
It then returns the new 2D point.
|
It then returns the new 2D point.
|
||||||
.TP
|
.TP
|
||||||
.B invrframexform3(\fIp\fP,\fIrf\fP)
|
.B invrframexform3(\fIp\fP,\fIrf\fP)
|
||||||
|
@ -666,7 +668,7 @@ Transforms the point
|
||||||
.IR p ,
|
.IR p ,
|
||||||
relative to
|
relative to
|
||||||
.IR rf ,
|
.IR rf ,
|
||||||
into a point relative to the origin frame of reference O.
|
into a point relative to the origin rframe O.
|
||||||
It then returns the new 3D point.
|
It then returns the new 3D point.
|
||||||
.SS Triangles
|
.SS Triangles
|
||||||
.TP
|
.TP
|
||||||
|
@ -689,7 +691,53 @@ relative to the triangle
|
||||||
Returns the geometric center of
|
Returns the geometric center of
|
||||||
.B Triangle3
|
.B Triangle3
|
||||||
.IR t .
|
.IR t .
|
||||||
.SH EXAMPLE
|
.SH EXAMPLES
|
||||||
|
.PP
|
||||||
|
Rotate a point p by θ, scale it 2x, then translate it by vector v:
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
Matrix R = {
|
||||||
|
cos(θ), -sin(θ), 0,
|
||||||
|
sin(θ), cos(θ), 0,
|
||||||
|
0, 0, 1,
|
||||||
|
}, S = {
|
||||||
|
2, 0, 0,
|
||||||
|
0, 2, 0,
|
||||||
|
0, 0, 1,
|
||||||
|
}, T = {
|
||||||
|
1, 0, v.x,
|
||||||
|
0, 1, v.y,
|
||||||
|
0, 0, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
mulm(S, R);
|
||||||
|
mulm(T, S);
|
||||||
|
p = xform(p, T); /* p' = T·S·R·p */
|
||||||
|
.EE
|
||||||
|
|
||||||
|
.PP
|
||||||
|
Given a space with two observers, A and B, and a point p relative to
|
||||||
|
A, find its location relative to B:
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
pb = rframexform(invrframexform(p, A), B);
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
Now let's say observer C is located relative to A; find the point's
|
||||||
|
location in C:
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
pc = rframexform(p, C);
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
Finally, to obtain its location relative to the space itself (its
|
||||||
|
global position):
|
||||||
|
.IP
|
||||||
|
.EX
|
||||||
|
pg = invrframexform(p, A);
|
||||||
|
.EE
|
||||||
|
|
||||||
|
.PP
|
||||||
The following is a common example of an
|
The following is a common example of an
|
||||||
.B RFrame
|
.B RFrame
|
||||||
being used to define the coordinate system of a
|
being used to define the coordinate system of a
|
||||||
|
@ -701,13 +749,8 @@ pointing upwards, to contrast with the window system where
|
||||||
.IR y -values
|
.IR y -values
|
||||||
grow downwards (see
|
grow downwards (see
|
||||||
.IR graphics (2)).
|
.IR graphics (2)).
|
||||||
.PP
|
.IP
|
||||||
.EX
|
.EX
|
||||||
#include <u.h>
|
|
||||||
#include <libc.h>
|
|
||||||
#include <draw.h>
|
|
||||||
#include <geometry.h>
|
|
||||||
|
|
||||||
RFrame worldrf;
|
RFrame worldrf;
|
||||||
|
|
||||||
/* from screen... */
|
/* from screen... */
|
||||||
|
@ -733,112 +776,6 @@ main(void)
|
||||||
worldrf.by = Vec2(0,-1);
|
worldrf.by = Vec2(0,-1);
|
||||||
⋯
|
⋯
|
||||||
.EE
|
.EE
|
||||||
.PP
|
|
||||||
The following snippet shows how to use the
|
|
||||||
.B RFrame
|
|
||||||
declared earlier to locate and draw a ship based on its orientation,
|
|
||||||
for which we use matrix translation
|
|
||||||
.B T
|
|
||||||
and rotation
|
|
||||||
.BR R
|
|
||||||
transformations.
|
|
||||||
.PP
|
|
||||||
.EX
|
|
||||||
⋯
|
|
||||||
typedef struct Ship Ship;
|
|
||||||
typedef struct Shipmdl Shipmdl;
|
|
||||||
|
|
||||||
struct Ship
|
|
||||||
{
|
|
||||||
RFrame;
|
|
||||||
double θ; /* orientation (yaw) */
|
|
||||||
Shipmdl mdl;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Shipmdl
|
|
||||||
{
|
|
||||||
Point2 pts[3]; /* a free-form triangle */
|
|
||||||
};
|
|
||||||
|
|
||||||
Ship *ship;
|
|
||||||
|
|
||||||
void
|
|
||||||
redraw(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Point pts[3+1];
|
|
||||||
Point2 *p;
|
|
||||||
Matrix T = {
|
|
||||||
1, 0, ship->p.x,
|
|
||||||
0, 1, ship->p.y,
|
|
||||||
0, 0, 1,
|
|
||||||
}, R = {
|
|
||||||
cos(ship->θ), -sin(ship->θ), 0,
|
|
||||||
sin(ship->θ), cos(ship->θ), 0,
|
|
||||||
0, 0, 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
mulm(T, R); /* rotate, then translate */
|
|
||||||
p = ship->mdl.pts;
|
|
||||||
for(i = 0; i < nelem(pts)-1; i++)
|
|
||||||
pts[i] = fromworld(xform(p[i], T));
|
|
||||||
pts[i] = pts[0];
|
|
||||||
draw(screen, screen->r, display->white, nil, ZP);
|
|
||||||
poly(screen, pts, nelem(pts), 0, 0, 0, display->black, ZP);
|
|
||||||
}
|
|
||||||
⋯
|
|
||||||
main(void)
|
|
||||||
⋯
|
|
||||||
ship = malloc(sizeof(Ship));
|
|
||||||
ship->p = Pt2(0,0,1); /* place it at the origin */
|
|
||||||
ship->θ = 45*DEG; /* counter-clockwise */
|
|
||||||
ship->mdl.pts[0] = Pt2( 10, 0,1);
|
|
||||||
ship->mdl.pts[1] = Pt2(-10, 5,1);
|
|
||||||
ship->mdl.pts[2] = Pt2(-10,-5,1);
|
|
||||||
⋯
|
|
||||||
redraw();
|
|
||||||
⋯
|
|
||||||
.EE
|
|
||||||
.PP
|
|
||||||
Notice how we could've used the
|
|
||||||
.B RFrame
|
|
||||||
embedded in the
|
|
||||||
.B ship
|
|
||||||
to transform the
|
|
||||||
.B Shipmdl
|
|
||||||
into the window. Instead of applying the matrices to every point, the
|
|
||||||
ship's local frame of reference can be rotated, effectively changing
|
|
||||||
the model coordinates after an
|
|
||||||
.IR invrframexform .
|
|
||||||
We are also getting rid of the
|
|
||||||
.B θ
|
|
||||||
variable, since it's no longer needed.
|
|
||||||
.PP
|
|
||||||
.EX
|
|
||||||
⋯
|
|
||||||
struct Ship
|
|
||||||
{
|
|
||||||
RFrame;
|
|
||||||
Shipmdl mdl;
|
|
||||||
};
|
|
||||||
⋯
|
|
||||||
redraw(void)
|
|
||||||
⋯
|
|
||||||
pts[i] = fromworld(invrframexform(p[i], *ship));
|
|
||||||
⋯
|
|
||||||
main(void)
|
|
||||||
⋯
|
|
||||||
Matrix R = {
|
|
||||||
cos(45*DEG), -sin(45*DEG), 0,
|
|
||||||
sin(45*DEG), cos(45*DEG), 0,
|
|
||||||
0, 0, 1,
|
|
||||||
};
|
|
||||||
⋯
|
|
||||||
//ship->θ = 45*DEG; /* counter-clockwise */
|
|
||||||
ship->bx = xform(ship->bx, R);
|
|
||||||
ship->by = xform(ship->by, R);
|
|
||||||
⋯
|
|
||||||
.EE
|
|
||||||
.SH SOURCE
|
.SH SOURCE
|
||||||
.B /sys/src/libgeometry
|
.B /sys/src/libgeometry
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
|
@ -857,6 +794,8 @@ Jonathan Blow,
|
||||||
The Inner Product, April 2004.
|
The Inner Product, April 2004.
|
||||||
.br
|
.br
|
||||||
https://www.3dgep.com/understanding-quaternions/
|
https://www.3dgep.com/understanding-quaternions/
|
||||||
|
.br
|
||||||
|
https://motion.cs.illinois.edu/RoboticSystems/CoordinateTransformations.html
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
No care is taken to avoid numeric overflows.
|
No care is taken to avoid numeric overflows.
|
||||||
.SH HISTORY
|
.SH HISTORY
|
||||||
|
|
|
@ -2,106 +2,57 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <geometry.h>
|
#include <geometry.h>
|
||||||
|
|
||||||
/*
|
void
|
||||||
* implicit identity origin rframes
|
rframematrix(Matrix m, RFrame rf)
|
||||||
*
|
|
||||||
* static RFrame IRF2 = {
|
|
||||||
* .p = {0,0,1},
|
|
||||||
* .bx = {1,0,0},
|
|
||||||
* .by = {0,1,0},
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* static RFrame3 IRF3 = {
|
|
||||||
* .p = {0,0,0,1},
|
|
||||||
* .bx = {1,0,0,0},
|
|
||||||
* .by = {0,1,0,0},
|
|
||||||
* .bz = {0,0,1,0},
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* these rframes are used on every xform to keep the points in the
|
|
||||||
* correct plane (i.e. with proper w values); they are written here as a
|
|
||||||
* reference for future changes. the bases are ignored since they turn
|
|
||||||
* into an unnecessary identity xform.
|
|
||||||
*
|
|
||||||
* the implicitness comes from the fact that using the _irf* filters
|
|
||||||
* makes the rframexform equivalent to:
|
|
||||||
* rframexform(invrframexform(p, IRF), rf);
|
|
||||||
* and the invrframexform to:
|
|
||||||
* rframexform(invrframexform(p, rf), IRF);
|
|
||||||
*/
|
|
||||||
|
|
||||||
static Point2
|
|
||||||
_irfxform(Point2 p)
|
|
||||||
{
|
{
|
||||||
p.w--;
|
m[0][0] = rf.bx.x; m[0][1] = rf.by.x; m[0][2] = rf.p.x;
|
||||||
return p;
|
m[1][0] = rf.bx.y; m[1][1] = rf.by.y; m[1][2] = rf.p.y;
|
||||||
|
m[2][0] = 0; m[2][1] = 0; m[2][2] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Point2
|
void
|
||||||
_irfxform⁻¹(Point2 p)
|
rframematrix3(Matrix3 m, RFrame3 rf)
|
||||||
{
|
{
|
||||||
p.w++;
|
m[0][0] = rf.bx.x; m[0][1] = rf.by.x; m[0][2] = rf.bz.x; m[0][3] = rf.p.x;
|
||||||
return p;
|
m[1][0] = rf.bx.y; m[1][1] = rf.by.y; m[1][2] = rf.bz.y; m[1][3] = rf.p.y;
|
||||||
}
|
m[2][0] = rf.bx.z; m[2][1] = rf.by.z; m[2][2] = rf.bz.z; m[2][3] = rf.p.z;
|
||||||
|
m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
|
||||||
static Point3
|
|
||||||
_irfxform3(Point3 p)
|
|
||||||
{
|
|
||||||
p.w--;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Point3
|
|
||||||
_irfxform3⁻¹(Point3 p)
|
|
||||||
{
|
|
||||||
p.w++;
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Point2
|
Point2
|
||||||
rframexform(Point2 p, RFrame rf)
|
rframexform(Point2 p, RFrame rf)
|
||||||
{
|
{
|
||||||
Matrix m = {
|
Matrix m;
|
||||||
rf.bx.x, rf.by.x, 0,
|
|
||||||
rf.bx.y, rf.by.y, 0,
|
rframematrix(m, rf);
|
||||||
0, 0, 1,
|
|
||||||
};
|
|
||||||
invm(m);
|
invm(m);
|
||||||
return xform(subpt2(_irfxform⁻¹(p), rf.p), m);
|
return xform(p, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point3
|
Point3
|
||||||
rframexform3(Point3 p, RFrame3 rf)
|
rframexform3(Point3 p, RFrame3 rf)
|
||||||
{
|
{
|
||||||
Matrix3 m = {
|
Matrix3 m;
|
||||||
rf.bx.x, rf.by.x, rf.bz.x, 0,
|
|
||||||
rf.bx.y, rf.by.y, rf.bz.y, 0,
|
rframematrix3(m, rf);
|
||||||
rf.bx.z, rf.by.z, rf.bz.z, 0,
|
|
||||||
0, 0, 0, 1,
|
|
||||||
};
|
|
||||||
invm3(m);
|
invm3(m);
|
||||||
return xform3(subpt3(_irfxform3⁻¹(p), rf.p), m);
|
return xform3(p, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point2
|
Point2
|
||||||
invrframexform(Point2 p, RFrame rf)
|
invrframexform(Point2 p, RFrame rf)
|
||||||
{
|
{
|
||||||
Matrix m = {
|
Matrix m;
|
||||||
rf.bx.x, rf.by.x, 0,
|
|
||||||
rf.bx.y, rf.by.y, 0,
|
rframematrix(m, rf);
|
||||||
0, 0, 1,
|
return xform(p, m);
|
||||||
};
|
|
||||||
return _irfxform(addpt2(xform(p, m), rf.p));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Point3
|
Point3
|
||||||
invrframexform3(Point3 p, RFrame3 rf)
|
invrframexform3(Point3 p, RFrame3 rf)
|
||||||
{
|
{
|
||||||
Matrix3 m = {
|
Matrix3 m;
|
||||||
rf.bx.x, rf.by.x, rf.bz.x, 0,
|
|
||||||
rf.bx.y, rf.by.y, rf.bz.y, 0,
|
rframematrix3(m, rf);
|
||||||
rf.bx.z, rf.by.z, rf.bz.z, 0,
|
return xform3(p, m);
|
||||||
0, 0, 0, 1,
|
|
||||||
};
|
|
||||||
return _irfxform3(addpt3(xform3(p, m), rf.p));
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue