Basic 3d support with vectors, points, matrices and some basic utilities. Vectors are implemented as direction vectors, ie. when transformed with a matrix the translation part of matrix is ignored. The coordinate system used is right handed, because its compatible with 2d coordinate system (rotation around zaxis equals 2d rotation). Operators *+* , *-* , *** , */* , *+=* , *-=* , **=* and */=* are implemented for vectors and scalars.

Quick start example:

# Create a matrix which first rotates, then scales and at last translates var m:Matrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0) # Create a 3d point at (100,150,200) and a vector (5,2,3) var pt:Point3d=point3d(100.0,150.0,200.0) var vec:Vector3d=vector3d(5.0,2.0,3.0) pt &= m # transforms pt in place var pt2:Point3d=pt & m #concatenates pt with m and returns a new point var vec2:Vector3d=vec & m #concatenates vec with m and returns a new vector

Matrix3d = object ax*, ay*, az*, aw*, bx*, by*, bz*, bw*, cx*, cy*, cz*, cw*, tx*, ty*, tz*, tw*: float

- Implements a row major 3d matrix, which means transformations are applied the order they are concatenated. This matrix is stored as an 4x4 matrix: [ ax ay az aw ] [ bx by bz bw ] [ cx cy cz cw ] [ tx ty tz tw ]
Point3d = object x*, y*, z*: float

- Implements a non-homogeneous 3d point stored as an
*x*,*y*and*z*coordinate. Vector3d = object x*, y*, z*: float

- Implements a 3d
**direction vector**stored as an*x*,*y*and*z*coordinate. Direction vector means, that when transforming a vector with a matrix, the translational part of the matrix is ignored.

IDMATRIX: Matrix3d = matrix3d(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0)

- Quick access to a 3d identity matrix
ORIGO: Point3d = point3d(0.0, 0.0, 0.0)

- Quick access to point (0,0)
XAXIS: Vector3d = vector3d(1.0, 0.0, 0.0)

- Quick access to an 3d x-axis unit vector
YAXIS: Vector3d = vector3d(0.0, 1.0, 0.0)

- Quick access to an 3d y-axis unit vector
ZAXIS: Vector3d = vector3d(0.0, 0.0, 1.0)

- Quick access to an 3d z-axis unit vector

proc setElements(t: var Matrix3d; ax, ay, az, aw, bx, by, bz, bw, cx, cy, cz, cw, tx, ty, tz, tw: float) {. inline, raises: [], tags: [].}

- Sets arbitrary elements in an exisitng matrix.
proc matrix3d(ax, ay, az, aw, bx, by, bz, bw, cx, cy, cz, cw, tx, ty, tz, tw: float): Matrix3d {. noInit, raises: [], tags: [].}

- Creates a new 4x4 3d transformation matrix.
*ax*,*ay*,*az*is the local x axis.*bx*,*by*,*bz*is the local y axis.*cx*,*cy*,*cz*is the local z axis.*tx*,*ty*,*tz*is the translation. proc `&`(a, b: Matrix3d): Matrix3d {.noinit, raises: [], tags: [].}

- Concatenates matrices returning a new matrix.
proc scale(s: float): Matrix3d {.noInit, raises: [], tags: [].}

- Returns a new scaling matrix.
proc scale(s: float; org: Point3d): Matrix3d {.noInit, raises: [], tags: [].}

- Returns a new scaling matrix using,
*org*as scale origin. proc stretch(sx, sy, sz: float): Matrix3d {.noInit, raises: [], tags: [].}

- Returns new a stretch matrix, which is a scale matrix with non uniform scale in x,y and z.
proc stretch(sx, sy, sz: float; org: Point3d): Matrix3d {.noInit, raises: [], tags: [].}

- Returns a new stretch matrix, which is a scale matrix with non uniform scale in x,y and z.
*org*is used as stretch origin. proc move(dx, dy, dz: float): Matrix3d {.noInit, raises: [], tags: [].}

- Returns a new translation matrix.
proc move(v: Vector3d): Matrix3d {.noInit, raises: [], tags: [].}

- Returns a new translation matrix from a vector.
proc rotate(angle: float; axis: Vector3d): Matrix3d {.noInit, raises: [Exception, DivByZeroError], tags: [RootEffect].}

- Creates a rotation matrix that rotates
*angle*radians over*axis*, which passes through origo. proc rotate(angle: float; org: Point3d; axis: Vector3d): Matrix3d {.noInit, raises: [Exception, DivByZeroError], tags: [RootEffect].}

