2008-03-27 09:53:51 +00:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
2008-06-25 05:14:49 +00:00
|
|
|
void MakePathRelative(char *basep, char *pathp)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *p;
|
|
|
|
char base[MAX_PATH], path[MAX_PATH], out[MAX_PATH];
|
|
|
|
|
|
|
|
// Convert everything to lowercase
|
|
|
|
p = basep;
|
|
|
|
for(i = 0; *p; p++) {
|
|
|
|
base[i++] = tolower(*p);
|
|
|
|
}
|
|
|
|
base[i++] = '\0';
|
|
|
|
p = pathp;
|
|
|
|
for(i = 0; *p; p++) {
|
|
|
|
path[i++] = tolower(*p);
|
|
|
|
}
|
|
|
|
path[i++] = '\0';
|
|
|
|
|
|
|
|
// Find the length of the common prefix
|
|
|
|
int com;
|
|
|
|
for(com = 0; base[com] && path[com]; com++) {
|
|
|
|
if(base[com] != path[com]) break;
|
|
|
|
}
|
|
|
|
if(!(base[com] && path[com])) return; // weird, prefix is entire string
|
|
|
|
if(com == 0) return; // maybe on different drive letters?
|
|
|
|
|
2008-07-17 05:29:10 +00:00
|
|
|
// Align the common prefix to the nearest slash; otherwise would break
|
|
|
|
// on subdirectories or filenames that shared a prefix.
|
|
|
|
while(com >= 1 && base[com-1] != '/' && base[com-1] != '\\') {
|
|
|
|
com--;
|
|
|
|
}
|
|
|
|
if(com == 0) return;
|
|
|
|
|
2008-06-25 05:14:49 +00:00
|
|
|
int sections = 0;
|
|
|
|
int secLen = 0, secStart = 0;
|
|
|
|
for(i = com; base[i]; i++) {
|
|
|
|
if(base[i] == '/' || base[i] == '\\') {
|
|
|
|
if(secLen == 2 && memcmp(base+secStart, "..", 2)==0) return;
|
|
|
|
if(secLen == 1 && memcmp(base+secStart, ".", 1)==0) return;
|
|
|
|
|
|
|
|
sections++;
|
|
|
|
secLen = 0;
|
|
|
|
secStart = i+1;
|
|
|
|
} else {
|
|
|
|
secLen++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For every directory in the prefix of the base, we must go down a
|
|
|
|
// directory in the relative path name
|
|
|
|
strcpy(out, "");
|
|
|
|
for(i = 0; i < sections; i++) {
|
|
|
|
strcat(out, "../");
|
|
|
|
}
|
|
|
|
strcat(out, path+com);
|
|
|
|
|
|
|
|
strcpy(pathp, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakePathAbsolute(char *basep, char *pathp) {
|
|
|
|
char out[MAX_PATH];
|
|
|
|
strcpy(out, basep);
|
|
|
|
|
|
|
|
// Chop off the filename
|
|
|
|
int i;
|
|
|
|
for(i = strlen(out) - 1; i >= 0; i--) {
|
|
|
|
if(out[i] == '\\' || out[i] == '/') break;
|
|
|
|
}
|
|
|
|
if(i < 0) return; // base is not an absolute path, or something?
|
|
|
|
out[i+1] = '\0';
|
|
|
|
|
|
|
|
strcat(out, pathp);
|
|
|
|
GetAbsoluteFilename(out);
|
|
|
|
|
|
|
|
strcpy(pathp, out);
|
|
|
|
}
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
|
|
|
|
double a21, double a22, double a23, double a24,
|
|
|
|
double a31, double a32, double a33, double a34,
|
|
|
|
double a41, double a42, double a43, double a44)
|
|
|
|
{
|
|
|
|
mat[ 0] = a11;
|
|
|
|
mat[ 1] = a21;
|
|
|
|
mat[ 2] = a31;
|
|
|
|
mat[ 3] = a41;
|
|
|
|
mat[ 4] = a12;
|
|
|
|
mat[ 5] = a22;
|
|
|
|
mat[ 6] = a32;
|
|
|
|
mat[ 7] = a42;
|
|
|
|
mat[ 8] = a13;
|
|
|
|
mat[ 9] = a23;
|
|
|
|
mat[10] = a33;
|
|
|
|
mat[11] = a43;
|
|
|
|
mat[12] = a14;
|
|
|
|
mat[13] = a24;
|
|
|
|
mat[14] = a34;
|
|
|
|
mat[15] = a44;
|
|
|
|
}
|
|
|
|
|
2009-03-15 23:04:45 +00:00
|
|
|
const Quaternion Quaternion::IDENTITY = { 1, 0, 0, 0 };
|
|
|
|
|
2008-06-01 08:45:11 +00:00
|
|
|
Quaternion Quaternion::From(double w, double vx, double vy, double vz) {
|
2008-04-18 11:11:48 +00:00
|
|
|
Quaternion q;
|
2008-05-05 06:18:01 +00:00
|
|
|
q.w = w;
|
|
|
|
q.vx = vx;
|
|
|
|
q.vy = vy;
|
|
|
|
q.vz = vz;
|
2008-04-18 11:11:48 +00:00
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2008-06-02 03:31:37 +00:00
|
|
|
Quaternion Quaternion::From(hParam w, hParam vx, hParam vy, hParam vz) {
|
|
|
|
Quaternion q;
|
2009-04-19 05:53:16 +00:00
|
|
|
q.w = SK.GetParam(w )->val;
|
|
|
|
q.vx = SK.GetParam(vx)->val;
|
|
|
|
q.vy = SK.GetParam(vy)->val;
|
|
|
|
q.vz = SK.GetParam(vz)->val;
|
2008-06-02 03:31:37 +00:00
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2009-04-29 02:42:44 +00:00
|
|
|
Quaternion Quaternion::From(Vector axis, double dtheta) {
|
|
|
|
Quaternion q;
|
|
|
|
double c = cos(dtheta / 2), s = sin(dtheta / 2);
|
|
|
|
axis = axis.WithMagnitude(s);
|
|
|
|
q.w = c;
|
|
|
|
q.vx = axis.x;
|
|
|
|
q.vy = axis.y;
|
|
|
|
q.vz = axis.z;
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2008-06-01 08:45:11 +00:00
|
|
|
Quaternion Quaternion::From(Vector u, Vector v)
|
2008-04-18 11:11:48 +00:00
|
|
|
{
|
|
|
|
Vector n = u.Cross(v);
|
|
|
|
|
|
|
|
Quaternion q;
|
2008-05-03 03:33:35 +00:00
|
|
|
double s, tr = 1 + u.x + v.y + n.z;
|
|
|
|
if(tr > 1e-4) {
|
|
|
|
s = 2*sqrt(tr);
|
2008-05-05 06:18:01 +00:00
|
|
|
q.w = s/4;
|
|
|
|
q.vx = (v.z - n.y)/s;
|
|
|
|
q.vy = (n.x - u.z)/s;
|
|
|
|
q.vz = (u.y - v.x)/s;
|
2008-05-03 03:33:35 +00:00
|
|
|
} else {
|
2008-02-10 13:34:32 +00:00
|
|
|
if(u.x > v.y && u.x > n.z) {
|
2008-05-03 03:33:35 +00:00
|
|
|
s = 2*sqrt(1 + u.x - v.y - n.z);
|
2008-05-05 06:18:01 +00:00
|
|
|
q.w = (v.z - n.y)/s;
|
|
|
|
q.vx = s/4;
|
|
|
|
q.vy = (u.y + v.x)/s;
|
|
|
|
q.vz = (n.x + u.z)/s;
|
2008-02-10 13:34:32 +00:00
|
|
|
} else if(v.y > n.z) {
|
2008-05-03 03:33:35 +00:00
|
|
|
s = 2*sqrt(1 - u.x + v.y - n.z);
|
2008-05-05 06:18:01 +00:00
|
|
|
q.w = (n.x - u.z)/s;
|
|
|
|
q.vx = (u.y + v.x)/s;
|
|
|
|
q.vy = s/4;
|
|
|
|
q.vz = (v.z + n.y)/s;
|
2008-02-10 13:34:32 +00:00
|
|
|
} else {
|
2008-05-03 03:33:35 +00:00
|
|
|
s = 2*sqrt(1 - u.x - v.y + n.z);
|
2008-05-05 06:18:01 +00:00
|
|
|
q.w = (u.y - v.x)/s;
|
|
|
|
q.vx = (n.x + u.z)/s;
|
|
|
|
q.vy = (v.z + n.y)/s;
|
|
|
|
q.vz = s/4;
|
2008-02-10 13:34:32 +00:00
|
|
|
}
|
2008-05-03 03:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return q.WithMagnitude(1);
|
2008-04-18 11:11:48 +00:00
|
|
|
}
|
|
|
|
|
2008-05-05 06:18:01 +00:00
|
|
|
Quaternion Quaternion::Plus(Quaternion b) {
|
2008-04-18 11:11:48 +00:00
|
|
|
Quaternion q;
|
2008-05-05 06:18:01 +00:00
|
|
|
q.w = w + b.w;
|
|
|
|
q.vx = vx + b.vx;
|
|
|
|
q.vy = vy + b.vy;
|
|
|
|
q.vz = vz + b.vz;
|
2008-04-18 11:11:48 +00:00
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2008-05-05 06:18:01 +00:00
|
|
|
Quaternion Quaternion::Minus(Quaternion b) {
|
2008-04-18 11:11:48 +00:00
|
|
|
Quaternion q;
|
2008-05-05 06:18:01 +00:00
|
|
|
q.w = w - b.w;
|
|
|
|
q.vx = vx - b.vx;
|
|
|
|
q.vy = vy - b.vy;
|
|
|
|
q.vz = vz - b.vz;
|
2008-04-18 11:11:48 +00:00
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion Quaternion::ScaledBy(double s) {
|
|
|
|
Quaternion q;
|
2008-05-05 06:18:01 +00:00
|
|
|
q.w = w*s;
|
|
|
|
q.vx = vx*s;
|
|
|
|
q.vy = vy*s;
|
|
|
|
q.vz = vz*s;
|
2008-04-18 11:11:48 +00:00
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
double Quaternion::Magnitude(void) {
|
2008-05-05 06:18:01 +00:00
|
|
|
return sqrt(w*w + vx*vx + vy*vy + vz*vz);
|
2008-04-09 08:39:01 +00:00
|
|
|
}
|
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
Quaternion Quaternion::WithMagnitude(double s) {
|
|
|
|
return ScaledBy(s/Magnitude());
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector Quaternion::RotationU(void) {
|
2008-04-09 08:39:01 +00:00
|
|
|
Vector v;
|
2008-05-05 06:18:01 +00:00
|
|
|
v.x = w*w + vx*vx - vy*vy - vz*vz;
|
|
|
|
v.y = 2*w *vz + 2*vx*vy;
|
|
|
|
v.z = 2*vx*vz - 2*w *vy;
|
2008-04-09 08:39:01 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
Vector Quaternion::RotationV(void) {
|
2008-04-09 08:39:01 +00:00
|
|
|
Vector v;
|
2008-05-05 06:18:01 +00:00
|
|
|
v.x = 2*vx*vy - 2*w*vz;
|
|
|
|
v.y = w*w - vx*vx + vy*vy - vz*vz;
|
|
|
|
v.z = 2*w*vx + 2*vy*vz;
|
2008-04-09 08:39:01 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2008-05-05 06:18:01 +00:00
|
|
|
Vector Quaternion::RotationN(void) {
|
2008-06-06 07:50:08 +00:00
|
|
|
Vector v;
|
|
|
|
v.x = 2*w*vy + 2*vx*vz;
|
|
|
|
v.y = 2*vy*vz - 2*w*vx;
|
|
|
|
v.z = w*w - vx*vx - vy*vy + vz*vz;
|
|
|
|
return v;
|
2008-05-05 06:18:01 +00:00
|
|
|
}
|
|
|
|
|
2008-05-11 06:09:46 +00:00
|
|
|
Vector Quaternion::Rotate(Vector p) {
|
|
|
|
// Express the point in the new basis
|
|
|
|
return (RotationU().ScaledBy(p.x)).Plus(
|
|
|
|
RotationV().ScaledBy(p.y)).Plus(
|
|
|
|
RotationN().ScaledBy(p.z));
|
|
|
|
}
|
|
|
|
|
2008-05-14 14:23:58 +00:00
|
|
|
Quaternion Quaternion::Inverse(void) {
|
|
|
|
Quaternion r;
|
|
|
|
r.w = w;
|
|
|
|
r.vx = -vx;
|
|
|
|
r.vy = -vy;
|
|
|
|
r.vz = -vz;
|
|
|
|
return r.WithMagnitude(1); // not that the normalize should be reqd
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion Quaternion::ToThe(double p) {
|
2008-07-02 09:52:32 +00:00
|
|
|
// Avoid division by zero, or arccos of something not in its domain
|
|
|
|
if(w >= (1 - 1e-6)) {
|
|
|
|
return From(1, 0, 0, 0);
|
|
|
|
} else if(w <= (-1 + 1e-6)) {
|
|
|
|
return From(-1, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
2008-05-14 14:23:58 +00:00
|
|
|
Quaternion r;
|
2008-06-01 08:45:11 +00:00
|
|
|
Vector axis = Vector::From(vx, vy, vz);
|
2008-05-14 14:23:58 +00:00
|
|
|
double theta = acos(w); // okay, since magnitude is 1, so -1 <= w <= 1
|
|
|
|
theta *= p;
|
|
|
|
r.w = cos(theta);
|
|
|
|
axis = axis.WithMagnitude(sin(theta));
|
|
|
|
r.vx = axis.x;
|
|
|
|
r.vy = axis.y;
|
|
|
|
r.vz = axis.z;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-05-11 06:09:46 +00:00
|
|
|
Quaternion Quaternion::Times(Quaternion b) {
|
|
|
|
double sa = w, sb = b.w;
|
|
|
|
Vector va = { vx, vy, vz };
|
|
|
|
Vector vb = { b.vx, b.vy, b.vz };
|
|
|
|
|
|
|
|
Quaternion r;
|
|
|
|
r.w = sa*sb - va.Dot(vb);
|
|
|
|
Vector vr = vb.ScaledBy(sa).Plus(
|
|
|
|
va.ScaledBy(sb).Plus(
|
|
|
|
va.Cross(vb)));
|
|
|
|
r.vx = vr.x;
|
|
|
|
r.vy = vr.y;
|
|
|
|
r.vz = vr.z;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
|
2008-06-01 08:45:11 +00:00
|
|
|
Vector Vector::From(double x, double y, double z) {
|
2008-04-18 11:11:48 +00:00
|
|
|
Vector v;
|
|
|
|
v.x = x; v.y = y; v.z = z;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2008-06-01 08:45:11 +00:00
|
|
|
Vector Vector::From(hParam x, hParam y, hParam z) {
|
2008-06-01 08:29:59 +00:00
|
|
|
Vector v;
|
2009-04-19 05:53:16 +00:00
|
|
|
v.x = SK.GetParam(x)->val;
|
|
|
|
v.y = SK.GetParam(y)->val;
|
|
|
|
v.z = SK.GetParam(z)->val;
|
2008-06-01 08:29:59 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2008-07-06 07:56:24 +00:00
|
|
|
double Vector::Element(int i) {
|
|
|
|
switch(i) {
|
|
|
|
case 0: return x;
|
|
|
|
case 1: return y;
|
|
|
|
case 2: return z;
|
|
|
|
default: oops();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-09 05:19:54 +00:00
|
|
|
bool Vector::Equals(Vector v, double tol) {
|
2008-07-06 07:56:24 +00:00
|
|
|
// Quick axis-aligned tests before going further
|
2008-09-09 05:19:54 +00:00
|
|
|
double dx = v.x - x; if(dx < -tol || dx > tol) return false;
|
|
|
|
double dy = v.y - y; if(dy < -tol || dy > tol) return false;
|
|
|
|
double dz = v.z - z; if(dz < -tol || dz > tol) return false;
|
2008-07-06 07:56:24 +00:00
|
|
|
|
2008-09-09 05:19:54 +00:00
|
|
|
return (this->Minus(v)).MagSquared() < tol*tol;
|
2008-07-06 07:56:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Vector::EqualsExactly(Vector v) {
|
|
|
|
return (x == v.x) &&
|
|
|
|
(y == v.y) &&
|
|
|
|
(z == v.z);
|
2008-04-25 07:04:09 +00:00
|
|
|
}
|
2008-04-18 11:11:48 +00:00
|
|
|
|
2008-04-01 10:48:44 +00:00
|
|
|
Vector Vector::Plus(Vector b) {
|
|
|
|
Vector r;
|
|
|
|
|
|
|
|
r.x = x + b.x;
|
|
|
|
r.y = y + b.y;
|
|
|
|
r.z = z + b.z;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector Vector::Minus(Vector b) {
|
|
|
|
Vector r;
|
|
|
|
|
|
|
|
r.x = x - b.x;
|
|
|
|
r.y = y - b.y;
|
|
|
|
r.z = z - b.z;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector Vector::Negated(void) {
|
|
|
|
Vector r;
|
|
|
|
|
|
|
|
r.x = -x;
|
|
|
|
r.y = -y;
|
|
|
|
r.z = -z;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2008-03-27 09:53:51 +00:00
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
Vector Vector::Cross(Vector b) {
|
2008-03-27 09:53:51 +00:00
|
|
|
Vector r;
|
|
|
|
|
|
|
|
r.x = -(z*b.y) + (y*b.z);
|
|
|
|
r.y = (z*b.x) - (x*b.z);
|
|
|
|
r.z = -(y*b.x) + (x*b.y);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
double Vector::Dot(Vector b) {
|
2008-03-27 09:53:51 +00:00
|
|
|
return (x*b.x + y*b.y + z*b.z);
|
|
|
|
}
|
|
|
|
|
2008-04-01 10:48:44 +00:00
|
|
|
Vector Vector::Normal(int which) {
|
|
|
|
Vector n;
|
|
|
|
|
|
|
|
// Arbitrarily choose one vector that's normal to us, pivoting
|
|
|
|
// appropriately.
|
|
|
|
double xa = fabs(x), ya = fabs(y), za = fabs(z);
|
2008-07-08 06:30:13 +00:00
|
|
|
if(this->Equals(Vector::From(0, 0, 1))) {
|
|
|
|
// Make DXFs exported in the XY plane work nicely...
|
|
|
|
n = Vector::From(1, 0, 0);
|
|
|
|
} else if(xa < ya && xa < za) {
|
2008-04-01 10:48:44 +00:00
|
|
|
n.x = 0;
|
|
|
|
n.y = z;
|
|
|
|
n.z = -y;
|
2008-07-08 06:30:13 +00:00
|
|
|
} else if(ya < za) {
|
|
|
|
n.x = -z;
|
2008-04-01 10:48:44 +00:00
|
|
|
n.y = 0;
|
|
|
|
n.z = x;
|
2008-07-08 06:30:13 +00:00
|
|
|
} else {
|
2008-04-01 10:48:44 +00:00
|
|
|
n.x = y;
|
|
|
|
n.y = -x;
|
2008-07-08 06:30:13 +00:00
|
|
|
n.z = 0;
|
|
|
|
}
|
2008-04-01 10:48:44 +00:00
|
|
|
|
|
|
|
if(which == 0) {
|
|
|
|
// That's the vector we return.
|
|
|
|
} else if(which == 1) {
|
|
|
|
n = this->Cross(n);
|
2008-05-05 06:18:01 +00:00
|
|
|
} else oops();
|
2008-04-01 10:48:44 +00:00
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
n = n.WithMagnitude(1);
|
2008-04-01 10:48:44 +00:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2008-06-06 11:35:28 +00:00
|
|
|
Vector Vector::RotatedAbout(Vector orig, Vector axis, double theta) {
|
|
|
|
Vector r = this->Minus(orig);
|
|
|
|
r = r.RotatedAbout(axis, theta);
|
|
|
|
return r.Plus(orig);
|
|
|
|
}
|
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
Vector Vector::RotatedAbout(Vector axis, double theta) {
|
2008-03-27 09:53:51 +00:00
|
|
|
double c = cos(theta);
|
|
|
|
double s = sin(theta);
|
|
|
|
|
2008-05-03 03:33:35 +00:00
|
|
|
axis = axis.WithMagnitude(1);
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
Vector r;
|
|
|
|
|
|
|
|
r.x = (x)*(c + (1 - c)*(axis.x)*(axis.x)) +
|
|
|
|
(y)*((1 - c)*(axis.x)*(axis.y) - s*(axis.z)) +
|
|
|
|
(z)*((1 - c)*(axis.x)*(axis.z) + s*(axis.y));
|
|
|
|
|
|
|
|
r.y = (x)*((1 - c)*(axis.y)*(axis.x) + s*(axis.z)) +
|
|
|
|
(y)*(c + (1 - c)*(axis.y)*(axis.y)) +
|
|
|
|
(z)*((1 - c)*(axis.y)*(axis.z) - s*(axis.x));
|
|
|
|
|
|
|
|
r.z = (x)*((1 - c)*(axis.z)*(axis.x) - s*(axis.y)) +
|
|
|
|
(y)*((1 - c)*(axis.z)*(axis.y) + s*(axis.x)) +
|
|
|
|
(z)*(c + (1 - c)*(axis.z)*(axis.z));
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-06-21 10:18:20 +00:00
|
|
|
Vector Vector::DotInToCsys(Vector u, Vector v, Vector n) {
|
|
|
|
Vector r = {
|
|
|
|
this->Dot(u),
|
|
|
|
this->Dot(v),
|
|
|
|
this->Dot(n)
|
|
|
|
};
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector Vector::ScaleOutOfCsys(Vector u, Vector v, Vector n) {
|
|
|
|
Vector r = u.ScaledBy(x).Plus(
|
|
|
|
v.ScaledBy(y).Plus(
|
|
|
|
n.ScaledBy(z)));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-03-17 16:33:46 +00:00
|
|
|
Vector Vector::InPerspective(Vector u, Vector v, Vector n,
|
|
|
|
Vector origin, double cameraTan)
|
|
|
|
{
|
|
|
|
Vector r = this->Minus(origin);
|
|
|
|
r = r.DotInToCsys(u, v, n);
|
|
|
|
// yes, minus; we are assuming a csys where u cross v equals n, backwards
|
|
|
|
// from the display stuff
|
|
|
|
double w = (1 - r.z*cameraTan);
|
|
|
|
r = r.ScaledBy(1/w);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-06-06 11:35:28 +00:00
|
|
|
double Vector::DistanceToLine(Vector p0, Vector dp) {
|
|
|
|
double m = dp.Magnitude();
|
|
|
|
return ((this->Minus(p0)).Cross(dp)).Magnitude() / m;
|
|
|
|
}
|
|
|
|
|
2008-07-06 07:56:24 +00:00
|
|
|
bool Vector::OnLineSegment(Vector a, Vector b) {
|
|
|
|
Vector d = b.Minus(a);
|
|
|
|
|
|
|
|
double m = d.MagSquared();
|
|
|
|
double distsq = ((this->Minus(a)).Cross(d)).MagSquared() / m;
|
|
|
|
|
|
|
|
if(distsq >= LENGTH_EPS*LENGTH_EPS) return false;
|
|
|
|
|
|
|
|
double t = (this->Minus(a)).DivPivoting(d);
|
|
|
|
// On-endpoint must be tested for separately.
|
|
|
|
if(t < 0 || t > 1) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-06-14 11:16:14 +00:00
|
|
|
Vector Vector::ClosestPointOnLine(Vector p0, Vector dp) {
|
|
|
|
dp = dp.WithMagnitude(1);
|
|
|
|
// this, p0, and (p0+dp) define a plane; the min distance is in
|
|
|
|
// that plane, so calculate its normal
|
|
|
|
Vector pn = (this->Minus(p0)).Cross(dp);
|
|
|
|
// The minimum distance line is in that plane, perpendicular
|
|
|
|
// to the line
|
|
|
|
Vector n = pn.Cross(dp);
|
|
|
|
|
|
|
|
// Calculate the actual distance
|
|
|
|
double d = (dp.Cross(p0.Minus(*this))).Magnitude();
|
|
|
|
return this->Plus(n.WithMagnitude(d));
|
|
|
|
}
|
|
|
|
|
2008-07-06 07:56:24 +00:00
|
|
|
double Vector::MagSquared(void) {
|
|
|
|
return x*x + y*y + z*z;
|
|
|
|
}
|
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
double Vector::Magnitude(void) {
|
2008-03-27 09:53:51 +00:00
|
|
|
return sqrt(x*x + y*y + z*z);
|
|
|
|
}
|
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
Vector Vector::ScaledBy(double v) {
|
2008-03-27 09:53:51 +00:00
|
|
|
Vector r;
|
|
|
|
|
|
|
|
r.x = x * v;
|
|
|
|
r.y = y * v;
|
|
|
|
r.z = z * v;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2008-04-01 10:48:44 +00:00
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
Vector Vector::WithMagnitude(double v) {
|
|
|
|
double m = Magnitude();
|
2008-05-26 06:23:05 +00:00
|
|
|
if(m == 0) {
|
2008-06-01 08:45:11 +00:00
|
|
|
return From(v, 0, 0);
|
2008-04-14 10:28:32 +00:00
|
|
|
} else {
|
2008-05-26 06:23:05 +00:00
|
|
|
return ScaledBy(v/m);
|
2008-04-14 10:28:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-17 11:15:14 +00:00
|
|
|
Vector Vector::ProjectVectorInto(hEntity wrkpl) {
|
2009-04-20 07:30:09 +00:00
|
|
|
EntityBase *w = SK.GetEntity(wrkpl);
|
2008-05-08 07:30:30 +00:00
|
|
|
Vector u = w->Normal()->NormalU();
|
|
|
|
Vector v = w->Normal()->NormalV();
|
2008-05-17 11:15:14 +00:00
|
|
|
|
|
|
|
double up = this->Dot(u);
|
|
|
|
double vp = this->Dot(v);
|
|
|
|
|
|
|
|
return (u.ScaledBy(up)).Plus(v.ScaledBy(vp));
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector Vector::ProjectInto(hEntity wrkpl) {
|
2009-04-20 07:30:09 +00:00
|
|
|
EntityBase *w = SK.GetEntity(wrkpl);
|
2008-05-08 07:30:30 +00:00
|
|
|
Vector p0 = w->WorkplaneGetOffset();
|
|
|
|
|
|
|
|
Vector f = this->Minus(p0);
|
|
|
|
|
2008-05-17 11:15:14 +00:00
|
|
|
return p0.Plus(f.ProjectVectorInto(wrkpl));
|
2008-05-08 07:30:30 +00:00
|
|
|
}
|
|
|
|
|
2008-05-12 10:01:44 +00:00
|
|
|
Point2d Vector::Project2d(Vector u, Vector v) {
|
|
|
|
Point2d p;
|
|
|
|
p.x = this->Dot(u);
|
|
|
|
p.y = this->Dot(v);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2009-02-01 05:13:43 +00:00
|
|
|
Point2d Vector::ProjectXy(void) {
|
|
|
|
Point2d p;
|
|
|
|
p.x = x;
|
|
|
|
p.y = y;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2009-04-14 04:19:23 +00:00
|
|
|
Vector4 Vector::Project4d(void) {
|
|
|
|
return Vector4::From(1, x, y, z);
|
|
|
|
}
|
|
|
|
|
2008-05-08 08:12:23 +00:00
|
|
|
double Vector::DivPivoting(Vector delta) {
|
2008-02-10 13:34:32 +00:00
|
|
|
double mx = fabs(delta.x), my = fabs(delta.y), mz = fabs(delta.z);
|
2008-05-08 08:12:23 +00:00
|
|
|
|
2008-02-10 13:34:32 +00:00
|
|
|
if(mx > my && mx > mz) {
|
2008-05-08 08:12:23 +00:00
|
|
|
return x/delta.x;
|
2008-02-10 13:34:32 +00:00
|
|
|
} else if(my > mz) {
|
2008-05-08 08:12:23 +00:00
|
|
|
return y/delta.y;
|
2008-02-10 13:34:32 +00:00
|
|
|
} else {
|
2008-05-08 08:12:23 +00:00
|
|
|
return z/delta.z;
|
2008-02-10 13:34:32 +00:00
|
|
|
}
|
2008-05-08 08:12:23 +00:00
|
|
|
}
|
|
|
|
|
2008-05-11 10:40:37 +00:00
|
|
|
Vector Vector::ClosestOrtho(void) {
|
2008-02-10 13:34:32 +00:00
|
|
|
double mx = fabs(x), my = fabs(y), mz = fabs(z);
|
2008-05-11 10:40:37 +00:00
|
|
|
|
2008-02-10 13:34:32 +00:00
|
|
|
if(mx > my && mx > mz) {
|
2008-06-01 08:45:11 +00:00
|
|
|
return From((x > 0) ? 1 : -1, 0, 0);
|
2008-02-10 13:34:32 +00:00
|
|
|
} else if(my > mz) {
|
2008-06-01 08:45:11 +00:00
|
|
|
return From(0, (y > 0) ? 1 : -1, 0);
|
2008-02-10 13:34:32 +00:00
|
|
|
} else {
|
2008-06-01 08:45:11 +00:00
|
|
|
return From(0, 0, (z > 0) ? 1 : -1);
|
2008-02-10 13:34:32 +00:00
|
|
|
}
|
2008-05-11 10:40:37 +00:00
|
|
|
}
|
|
|
|
|
2009-01-21 05:04:38 +00:00
|
|
|
void Vector::MakeMaxMin(Vector *maxv, Vector *minv) {
|
|
|
|
maxv->x = max(maxv->x, x);
|
|
|
|
maxv->y = max(maxv->y, y);
|
|
|
|
maxv->z = max(maxv->z, z);
|
|
|
|
|
|
|
|
minv->x = min(minv->x, x);
|
|
|
|
minv->y = min(minv->y, y);
|
|
|
|
minv->z = min(minv->z, z);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Vector::OutsideAndNotOn(Vector maxv, Vector minv) {
|
|
|
|
return (x > maxv.x + LENGTH_EPS) || (x < minv.x - LENGTH_EPS) ||
|
|
|
|
(y > maxv.y + LENGTH_EPS) || (y < minv.y - LENGTH_EPS) ||
|
|
|
|
(z > maxv.z + LENGTH_EPS) || (z < minv.z - LENGTH_EPS);
|
|
|
|
}
|
|
|
|
|
2009-01-27 07:59:58 +00:00
|
|
|
bool Vector::BoundingBoxesDisjoint(Vector amax, Vector amin,
|
|
|
|
Vector bmax, Vector bmin)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 3; i++) {
|
|
|
|
if(amax.Element(i) < bmin.Element(i) - LENGTH_EPS) return true;
|
|
|
|
if(amin.Element(i) > bmax.Element(i) + LENGTH_EPS) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-03-08 10:59:57 +00:00
|
|
|
bool Vector::BoundingBoxIntersectsLine(Vector amax, Vector amin,
|
|
|
|
Vector p0, Vector p1, bool segment)
|
|
|
|
{
|
|
|
|
Vector dp = p1.Minus(p0);
|
|
|
|
double lp = dp.Magnitude();
|
|
|
|
dp = dp.ScaledBy(1.0/lp);
|
|
|
|
|
|
|
|
int i, a;
|
|
|
|
for(i = 0; i < 3; i++) {
|
|
|
|
int j = WRAP(i+1, 3), k = WRAP(i+2, 3);
|
|
|
|
if(lp*fabs(dp.Element(i)) < LENGTH_EPS) continue; // parallel to plane
|
|
|
|
|
|
|
|
for(a = 0; a < 2; a++) {
|
|
|
|
double d = (a == 0) ? amax.Element(i) : amin.Element(i);
|
|
|
|
// n dot (p0 + t*dp) = d
|
|
|
|
// (n dot p0) + t * (n dot dp) = d
|
|
|
|
double t = (d - p0.Element(i)) / dp.Element(i);
|
|
|
|
Vector p = p0.Plus(dp.ScaledBy(t));
|
|
|
|
|
|
|
|
if(segment && (t < -LENGTH_EPS || t > (lp+LENGTH_EPS))) continue;
|
|
|
|
|
|
|
|
if(p.Element(j) > amax.Element(j) + LENGTH_EPS) continue;
|
|
|
|
if(p.Element(k) > amax.Element(k) + LENGTH_EPS) continue;
|
|
|
|
|
|
|
|
if(p.Element(j) < amin.Element(j) - LENGTH_EPS) continue;
|
|
|
|
if(p.Element(k) < amin.Element(k) - LENGTH_EPS) continue;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-05-19 09:23:49 +00:00
|
|
|
Vector Vector::AtIntersectionOfPlanes(Vector n1, double d1,
|
|
|
|
Vector n2, double d2)
|
|
|
|
{
|
|
|
|
double det = (n1.Dot(n1))*(n2.Dot(n2)) -
|
|
|
|
(n1.Dot(n2))*(n1.Dot(n2));
|
|
|
|
double c1 = (d1*n2.Dot(n2) - d2*n1.Dot(n2))/det;
|
|
|
|
double c2 = (d2*n1.Dot(n1) - d1*n1.Dot(n2))/det;
|
|
|
|
|
|
|
|
return (n1.ScaledBy(c1)).Plus(n2.ScaledBy(c2));
|
|
|
|
}
|
|
|
|
|
2009-01-03 12:27:33 +00:00
|
|
|
Vector Vector::AtIntersectionOfLines(Vector a0, Vector a1,
|
|
|
|
Vector b0, Vector b1,
|
2009-01-21 05:04:38 +00:00
|
|
|
bool *skew,
|
|
|
|
double *parama, double *paramb)
|
2009-01-03 12:27:33 +00:00
|
|
|
{
|
|
|
|
Vector da = a1.Minus(a0), db = b1.Minus(b0);
|
|
|
|
|
|
|
|
// Make an orthogonal coordinate system from those directions
|
|
|
|
Vector dn = da.Cross(db); // normal to both
|
|
|
|
Vector dna = dn.Cross(da); // normal to da
|
|
|
|
Vector dnb = dn.Cross(db); // normal to db
|
|
|
|
|
|
|
|
// At the intersection of the lines
|
|
|
|
// a0 + pa*da = b0 + pb*db (where pa, pb are scalar params)
|
|
|
|
// So dot this equation against dna and dnb to get two equations
|
|
|
|
// to solve for da and db
|
|
|
|
double pb = ((a0.Minus(b0)).Dot(dna))/(db.Dot(dna));
|
|
|
|
double pa = -((a0.Minus(b0)).Dot(dnb))/(da.Dot(dnb));
|
2009-01-21 05:04:38 +00:00
|
|
|
if(parama) *parama = pa;
|
|
|
|
if(paramb) *paramb = pb;
|
2009-01-03 12:27:33 +00:00
|
|
|
|
|
|
|
// And from either of those, we get the intersection point.
|
|
|
|
Vector pi = a0.Plus(da.ScaledBy(pa));
|
|
|
|
|
|
|
|
if(skew) {
|
|
|
|
// Check if the intersection points on each line are actually
|
|
|
|
// coincident...
|
|
|
|
if(pi.Equals(b0.Plus(db.ScaledBy(pb)))) {
|
|
|
|
*skew = false;
|
|
|
|
} else {
|
|
|
|
*skew = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pi;
|
|
|
|
}
|
|
|
|
|
2009-02-23 10:06:02 +00:00
|
|
|
Vector Vector::AtIntersectionOfPlaneAndLine(Vector n, double d,
|
|
|
|
Vector p0, Vector p1,
|
|
|
|
bool *parallel)
|
|
|
|
{
|
|
|
|
Vector dp = p1.Minus(p0);
|
|
|
|
|
|
|
|
if(fabs(n.Dot(dp)) < LENGTH_EPS) {
|
|
|
|
if(parallel) *parallel = true;
|
|
|
|
return Vector::From(0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(parallel) *parallel = false;
|
|
|
|
|
|
|
|
// n dot (p0 + t*dp) = d
|
|
|
|
// (n dot p0) + t * (n dot dp) = d
|
|
|
|
double t = (d - n.Dot(p0)) / (n.Dot(dp));
|
|
|
|
|
|
|
|
return p0.Plus(dp.ScaledBy(t));
|
|
|
|
}
|
|
|
|
|
2009-02-27 13:04:36 +00:00
|
|
|
static double det2(double a1, double b1,
|
|
|
|
double a2, double b2)
|
|
|
|
{
|
|
|
|
return (a1*b2) - (b1*a2);
|
|
|
|
}
|
|
|
|
static double det3(double a1, double b1, double c1,
|
|
|
|
double a2, double b2, double c2,
|
|
|
|
double a3, double b3, double c3)
|
|
|
|
{
|
|
|
|
return a1*det2(b2, c2, b3, c3) -
|
|
|
|
b1*det2(a2, c2, a3, c3) +
|
|
|
|
c1*det2(a2, b2, a3, b3);
|
|
|
|
}
|
|
|
|
Vector Vector::AtIntersectionOfPlanes(Vector na, double da,
|
|
|
|
Vector nb, double db,
|
|
|
|
Vector nc, double dc,
|
|
|
|
bool *parallel)
|
|
|
|
{
|
|
|
|
double det = det3(na.x, na.y, na.z,
|
|
|
|
nb.x, nb.y, nb.z,
|
|
|
|
nc.x, nc.y, nc.z);
|
|
|
|
if(fabs(det) < 1e-10) { // arbitrary tolerance, not so good
|
|
|
|
*parallel = true;
|
|
|
|
return Vector::From(0, 0, 0);
|
|
|
|
}
|
|
|
|
*parallel = false;
|
|
|
|
|
|
|
|
double detx = det3(da, na.y, na.z,
|
|
|
|
db, nb.y, nb.z,
|
|
|
|
dc, nc.y, nc.z);
|
|
|
|
|
|
|
|
double dety = det3(na.x, da, na.z,
|
|
|
|
nb.x, db, nb.z,
|
|
|
|
nc.x, dc, nc.z);
|
|
|
|
|
|
|
|
double detz = det3(na.x, na.y, da,
|
|
|
|
nb.x, nb.y, db,
|
|
|
|
nc.x, nc.y, dc );
|
|
|
|
|
|
|
|
return Vector::From(detx/det, dety/det, detz/det);
|
|
|
|
}
|
|
|
|
|
2009-04-14 04:19:23 +00:00
|
|
|
Vector4 Vector4::From(double w, double x, double y, double z) {
|
|
|
|
Vector4 ret;
|
|
|
|
ret.w = w;
|
|
|
|
ret.x = x;
|
|
|
|
ret.y = y;
|
|
|
|
ret.z = z;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 Vector4::From(double w, Vector v) {
|
|
|
|
return Vector4::From(w, w*v.x, w*v.y, w*v.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 Vector4::Blend(Vector4 a, Vector4 b, double t) {
|
|
|
|
return (a.ScaledBy(1 - t)).Plus(b.ScaledBy(t));
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 Vector4::Plus(Vector4 b) {
|
|
|
|
return Vector4::From(w + b.w, x + b.x, y + b.y, z + b.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 Vector4::Minus(Vector4 b) {
|
|
|
|
return Vector4::From(w - b.w, x - b.x, y - b.y, z - b.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector4 Vector4::ScaledBy(double s) {
|
|
|
|
return Vector4::From(w*s, x*s, y*s, z*s);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector Vector4::PerspectiveProject(void) {
|
|
|
|
return Vector::From(x / w, y / w, z / w);
|
|
|
|
}
|
|
|
|
|
2009-03-14 20:01:20 +00:00
|
|
|
Point2d Point2d::From(double x, double y) {
|
|
|
|
Point2d r;
|
|
|
|
r.x = x; r.y = y;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-04-12 14:12:26 +00:00
|
|
|
Point2d Point2d::Plus(Point2d b) {
|
|
|
|
Point2d r;
|
|
|
|
r.x = x + b.x;
|
|
|
|
r.y = y + b.y;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
Point2d Point2d::Minus(Point2d b) {
|
|
|
|
Point2d r;
|
|
|
|
r.x = x - b.x;
|
|
|
|
r.y = y - b.y;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
Point2d Point2d::ScaledBy(double s) {
|
|
|
|
Point2d r;
|
|
|
|
r.x = x*s;
|
|
|
|
r.y = y*s;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-03-19 17:40:11 +00:00
|
|
|
double Point2d::DivPivoting(Point2d delta) {
|
|
|
|
if(fabs(delta.x) > fabs(delta.y)) {
|
|
|
|
return x/delta.x;
|
|
|
|
} else {
|
|
|
|
return y/delta.y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-23 10:06:02 +00:00
|
|
|
double Point2d::MagSquared(void) {
|
|
|
|
return x*x + y*y;
|
|
|
|
}
|
|
|
|
|
2008-04-22 05:00:49 +00:00
|
|
|
double Point2d::Magnitude(void) {
|
|
|
|
return sqrt(x*x + y*y);
|
|
|
|
}
|
|
|
|
|
|
|
|
Point2d Point2d::WithMagnitude(double v) {
|
|
|
|
double m = Magnitude();
|
2009-03-02 05:52:08 +00:00
|
|
|
if(m < 1e-20) {
|
|
|
|
dbp("!!! WithMagnitude() of zero vector");
|
2008-04-22 05:00:49 +00:00
|
|
|
Point2d r = { v, 0 };
|
|
|
|
return r;
|
|
|
|
} else {
|
2009-03-02 05:52:08 +00:00
|
|
|
return ScaledBy(v/m);
|
2008-04-22 05:00:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-12 14:12:26 +00:00
|
|
|
double Point2d::DistanceTo(Point2d p) {
|
|
|
|
double dx = x - p.x;
|
|
|
|
double dy = y - p.y;
|
|
|
|
return sqrt(dx*dx + dy*dy);
|
|
|
|
}
|
|
|
|
|
2009-02-01 05:13:43 +00:00
|
|
|
double Point2d::Dot(Point2d p) {
|
|
|
|
return x*p.x + y*p.y;
|
|
|
|
}
|
|
|
|
|
2008-04-12 14:12:26 +00:00
|
|
|
double Point2d::DistanceToLine(Point2d p0, Point2d dp, bool segment) {
|
|
|
|
double m = dp.x*dp.x + dp.y*dp.y;
|
2009-02-01 13:01:28 +00:00
|
|
|
if(m < LENGTH_EPS*LENGTH_EPS) return VERY_POSITIVE;
|
2008-04-12 14:12:26 +00:00
|
|
|
|
|
|
|
// Let our line be p = p0 + t*dp, for a scalar t from 0 to 1
|
|
|
|
double t = (dp.x*(x - p0.x) + dp.y*(y - p0.y))/m;
|
|
|
|
|
|
|
|
if((t < 0 || t > 1) && segment) {
|
|
|
|
// The closest point is one of the endpoints; determine which.
|
|
|
|
double d0 = DistanceTo(p0);
|
|
|
|
double d1 = DistanceTo(p0.Plus(dp));
|
|
|
|
|
|
|
|
return min(d1, d0);
|
|
|
|
} else {
|
|
|
|
Point2d closest = p0.Plus(dp.ScaledBy(t));
|
|
|
|
return DistanceTo(closest);
|
|
|
|
}
|
|
|
|
}
|
2008-04-11 11:13:47 +00:00
|
|
|
|
2009-02-01 05:13:43 +00:00
|
|
|
Point2d Point2d::Normal(void) {
|
|
|
|
Point2d ret;
|
|
|
|
ret.x = y;
|
|
|
|
ret.y = -x;
|
|
|
|
return ret;
|
|
|
|
}
|
2008-05-08 07:30:30 +00:00
|
|
|
|
2009-02-23 10:06:02 +00:00
|
|
|
bool Point2d::Equals(Point2d v, double tol) {
|
|
|
|
double dx = v.x - x; if(dx < -tol || dx > tol) return false;
|
|
|
|
double dy = v.y - y; if(dy < -tol || dy > tol) return false;
|
|
|
|
|
|
|
|
return (this->Minus(v)).MagSquared() < tol*tol;
|
|
|
|
}
|
|
|
|
|