Generate the group's polygon from the exact curves, not from edges;
so now we've got the exact curve loops, with their direction standardized so that we can tell which direction is out. We still need the polygon in any case, since that's a convenient way to find each curve's winding number. And remove some more leftover code from mesh sweeps. [git-p4: depot-paths = "//depot/solvespace/": change = 1897]
This commit is contained in:
parent
7a874c20c0
commit
0e623c90c0
|
@ -192,6 +192,12 @@ void Entity::GeneratePolyCurves(SPolyCurveList *spcl) {
|
||||||
double r = CircleGetRadiusNum();
|
double r = CircleGetRadiusNum();
|
||||||
double thetaa, thetab, dtheta;
|
double thetaa, thetab, dtheta;
|
||||||
|
|
||||||
|
if(r < LENGTH_EPS) {
|
||||||
|
// If a circle or an arc gets dragged through zero radius,
|
||||||
|
// then we just don't generate anything.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(type == CIRCLE) {
|
if(type == CIRCLE) {
|
||||||
thetaa = 0;
|
thetaa = 0;
|
||||||
thetab = 2*PI;
|
thetab = 2*PI;
|
||||||
|
|
7
dsc.h
7
dsc.h
|
@ -134,6 +134,13 @@ public:
|
||||||
n = dest;
|
n = dest;
|
||||||
// and elemsAllocated is untouched, because we didn't resize
|
// 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
|
// A list, where each element has an integer identifier. The list is kept
|
||||||
|
|
|
@ -222,7 +222,7 @@ void SolveSpace::GenerateAll(int first, int last, bool andFindFree) {
|
||||||
// The group falls inside the range, so really solve it,
|
// The group falls inside the range, so really solve it,
|
||||||
// and then regenerate the mesh based on the solved stuff.
|
// and then regenerate the mesh based on the solved stuff.
|
||||||
SolveGroup(g->h, andFindFree);
|
SolveGroup(g->h, andFindFree);
|
||||||
g->GeneratePolygon();
|
g->GenerateLoops();
|
||||||
g->GenerateMesh();
|
g->GenerateMesh();
|
||||||
g->clean = true;
|
g->clean = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,112 +2,50 @@
|
||||||
|
|
||||||
#define gs (SS.GW.gs)
|
#define gs (SS.GW.gs)
|
||||||
|
|
||||||
bool Group::AssemblePolygon(SPolygon *p, SEdge *error) {
|
bool Group::AssembleLoops(void) {
|
||||||
SEdgeList edges; ZERO(&edges);
|
SPolyCurveList spcl;
|
||||||
|
ZERO(&spcl);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < SS.entity.n; i++) {
|
for(i = 0; i < SS.entity.n; i++) {
|
||||||
Entity *e = &(SS.entity.elem[i]);
|
Entity *e = &(SS.entity.elem[i]);
|
||||||
if(e->group.v != h.v) continue;
|
if(e->group.v != h.v) continue;
|
||||||
|
if(e->construction) continue;
|
||||||
|
|
||||||
e->GenerateEdges(&edges);
|
e->GeneratePolyCurves(&spcl);
|
||||||
}
|
}
|
||||||
bool ret = edges.AssemblePolygon(p, error);
|
|
||||||
edges.Clear();
|
bool allClosed;
|
||||||
return ret;
|
curveLoops = SPolyCurveLoops::From(&spcl, &poly,
|
||||||
|
&allClosed, &(polyError.notClosedAt));
|
||||||
|
spcl.Clear();
|
||||||
|
return allClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Group::GeneratePolygon(void) {
|
void Group::GenerateLoops(void) {
|
||||||
poly.Clear();
|
poly.Clear();
|
||||||
|
curveLoops.Clear();
|
||||||
|
|
||||||
if(type == DRAWING_3D || type == DRAWING_WORKPLANE ||
|
if(type == DRAWING_3D || type == DRAWING_WORKPLANE ||
|
||||||
type == ROTATE || type == TRANSLATE || type == IMPORTED)
|
type == ROTATE || type == TRANSLATE || type == IMPORTED)
|
||||||
{
|
{
|
||||||
if(AssemblePolygon(&poly, &(polyError.notClosedAt))) {
|
if(AssembleLoops()) {
|
||||||
polyError.how = POLY_GOOD;
|
polyError.how = POLY_GOOD;
|
||||||
poly.normal = poly.ComputeNormal();
|
|
||||||
poly.FixContourDirections();
|
|
||||||
|
|
||||||
if(!poly.AllPointsInPlane(&(polyError.notCoplanarAt))) {
|
if(!poly.AllPointsInPlane(&(polyError.notCoplanarAt))) {
|
||||||
// The edges aren't all coplanar; so not a good polygon
|
// The edges aren't all coplanar; so not a good polygon
|
||||||
polyError.how = POLY_NOT_COPLANAR;
|
polyError.how = POLY_NOT_COPLANAR;
|
||||||
poly.Clear();
|
poly.Clear();
|
||||||
|
curveLoops.Clear();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
polyError.how = POLY_NOT_CLOSED;
|
polyError.how = POLY_NOT_CLOSED;
|
||||||
poly.Clear();
|
poly.Clear();
|
||||||
|
curveLoops.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Group::GetTrajectory(hGroup hg, SContour *traj, SPolygon *section) {
|
|
||||||
if(section->IsEmpty()) return;
|
|
||||||
|
|
||||||
SEdgeList edges; ZERO(&edges);
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for(i = 0; i < SS.entity.n; i++) {
|
|
||||||
Entity *e = &(SS.entity.elem[i]);
|
|
||||||
if(e->group.v != hg.v) continue;
|
|
||||||
e->GenerateEdges(&edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector pn = (section->normal).WithMagnitude(1);
|
|
||||||
double pd = pn.Dot(section->AnyPoint());
|
|
||||||
|
|
||||||
// Find the start of the trajectory
|
|
||||||
Vector first, last;
|
|
||||||
for(i = 0; i < edges.l.n; i++) {
|
|
||||||
SEdge *se = &(edges.l.elem[i]);
|
|
||||||
|
|
||||||
bool startA = true, startB = true;
|
|
||||||
for(j = 0; j < edges.l.n; j++) {
|
|
||||||
if(i == j) continue;
|
|
||||||
SEdge *set = &(edges.l.elem[j]);
|
|
||||||
if((set->a).Equals(se->a)) startA = false;
|
|
||||||
if((set->b).Equals(se->a)) startA = false;
|
|
||||||
if((set->a).Equals(se->b)) startB = false;
|
|
||||||
if((set->b).Equals(se->b)) startB = false;
|
|
||||||
}
|
|
||||||
if(startA || startB) {
|
|
||||||
// It's possible for both to be true, if only one segment exists
|
|
||||||
if(startA) {
|
|
||||||
first = se->a;
|
|
||||||
last = se->b;
|
|
||||||
} else {
|
|
||||||
first = se->b;
|
|
||||||
last = se->a;
|
|
||||||
}
|
|
||||||
se->tag = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(i >= edges.l.n) goto cleanup;
|
|
||||||
edges.AssembleContour(first, last, traj, NULL);
|
|
||||||
if(traj->l.n < 1) goto cleanup;
|
|
||||||
|
|
||||||
// Starting and ending points of the trajectory
|
|
||||||
Vector ps, pf;
|
|
||||||
ps = traj->l.elem[0].p;
|
|
||||||
pf = traj->l.elem[traj->l.n - 1].p;
|
|
||||||
// Distances of those points to the section plane
|
|
||||||
double ds = fabs(pn.Dot(ps) - pd), df = fabs(pn.Dot(pf) - pd);
|
|
||||||
if(ds < LENGTH_EPS && df < LENGTH_EPS) {
|
|
||||||
if(section->WindingNumberForPoint(pf) > 0) {
|
|
||||||
// Both the start and finish lie on the section plane; let the
|
|
||||||
// start be the one that's somewhere within the section. Use
|
|
||||||
// winding > 0, not odd/even, since it's natural e.g. to sweep
|
|
||||||
// a ring to make a pipe, and draw the trajectory through the
|
|
||||||
// center of the ring.
|
|
||||||
traj->Reverse();
|
|
||||||
}
|
|
||||||
} else if(ds > df) {
|
|
||||||
// The starting point is the endpoint that's closer to the plane
|
|
||||||
traj->Reverse();
|
|
||||||
}
|
|
||||||
cleanup:
|
|
||||||
edges.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Group::AddQuadWithNormal(STriMeta meta, Vector out,
|
void Group::AddQuadWithNormal(STriMeta meta, Vector out,
|
||||||
Vector a, Vector b, Vector c, Vector d)
|
Vector a, Vector b, Vector c, Vector d)
|
||||||
{
|
{
|
||||||
|
|
13
polygon.cpp
13
polygon.cpp
|
@ -181,7 +181,6 @@ bool SContour::IsClockwiseProjdToNormal(Vector n) {
|
||||||
|
|
||||||
area += ((v0 + v1)/2)*(u1 - u0);
|
area += ((v0 + v1)/2)*(u1 - u0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (area < 0);
|
return (area < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,13 +223,7 @@ bool SContour::AllPointsInPlane(Vector n, double d, Vector *notCoplanarAt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SContour::Reverse(void) {
|
void SContour::Reverse(void) {
|
||||||
int i;
|
l.Reverse();
|
||||||
for(i = 0; i < (l.n / 2); i++) {
|
|
||||||
int i2 = (l.n - 1) - i;
|
|
||||||
SPoint t = l.elem[i2];
|
|
||||||
l.elem[i2] = l.elem[i];
|
|
||||||
l.elem[i] = t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -277,6 +270,9 @@ int SPolygon::WindingNumberForPoint(Vector p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPolygon::FixContourDirections(void) {
|
void SPolygon::FixContourDirections(void) {
|
||||||
|
// At output, the contour's tag will be 1 if we reversed it, else 0.
|
||||||
|
l.ClearTags();
|
||||||
|
|
||||||
// Outside curve looks counterclockwise, projected against our normal.
|
// Outside curve looks counterclockwise, projected against our normal.
|
||||||
int i, j;
|
int i, j;
|
||||||
for(i = 0; i < l.n; i++) {
|
for(i = 0; i < l.n; i++) {
|
||||||
|
@ -296,6 +292,7 @@ void SPolygon::FixContourDirections(void) {
|
||||||
bool clockwise = sc->IsClockwiseProjdToNormal(normal);
|
bool clockwise = sc->IsClockwiseProjdToNormal(normal);
|
||||||
if(clockwise && outer || (!clockwise && !outer)) {
|
if(clockwise && outer || (!clockwise && !outer)) {
|
||||||
sc->Reverse();
|
sc->Reverse();
|
||||||
|
sc->tag = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ public:
|
||||||
|
|
||||||
class SContour {
|
class SContour {
|
||||||
public:
|
public:
|
||||||
|
int tag;
|
||||||
List<SPoint> l;
|
List<SPoint> l;
|
||||||
|
|
||||||
void AddPoint(Vector p);
|
void AddPoint(Vector p);
|
||||||
|
|
9
sketch.h
9
sketch.h
|
@ -137,6 +137,7 @@ public:
|
||||||
} predef;
|
} predef;
|
||||||
|
|
||||||
SPolygon poly;
|
SPolygon poly;
|
||||||
|
SPolyCurveLoops curveLoops;
|
||||||
static const int POLY_GOOD = 0;
|
static const int POLY_GOOD = 0;
|
||||||
static const int POLY_NOT_CLOSED = 1;
|
static const int POLY_NOT_CLOSED = 1;
|
||||||
static const int POLY_NOT_COPLANAR = 2;
|
static const int POLY_NOT_COPLANAR = 2;
|
||||||
|
@ -198,12 +199,12 @@ public:
|
||||||
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
|
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
|
||||||
void GenerateEquations(IdList<Equation,hEquation> *l);
|
void GenerateEquations(IdList<Equation,hEquation> *l);
|
||||||
|
|
||||||
// Assembling piecewise linear sections into polygons
|
// Assembling the curves into loops, and into a piecewise linear polygon
|
||||||
bool AssemblePolygon(SPolygon *p, SEdge *error);
|
// at the same time.
|
||||||
void GeneratePolygon(void);
|
bool AssembleLoops(void);
|
||||||
|
void GenerateLoops(void);
|
||||||
// And the mesh stuff
|
// And the mesh stuff
|
||||||
SMesh *PreviousGroupMesh(void);
|
SMesh *PreviousGroupMesh(void);
|
||||||
void GetTrajectory(hGroup hg, SContour *traj, SPolygon *section);
|
|
||||||
void AddQuadWithNormal(STriMeta meta, Vector out,
|
void AddQuadWithNormal(STriMeta meta, Vector out,
|
||||||
Vector a, Vector b, Vector c, Vector d);
|
Vector a, Vector b, Vector c, Vector d);
|
||||||
void GenerateMeshForStepAndRepeat(void);
|
void GenerateMeshForStepAndRepeat(void);
|
||||||
|
|
109
srf/ratpoly.cpp
109
srf/ratpoly.cpp
|
@ -77,7 +77,7 @@ Vector SPolyCurve::Finish(void) {
|
||||||
return ctrl[deg];
|
return ctrl[deg];
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector SPolyCurve::EvalAt(double t) {
|
Vector SPolyCurve::PointAt(double t) {
|
||||||
Vector pt = Vector::From(0, 0, 0);
|
Vector pt = Vector::From(0, 0, 0);
|
||||||
double d = 0;
|
double d = 0;
|
||||||
|
|
||||||
|
@ -97,15 +97,15 @@ void SPolyCurve::MakePwlInto(List<Vector> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPolyCurve::MakePwlWorker(List<Vector> *l, double ta, double tb) {
|
void SPolyCurve::MakePwlWorker(List<Vector> *l, double ta, double tb) {
|
||||||
Vector pa = EvalAt(ta);
|
Vector pa = PointAt(ta);
|
||||||
Vector pb = EvalAt(tb);
|
Vector pb = PointAt(tb);
|
||||||
|
|
||||||
// Can't test in the middle, or certain cubics would break.
|
// Can't test in the middle, or certain cubics would break.
|
||||||
double tm1 = (2*ta + tb) / 3;
|
double tm1 = (2*ta + tb) / 3;
|
||||||
double tm2 = (ta + 2*tb) / 3;
|
double tm2 = (ta + 2*tb) / 3;
|
||||||
|
|
||||||
Vector pm1 = EvalAt(tm1);
|
Vector pm1 = PointAt(tm1);
|
||||||
Vector pm2 = EvalAt(tm2);
|
Vector pm2 = PointAt(tm2);
|
||||||
|
|
||||||
double d = max(pm1.DistanceToLine(pa, pb.Minus(pa)),
|
double d = max(pm1.DistanceToLine(pa, pb.Minus(pa)),
|
||||||
pm2.DistanceToLine(pa, pb.Minus(pa)));
|
pm2.DistanceToLine(pa, pb.Minus(pa)));
|
||||||
|
@ -135,7 +135,8 @@ void SPolyCurveList::Clear(void) {
|
||||||
l.Clear();
|
l.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SPolyCurveLoop SPolyCurveLoop::FromCurves(SPolyCurveList *spcl, bool *notClosed)
|
SPolyCurveLoop SPolyCurveLoop::FromCurves(SPolyCurveList *spcl,
|
||||||
|
bool *allClosed, SEdge *errorAt)
|
||||||
{
|
{
|
||||||
SPolyCurveLoop loop;
|
SPolyCurveLoop loop;
|
||||||
ZERO(&loop);
|
ZERO(&loop);
|
||||||
|
@ -153,35 +154,114 @@ SPolyCurveLoop SPolyCurveLoop::FromCurves(SPolyCurveList *spcl, bool *notClosed)
|
||||||
|
|
||||||
while(spcl->l.n > 0 && !hanging.Equals(start)) {
|
while(spcl->l.n > 0 && !hanging.Equals(start)) {
|
||||||
int i;
|
int i;
|
||||||
|
bool foundNext = false;
|
||||||
for(i = 0; i < spcl->l.n; i++) {
|
for(i = 0; i < spcl->l.n; i++) {
|
||||||
SPolyCurve *test = &(spcl->l.elem[i]);
|
SPolyCurve *test = &(spcl->l.elem[i]);
|
||||||
|
|
||||||
if((test->Finish()).Equals(hanging)) {
|
if((test->Finish()).Equals(hanging)) {
|
||||||
test->Reverse();
|
test->Reverse();
|
||||||
|
// and let the next test catch it
|
||||||
}
|
}
|
||||||
if((test->Start()).Equals(hanging)) {
|
if((test->Start()).Equals(hanging)) {
|
||||||
test->tag = 1;
|
test->tag = 1;
|
||||||
loop.l.Add(test);
|
loop.l.Add(test);
|
||||||
hanging = test->Finish();
|
hanging = test->Finish();
|
||||||
spcl->l.RemoveTagged();
|
spcl->l.RemoveTagged();
|
||||||
|
foundNext = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(i >= spcl->l.n) {
|
if(!foundNext) {
|
||||||
// Didn't find the next curve in the loop
|
// The loop completed without finding the hanging edge, so
|
||||||
*notClosed = true;
|
// it's an open loop
|
||||||
|
errorAt->a = hanging;
|
||||||
|
errorAt->b = start;
|
||||||
|
*allClosed = false;
|
||||||
return loop;
|
return loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(hanging.Equals(start)) {
|
if(hanging.Equals(start)) {
|
||||||
*notClosed = false;
|
*allClosed = true;
|
||||||
} else {
|
} else {
|
||||||
*notClosed = true;
|
// We ran out of edges without forming a closed loop.
|
||||||
|
errorAt->a = hanging;
|
||||||
|
errorAt->b = start;
|
||||||
|
*allClosed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loop;
|
return loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SPolyCurveLoop::Reverse(void) {
|
||||||
|
l.Reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPolyCurveLoop::MakePwlInto(SContour *sc) {
|
||||||
|
List<Vector> lv;
|
||||||
|
ZERO(&lv);
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
for(i = 0; i < l.n; i++) {
|
||||||
|
SPolyCurve *spc = &(l.elem[i]);
|
||||||
|
spc->MakePwlInto(&lv);
|
||||||
|
|
||||||
|
// Each curve's piecewise linearization includes its endpoints,
|
||||||
|
// which we don't want to duplicate (creating zero-len edges).
|
||||||
|
for(j = (i == 0 ? 0 : 1); j < lv.n; j++) {
|
||||||
|
sc->AddPoint(lv.elem[j]);
|
||||||
|
}
|
||||||
|
lv.Clear();
|
||||||
|
}
|
||||||
|
// Ensure that it's exactly closed, not just within a numerical tolerance.
|
||||||
|
sc->l.elem[sc->l.n - 1] = sc->l.elem[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
SPolyCurveLoops SPolyCurveLoops::From(SPolyCurveList *spcl, SPolygon *poly,
|
||||||
|
bool *allClosed, SEdge *errorAt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
SPolyCurveLoops ret;
|
||||||
|
ZERO(&ret);
|
||||||
|
|
||||||
|
while(spcl->l.n > 0) {
|
||||||
|
bool thisClosed;
|
||||||
|
SPolyCurveLoop loop;
|
||||||
|
loop = SPolyCurveLoop::FromCurves(spcl, &thisClosed, errorAt);
|
||||||
|
if(!thisClosed) {
|
||||||
|
ret.Clear();
|
||||||
|
*allClosed = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.l.Add(&loop);
|
||||||
|
poly->AddEmptyContour();
|
||||||
|
loop.MakePwlInto(&(poly->l.elem[poly->l.n-1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
poly->normal = poly->ComputeNormal();
|
||||||
|
ret.normal = poly->normal;
|
||||||
|
poly->FixContourDirections();
|
||||||
|
|
||||||
|
for(i = 0; i < poly->l.n; i++) {
|
||||||
|
if(poly->l.elem[i].tag) {
|
||||||
|
// We had to reverse this contour in order to fix the poly
|
||||||
|
// contour directions; so need to do the same with the curves.
|
||||||
|
ret.l.elem[i].Reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*allClosed = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPolyCurveLoops::Clear(void) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < l.n; i++) {
|
||||||
|
(l.elem[i]).Clear();
|
||||||
|
}
|
||||||
|
l.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
SSurface SSurface::FromExtrusionOf(SPolyCurve *spc, Vector t0, Vector t1) {
|
SSurface SSurface::FromExtrusionOf(SPolyCurve *spc, Vector t0, Vector t1) {
|
||||||
SSurface ret;
|
SSurface ret;
|
||||||
ZERO(&ret);
|
ZERO(&ret);
|
||||||
|
@ -205,11 +285,10 @@ SShell SShell::FromExtrusionOf(SPolyCurveList *spcl, Vector t0, Vector t1) {
|
||||||
SShell ret;
|
SShell ret;
|
||||||
ZERO(&ret);
|
ZERO(&ret);
|
||||||
|
|
||||||
// Find the plane that contains our input section.
|
// Group the input curves into loops, not necessarily in the right order.
|
||||||
|
|
||||||
// Group the input curves into loops; this will reverse some of the
|
|
||||||
// curves if necessary for consistent (but not necessarily correct yet)
|
// Find the plane that contains our input section.
|
||||||
// direction.
|
|
||||||
|
|
||||||
// Generate a polygon from the curves, and use this to test how many
|
// Generate a polygon from the curves, and use this to test how many
|
||||||
// times each loop is enclosed. Then set the direction (cw/ccw) to
|
// times each loop is enclosed. Then set the direction (cw/ccw) to
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
#ifndef __SURFACE_H
|
#ifndef __SURFACE_H
|
||||||
#define __SURFACE_H
|
#define __SURFACE_H
|
||||||
|
|
||||||
// Utility function
|
// Utility functions, Bernstein polynomials of order 1-3 and their derivatives.
|
||||||
double Bernstein(int k, int deg, double t);
|
double Bernstein(int k, int deg, double t);
|
||||||
|
double BernsteinDerivative(int k, int deg, double t);
|
||||||
|
|
||||||
class hSSurface {
|
class hSSurface {
|
||||||
public:
|
public:
|
||||||
|
@ -24,7 +25,7 @@ public:
|
||||||
Vector ctrl[4];
|
Vector ctrl[4];
|
||||||
double weight[4];
|
double weight[4];
|
||||||
|
|
||||||
Vector EvalAt(double t);
|
Vector PointAt(double t);
|
||||||
Vector Start(void);
|
Vector Start(void);
|
||||||
Vector Finish(void);
|
Vector Finish(void);
|
||||||
void MakePwlInto(List<Vector> *l);
|
void MakePwlInto(List<Vector> *l);
|
||||||
|
@ -48,11 +49,24 @@ class SPolyCurveLoop {
|
||||||
public:
|
public:
|
||||||
List<SPolyCurve> l;
|
List<SPolyCurve> l;
|
||||||
|
|
||||||
bool IsClockwiseProjdToNormal(Vector n);
|
inline void Clear(void) { l.Clear(); }
|
||||||
|
void Reverse(void);
|
||||||
|
void MakePwlInto(SContour *sc);
|
||||||
|
|
||||||
static SPolyCurveLoop FromCurves(SPolyCurveList *spcl, bool *notClosed);
|
static SPolyCurveLoop FromCurves(SPolyCurveList *spcl,
|
||||||
|
bool *allClosed, SEdge *errorAt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SPolyCurveLoops {
|
||||||
|
public:
|
||||||
|
List<SPolyCurveLoop> l;
|
||||||
|
Vector normal;
|
||||||
|
|
||||||
|
static SPolyCurveLoops From(SPolyCurveList *spcl, SPolygon *poly,
|
||||||
|
bool *allClosed, SEdge *errorAt);
|
||||||
|
|
||||||
|
void Clear(void);
|
||||||
|
};
|
||||||
|
|
||||||
// Stuff for the surface trim curves: piecewise linear
|
// Stuff for the surface trim curves: piecewise linear
|
||||||
class SCurve {
|
class SCurve {
|
||||||
|
@ -84,12 +98,17 @@ public:
|
||||||
int degm, degn;
|
int degm, degn;
|
||||||
Vector ctrl[4][4];
|
Vector ctrl[4][4];
|
||||||
double weight[4][4];
|
double weight[4][4];
|
||||||
Vector out00; // outer normal at ctrl[0][0]
|
|
||||||
|
|
||||||
List<STrimBy> trim;
|
List<STrimBy> trim;
|
||||||
|
|
||||||
static SSurface FromExtrusionOf(SPolyCurve *spc, Vector t0, Vector t1);
|
static SSurface FromExtrusionOf(SPolyCurve *spc, Vector t0, Vector t1);
|
||||||
|
|
||||||
|
void ClosestPointTo(Vector p, double *u, double *v);
|
||||||
|
Vector PointAt(double u, double v);
|
||||||
|
Vector TangentWrtUAt(double u, double v);
|
||||||
|
Vector TangentWrtVAt(double u, double v);
|
||||||
|
Vector NormalAt(double u, double v);
|
||||||
|
|
||||||
void TriangulateInto(SMesh *sm);
|
void TriangulateInto(SMesh *sm);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ void SolveSpace::PushFromCurrentOnto(UndoStack *uk) {
|
||||||
dest.vvMeshClean = false;
|
dest.vvMeshClean = false;
|
||||||
ZERO(&(dest.solved));
|
ZERO(&(dest.solved));
|
||||||
ZERO(&(dest.poly));
|
ZERO(&(dest.poly));
|
||||||
|
ZERO(&(dest.curveLoops));
|
||||||
ZERO(&(dest.polyError));
|
ZERO(&(dest.polyError));
|
||||||
ZERO(&(dest.thisMesh));
|
ZERO(&(dest.thisMesh));
|
||||||
ZERO(&(dest.runningMesh));
|
ZERO(&(dest.runningMesh));
|
||||||
|
@ -91,6 +92,7 @@ void SolveSpace::PopOntoCurrentFrom(UndoStack *uk) {
|
||||||
for(i = 0; i < group.n; i++) {
|
for(i = 0; i < group.n; i++) {
|
||||||
Group *g = &(group.elem[i]);
|
Group *g = &(group.elem[i]);
|
||||||
g->poly.Clear();
|
g->poly.Clear();
|
||||||
|
g->curveLoops.Clear();
|
||||||
g->thisMesh.Clear();
|
g->thisMesh.Clear();
|
||||||
g->runningMesh.Clear();
|
g->runningMesh.Clear();
|
||||||
g->meshError.interferesAt.Clear();
|
g->meshError.interferesAt.Clear();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user