- Creates a rotation matrix that rotates
*angle*radians over*axis*, which passes through*org*. proc rotateX(angle: float): Matrix3d {.noInit, raises: [], tags: [].}

- Creates a matrix that rotates around the x-axis with
*angle*radians, which is also called a 'roll' matrix. proc rotateY(angle: float): Matrix3d {.noInit, raises: [], tags: [].}

- Creates a matrix that rotates around the y-axis with
*angle*radians, which is also called a 'pitch' matrix. proc rotateZ(angle: float): Matrix3d {.noInit, raises: [], tags: [].}

- Creates a matrix that rotates around the z-axis with
*angle*radians, which is also called a 'yaw' matrix. proc isUniform(m: Matrix3d; tol = 1e-006): bool {.raises: [], tags: [].}

- Checks if the transform is uniform, that is perpendicular axes of equal length, which means (for example) it cannot transform a sphere into an ellipsoid.
*tol*is used as tolerance for both equal length comparison and perpendicular comparison. proc mirror(planeperp: Vector3d): Matrix3d {.noInit, raises: [Exception, DivByZeroError], tags: [RootEffect].}

- Creates a matrix that mirrors over the plane that has
*planeperp*as normal, and passes through origo.*planeperp*does not need to be normalized. proc mirror(org: Point3d; planeperp: Vector3d): Matrix3d {.noInit, raises: [Exception, DivByZeroError], tags: [RootEffect].}

- Creates a matrix that mirrors over the plane that has
*planeperp*as normal, and passes through*org*.*planeperp*does not need to be normalized. proc determinant(m: Matrix3d): float {.raises: [], tags: [].}

- Computes the determinant of matrix
*m*. proc inverse(m: Matrix3d): Matrix3d {.noInit, raises: [DivByZeroError], tags: [].}

- Computes the inverse of matrix
*m*. If the matrix determinant is zero, thus not invertible, a EDivByZero will be raised. proc equals(m1: Matrix3d; m2: Matrix3d; tol = 1e-006): bool {.raises: [], tags: [].}

- Checks if all elements of
*m1`and `m2*is equal within a given tolerance*tol*. proc `=~`(m1, m2: Matrix3d): bool {.raises: [], tags: [].}

- Checks if
*m1*and*m2*is approximately equal, using a tolerance of 1e-6. proc transpose(m: Matrix3d): Matrix3d {.noInit, raises: [], tags: [].}

- Returns the transpose of
*m* proc getXAxis(m: Matrix3d): Vector3d {.noInit, raises: [], tags: [].}

- Gets the local x axis of
*m* proc getYAxis(m: Matrix3d): Vector3d {.noInit, raises: [], tags: [].}

- Gets the local y axis of
*m* proc getZAxis(m: Matrix3d): Vector3d {.noInit, raises: [], tags: [].}

- Gets the local y axis of
*m* proc `$`(m: Matrix3d): string {.raises: [], tags: [].}

- String representation of
*m* proc apply(m: Matrix3d; x, y, z: var float; translate = false) {.raises: [], tags: [].}

- Applies transformation
*m*onto*x*,*y*,*z*, optionally using the translation part of the matrix. proc vector3d(x, y, z: float): Vector3d {.noInit, inline, raises: [], tags: [].}

- Returns a new 3d vector (
*x*,`y`,`z`) proc len(v: Vector3d): float {.raises: [], tags: [].}

- Returns the length of the vector
*v*. proc len=(v: var Vector3d; newlen: float) {.noInit, raises: [], tags: [].}

- Sets the length of the vector, keeping its direction. If the vector has zero length before changing it's length, an arbitrary vector of the requested length is returned.
proc sqrLen(v: Vector3d): float {.inline, raises: [], tags: [].}

- Computes the squared length of the vector, which is faster than computing the absolute length.
proc `$`(v: Vector3d): string {.raises: [], tags: [].}

- String representation of
*v* proc `&`(v: Vector3d; m: Matrix3d): Vector3d {.noInit, raises: [], tags: [].}

- Concatenate vector
*v*with a transformation matrix. Transforming a vector ignores the translational part of the matrix. proc `&=`(v: var Vector3d; m: Matrix3d) {.noInit, raises: [], tags: [].}

- Applies transformation
*m*onto*v*in place. Transforming a vector ignores the translational part of the matrix. proc transformNorm(v: var Vector3d; m: Matrix3d) {.raises: [DivByZeroError], tags: [].}

