W3cubDocs

/Nim

Module basic3d

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

Imports

math, strutils, times

Types

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.

Lets

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

Procs

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