summaryrefslogtreecommitdiffstats
path: root/libdimension
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-06-13 22:55:15 +0000
committerTavian Barnes <tavianator@gmail.com>2009-06-13 22:55:15 +0000
commit9b85799fb274f291d4fefd9de08c069fe11d46f1 (patch)
treee6705d98f1a22f47bef46e2bac336a46e07c22ac /libdimension
parent5c8f366a3b5d7303bf73bd6d5d0af0459bac72a2 (diff)
downloaddimension-9b85799fb274f291d4fefd9de08c069fe11d46f1.tar.xz
Add support for transformation matricies.
Diffstat (limited to 'libdimension')
-rw-r--r--libdimension/dimension/geometry.h55
-rw-r--r--libdimension/geometry.c144
2 files changed, 177 insertions, 22 deletions
diff --git a/libdimension/dimension/geometry.h b/libdimension/dimension/geometry.h
index e1d1497..ca10163 100644
--- a/libdimension/dimension/geometry.h
+++ b/libdimension/dimension/geometry.h
@@ -25,24 +25,16 @@
#ifndef DIMENSION_GEOMETRY_H
#define DIMENSION_GEOMETRY_H
-/* Scalar and vector types. */
-typedef double dmnsn_scalar;
-typedef struct { dmnsn_scalar x, y, z; } dmnsn_vector;
+/* Vector and matrix types. */
-/* Shorthand for vector construction */
-dmnsn_vector dmnsn_vector_construct(dmnsn_scalar x,
- dmnsn_scalar y,
- dmnsn_scalar z);
+typedef struct { double x, y, z; } dmnsn_vector;
-/* Vector arithmetic */
-
-dmnsn_vector dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs);
-dmnsn_vector dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs);
-dmnsn_vector dmnsn_vector_mul(dmnsn_scalar lhs, dmnsn_vector rhs);
-dmnsn_vector dmnsn_vector_div(dmnsn_vector lhs, dmnsn_scalar rhs);
-
-dmnsn_scalar dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs);
-dmnsn_vector dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs);
+typedef struct {
+ double n00, n01, n02, n03,
+ n10, n11, n12, n13,
+ n20, n21, n22, n23,
+ n30, n31, n32, n33;
+} dmnsn_matrix;
/* A line, or ray. */
typedef struct {
@@ -50,7 +42,36 @@ typedef struct {
dmnsn_vector n; /* A normal vector; the direction of the line */
} dmnsn_line;
+/* Shorthand for vector/matrix construction */
+
+dmnsn_vector dmnsn_vector_construct(double x, double y, double z);
+
+dmnsn_matrix dmnsn_matrix_construct(double a0, double a1, double a2, double a3,
+ double b0, double b1, double b2, double b3,
+ double c0, double c1, double c2, double c3,
+ double d0, double d1, double d2, double d3);
+dmnsn_matrix dmnsn_translation_matrix(dmnsn_vector d);
+/* theta/|theta| = axis, |theta| = angle */
+dmnsn_matrix dmnsn_rotation_matrix(dmnsn_vector theta);
+
+/* Vector and matrix arithmetic */
+
+dmnsn_vector dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs);
+dmnsn_vector dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs);
+dmnsn_vector dmnsn_vector_mul(double lhs, dmnsn_vector rhs);
+dmnsn_vector dmnsn_vector_div(dmnsn_vector lhs, double rhs);
+
+double dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs);
+dmnsn_vector dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs);
+
+double dmnsn_vector_norm(dmnsn_vector n);
+dmnsn_vector dmnsn_vector_normalize(dmnsn_vector n);
+
+dmnsn_matrix dmnsn_matrix_mul(dmnsn_matrix lhs, dmnsn_matrix rhs);
+dmnsn_vector dmnsn_matrix_vector_mul(dmnsn_matrix lhs, dmnsn_vector rhs);
+dmnsn_line dmnsn_matrix_line_mul(dmnsn_matrix lhs, dmnsn_line rhs);
+
/* A point on a line, defined by x0 + t*n */
-dmnsn_vector dmnsn_line_point(dmnsn_line l, dmnsn_scalar t);
+dmnsn_vector dmnsn_line_point(dmnsn_line l, double t);
#endif /* DIMENSION_GEOMETRY_H */
diff --git a/libdimension/geometry.c b/libdimension/geometry.c
index 0eab10b..548aae1 100644
--- a/libdimension/geometry.c
+++ b/libdimension/geometry.c
@@ -19,15 +19,78 @@
*************************************************************************/
#include "dimension.h"
+#include <math.h>
/* Construct a vector from x, y, and z. Just for convienence. */
dmnsn_vector
-dmnsn_vector_construct(dmnsn_scalar x, dmnsn_scalar y, dmnsn_scalar z)
+dmnsn_vector_construct(double x, double y, double z)
{
dmnsn_vector v = { .x = x, .y = y, .z = z };
return v;
}
+/* Construct a matrix. */
+dmnsn_matrix
+dmnsn_matrix_construct(double a0, double a1, double a2, double a3,
+ double b0, double b1, double b2, double b3,
+ double c0, double c1, double c2, double c3,
+ double d0, double d1, double d2, double d3)
+{
+ dmnsn_matrix m = { .n00 = a0, .n01 = a1, .n02 = a2, .n03 = a3,
+ .n10 = b0, .n11 = b1, .n12 = b2, .n13 = b3,
+ .n20 = c0, .n21 = c1, .n22 = c2, .n23 = c3,
+ .n30 = d0, .n31 = d1, .n32 = d2, .n33 = d3 };
+ return m;
+}
+
+/* Translation matrix */
+dmnsn_matrix
+dmnsn_translation_matrix(dmnsn_vector d)
+{
+ return dmnsn_matrix_construct(1.0, 0.0, 0.0, d.x,
+ 0.0, 1.0, 0.0, d.y,
+ 0.0, 0.0, 1.0, d.z,
+ 0.0, 0.0, 0.0, 1.0);
+}
+
+/* Rotation matrix; theta/|theta| = axis, |theta| = angle */
+dmnsn_matrix
+dmnsn_rotation_matrix(dmnsn_vector theta)
+{
+ dmnsn_vector axis, n1, n2, n3;
+ double angle, s, t, x, y, z;
+
+ axis = dmnsn_vector_normalize(theta);
+ angle = dmnsn_vector_norm(theta);
+
+ /* Shorthand to fit logical lines on one line */
+
+ s = sin(angle);
+ t = 1.0 - cos(angle);
+
+ x = axis.x;
+ y = axis.y;
+ z = axis.z;
+
+ /* Construct vectors, then a matrix, so our dmnsn_matrix_construct() call
+ is reasonably small */
+
+ n1 = dmnsn_vector_construct(1.0 + t*(x*x - 1.0),
+ z*s + t*x*y,
+ -y*s + t*x*z);
+ n2 = dmnsn_vector_construct(-z*s + t*x*y,
+ 1.0 + t*(y*y - 1.0),
+ x*s + t*y*z);
+ n3 = dmnsn_vector_construct(y*s + t*x*z,
+ -x*s + t*y*z,
+ 1.0 + t*(z*z - 1.0));
+
+ return dmnsn_matrix_construct(n1.x, n2.x, n3.x, 0.0,
+ n1.y, n2.y, n3.y, 0.0,
+ n1.z, n2.z, n3.z, 0.0,
+ 0.0, 0.0, 0.0, 1.0);
+}
+
/* Add two vectors */
dmnsn_vector
dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs)
@@ -50,7 +113,7 @@ dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs)
/* Multiply a vector by a scalar */
dmnsn_vector
-dmnsn_vector_mul(dmnsn_scalar lhs, dmnsn_vector rhs)
+dmnsn_vector_mul(double lhs, dmnsn_vector rhs)
{
dmnsn_vector v = { .x = lhs*rhs.x, .y = lhs*rhs.y, .z = lhs*rhs.z };
return v;
@@ -58,14 +121,14 @@ dmnsn_vector_mul(dmnsn_scalar lhs, dmnsn_vector rhs)
/* Divide a vector by a scalar */
dmnsn_vector
-dmnsn_vector_div(dmnsn_vector lhs, dmnsn_scalar rhs)
+dmnsn_vector_div(dmnsn_vector lhs, double rhs)
{
dmnsn_vector v = { .x = lhs.x/rhs, .y = lhs.y/rhs, .z = lhs.z/rhs };
return v;
}
/* Dot product */
-dmnsn_scalar
+double
dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs)
{
return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
@@ -81,9 +144,80 @@ dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs)
return v;
}
+/* Length of vector */
+double
+dmnsn_vector_norm(dmnsn_vector n)
+{
+ return sqrt(n.x*n.x + n.y*n.y + n.z*n.z);
+}
+
+/* Normalized vector */
+dmnsn_vector
+dmnsn_vector_normalize(dmnsn_vector n)
+{
+ return dmnsn_vector_div(n, dmnsn_vector_norm(n));
+}
+
+/* 4x4 matrix multiplication */
+dmnsn_matrix
+dmnsn_matrix_mul(dmnsn_matrix lhs, dmnsn_matrix rhs)
+{
+ dmnsn_matrix r;
+
+ r.n00 = lhs.n00*rhs.n00 + lhs.n01*rhs.n10 + lhs.n02*rhs.n20 + lhs.n03*rhs.n30;
+ r.n01 = lhs.n00*rhs.n01 + lhs.n01*rhs.n11 + lhs.n02*rhs.n21 + lhs.n03*rhs.n31;
+ r.n02 = lhs.n00*rhs.n02 + lhs.n01*rhs.n12 + lhs.n02*rhs.n22 + lhs.n03*rhs.n32;
+ r.n03 = lhs.n00*rhs.n03 + lhs.n01*rhs.n13 + lhs.n02*rhs.n23 + lhs.n03*rhs.n33;
+
+ r.n10 = lhs.n10*rhs.n00 + lhs.n11*rhs.n10 + lhs.n12*rhs.n20 + lhs.n13*rhs.n30;
+ r.n11 = lhs.n10*rhs.n01 + lhs.n11*rhs.n11 + lhs.n12*rhs.n21 + lhs.n13*rhs.n31;
+ r.n12 = lhs.n10*rhs.n02 + lhs.n11*rhs.n12 + lhs.n12*rhs.n22 + lhs.n13*rhs.n32;
+ r.n13 = lhs.n10*rhs.n03 + lhs.n11*rhs.n13 + lhs.n12*rhs.n23 + lhs.n13*rhs.n33;
+
+ r.n20 = lhs.n20*rhs.n00 + lhs.n21*rhs.n10 + lhs.n22*rhs.n20 + lhs.n23*rhs.n30;
+ r.n21 = lhs.n20*rhs.n01 + lhs.n21*rhs.n11 + lhs.n22*rhs.n21 + lhs.n23*rhs.n31;
+ r.n22 = lhs.n20*rhs.n02 + lhs.n21*rhs.n12 + lhs.n22*rhs.n22 + lhs.n23*rhs.n32;
+ r.n23 = lhs.n20*rhs.n03 + lhs.n21*rhs.n13 + lhs.n22*rhs.n23 + lhs.n23*rhs.n33;
+
+ r.n30 = lhs.n30*rhs.n00 + lhs.n31*rhs.n10 + lhs.n32*rhs.n20 + lhs.n33*rhs.n30;
+ r.n31 = lhs.n30*rhs.n01 + lhs.n31*rhs.n11 + lhs.n32*rhs.n21 + lhs.n33*rhs.n31;
+ r.n32 = lhs.n30*rhs.n02 + lhs.n31*rhs.n12 + lhs.n32*rhs.n22 + lhs.n33*rhs.n32;
+ r.n33 = lhs.n30*rhs.n03 + lhs.n31*rhs.n13 + lhs.n32*rhs.n23 + lhs.n33*rhs.n33;
+
+ return r;
+}
+
+/* Affine transformation; lhs*(x,y,z,1), normalized so the fourth element is
+ 1 */
+dmnsn_vector
+dmnsn_matrix_vector_mul(dmnsn_matrix lhs, dmnsn_vector rhs)
+{
+ dmnsn_vector r;
+ double w;
+
+ r.x = lhs.n00*rhs.x + lhs.n01*rhs.y + lhs.n02*rhs.z + lhs.n03;
+ r.x = lhs.n10*rhs.x + lhs.n11*rhs.y + lhs.n12*rhs.z + lhs.n13;
+ r.x = lhs.n20*rhs.x + lhs.n21*rhs.y + lhs.n22*rhs.z + lhs.n23;
+ w = lhs.n30*rhs.x + lhs.n31*rhs.y + lhs.n32*rhs.z + lhs.n33;
+
+ return dmnsn_vector_div(r, w);
+}
+
+/* Affine line transformation; n = lhs*(x0 + n) - lhs*x0, x0 *= lhs */
+dmnsn_line
+dmnsn_matrix_line_mul(dmnsn_matrix lhs, dmnsn_line rhs)
+{
+ dmnsn_line l;
+ l.x0 = dmnsn_matrix_vector_mul(lhs, rhs.x0);
+ l.n = dmnsn_vector_sub(
+ dmnsn_matrix_vector_mul(lhs, dmnsn_vector_add(rhs.x0, rhs.n)),
+ l.x0);
+ return l;
+}
+
/* A point on a line, l. Returns l.x0 + t*l.n */
dmnsn_vector
-dmnsn_line_point(dmnsn_line l, dmnsn_scalar t)
+dmnsn_line_point(dmnsn_line l, double t)
{
return dmnsn_vector_add(l.x0, dmnsn_vector_mul(t, l.n));
}