- Applies a normal direction transformation
*m*onto*v*in place. The resulting vector is*not*normalized. Transforming a vector ignores the translational part of the matrix. If the matrix is not invertible (determinant=0), an EDivByZero will be raised. proc transformInv(v: var Vector3d; m: Matrix3d) {.raises: [DivByZeroError], tags: [].}

- Applies the inverse of
*m*on vector*v*. Transforming a vector ignores the translational part of the matrix. Transforming a vector ignores the translational part of the matrix. If the matrix is not invertible (determinant=0), an EDivByZero will be raised. proc transformNormInv(vec: var Vector3d; m: Matrix3d) {.raises: [], tags: [].}

- Applies an inverse normal direction transformation
*m*onto*v*in place. This is faster than creating an inverse matrix and transformNorm(...) it. Transforming a vector ignores the translational part of the matrix. proc tryNormalize(v: var Vector3d): bool {.raises: [], tags: [].}

- Modifies
*v*to have a length of 1.0, keeping its angle. If*v*has zero length (and thus no angle), it is left unmodified and false is returned, otherwise true is returned. proc normalize(v: var Vector3d) {.inline, raises: [DivByZeroError], tags: [].}

- Modifies
*v*to have a length of 1.0, keeping its angle. If*v*has zero length, an EDivByZero will be raised. proc rotate(vec: var Vector3d; angle: float; axis: Vector3d) {.raises: [DivByZeroError], tags: [].}

- Rotates
*vec*in place, with*angle*radians over*axis*, which passes through origo. proc scale(v: var Vector3d; s: float) {.raises: [], tags: [].}

- Scales the vector in place with factor
*s* proc stretch(v: var Vector3d; sx, sy, sz: float) {.raises: [], tags: [].}

- Scales the vector non uniformly with factors
*sx*,*sy*,*sz* proc mirror(v: var Vector3d; planeperp: Vector3d) {.raises: [DivByZeroError], tags: [].}

- Computes the mirrored vector of
*v*over the plane that has*planeperp*as normal direction.*planeperp*does not need to be normalized. proc `-`(v: Vector3d): Vector3d {.raises: [], tags: [].}

- Negates a vector
proc `+`(a135939, b135941: Vector3d): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `+`(a135943: Vector3d; b135945: float): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `+`(a135947: float; b135949: Vector3d): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `-`(a135960, b135962: Vector3d): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `-`(a135964: Vector3d; b135966: float): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `-`(a135968: float; b135970: Vector3d): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `*`(a135981, b135983: Vector3d): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `*`(a135985: Vector3d; b135987: float): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `*`(a135989: float; b135991: Vector3d): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `/`(a136002, b136004: Vector3d): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `/`(a136006: Vector3d; b136008: float): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `/`(a136010: float; b136012: Vector3d): Vector3d {.inline, noInit, raises: [], tags: [].}

proc `+=`(a136023: var Vector3d; b136025: Vector3d) {.inline, raises: [], tags: [].}

proc `+=`(a136027: var Vector3d; b136029: float) {.inline, raises: [], tags: [].}

proc `-=`(a136097: var Vector3d; b136099: Vector3d) {.inline, raises: [], tags: [].}

proc `-=`(a136101: var Vector3d; b136103: float) {.inline, raises: [], tags: [].}

proc `*=`(a136171: var Vector3d; b136173: Vector3d) {.inline, raises: [], tags: [].}

proc `*=`(a136175: var Vector3d; b136177: float) {.inline, raises: [], tags: [].}

proc `/=`(a136245: var Vector3d; b136247: Vector3d) {.inline, raises: [], tags: [].}

proc `/=`(a136249: var Vector3d; b136251: float) {.inline, raises: [], tags: [].}

proc dot(v1, v2: Vector3d): float {.inline, raises: [], tags: [].}

- Computes the dot product of two vectors. Returns 0.0 if the vectors are perpendicular.
proc cross(v1, v2: Vector3d): Vector3d {.inline, raises: [], tags: [].}

- Computes the cross product of two vectors. The result is a vector which is perpendicular to the plane of
*v1*and*v2*, which means cross(xaxis,yaxis)=zaxis. The magnitude of the result is zero if the vectors are colinear. proc equals(v1, v2: Vector3d; tol = 1e-006): bool {.raises: [], tags: [].}

- Checks if two vectors approximately equals with a tolerance.
proc `=~`(v1, v2: Vector3d): bool {.raises: [], tags: [].}

- Checks if two vectors approximately equals with a hardcoded tolerance 1e-6
proc angleTo(v1, v2: Vector3d): float {.raises: [], tags: [].}

