This comprehensive page is a practical collection about CAD faces with layman explanations of mathematics and additional code fragments. It deals with vectors, angles, normals, 2D projections, rotations and more. The best news is that even BricsCAD Lite supports both Lisp and 3D commands like RuleSurf
. Even with limited resources you can build great solutions. So: “Let’s face it! 😉
I made FlatMesh
in an attempt to create blanks from ruled surfaces. While the basics are relative easy – translating 3D coordinates to 2D – it turned out that the exceptions are the real math challenge. I couldn’t find a this page like this, in order to clarify and understand the subject. So this page was born. I hope it is of help. I think it is pretty complete. However, if you think something is wrong, missing or can be done better, just drop a comment.
Table of Contents
Definitions
- Face: A face is, by mathematical definition, a flat polygon and almost always a triangle in a CAD environment. A (CAD) face has three edges and vertices. Complex 3D surfaces can be simulated by using 2D triangular faces. Faces with four vertices could be suitable for orthogonal based surfaces (like a cube) but are almost never suitable for complex 3D surfaces.
- 3DFace: This is both the entity name and command name in CAD systems like BricsCAD and AutoCAD. A 3DFace entity can be visible as a tetragon or a triangle. The use of tetragons has the advantage of clarity. On the other hand, in 3D, the four corners of each tetragon are (almost) never in one plane. To fix that, for a better visual, each tetragon consists of two adjacent triangles i.e. faces. The common edge of these two faces forms an invisible diagonal of a visible tetragon – the visible sides of the two triangles give the impression of a tetragon but, again, upon examination, the corners (almost) never lie in a plane.
- Mesh: A mesh is a collection of triangular and or tetragonal 3Dface entities. A mesh forms a surface object.
- Vector: A vector is a direction with a size or magnitude.
- A vector V is represented as
- with a direction
- and a length or magnitude
- The edges of faces can be considered as vectors like and .
- Knowing the coordinates of the vertices, we can do calculations on these vectors, on these faces. That is where our journey in mathematics start!
- A vector V is represented as
Mathematical solutions
Let’s start a bit steep to refresh memory, once on the way it gets easy 😉
Calculate the magnitude of a vector
The magnitude is the size, or more precise, the exact length of a vector. For vector , magnitude is noted as .
For vector with value , the magnitude or length is according to the Pythagorean theorem.
For vector with coordinates and , the magnitude is:
.
Calculate the dot product of two vectors
The dot product is an operation on two vectors and with angle in between, resulting in a scalar (number, not a vector).
The dot product by itself has little meaning but is important as a value for other formulas. For example, the law of cosines has the dot product as its basis.
Dot product is written as:
There are two common ways to calculate the dot product:
This also means that:
- See “Calculate the angle between two vectors” for more and caveats.
Calculate the cross product of two vectors
The cross product is an algebraic operation on two vectors and resulting in a normal vector perpendicular to both and .
Cross product is written as:
Calculation:
- If vectors and consist of coordinates and , then the cross product is:
Valuable for solving equations: The magnitude of the resulting vector, , equals the area of the parallelogram of and .
Normal: A line, ray or vector perpendicular to something. In this case we mean a vector perpendicular to a plane. The side of the plane on which the normal starts is determined by the right hand rule. Therefore the order of and is important, and . More…
When not using the right hand rule, the sign (+,-) of the coordinates of should be inverterted.
Calculate the unit vector of a vector
A unit vector of a vector has the same direction but has a length or magnitude of 1. It can be retrieved by dividing each x, y and z of a vector by the magnitude of that vector, resulting in a new vector.
Calculate the angle between two vectors
In 2D, it is easy to comprehend. 3D is harder. For example grep a pencil in each hand and position and point them randomly before you. What on earth is the angle? Now bring the origins together. At that point, you can imagine a plane through the three points and it becomes clear there is an angle. Then the question becomes: What is the angle? And: Do you want the angle from pencil A to pencil B or the other way around? Finally, you can look at the plane from two sides, which changes the answers too. So there is enough complexity.
Using arccosine
The angle between and …
Example
AB = 1,2,3
AC = 4,5,6
|AB| =SQRT(1^2+2^2+3^2) = 3.74
|AC| =SQRT(4^2+5^2+6^2) = 8.77
AB.AC =1*4+2*5+3*6 = 32
acos((AB.AC)/(|AB|*|AC|)) = acos(32/(3.74*8.77)) = 0.226 rad = 12.9 degrees
Here, the angle range is 0 to . Although technically correct, that may not always be what you want – in cases with small angles there is a lot of cumulative error. What else is there?
Using arctangent
The same angle again but by using atan2.
Atan2 is arctan, arctangent, inverse tangent, of value x and y. But be careful, syntaxis, x and y order, can be different. For example, spreadsheet: atan2(x,y), C language: atan2(y,x) and CAD Lisp language: atan(y,x). Also keep in mind that angles range from 0 to radians.
How do we get x and y?
- y is the magnitude of the cross product of vector AB and AC
- x is the dot product of vector AB and AC.
Again, the angle between and …
In addition written out in sheet notation for vector AB and AC and angle alpha in radians:
AB = (x1,y1,z1)
AC = (x2,y2,z2)
x =x1*x2+y1*y2+z1*z2
y =sqrt((y1*z2-z1*y2)^2+(z1*x2-x1*z2)^2+(x1*y2-y1*x2)^2)
alpha =atan2(x,y)
Is a vector angle obtuse, perpendicular or acute?
Continuing with the previous… Instead of, or in addition to, calculating an angle, the dot product is enough to say whether the angle is obtuse, perpendicular or acute. It is depending on the sign of . More specific:
- If m is positive, the angle is acute.
- If m is zero, the angle is right, perpendicular.
- If m is negative, the angle is obtuse.
A rectangle contains two adjacent faces. We can say something about the angle between the faces by first calculating the normal vectors of each face.
Calculate the normal of a face
The normal vector is the cross product of vector AB times vector AC. According to the right hand rule, it is written as
Example
AB = (1,2,3)
AC = (4,5,6)
ABAC = (2*6-3*5,1*6-3*4,1*5-2*4) = (-3,6,-3)
The opposite normal vector is ACAB
, being ABAC
with opposite signs, i.e. (3,-6,3)
.
The magnitude of normal ABAC
is area . So you can tell something about angle CAB
if you have the magnitudes of all three vectors.
Calculate 2D projection of a face – Pythagorean
With three coordinates A
, B
and C
known of a 3D face, we can calculate a projection in 2D. Alternative, law of cosines can be used here too.
Calculating C
based on A
is (0,0)
and B
is (p,0)
Summary
Known:
Distances p
, q
, r
Constraints:
Point A = (0,0)
Point B = (p,0)
Point C
is above axis AB
First Cy
is positive
z coordinates always 0
Requested:
Coordinates of C
.
Answer:C = ((p^2+r^2-q^2)/(2*p),sqrt(r^2-t^2))
Subsequent Cy values can be negative too, i.e. -sqrt(r^2-t^2)
Rationale
A: (x,y,z)
C: (x',y',z')
Variant 1 Variant 2 ( is OR)
CAB <= pi()/2 CAB > pi()/2 =>
x <= x' x > x'
r^2 = t^2+s^2 =>
s^2 = r^2-t^2
q^2 = (p-t)^2+s^2 (p+t)^2+s^2
= (p-t)^2+r^2-t^2 (p+t)^2+r^2-t^2
= p^2-2pt+t^2+r^2-t^2 p^2+2pt+t^2+r^2-t^2
= p^2-2pt+r^2 p^2+2pt+r^2 =>
2pt = p^2+r^2-q^2 -p^2-r^2+q^2 =>
t = (p^2+r^2-q^2)/(2*p) (p^2+r^2-q^2)/(-2*p)
s^2=r^2-t^2
s=sqrt(r^2-t^2) s=-sqrt(r^2-t^2)
With two answers for t
it is tempting to just code both values. Annoying and itching is the fact I cannot say anything beforehand about CAB
.
Hmm, is that so? Climbing from the bottom – the resulting formula’s – up, there is fragment p^2+r^2-q^2
. Wait, Pythagoras! That should be 0
when CAB
is 90
!
More specific:
One problem solved, one problem created! Let’s see, If p^2+r^2-q^2 < 0
then t = (p^2+r^2-q^2)/(-2*p)
and else t = (p^2+r^2-q^2)/(2*p)
. So t
is always a positive value and whether it is on the left or right side of x=0
(point A) depends on the value of p^2+r^2-q^2
.
More specific, as an x-coordinate, t = (p^2+r^2-q^2)/(2*p)
. And that is always true! Great, and even my old brains survived this.
A final note about s
. It is a square root so the argument can be both positive and negative. It won’t bother us for the assumed first C, but it will bother us for subsequent C’s and all D’s.
Calculate 2D projection of an adjacent face
Getting the coordinate D
is similar to finding C
.
One segment of the RuleSurf
result is build out of two triangles or faces. Using FlatMesh
means in most cases: Start with A
and B
and calculate C
and D
, then treat those resulting C
and D
as a new set of A
and B
and start allover, until the complete mesh is processed. In most cases, the first picture is in play. However, sometimes the second picture can be in play. In addition, even C
can be under axis AB
but focus is on D
for proper explanation.
A
,B
,C
and D
are 3D points. There is a plane ABC
. D
is somewhere relative to this plane. We need to know where D
lies. More specific, in a planar view to ABC
, is D
under or above axis BC
? To get a better impression, look at it from a different angle:
This question seems not easy to answer, but, as long as we talk about angles, we can say that:
- If the angle between the face normals is acute,
D
lies aboveBC
. - If the angle between the face normals is obtuse,
D
lies underBC
.
After calculating the normals as explained before, the dot product is all we need to answer the question. Just remember to use the right hand rule.
That was actually the hard part. D
is more or less calculated the same way as C
.
However, we need to use the axis CB
(not AB
) as the base, as the mirror line for when D
gets under CB
. Finally, C
and B
were rotated around A
, D should also be rotated properly. That is where starts to play a role. Rotating…
Calculate rotation of a coordinate in 2D
Seriously written for mathematicians, so don’t read https://en.wikipedia.org/wiki/Rotation_(mathematics). Pff… Okay, it boils down to this:
Given is coordinate pair x,y
and angle α
. Get x',y'
by using:
x'=x*cos(α)-y*sin(α)
y'=y*cos(α)+x*sin(α)
In order not to get unexpected results, angle α
is positive when counter-clockwise – in this example it is a positive value.
Tip!:For calculating a rotation in 3D you can consider two rotations, one in the xy-plane and one in the yz-plane.
When dealing with angles of 90 degrees another, easier, approach means changing signs and positions of coordinate values.
Value | CCW | Description |
x,y | 0 | Equal |
-y,x | 90 | 90 (or -270) Normal (CCW) |
-x,-y | 180 | 180 Opposite |
y,-x | 270 | 270 (or -90) Normal (CW) |
Translating and scaling
This one is easy, translations, like command Move
, is just adding or subtracting static values to x, y and z values. Since we are talking about vectors, scaling means multiplying or dividing the x, y and z values individually with a constant factor. There is not much more to say about this, see the programming solutions below for more about lv:add lv:subtract lv:multiply lv:divide.
Determining bissectrice point
The image below:
- Two blue vectors V1 and V2 in space and the bisector as red vector V4.
- V1 and V2 start from corner point PtC.
- Angle bisector theorem: A/B=A’/B’.
- Magnitude, length, of V1 and V2 are A and B and can be calculated.
- V3 = V2 – V1. With that we also know (A’ + B’).
- By substitution we can now determine V4.
- Bisector point Pt3 is the sum of vectors PtC, V1 and V4, or,
Pt3 = PtC + V1 + V4.
Trivia
- Constructing the bisector can be done with circles (see picture).
- A common mistake is to think that the bisector goes through the middle of line Pt1-Pt2.
Programming solutions
The purpose of this code is educational. It works and aims to show the structure. Unless you experience slow processing, it should be sufficient.
In order to avoid interference with functions from third parties, functions below are prefixed with “lv:” as in Lib Vector.
Datatypes
Datatype will often be REAL but please be aware of the consequence of using integers as input. Some examples you can paste on the command line, divide 3 by 2 as in 3/2:
(/ 3 2) > 1
(/ 3.0 2) > 1.5
(/ 3 2.0) > 1.5
(/ 3.0 2.0) > 1.5
Also “divide by zero” is not handled.
Functions lv:realp and lv:intp can check input, protect you from wrong input. For example, force real input:
LV:REALP : (setq a 5) 5 : (lv:realp a) nil : (setq a 5.0) 5.0 : (lv:realp a) 5.0 |
So only when a
is a real, value a
is returned, otherwise nil
.
Additional variables
Multiplying and dividing pi or π is daunting, some variables are added:
- pim2 = π*2 ≈ 6.28, PI Multiplied by 2, i.e. 360°
- pidN = π/N, PI Divided by 2, with N = 2, 3, 4, 6 and 12, for resp. 90°, 60°, 45°, 30° and 15°. So pid2 = 90° ≈ 1.57 radians.
- fr2d = multiply Factor for Radians 2 Degrees ≈ 57.29. Function
(lv:r2d radians)
is an option too. - fd2r = multiply Factor for Degrees 2 Radians ≈ 0.01745. Function
(lv:d2r degrees)
is an option too.
acos
Calculate arccosine in AutoCAD. BricsCAD has a native function acos.
Returns the arccosine of a number in radians. This code can be used for (acos ...)
:
(acos num1 ) |
Arguments
Num1 is an integer or real.
Return Values
The arccosine of num1, in radians.
Examples
(acos (/ pi 4)) 0.667457216028384 |
asin
Calculate arcsine in AutoCAD. BricsCAD has a native function asin.
Returns the arcsine of a number in radians. This code can be used for (asin ...)
:
(asin num1 ) |
Arguments
Num1 is an integer or real.
Return Values
The arcsine of num1, in radians.
Examples
(asin (/ pi 4)) 0.903339110766513 |
lv:add
Returns the sum of two coordinate lists.
This functions is useful for vectors and or points.
Say, we have point1 and vector1, point1 is x,y,z
and vector1 is x',y',z'
. The result in spreadsheet notation is:x+x',y+y',z+z'
(lv:add list1 list2 ) |
Arguments
List1 and list2 are lists containing x,y,z coordinates.
Return Values
A list with coordinates.
Examples
:(setq pt1 (list 2 2 2)) (2 2 2) : (setq vec1 (list -2 -2 0)) (-2 -2 0) : (lv:add pt1 vec1) (0 0 2) |
lv:substract
Returns the difference of two coordinate lists.
This function subtracts the second argument from the first argument. This functions is useful for vectors and or points.
With point1 and vector1, point1 is x,y,z
and vector1 is x',y',z'
. The result in spreadsheet notation is:x-x',y-y',z-z'
(lv:substract list1 list2 ) |
Arguments
List1 and list2 are lists containing x,y,z coordinates.
Return Values
A list with coordinates.
Examples
:(setq pt1 (list 2 2 2)) (2 2 2) : (setq vec1 (list -2 -2 0)) (-2 -2 0) : (lv:subtract pt1 vec1) (4 4 2) |
lv:multiply
Multiplies coordinate values with a fixed value.
With coordinate list x,y,z
and factor f
, the result in spreadsheet notation is:x*f,y*f,z*f
(lv:multiply list factor ) |
Arguments
List contains x,y,z coordinates. Factor is a value.
Return Values
A list with coordinates.
Examples
:(setq vec (list 2 3 4)) (2 3 4) : (setq fac 2.0) 2.0 : (lv:multiply vec fac) (4 6 8) |
lv:divide
Divides coordinate values with a fixed value.
With coordinate list x,y,z
and factor f
, the result in spreadsheet notation is:x/f,y/f,z/f
(lv:divide list factor ) |
Arguments
List contains x,y,z coordinates. Factor is a value, real or integer, see example for consequences.
Return Values
A list with coordinates.
Examples
:(setq vec (list 2 3 4)) (2 3 4) : (setq fac 2.0) 2.0 : (lv:divide vec fac) (1.0 1.5 2.0) : (setq fac 2) 2 : (lv:divide vec fac) (1 1 2) |
lv:minus
Additional inverses a list with values.
Changes the sign of a vector, creating the opposite vector.
Arguments
List contains values, for example x,y,z coordinates.
Return Values
A list with coordinates or values.
Examples
:(setq vec (list 2 3 4.0)) (2 3 4) : (lv:minus vec ) (-2 -3 -4.0)) |
lv:dist3d
3D distance between point 1 and 2.
In Lisp there is a function (distance a b)
but it is tempting to use your own function because (distance a b)
treats all points 2D when it encounters one 2D point. An alternative function (lv:dist3d point1
point2)
works always 3D and calculates “the square root of the sum of the squares of the delta x, y and z values”.
With the distance between point1 and point2, point1 is x,y,z
and point2 is x',y',z'
, the formula in spreadsheet notation is:dist3d=sqrt(((x'-x)^2)+((y'-y)^2)+((z'-z)^2))
(lv:dist3d point1 point2 ) |
Arguments
Point1 and point2 are lists containing x,y,z coordinates.
Return Values
The 3D distance between point1 and point2 as a real.
Examples
:(setq pt2 (list 4 0 0)) (4 0 0) : (setq pt1 (list 0 3 0)) (0 3 0) : (lv:dist3d pt1 pt2) 5.0 |
lv:vector
Vector between point 1 and point 2
For the vector coordinates, point 2 is subtracted from point 1.
(lv:dist3d point1 point2 ) |
Arguments
Point1 and point2 are lists containing x,y,z coordinates.
Return Values
Resulting vector as a list of reals and or integers.
Examples
: (setq point1 (list 5.0 0.0 0.0)) (5.0 0.0 0.0) : (setq point2 (list 0.0 3.0 0.0)) (0.0 3.0 0.0) : (lv:vector point1 point2) (-5.0 3.0 0.0) |
lv:cross-product
Cross product of vector1 and vector2
Take care of the order of vector1 and vector2, it affects the sign of the coordinates.
(lv:cross-product vector1 vector2 ) |
Arguments
Vector1 and vector2 are lists containing x,y,z coordinates.
Return Values
The cross product as a list of reals and or integers.
Examples
: (setq v1 (list 0.0 3 0)) (0.0 3 0) : (setq v2 (list 4 0 0)) (4 0 0) : (lv:cross-product v1 v2) (0 0.0 -12.0) |
lv:dot-product
Dot product of vector1 and vector2
(lv:dot-product vector1 vector2 ) |
Arguments
Vector1 and vector2 are lists containing x,y,z coordinates.
Return Values
The dot product as a real or integer.
Examples
: (setq v1 (list 1 3 0)) (1 3 0) : (setq v2 (list 4 0 0)) (4 0 0) : (lv:dot-product v1 v2) 4 |
lv:magnitude
Magnitude of vector vc
(lv:magnitude vc ) |
Arguments
Vector is a list containing x,y,z coordinates.
Return Values
The magnitude, vector length, as a real.
Examples
: (setq vc (list 0.0 4.0 3.0)) (0.0 4.0 3.0) : (lv:magnitude vc) 5.0 |
lv:unit-vector
Unit vector of a vector vc.
(lv:unit-vector vc ) |
Arguments
Vector is a list containing x,y,z coordinates.
Return Values
The unit vector of vector vc as a list of reals.
Examples
: (setq vc (list 4 0 0)) (4 0 0) : (lv:unit-vector vc) (1.0 0.0 0.0) |
lv:acute
Check if angle between vector a and b is acute, according to right hand rule.
See also (lv:arop …).
(lv:acute vector1 vector2 ) |
Arguments
Vector1 and vector2 are lists containing x,y,z coordinates.
Return Values
T (true) is returned if angles are obtuse, else nil is returned.
Examples
: (setq vector1 (list 1.0 0.0 0.0)) (1.0 0.0 0.0) : (setq vector2 (list 0.0 1.0 0.0)) (0.0 1.0 0.0) : (not (lv:acute vector1 vector2)) T |
lv:arop
Determine if angle between vector a and b is acute, right or obtuse (aro).
Function lv:arop returns string “a”, “r” and “o” for resp. an acute, right or obtuse angle between vector a and b.
(lv:arop vector1 vector2 ) |
Arguments
Vector1 and vector2 are lists containing x,y,z coordinates.
Return Values
Function lv:arop returns string “a”, “r” and “o” for resp. an acute, right or obtuse angle between vector a and b.
Examples
: (setq vector1 (list 1.0 0.0 0.0)) (1.0 0.0 0.0) : (setq vector2 (list 0.0 1.0 0.0)) (0.0 1.0 0.0) : (lv:arop vector1 vector2) "r" |
lv:vector-ang
Angle between vector1 and vector2.
Calculation is based on right hand rule and function acos.
(lv:vector-ang vector1 vector2 ) |
Arguments
Vector1 and vector2 are lists containing x,y,z coordinates.
Return Values
Angle in radians as a real.
Examples
: (setq vector1 (list 1.0 0.0 0.0)) (1.0 0.0 0.0) : (setq vector2 (list 0.0 1.0 0.0)) (0.0 1.0 0.0) : (/ (lv:vector-ang vector1 vector2) pi 0.5) 1.0 |
lv:ang2d
Projected angle of a vector as a list in radians, similar to function (angle ...)
.
lv:r2d
Translate a value of radians to degrees.
lv:d2r
Translate a value of degrees to radians.
lv:rot-pt
Rotation of point pt over angle ang
Angle ang in radians, sign is positive when counter clock wise. Point pt: only x and y are evaluated.
(lv:rot-pt pt ang ) |
Arguments
Point pt is a list containing x,y or x,y,z coordinates and Angle ang is a real or integer.
Return Values
A list containing resulting x,y coordinates
Examples
: (setq pt (list 6.5 0.0 0.0)) (6.5 0.0 0.0) : (setq ang pi) 3.14159265358979 : (lv:rot-pt pt ang) (-6.5 0.0) |
lv:rot-q-pt
Quadrant rotation of point or vector pt in steps (1, 2 or 3) of 90 degrees CCW.
Quadrant q as a number, Point pt: only x and y are evaluated.
(lv:rot-q-pt q pt ) |
Shortcuts without quadrant number argument are functions lv:rot-q1
, lv:rot-q2
and lv:rot-q3
. See examples.
Arguments
Point pt is a list containing x,y or x,y,z coordinates and quadrant q is an integer 1, 2 or 3, i.e. 1 is 90, 2 is 180 and 3 is 270 degrees CCW.
Return Values
A list containing resulting x,y coordinates.
Examples
: (setq pt '(1.0 2.0 3.0)) (1.0 2.0 3.0) : (setq q 3) 3 : (lv:rot-q-pt pt q) (2.0 -1.0) : (lv:rot-q3 pt) (2.0 -1.0) : (lv:rot-q1 pt) (-2.0 1.0) |
lv:bisect
Determine bissectrice point
Two lines, under a certain angle, share one endpoint C. The other endpoints are L1 and L2.
(lv:bisect C L1 L2 ) |
Arguments
Arguments are point lists, in order: corner point, point on leg 1 and point on leg 2.
Return Values
A list containing resulting x,y,z coordinates.
Examples
: (setq C '(2.0 1.0 0.0) L1 '(4.0 2.0 0.0) L2'(3.0 4.0 2.0)) (3.0 4.0 2.0) : (lv:bisect C L1 L2) (3.6259 2.7481 0.7481) |
Lisp code as one file
The following can be put in a file “lib-vector.lsp” and can be loaded by dragging or proper loading in BricsCAD (and AutoCAD). Functions start with “lv:”: Library Vector.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | ;; Vector mathematic functions. ;; License: Creative Commons By (NedCAD) and SA, Share Alike ;; Put all of this in a file called lib-vector.lsp in the search path or drag file to the dwg. ;; "How it works...": ;; See https://vanderworp.org/applied-mathematics-concerning-cad-faces/ or search the net for "lib-vector.lsp" ;; Functions: lv:function-name and lv: means Library Vector. (setq lib-vector-loaded T) ; for testing, (if (not lib-vector-loaded) (load "lib-vector.lsp")) ;; Adding functionality for AutoCAD: function acos and asin (if (not acos)(defun acos (r / ) (atan (sqrt (- 1 (expt r 2))) r))) (if (not asin)(defun asin (r / ) (atan r (sqrt (- 1 (expt r 2)))))) ;; Some additional variables pim2, pid2... (setq pim2 (* pi 2) fr2d (/ 180.0 pi) fd2r (/ 1 fr2d)) (mapcar '(lambda (a) (set (read (strcat "pid" (itoa a))) (/ pi a))) '(2 3 4 6 12)) ;; Functions... (defun lv:intp (a / ) (if (= (vl-symbol-name (type a)) "INT") a )) (defun lv:realp (a / ) (if (= (vl-symbol-name (type a)) "REAL") a )) (defun lv:dist3d (a b / ) (sqrt (apply '+ (mapcar '(lambda (k l) (expt (- l k) 2)) a b))) ) (defun lv:vector (a b / ) (mapcar '(lambda (k l) (- l k)) a b)) (defun lv:cross-product (a b / lsa lsb lsc lsd xa xb ya yb za zb) (setq lsa (list (setq ya (cadr a)) (setq za (caddr a)) (setq xa (car a))) lsb (list (setq zb (caddr b)) (setq xb (car b)) (setq yb (cadr b))) lsc (list yb zb xb) lsd (list za xa ya) ) (mapcar '(lambda (o p q r) (- (* o p) (* q r))) lsa lsb lsc lsd) ) (defun lv:dot-product (a b / ) (apply '+ (mapcar '(lambda (k l) (* k l)) a b))) (defun lv:magnitude (a / ) (sqrt (apply '+ (mapcar '(lambda (b) (expt b 2.0)) a)))) (defun lv:add (a b / ) (mapcar '(lambda (c d) (+ c d)) a b)) (defun lv:subtract (a b / ) (mapcar '(lambda (c d) (- c d)) a b)) (defun lv:multiply (a b / ) (mapcar '(lambda (c) (* c b)) a)) (defun lv:divide (a b / ) (mapcar '(lambda (c) (/ c b)) a)) (defun lv:minus (a / ) (mapcar '(lambda (b) (- b)) a)) (defun lv:unit-vector (a / ma) (setq ma (lv:magnitude a)) (mapcar '(lambda (b) (/ b ma)) a) ) (defun lv:acute (a b / ) (if (> (lv:dot-product a b) 0.0) T)) (defun lv:arop (a b / dp) (setq dp (lv:dot-product a b)) (cond ((> dp 0.0) "a") ((< dp 0.0) "o") ("r")) ) (defun lv:vector-ang (a b / ) (acos (/ (lv:dot-product a b) (* (lv:magnitude a) (lv:magnitude b)))) ) (defun lv:ang2d (a / ) (angle '(0 0) a)) (defun lv:r2d (a / ) (* a (/ 180.0 pi))) (defun lv:d2r (a / ) (* (/ a 180.0) pi)) (defun lv:rot-pt (a g / sg cg xa ya) (setq sg (sin g) cg (cos g) xa (car a) ya (cadr a)) (list (- (* xa cg) (* ya sg)) (+ (* ya cg) (* xa sg))) ) (defun lv:rot-q-pt (q xy / ) (if (<= 1 q 3) (cond ((= 1 q) (list (- (cadr xy)) (car xy))) ((= 2 q) (list (- (car xy)) (- (cadr xy)))) ((= 3 q) (list (cadr xy) (- (car xy)))) T nil ) ) ) (defun lv:rot-q1 (a / ) (list (- (cadr a)) (car a))) (defun lv:rot-q2 (a / ) (list (- (car a)) (- (cadr a)))) (defun lv:rot-q3 (a / ) (list (cadr a) (- (car a)))) (defun lv:bisect (a b c / v1 v2) (setq v1 (lv:subtract b a) v2 (lv:subtract c a)) (lv:add b (lv:multiply (lv:subtract v2 v1) (expt (+ 1 (/ (lv:magnitude v2) (lv:magnitude v1))) -1.0) ) ) ) (princ "\nLibrary Vector (lv:function-name) loaded. ") (princ) |