
from an extrusion, with piecewise linear trim curves for everything (that are shared, so that they appear only once for the two surfaces that each trims). No Boolean operations on them, and the triangulation is bad, because gl seems to merge collinear edges. So before going further, I seem to need my own triangulation code. I have not had great luck in the past, but I can't live without it now. [git-p4: depot-paths = "//depot/solvespace/": change = 1899]
309 lines
7.5 KiB
C++
309 lines
7.5 KiB
C++
|
|
#ifndef __DSC_H
|
|
#define __DSC_H
|
|
|
|
typedef unsigned long DWORD;
|
|
typedef unsigned char BYTE;
|
|
|
|
class Vector;
|
|
class Point2d;
|
|
class hEntity;
|
|
class hParam;
|
|
|
|
class Quaternion {
|
|
public:
|
|
// a + (vx)*i + (vy)*j + (vz)*k
|
|
double w, vx, vy, vz;
|
|
|
|
static Quaternion From(double w, double vx, double vy, double vz);
|
|
static Quaternion From(hParam w, hParam vx, hParam vy, hParam vz);
|
|
static Quaternion From(Vector u, Vector v);
|
|
|
|
Quaternion Plus(Quaternion b);
|
|
Quaternion Minus(Quaternion b);
|
|
Quaternion ScaledBy(double s);
|
|
double Magnitude(void);
|
|
Quaternion WithMagnitude(double s);
|
|
|
|
// Call a rotation matrix [ u' v' n' ]'; this returns the first and
|
|
// second rows, where that matrix is generated by this quaternion
|
|
Vector RotationU(void);
|
|
Vector RotationV(void);
|
|
Vector RotationN(void);
|
|
Vector Rotate(Vector p);
|
|
|
|
Quaternion ToThe(double p);
|
|
Quaternion Inverse(void);
|
|
Quaternion Times(Quaternion b);
|
|
};
|
|
|
|
class Vector {
|
|
public:
|
|
double x, y, z;
|
|
|
|
static Vector From(double x, double y, double z);
|
|
static Vector From(hParam x, hParam y, hParam z);
|
|
static Vector AtIntersectionOfPlanes(Vector n1, double d1,
|
|
Vector n2, double d2);
|
|
static Vector AtIntersectionOfLines(Vector a0, Vector a1,
|
|
Vector b0, Vector b1,
|
|
bool *skew);
|
|
|
|
double Element(int i);
|
|
bool Equals(Vector v, double tol=LENGTH_EPS);
|
|
bool EqualsExactly(Vector v);
|
|
Vector Plus(Vector b);
|
|
Vector Minus(Vector b);
|
|
Vector Negated(void);
|
|
Vector Cross(Vector b);
|
|
double Dot(Vector b);
|
|
Vector Normal(int which);
|
|
Vector RotatedAbout(Vector orig, Vector axis, double theta);
|
|
Vector RotatedAbout(Vector axis, double theta);
|
|
Vector DotInToCsys(Vector u, Vector v, Vector n);
|
|
Vector ScaleOutOfCsys(Vector u, Vector v, Vector n);
|
|
double DistanceToLine(Vector p0, Vector dp);
|
|
bool OnLineSegment(Vector a, Vector b);
|
|
Vector ClosestPointOnLine(Vector p0, Vector dp);
|
|
double Magnitude(void);
|
|
double MagSquared(void);
|
|
Vector WithMagnitude(double s);
|
|
Vector ScaledBy(double s);
|
|
Vector ProjectInto(hEntity wrkpl);
|
|
Vector ProjectVectorInto(hEntity wrkpl);
|
|
double DivPivoting(Vector delta);
|
|
Vector ClosestOrtho(void);
|
|
Point2d Project2d(Vector u, Vector v);
|
|
};
|
|
|
|
class Point2d {
|
|
public:
|
|
double x, y;
|
|
|
|
Point2d Plus(Point2d b);
|
|
Point2d Minus(Point2d b);
|
|
Point2d ScaledBy(double s);
|
|
double DistanceTo(Point2d p);
|
|
double DistanceToLine(Point2d p0, Point2d dp, bool segment);
|
|
double Magnitude(void);
|
|
Point2d WithMagnitude(double v);
|
|
};
|
|
|
|
// A simple list
|
|
template <class T>
|
|
class List {
|
|
public:
|
|
T *elem;
|
|
int n;
|
|
int elemsAllocated;
|
|
|
|
void Add(T *t) {
|
|
if(n >= elemsAllocated) {
|
|
elemsAllocated = (elemsAllocated + 32)*2;
|
|
elem = (T *)MemRealloc(elem, elemsAllocated*sizeof(elem[0]));
|
|
}
|
|
elem[n++] = *t;
|
|
}
|
|
|
|
T *First(void) {
|
|
return (n == 0) ? NULL : &(elem[0]);
|
|
}
|
|
T *NextAfter(T *prev) {
|
|
if(!prev) return NULL;
|
|
if(prev - elem == (n - 1)) return NULL;
|
|
return prev + 1;
|
|
}
|
|
|
|
void ClearTags(void) {
|
|
int i;
|
|
for(i = 0; i < n; i++) {
|
|
elem[i].tag = 0;
|
|
}
|
|
}
|
|
|
|
void Clear(void) {
|
|
if(elem) MemFree(elem);
|
|
elem = NULL;
|
|
n = elemsAllocated = 0;
|
|
}
|
|
|
|
void RemoveTagged(void) {
|
|
int src, dest;
|
|
dest = 0;
|
|
for(src = 0; src < n; src++) {
|
|
if(elem[src].tag) {
|
|
// this item should be deleted
|
|
} else {
|
|
if(src != dest) {
|
|
elem[dest] = elem[src];
|
|
}
|
|
dest++;
|
|
}
|
|
}
|
|
n = dest;
|
|
// and elemsAllocated is untouched, because we didn't resize
|
|
}
|
|
|
|
void Reverse(void) {
|
|
int i;
|
|
for(i = 0; i < (n/2); i++) {
|
|
SWAP(T, elem[i], elem[(n-1)-i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
// A list, where each element has an integer identifier. The list is kept
|
|
// sorted by that identifier, and items can be looked up in log n time by
|
|
// id.
|
|
template <class T, class H>
|
|
class IdList {
|
|
public:
|
|
T *elem;
|
|
int n;
|
|
int elemsAllocated;
|
|
|
|
H AddAndAssignId(T *t) {
|
|
int i;
|
|
DWORD id = 0;
|
|
|
|
for(i = 0; i < n; i++) {
|
|
id = max(id, elem[i].h.v);
|
|
}
|
|
|
|
t->h.v = (id + 1);
|
|
Add(t);
|
|
|
|
return t->h;
|
|
}
|
|
|
|
void Add(T *t) {
|
|
if(n >= elemsAllocated) {
|
|
elemsAllocated = (elemsAllocated + 32)*2;
|
|
elem = (T *)MemRealloc(elem, elemsAllocated*sizeof(elem[0]));
|
|
}
|
|
|
|
int first = 0, last = n;
|
|
// We know that we must insert within the closed interval [first,last]
|
|
while(first != last) {
|
|
int mid = (first + last)/2;
|
|
H hm = elem[mid].h;
|
|
if(hm.v > t->h.v) {
|
|
last = mid;
|
|
} else if(hm.v < t->h.v) {
|
|
first = mid + 1;
|
|
} else {
|
|
oops();
|
|
}
|
|
}
|
|
int i = first;
|
|
|
|
memmove(elem+i+1, elem+i, (n-i)*sizeof(elem[0]));
|
|
elem[i] = *t;
|
|
n++;
|
|
}
|
|
|
|
T *FindById(H h) {
|
|
T *t = FindByIdNoOops(h);
|
|
if(!t) {
|
|
dbp("failed to look up item %08x, searched %d items", h.v, n);
|
|
oops();
|
|
}
|
|
return t;
|
|
}
|
|
|
|
T *FindByIdNoOops(H h) {
|
|
int first = 0, last = n-1;
|
|
while(first <= last) {
|
|
int mid = (first + last)/2;
|
|
H hm = elem[mid].h;
|
|
if(hm.v > h.v) {
|
|
last = mid-1; // and first stays the same
|
|
} else if(hm.v < h.v) {
|
|
first = mid+1; // and last stays the same
|
|
} else {
|
|
return &(elem[mid]);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
T *First(void) {
|
|
return (n == 0) ? NULL : &(elem[0]);
|
|
}
|
|
T *NextAfter(T *prev) {
|
|
if(!prev) return NULL;
|
|
if(prev - elem == (n - 1)) return NULL;
|
|
return prev + 1;
|
|
}
|
|
|
|
void ClearTags(void) {
|
|
int i;
|
|
for(i = 0; i < n; i++) {
|
|
elem[i].tag = 0;
|
|
}
|
|
}
|
|
|
|
void Tag(H h, int tag) {
|
|
int i;
|
|
for(i = 0; i < n; i++) {
|
|
if(elem[i].h.v == h.v) {
|
|
elem[i].tag = tag;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RemoveTagged(void) {
|
|
int src, dest;
|
|
dest = 0;
|
|
for(src = 0; src < n; src++) {
|
|
if(elem[src].tag) {
|
|
// this item should be deleted
|
|
} else {
|
|
if(src != dest) {
|
|
elem[dest] = elem[src];
|
|
}
|
|
dest++;
|
|
}
|
|
}
|
|
n = dest;
|
|
// and elemsAllocated is untouched, because we didn't resize
|
|
}
|
|
void RemoveById(H h) {
|
|
ClearTags();
|
|
FindById(h)->tag = 1;
|
|
RemoveTagged();
|
|
}
|
|
|
|
void MoveSelfInto(IdList<T,H> *l) {
|
|
memcpy(l, this, sizeof(*this));
|
|
elemsAllocated = n = 0;
|
|
elem = NULL;
|
|
}
|
|
|
|
void DeepCopyInto(IdList<T,H> *l) {
|
|
l->elem = (T *)MemAlloc(elemsAllocated * sizeof(elem[0]));
|
|
memcpy(l->elem, elem, elemsAllocated * sizeof(elem[0]));
|
|
l->elemsAllocated = elemsAllocated;
|
|
l->n = n;
|
|
}
|
|
|
|
void Clear(void) {
|
|
elemsAllocated = n = 0;
|
|
if(elem) MemFree(elem);
|
|
elem = NULL;
|
|
}
|
|
|
|
};
|
|
|
|
class NameStr {
|
|
public:
|
|
char str[64];
|
|
|
|
inline void strcpy(char *in) {
|
|
memcpy(str, in, min(strlen(in)+1, sizeof(str)));
|
|
str[sizeof(str)-1] = '\0';
|
|
}
|
|
};
|
|
|
|
#endif
|