- Returns the smallest angle between v1 and v2, which is in range 0-PI
proc arbitraryAxis(norm: Vector3d): Matrix3d {.noInit, raises: [DivByZeroError], tags: [].}

- Computes the rotation matrix that would transform world z vector into
*norm*. The inverse of this matrix is useful to transform a planar 3d object to 2d space. This is the same algorithm used to interpret DXF and DWG files. proc bisect(v1, v2: Vector3d): Vector3d {.noInit, raises: [DivByZeroError], tags: [].}

- Computes the bisector between v1 and v2 as a normalized vector. If one of the input vectors has zero length, a normalized version of the other is returned. If both input vectors has zero length, an arbitrary normalized vector
*v1*is returned. proc point3d(x, y, z: float): Point3d {.noInit, inline, raises: [], tags: [].}

- Returns a new 4d point (
*x*,`y`,`z`) proc sqrDist(a, b: Point3d): float {.raises: [], tags: [].}

- Computes the squared distance between
*a`and `b* proc dist(a, b: Point3d): float {.inline, raises: [], tags: [].}

- Computes the absolute distance between
*a`and `b* proc `$`(p: Point3d): string {.raises: [], tags: [].}

- String representation of
*p* proc `&`(p: Point3d; m: Matrix3d): Point3d {.raises: [], tags: [].}

- Concatenates a point
*p*with a transform*m*, resulting in a new, transformed point. proc `&=`(p: var Point3d; m: Matrix3d) {.raises: [], tags: [].}

- Applies transformation
*m*onto*p*in place. proc transformInv(p: var Point3d; m: Matrix3d) {.raises: [DivByZeroError], tags: [].}

- Applies the inverse of transformation
*m*onto*p*in place. If the matrix is not invertable (determinant=0) , EDivByZero will be raised. proc `+`(p: Point3d; v: Vector3d): Point3d {.noInit, inline, raises: [], tags: [].}

- Adds a vector
*v*to a point*p*, resulting in a new point. proc `+=`(p: var Point3d; v: Vector3d) {.noInit, inline, raises: [], tags: [].}

- Adds a vector
*v*to a point*p*in place. proc `-`(p: Point3d; v: Vector3d): Point3d {.noInit, inline, raises: [], tags: [].}

- Subtracts a vector
*v*from a point*p*, resulting in a new point. proc `-`(p1, p2: Point3d): Vector3d {.noInit, inline, raises: [], tags: [].}

- Subtracts
*p2`from `p1*resulting in a difference vector. proc `-=`(p: var Point3d; v: Vector3d) {.noInit, inline, raises: [], tags: [].}

- Subtracts a vector
*v*from a point*p*in place. proc `=~`(p1, p2: Point3d): bool {.inline, raises: [], tags: [].}

- Checks if two vectors approximately equals with a hardcoded tolerance 1e-6
proc rotate(p: var Point3d; rad: float; axis: Vector3d) {.raises: [DivByZeroError], tags: [].}

- Rotates point
*p*in place*rad*radians about an axis passing through origo. proc rotate(p: var Point3d; angle: float; org: Point3d; axis: Vector3d) {. raises: [DivByZeroError], tags: [].}

- Rotates point
*p*in place*rad*radians about an axis passing through*org* proc scale(p: var Point3d; fac: float) {.inline, raises: [], tags: [].}

- Scales a point in place
*fac*times with world origo as origin. proc scale(p: var Point3d; fac: float; org: Point3d) {.inline, raises: [], tags: [].}

- Scales the point in place
*fac*times with*org*as origin. proc stretch(p: var Point3d; facx, facy, facz: float) {.inline, raises: [], tags: [].}

- Scales a point in place non uniformly
*facx*,*facy*,*facz*times with world origo as origin. proc stretch(p: var Point3d; facx, facy, facz: float; org: Point3d) {.inline, raises: [], tags: [].}

- Scales the point in place non uniformly
*facx*,*facy*,*facz*times with*org*as origin. proc move(p: var Point3d; dx, dy, dz: float) {.inline, raises: [], tags: [].}

- Translates a point
*dx*,*dy*,*dz*in place. proc move(p: var Point3d; v: Vector3d) {.inline, raises: [], tags: [].}

- Translates a point with vector
*v*in place. proc area(a, b, c: Point3d): float {.inline, raises: [], tags: [].}

- Computes the area of the triangle thru points
*a*,*b*and*c*

© 2006–2017 Andreas Rumpf

Licensed under the MIT License.

https://nim-lang.org/docs/basic3d.html