code: plan9front

Download patch

ref: 9bbbc13ce25dab109f640f469d1a633ae5024932
parent: 33572bd895dcb450302d36b48f92e136b6838d35
author: rodri <rgl@antares-labs.eu>
date: Thu May 30 17:11:33 EDT 2024

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.

--- a/sys/include/geometry.h
+++ b/sys/include/geometry.h
@@ -124,6 +124,8 @@
 Point3 qrotate(Point3, Point3, double);
 
 /* RFrame */
+void rframematrix(Matrix, RFrame);
+void rframematrix3(Matrix3, RFrame3);
 Point2 rframexform(Point2, RFrame);
 Point3 rframexform3(Point3, RFrame3);
 Point2 invrframexform(Point2, RFrame);
--- a/sys/man/2/geometry
+++ b/sys/man/2/geometry
@@ -1,6 +1,6 @@
 .TH GEOMETRY 2
 .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
 .de PB
 .PP
@@ -135,6 +135,8 @@
 Point3 qrotate(Point3 p, Point3 axis, double θ);
 .PB
 /* RFrame */
+void rframematrix(Matrix, RFrame);
+void rframematrix3(Matrix3, RFrame3);
 Point2 rframexform(Point2 p, RFrame rf);
 Point3 rframexform3(Point3 p, RFrame3 rf);
 Point2 invrframexform(Point2 p, RFrame rf);
@@ -615,7 +617,7 @@
 .I θ
 radians.
 .SS Frames of reference
-A frame of reference in a
+A frame of reference (or rframe) in a
 .IR n -dimensional
 space is made out of n+1 points, one being the origin
 .IR p ,
@@ -623,26 +625,26 @@
 basis vectors
 .I b1,⋯,bn
 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
 Name
 Description
 .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)
 Transforms the point
 .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 .
 It then returns the new 2D point.
 .TP
@@ -649,7 +651,7 @@
 .B rframexform3(\fIp\fP,\fIrf\fP)
 Transforms the point
 .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 .
 It then returns the new 3D point.
 .TP
@@ -658,7 +660,7 @@
 .IR p ,
 relative to
 .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.
 .TP
 .B invrframexform3(\fIp\fP,\fIrf\fP)
@@ -666,7 +668,7 @@
 .IR p ,
 relative to
 .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.
 .SS Triangles
 .TP
@@ -689,7 +691,53 @@
 Returns the geometric center of
 .B Triangle3
 .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
 .B RFrame
 being used to define the coordinate system of a
@@ -701,13 +749,8 @@
 .IR y -values
 grow downwards (see
 .IR graphics (2)).
-.PP
+.IP
 .EX
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <geometry.h>
-
 RFrame worldrf;
 
 /* from screen... */
@@ -733,112 +776,6 @@
 	worldrf.by = Vec2(0,-1);
 .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
 .B /sys/src/libgeometry
 .SH SEE ALSO
@@ -857,6 +794,8 @@
 The Inner Product, April 2004.
 .br
 https://www.3dgep.com/understanding-quaternions/
+.br
+https://motion.cs.illinois.edu/RoboticSystems/CoordinateTransformations.html
 .SH BUGS
 No care is taken to avoid numeric overflows.
 .SH HISTORY
--- a/sys/src/libgeometry/rframe.c
+++ b/sys/src/libgeometry/rframe.c
@@ -2,106 +2,57 @@
 #include <libc.h>
 #include <geometry.h>
 
-/*
- * implicit identity origin rframes
- *
- * 	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)
+void
+rframematrix(Matrix m, RFrame rf)
 {
-	p.w--;
-	return p;
+	m[0][0] = rf.bx.x; m[0][1] = rf.by.x; m[0][2] = rf.p.x;
+	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
-_irfxform⁻¹(Point2 p)
+void
+rframematrix3(Matrix3 m, RFrame3 rf)
 {
-	p.w++;
-	return p;
+	m[0][0] = rf.bx.x; m[0][1] = rf.by.x; m[0][2] = rf.bz.x; m[0][3] = rf.p.x;
+	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
 rframexform(Point2 p, RFrame rf)
 {
-	Matrix m = {
-		rf.bx.x, rf.by.x, 0,
-		rf.bx.y, rf.by.y, 0,
-		0, 0, 1,
-	};
+	Matrix m;
+
+	rframematrix(m, rf);
 	invm(m);
-	return xform(subpt2(_irfxform⁻¹(p), rf.p), m);
+	return xform(p, m);
 }
 
 Point3
 rframexform3(Point3 p, RFrame3 rf)
 {
-	Matrix3 m = {
-		rf.bx.x, rf.by.x, rf.bz.x, 0,
-		rf.bx.y, rf.by.y, rf.bz.y, 0,
-		rf.bx.z, rf.by.z, rf.bz.z, 0,
-		0, 0, 0, 1,
-	};
+	Matrix3 m;
+
+	rframematrix3(m, rf);
 	invm3(m);
-	return xform3(subpt3(_irfxform3⁻¹(p), rf.p), m);
+	return xform3(p, m);
 }
 
 Point2
 invrframexform(Point2 p, RFrame rf)
 {
-	Matrix m = {
-		rf.bx.x, rf.by.x, 0,
-		rf.bx.y, rf.by.y, 0,
-		0, 0, 1,
-	};
-	return _irfxform(addpt2(xform(p, m), rf.p));
+	Matrix m;
+
+	rframematrix(m, rf);
+	return xform(p, m);
 }
 
 Point3
 invrframexform3(Point3 p, RFrame3 rf)
 {
-	Matrix3 m = {
-		rf.bx.x, rf.by.x, rf.bz.x, 0,
-		rf.bx.y, rf.by.y, rf.bz.y, 0,
-		rf.bx.z, rf.by.z, rf.bz.z, 0,
-		0, 0, 0, 1,
-	};
-	return _irfxform3(addpt3(xform3(p, m), rf.p));
+	Matrix3 m;
+
+	rframematrix3(m, rf);
+	return xform3(p, m);
 }