|
|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Design Decisions |
| Point Class API |
|
|
|
|
|
|
|
|
| Vector Class API |
|
|
|
|
|
|
|
|
| Implementation |
|
|
|
|
|
|
|
|
|
|
| References |
This algorithm is not really an algorithm, but a piece of code that has been missing from all the other algorithms. All of our algorithm implementations have started with the following comment.
// Assume that C++ classes are
already given for the objects:
// Point and Vector with
// coordinates {float x, y, z;}
// operators for:
...etc...
Although providing this was felt to be both application-specific and somewhat straightforward, many programmers have found this to be an obstacle. Indeed, a clean general-purpose implementation of these classes is not trivial, and some hard design decisions need to be made. In fact, while developing these classes, we changed the symbols we had previously suggested for overloading certain operators. For example the "*" operator for two vectors had denoted the cross product in past algorithms, but we now prefer it to be used for the dot product, and prefer the cross product operator to be "^" (the Grassmann "exterior product" wedge [Crowe, 1994]). As a result, we have done a complete redesign so that almost all point and vector formulas can be given by clean algebraic expressions. The advantage of this redesign outweighs the momentary confusion that may be created. Nevertheless, we hope to rectify this situation by refactoring all prior algorithms so that they use these new classes, and then linking all refactored algorithms to this page. Also, in time, we may expand and enhance the methods provided for these classes. If a significant change is made, we will start to use version numbers. Until then, this is the unnumbered version 0.
Of course, there are other definitions available for such classes, but we feel that the ones presented here are both more powerful and easier to use. Let us know what you think. We welcome all feedback concerning our implementation, whether a suggestion for an improvement, a problem (bug or deficiency) report, or just your opinion of its usefulness. For easy accessibility, you can download all source code in the file geometry.tar which contains these class definitions plus test programs.
Before describing the API for the new Point and Vector classes, we first summarize the rationale for a number of design decisions that were made, as follows.
We wanted to make the classes as easy to use and
remember as possible by minimizing the complexity of their API's. Our other
design decisions were guided by this overall goal. Note that this differs from
many other Point and Vector class definitions currently available.
Both Point and Vector classes are dimension-independent. We do not have separate classes for every specific dimension (like, Point2D, Point3D, etc). The advantages of this dim-free design are:
Code is easier to understand without multiple instances for each dimension. The dimension of a Point or Vector is given by a member variable that specifies the number of coordinates to use.
Lower dimensions are treated as embedded in higher dimensions by appending 0-valued coordinates. That is, a 2D point (x,y) is considered embedded in 3D as (x,y,0).
Using the dimension value and embedded dimensions, many
representations, operations, and algorithms can be defined generically for n
dimensions [Note: despite this, we have only implemented the Point and Vector
classes for dimensions 1, 2, and 3]. For example, vector sums, scalar operations,
and the dot product work in any dimension. Thus, a line can be represented
as a dimension-free affine combination of two points; namely,
P(t) = (1-t)*P0 + t*P1.
Further, algorithms can often be implemented to be dimension-free.
Point is a base class, and the Vector class is
derived from it. This is because many vector operations (like the products) do
not make sense for points, but all point operations apply also to vectors.
Although we try to be strict in defining
appropriate point and vector operations, there is one area of difficulty;
namely, points can only be added as affine sums, whereas any weighted sum works for
vectors. In the end, we decided to allow scalar multiplication and
addition of points, even though the result depends on the chosen coordinate frame of
reference. It's too bad that C++ operator overloading does not permit
detection of whether a sum is affine or not, and that's the rub. So, for
the convenience of being able to write concise algebraic expressions, we decided
to allow these
operations for points. Caveat programmer, for you are now responsible for
doing point arithmetic correctly! However, for the cautious, there is a "sum(m,c[i],P[i])" member
function to add the m scalar products c[i]*P[i]
for i=0,m-1;
and it checks whether the sum of the coefficients
c[i] is equal to one. If not, an error flag is set (but the
coordinate computation is done anyway, and returned). If desired, it is up
to the programmer to test the value of the error flag.
We wanted concise algebraic expressions for all common point and vector operations (see our summary of Basic Linear Algebra (Sunday, 2002)). Aside from the straightforward operations ("+", "-", etc), we decided to use:
"*" in all dimensions for both scalar multiplication ({int|double}*{Point|Vector}), and also for the dot product (Vector*Vector). Both the scalar and dot products are defined in all dimensions, and are frequently used operations, so we used the most familiar multiplication operator symbol.
"^" is the Grassmann "exterior product" wedge symbol (Crowe, 1994), which corresponds in 3D to the cross product for two vectors. Thus, we use "^" as the cross product symbol. Non-3D vectors are viewed as embedded in 3D when this operator is used. It would have been nice to have this symbol also represent the 2D exterior product, which is the same as the scalar "perp product" of (Hill, 1994). But then the "^" operator would have to return different object types for different dimensions, and C++ does not allow this. In any case, embedding vectors in 3D for applying "^" is a useful convention.
"|" is chosen to be the 2D vector perp product (since C++ has a limited choice of operator symbols).
"~" is,
similarly, the unary 2D vector perp
operator. Thus, v|w = (~v)*w, for 2D vectors.
Some error detection was done by setting a class variable "err" with an error code. This is probably not enough, and more error catching should be added.
Well, that is sufficient to indicate our approach, and to understand the rationale behind our definitions for the Point and Vector classes. We now describe the application programmer interface (API) for each class.
In describing the Point API, we use the following
notations:
1)
P,
P1, and
P2 are instances of a
Point
2)
P1 has coordinates
(x1,y1,z1)
3)
P2 has coordinates
(x2,y2,z2)
4) v is an instance of a
Vector, and has coordinates
(vx,vy,vz)
5) c denotes a scalar, and is either an integer,
a float, or
a double.
The Point class has the following member parameters [Note: we list private ones to aid understanding].
|
Scope |
Type |
Name |
Description |
| private | int | dimn | Dimension of the point. Valid range is 0<dimn<=3. |
| private | enum Error | err | Error flag.
Defined enum values are: Enot - No error (the default) Edim - A dimension error, usually for an invalid operation. Esum - An affine summation error. The coefficients of a weighted sum do not add to 1. |
| public | double | x, y, z | The coordinates of the point. Only use as many as the point's dimension "dimn", and set extra coordinates to zero. Thus, a 2D point (x,y) has dimn==2 and coordinates (x,y,0), and all three coordinates can be used in 3D operations (such as, the cross product). |
| Point P; | ||
| Creates a default 3D point (dimn=3) with x=y=z=0. Sets err=Enot. | ||
|
|
||
|
Point P(int a); Point P(double a); |
||
| Creates a 1D point (dimn=1) with x=a, y=z=0. Sets err=Enot. | ||
|
|
||
|
Point P(int a, int b); Point P(double a, double b); |
||
| Creates a 2D point (dimn=2) with x=a, y=b, z=0. Sets err=Enot. | ||
|
|
||
|
Point P(int a, int b, int c); Point P(double a, double b, double c); |
||
| Creates a 3D point (dimn=3) with x=a, y=b, z=c. Sets err=Enot. | ||
|
|
||
|
Point P(int n, int a[]); Point P(int n, double a[]); |
||
| Creates an n-dim point (dimn=n, 0<n<=3) with the first n coordinates set to a[0],...,a[n-1], and the remaining ones set to 0. Sets err=Enot. | ||
|
|
|
|
| Symbol |
Returns |
Format |
| >> | Point | cin >> P |
| Input and parse a formatted string into the parameters x,y,z of P. Currently accepted formats are: "(x)", "(x,y)", and "(x,y,z)", for which the dimension of P is also set to 1, 2, or 3 respectively. | ||
|
|
||
| << | String | cout << P |
| Output the parameters x,y,z of P as one of the formatted strings: "(x)", "(x,y)", or "(x,y,z)" according to whether the dimension of P is 1, 2, or 3. | ||
|
|
||
| = | Point | P1 = P2 |
| Copy all P2 parameter values to the corresponding P1 parameters. | ||
|
|
||
| == | int | P1 == P2 |
| Equality Test - parameters x,y,z and dimn are all equal (err is not tested). | ||
|
|
||
| != | int | P1 != P2 |
| Inequality Test - parameters x,y,z and dimn are not all equal (err is not tested). | ||
|
|
||
| - | Vector | P1 - P2 |
| Vector
difference between two points. The resulting vector has coordinates (x1-x2, y1-y2, z1-z2) and has the maximum dimension of the two points. |
||
|
|
||
| + | Point | P + v |
| Translate
point
P by vector
v. The resulting new point has coordinates (x+vx, y+vy, z+vz) and has the maximum dimension of P and v. |
||
|
|
||
| - | Point | P - v |
| Translate
point
P by vector
-v. The resulting new point has coordinates (x-vx, y-vy, z-vz) and has the maximum dimension of P and v. |
||
|
|
||
| += | Point | P += v |
| Translate
point
P by vector
v. The point P has its coordinates changed to (x+vx, y+vy, z+vz), and has the maximum dimension of P and v. |
||
|
|
||
| -= | Point | P -= v |
| Translate
point
P by vector
-v. The point P has its coordinates changed to (x-vx, y-vy, z-vz), and has the maximum dimension of P and v. |
||
|
|
||
| * | Point |
c * P P * c |
| Scalar
multiplication of point
P by scalar c. The resulting new point has coordinates (c*x, c*y, c*z). NOTE: this operation is only valid as part of an affine sum of points.¹ |
||
|
|
||
| / | Point | P / c |
| Scalar
division of point
P by scalar
c. The resulting new point has coordinates (x/c, y/c, z/c). NOTE: this operation is only valid as part of an affine sum of points.¹ |
||
|
|
||
| + | Point | P1 + P2 |
| Addition
of two points. The resulting new point has coordinates (x1+x2, y1+y2, z1+z2) and has the maximum dimension of the two points. NOTE: this operation is only valid as part of an affine sum of points.¹ |
¹ An "affine" sum of points is a weighted sum c1*P1+...+cm*Pm where the coefficients add to 1, namely c1+...+cm=1. An affine sum of points defines another point object, which is in a unique spatial location no matter which coordinate frame of reference is used. Thus, affine sums of points make geometric sense. But, non-affine sums of points do not make sense, and give different geometric results for different frames of reference. Unfortunately, C++ operator overloading does not allow one to check for this condition in an algebraic expression. The cautious programmer may want to use the "sum(...)" member function instead.
| int dim() | ||
| P.dim() returns the dimension of point P. | ||
|
|
||
| int setdim( int n) | ||
| P.setdim(n) sets the dimension of point P to n. The first n coordinates are unchanged, and the rest are set to 0. | ||
|
|
||
|
Point asum( int m, int c[], Point P[]) Point asum( int m, double c[], Point P[]) |
||
| asum(m, c[], P[]) computes and returns c[0]*P[0]+...+c[m-1]*P[m-1], the weighted sum of the points P[i], which is also a point when the sum of the coefficients c[0]+...+c[m-1] = 1, and the point sum is said to be "affine". When the sum is not affine, then the error flag err is set to Esum, although the weighted sum is computed and returned anyway. When needed, the programmer can and should check for the error. | ||
|
|
||
| double d( Point P1, Point P2) | ||
| d(P1,P2) returns the Euclidean distance between points P1 and P2. This is the square root of the sum of the squared coordinates of their difference vector (P1-P2). | ||
|
|
||
| double d2( Point P1, Point P2) | ||
| d2(P1,P2) returns the squared Euclidean distance between points P1 and P2. This is faster than d(P1,P2) since the square root is not computed. | ||
|
|
||
| double isLeft( Point P1, Point P2) | ||
| P.isLeft(P1,P2) returns >0, 0, or <0 for the point P being "left of", "on", or "right of" the directed line going from P1 to P2. This is only meaningful for 2D points, and err will be set to Edim if any of the points P, P1, or P2 does not have dimension 2. In any case, the determination is done based on only the (x,y) values of the points, that is, based on the projection of the points into the xy-plane. | ||
|
|
|
|
| void clerr() | ||
| P.clerr() clears the error flag err of P to Enot. | ||
|
|
||
| int geterr() | ||
| P.geterr() returns the current value of the error flag err for P. | ||
|
|
||
| char* errstr() | ||
| P.errstr() returns a string describing the current value of the error flag err for P. | ||
|
|
|
|
The Vector class is derived from the Point base class.
In describing the
Vector API, we use the following
notations:
1) v,
v1, and
v2 are instances of a
Vector
2) v has coordinates
(vx,vy,vz)
3)
v1 has coordinates
(vx1,vy1,vz1)
4)
v2 has coordinates
(vx2,vy2,vz2)
5) c denotes a scalar, and is either an integer,
a float, or
a double.
The Vector class inherits its parameters from the Point class parameters.
The Vector class inherits the Point class constructors. All Vector constructors are given in the following table.
| Vector v; | ||
| Creates a default 3D vector (dimn=3) with x=y=z=0. Sets err=Enot. | ||
|
|
||
|
Vector v(int a); Vector v(double a); |
||
| Creates a 1D vector (dimn=1) with x=a, y=z=0. Sets err=Enot. | ||
|
|
||
|
Vector v(int a, int b); Vector v(double a, double b); |
||
| Creates a 2D vector (dimn=2) with x=a, y=b, z=0. Sets err=Enot. | ||
|
|
||
|
Vector v(int a, int b, int c); Vector v(double a, double b, double c); |
||
| Creates a 3D vector (dimn=3) with x=a, y=b, z=c. Sets err=Enot. | ||
|
|
||
|
Vector v(int n, int a[]); Vector v(int n, double a[]); |
||
| Creates an n-dim vector (dimn=n, 0<n<=3) with the first n coordinates set to a[0],...,a[n-1], and the remaining ones set to 0. Sets err=Enot. | ||
|
|
|
|
Some Vector operators are inherited from the Point class operators, some are redefined, and some are new. All useful Vector operators are given in the following table.
| Symbol |
Returns |
Format |
| >> | Vector | cin >> v |
| Inherited from the Point class. | ||
|
|
||
| << | String | cout << v |
| Inherited from the Point class. | ||
|
|
||
| = | Vector | v1 = v2 |
| Inherited from the Point class. | ||
|
|
||
| == | int | v1 == v2 |
| Inherited from the Point class. | ||
|
|
||
| != | int | v1 != v2 |
| Inherited from the Point class. | ||
|
|
||
| - | Vector | -v |
| Unary
negative vector. The resulting new vector has coordinates (-vx, -vy, -vz). |
||
|
|
||
| ~ | Vector | ~v |
| Unary 2D
perp vector. The resulting new vector has coordinates (-vy, vx, vz). Typically used with 2D vectors, where it yields the leftward normal vector to v; namely, (-vy, vx). |
||
|
|
||
| + | Vector | v1 + v2 |
| Sum
of two vectors. The resulting new vector has coordinates (vx1+vx2, vy1+vy2, vz1+vz2) and has the maximum dimension of v1 and v2. |
||
|
|
||
| - | Vector | v1 - v2 |
| Difference
of two vectors. The resulting new vector has coordinates (vx1-vx2, vy1-vy2, vz1-vz2) and has the maximum dimension of v1 and v2. |
||
|
|
||
| += | Vector | v1 += v2 |
| Increment
vector
v1 by vector
v2. The vector v1 has its coordinates changed to (vx1+vx2, vy1+vy2, vz1+vz2), and has the maximum dimension of v1 and v2. |
||
|
|
||
| -= | Vector | v1 -= v2 |
| Decrement
vector
v1 by vector
v2. The vector v1 has its coordinates changed to (vx1-vx2, vy1-vy2, vz1-vz2), and has the maximum dimension of v1 and v2. |
||
|
|
||
| * | Vector |
c * v v * c |
| Scalar
multiplication of vector v by
scalar c. The resulting new vector has coordinates (c*vx, c*vy, c*vz). |
||
|
|
||
| / | Vector | v / c |
| Scalar
division of vector v by scalar c. The resulting new vector has coordinates (vx/c, vy/c, vz/c). |
||
|
|
||
| * | double | v1 * v2 |
| Dot product
of two vectors. The resulting scalar value = vx1*vx2 + vy1*vy2 + vz1*vz2. |
||
|
|
||
| ^ | Vector | v1 ^ v2 |
| 3D cross product
of vectors
v1 and
v2. The resulting new vector has coordinates = (vy1*vz2-vz1*vy2, vz1*vx2-vx1*vz2, vx1*vy2-vy1*vx2). |
||
|
|
||
| | | double | v1 | v2 |
| 2D perp product
of vectors
v1 and
v2. The resulting scalar value = vx1*vy2 - vy1*vx2. Mostly used for 2D vectors for which this is the Grassmann exterior product. |
||
|
|
||
| *= | Vector | v *= c |
| Scalar
multiplication of vector v by
scalar c. The vector v has its coordinates changed to (c*vx, c*vy, c*vz). |
||
|
|
||
| /= | Vector | v /= c |
| Scalar
division of vector v by scalar c. The vector v has its coordinates changed to (vx/c, vy/c, vz/c). |
||
|
|
||
| ^= | Vector | v1 ^= v2 |
| 3D cross product
of vectors
v1 and
v2. The vector v1 has its coordinates changed to (vy1*vz2-vz1*vy2, vz1*vx2-vx1*vz2, vx1*vy2-vy1*vx2). |
The
Vector class inherits the
Point class methods.
Additional
Vector class methods are as follows.
| double len() | ||
| v.len() returns the Euclidean length of vector v. This is the square root of the sum of its squared coordinates. | ||
|
|
||
| double len2() | ||
| v.len2() returns the squared Euclidean length of vector v. This is faster than len() since the square root is not computed. | ||
|
|
||
| Vector normalize() | ||
| v.normalize() results in the vector v being positively scaled to a unit vector. The vector v has its coordinates changed to those of v/v.len(). | ||
|
|
||
|
Vector sum( int m, int c[], Vector v[]) Vector sum( int m, double c[], Vector v[]) |
||
| sum(m, c[], v[]) computes and returns c[0]*v[0]+...+c[m-1]*v[m-1], the weighted sum of the vectors v[i], which is always a vector. | ||
|
|
|
|
The "C++" implementations of the Point and Vector classes is contained in the files:
common.h
- common definition header file
point.h - Point class definition
point.c - Point class methods
vector.h - Vector class definition
vector.c - Vector class methods
DOWNLOAD: These files (plus test programs and a Makefile) are available in a tar file: geometry.tar.
NOTE: All source code is copyrighted as follows.
//
Copyright 2003, softSurfer (www.softsurfer.com)
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// SoftSurfer makes no warranty for this code, and cannot be held
// liable for any real or imagined damage resulting from its use.
// Users of this code must verify correctness for their application.
//--------------------------------------------------------------------
// common.h - common definition header file
//--------------------------------------------------------------------
#ifndef SS_Common_H #define SS_Common_H
#include <iostream.h>
enum {FALSE=0, TRUE=1, ERROR=(-1)};
// Error codes
enum Error {
Enot, // no error
Edim, // error: dim of point invalid for operation
Esum // error: sum not affine (cooefs add to 1)
};
// utility macros #define abs(x) ((x) >= 0 ? x : -(x)); #define min(x,y) ((x) < (y) ? (x) : (y)); #define max(x,y) ((x) > (y) ? (x) : (y));
#endif SS_Common_H
//--------------------------------------------------------------------
// point.h - Point class definition
//--------------------------------------------------------------------
#ifndef SS_Point_H #define SS_Point_H
#include "common.h"
class Point {
friend class Vector;
private:
int dimn; // # coords (1, 2, or 3 max here)
Error err; // error indicator
public:
double x, y, z; // z=0 for 2D, y=z=0 for 1D
//----------------------------------------------------------
// Lots of Constructors (add more as needed)
Point() { dimn=3; x=y=z=0; err=Enot; }
// 1D Point
Point( int a) {
dimn=1; x=a; y=z=0; err=Enot; }
Point( double a) {
dimn=1; x=a; y=z=0; err=Enot; }
// 2D Point
Point( int a, int b) {
dimn=2; x=a; y=b; z=0; err=Enot; }
Point( double a, double b) {
dimn=2; x=a; y=b; z=0; err=Enot; }
// 3D Point
Point( int a, int b, int c) {
dimn=3; x=a; y=b; z=c; err=Enot; }
Point( double a, double b, double c) {
dimn=3; x=a; y=b; z=c; err=Enot; }
// n-dim Point
Point( int n, int a[]);
Point( int n, double a[]);
// Destructor
~Point() {};
//---------------------------------------------------------- // Input/Output streams friend istream& operator>>( istream&, Point&); friend ostream& operator<<( ostream&, Point);
//----------------------------------------------------------
// Assignment "=": use the default to copy all members
int dim() { return dimn; } // get dimension
int setdim( int); // set new dimension
//---------------------------------------------------------- // Comparison (dimension must match, or not) int operator==( Point); int operator!=( Point);
//---------------------------------------------------------- // Point and Vector Operations (always valid) Vector operator-( Point); // Vector difference Point operator+( Vector); // +translate Point operator-( Vector); // -translate Point& operator+=( Vector); // inc translate Point& operator-=( Vector); // dec translate
//---------------------------------------------------------- // Point Scalar Operations (convenient but often illegal) // using any type of scalar (int, float, or double) // are not valid for points in general, // unless they are 'affine' as coeffs of // a sum in which all the coeffs add to 1, // such as: the sum (a*P + b*Q) with (a+b == 1). // The programmer must enforce this (if they want to).
// Scalar Multiplication friend Point operator*( int, Point); friend Point operator*( double, Point); friend Point operator*( Point, int); friend Point operator*( Point, double); // Scalar Division friend Point operator/( Point, int); friend Point operator/( Point, double);
//---------------------------------------------------------- // Point Addition (also convenient but often illegal) // is not valid unless part of an affine sum. // The programmer must enforce this (if they want to). friend Point operator+( Point, Point); // add points
// Affine Sum // Returns weighted sum, even when not affine, but... // Tests if coeffs add to 1. If not, sets: err = Esum. friend Point asum( int, int[], Point[]); friend Point asum( int, double[], Point[]);
//---------------------------------------------------------- // Point Relations friend double d( Point, Point); // Distance friend double d2( Point, Point); // Distance^2 double isLeft( Point, Point); // 2D only
//----------------------------------------------------------
// Error Handling
void clerr() { err = Enot;} // clear error
int geterr() { return err;} // get error
char* errstr(); // return error string
};
#endif SS_Point_H
//--------------------------------------------------------------------
// vector.h - Vector class definition
//--------------------------------------------------------------------
#ifndef SS_Vector_H #define SS_Vector_H
#include "common.h"
class Vector : public Point { public: // Constructors same as Point class Vector() : Point() {}; Vector( int a) : Point(a) {}; Vector( double a) : Point(a) {}; Vector( int a, int b) : Point(a,b) {}; Vector( double a, double b) : Point(a,b) {}; Vector( int a, int b, int c) : Point(a,b,c) {}; Vector( double a, double b, double c) : Point(a,b,c) {}; Vector( int n, int a[]) : Point(n,a) {}; Vector( int n, double a[]) : Point(n,a) {}; ~Vector() {};
//---------------------------------------------------------- // IO streams and Comparisons: inherit from Point class
//---------------------------------------------------------- // Vector Unary Operations Vector operator-(); // unary minus Vector operator~(); // unary 2D perp operator
//---------------------------------------------------------- // Scalar Multiplication friend Vector operator*( int, Vector); friend Vector operator*( double, Vector); friend Vector operator*( Vector, int); friend Vector operator*( Vector, double); // Scalar Division friend Vector operator/( Vector, int); friend Vector operator/( Vector, double);
//---------------------------------------------------------- // Vector Arithmetic Operations Vector operator+( Vector); // vector add Vector operator-( Vector); // vector subtract double operator*( Vector); // inner dot product double operator|( Vector); // 2D exterior perp product Vector operator^( Vector); // 3D exterior cross product
Vector& operator*=( double); // vector scalar mult Vector& operator/=( double); // vector scalar div Vector& operator+=( Vector); // vector increment Vector& operator-=( Vector); // vector decrement Vector& operator^=( Vector); // 3D exterior cross product
//----------------------------------------------------------
// Vector Properties
double len() { // vector length
return sqrt(x*x + y*y + z*z);
}
double len2() { // vector length squared (faster)
return (x*x + y*y + z*z);
}
//---------------------------------------------------------- // Special Operations void normalize(); // convert vector to unit length friend Vector sum( int, int[], Vector[]); // vector sum friend Vector sum( int, double[], Vector[]); // vector sum }; #endif SS_Vector_H
Michael Crowe, A History of Vector Analysis, (1967, revised reprint 1994)
Francis Hill, "The Pleasures of 'Perp Dot'
Products" in
Graphics Gems IV (1994)
[Note: the first critical definition has a typo, and should be: a^
= (-ay, ax).]
Dan Sunday, "Basic Linear Algebra", softsurfer.com (2002)
|
Copyright ©
2001-2006 softSurfer. All rights reserved. |