2013-07-28 22:08:34 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Top-level functions to compute the Boolean union or difference between
|
|
|
|
// two shells of rational polynomial surfaces.
|
2015-03-29 00:30:52 +00:00
|
|
|
//
|
2013-07-28 22:08:34 +00:00
|
|
|
// Copyright 2008-2013 Jonathan Westhues.
|
|
|
|
//-----------------------------------------------------------------------------
|
2009-01-23 03:30:30 +00:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
2016-02-14 00:36:54 +00:00
|
|
|
static int I;
|
2009-02-01 05:13:43 +00:00
|
|
|
|
2009-01-23 03:30:30 +00:00
|
|
|
void SShell::MakeFromUnionOf(SShell *a, SShell *b) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
MakeFromBoolean(a, b, SSurface::CombineAs::UNION);
|
2009-01-23 03:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SShell::MakeFromDifferenceOf(SShell *a, SShell *b) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
MakeFromBoolean(a, b, SSurface::CombineAs::DIFFERENCE);
|
2009-01-25 11:52:29 +00:00
|
|
|
}
|
|
|
|
|
2009-02-27 13:04:36 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Take our original pwl curve. Wherever an edge intersects a surface within
|
|
|
|
// either agnstA or agnstB, split the piecewise linear element. Then refine
|
|
|
|
// the intersection so that it lies on all three relevant surfaces: the
|
|
|
|
// intersecting surface, srfA, and srfB. (So the pwl curve should lie at
|
|
|
|
// the intersection of srfA and srfB.) Return a new pwl curve with everything
|
|
|
|
// split.
|
|
|
|
//-----------------------------------------------------------------------------
|
2009-02-01 05:13:43 +00:00
|
|
|
static Vector LineStart, LineDirection;
|
|
|
|
static int ByTAlongLine(const void *av, const void *bv)
|
|
|
|
{
|
2009-02-01 13:01:28 +00:00
|
|
|
SInter *a = (SInter *)av,
|
|
|
|
*b = (SInter *)bv;
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2009-02-01 13:01:28 +00:00
|
|
|
double ta = (a->p.Minus(LineStart)).DivPivoting(LineDirection),
|
|
|
|
tb = (b->p.Minus(LineStart)).DivPivoting(LineDirection);
|
2009-02-01 05:13:43 +00:00
|
|
|
|
|
|
|
return (ta > tb) ? 1 : -1;
|
|
|
|
}
|
2009-02-27 13:04:36 +00:00
|
|
|
SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
2016-05-21 05:18:00 +00:00
|
|
|
SSurface *srfA, SSurface *srfB) const
|
2009-02-27 13:04:36 +00:00
|
|
|
{
|
2009-01-25 11:52:29 +00:00
|
|
|
SCurve ret;
|
2009-01-27 07:59:58 +00:00
|
|
|
ret = *this;
|
2015-03-27 15:31:23 +00:00
|
|
|
ret.pts = {};
|
2009-01-25 11:52:29 +00:00
|
|
|
|
2016-05-21 05:18:00 +00:00
|
|
|
const SCurvePt *p = pts.First();
|
2016-05-18 22:51:36 +00:00
|
|
|
ssassert(p != NULL, "Cannot split an empty curve");
|
2009-05-18 07:26:51 +00:00
|
|
|
SCurvePt prev = *p;
|
2009-02-01 05:13:43 +00:00
|
|
|
ret.pts.Add(p);
|
|
|
|
p = pts.NextAfter(p);
|
|
|
|
|
|
|
|
for(; p; p = pts.NextAfter(p)) {
|
2015-03-27 15:31:23 +00:00
|
|
|
List<SInter> il = {};
|
2009-02-01 05:13:43 +00:00
|
|
|
|
|
|
|
// Find all the intersections with the two passed shells
|
2009-05-18 07:26:51 +00:00
|
|
|
if(agnstA)
|
2009-08-21 04:58:28 +00:00
|
|
|
agnstA->AllPointsIntersecting(prev.p, p->p, &il, true, false, true);
|
2009-05-18 07:26:51 +00:00
|
|
|
if(agnstB)
|
2009-08-21 04:58:28 +00:00
|
|
|
agnstB->AllPointsIntersecting(prev.p, p->p, &il, true, false, true);
|
2009-02-01 05:13:43 +00:00
|
|
|
|
|
|
|
if(il.n > 0) {
|
2009-03-08 10:59:57 +00:00
|
|
|
// The intersections were generated by intersecting the pwl
|
|
|
|
// edge against a surface; so they must be refined to lie
|
|
|
|
// exactly on the original curve.
|
2009-06-21 09:54:21 +00:00
|
|
|
il.ClearTags();
|
2009-02-01 13:01:28 +00:00
|
|
|
SInter *pi;
|
2009-02-01 05:13:43 +00:00
|
|
|
for(pi = il.First(); pi; pi = il.NextAfter(pi)) {
|
2009-06-21 09:54:21 +00:00
|
|
|
if(pi->srf == srfA || pi->srf == srfB) {
|
|
|
|
// The edge certainly intersects the surfaces that it
|
|
|
|
// trims (at its endpoints), but those ones don't count.
|
|
|
|
// They are culled later, but no sense calculating them
|
|
|
|
// and they will cause numerical problems (since two
|
|
|
|
// of the three surfaces they're refined to lie on will
|
|
|
|
// be identical, so the matrix will be singular).
|
|
|
|
pi->tag = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2009-08-21 04:58:28 +00:00
|
|
|
|
|
|
|
Point2d puv;
|
|
|
|
(pi->srf)->ClosestPointTo(pi->p, &puv, false);
|
|
|
|
|
|
|
|
// Split the edge if the intersection lies within the surface's
|
|
|
|
// trim curves, or within the chord tol of the trim curve; want
|
|
|
|
// some slop if points are close to edge and pwl is too coarse,
|
|
|
|
// and it doesn't hurt to split unnecessarily.
|
|
|
|
Point2d dummy = { 0, 0 };
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
SBspUv::Class c = (pi->srf->bsp) ? pi->srf->bsp->ClassifyPoint(puv, dummy, pi->srf) : SBspUv::Class::OUTSIDE;
|
|
|
|
if(c == SBspUv::Class::OUTSIDE) {
|
2016-03-25 14:16:58 +00:00
|
|
|
double d = VERY_POSITIVE;
|
|
|
|
if(pi->srf->bsp) d = pi->srf->bsp->MinimumDistanceToEdge(puv, pi->srf);
|
2009-08-21 04:58:28 +00:00
|
|
|
if(d > SS.ChordTolMm()) {
|
|
|
|
pi->tag = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're keeping the intersection, so actually refine it.
|
|
|
|
(pi->srf)->PointOnSurfaces(srfA, srfB, &(puv.x), &(puv.y));
|
|
|
|
pi->p = (pi->srf)->PointAt(puv);
|
2009-03-08 10:59:57 +00:00
|
|
|
}
|
2009-06-21 09:54:21 +00:00
|
|
|
il.RemoveTagged();
|
2009-02-27 13:04:36 +00:00
|
|
|
|
2009-03-08 10:59:57 +00:00
|
|
|
// And now sort them in order along the line. Note that we must
|
|
|
|
// do that after refining, in case the refining would make two
|
|
|
|
// points switch places.
|
2009-05-18 07:26:51 +00:00
|
|
|
LineStart = prev.p;
|
|
|
|
LineDirection = (p->p).Minus(prev.p);
|
2009-03-08 10:59:57 +00:00
|
|
|
qsort(il.elem, il.n, sizeof(il.elem[0]), ByTAlongLine);
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2009-03-08 10:59:57 +00:00
|
|
|
// And now uses the intersections to generate our split pwl edge(s)
|
|
|
|
Vector prev = Vector::From(VERY_POSITIVE, 0, 0);
|
|
|
|
for(pi = il.First(); pi; pi = il.NextAfter(pi)) {
|
2009-02-09 12:40:48 +00:00
|
|
|
// On-edge intersection will generate same split point for
|
|
|
|
// both surfaces, so don't create zero-length edge.
|
|
|
|
if(!prev.Equals(pi->p)) {
|
2009-05-18 07:26:51 +00:00
|
|
|
SCurvePt scpt;
|
|
|
|
scpt.tag = 0;
|
|
|
|
scpt.p = pi->p;
|
|
|
|
scpt.vertex = true;
|
|
|
|
ret.pts.Add(&scpt);
|
2009-02-09 12:40:48 +00:00
|
|
|
}
|
|
|
|
prev = pi->p;
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-01 13:01:28 +00:00
|
|
|
il.Clear();
|
2009-01-25 11:52:29 +00:00
|
|
|
ret.pts.Add(p);
|
2009-02-01 05:13:43 +00:00
|
|
|
prev = *p;
|
2009-01-25 11:52:29 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-03-29 00:30:52 +00:00
|
|
|
void SShell::CopyCurvesSplitAgainst(bool opA, SShell *agnst, SShell *into) {
|
2009-01-25 11:52:29 +00:00
|
|
|
SCurve *sc;
|
|
|
|
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
|
2009-02-27 13:04:36 +00:00
|
|
|
SCurve scn = sc->MakeCopySplitAgainst(agnst, NULL,
|
|
|
|
surface.FindById(sc->surfA),
|
|
|
|
surface.FindById(sc->surfB));
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
scn.source = opA ? SCurve::Source::A : SCurve::Source::B;
|
2009-02-27 13:04:36 +00:00
|
|
|
|
2009-01-25 11:52:29 +00:00
|
|
|
hSCurve hsc = into->curve.AddAndAssignId(&scn);
|
|
|
|
// And note the new ID so that we can rewrite the trims appropriately
|
|
|
|
sc->newH = hsc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-05 05:38:41 +00:00
|
|
|
void SSurface::TrimFromEdgeList(SEdgeList *el, bool asUv) {
|
2009-01-25 11:52:29 +00:00
|
|
|
el->l.ClearTags();
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2015-03-27 15:31:23 +00:00
|
|
|
STrimBy stb = {};
|
2009-01-25 11:52:29 +00:00
|
|
|
for(;;) {
|
|
|
|
// Find an edge, any edge; we'll start from there.
|
|
|
|
SEdge *se;
|
|
|
|
for(se = el->l.First(); se; se = el->l.NextAfter(se)) {
|
|
|
|
if(se->tag) continue;
|
2015-03-29 00:30:52 +00:00
|
|
|
break;
|
2009-01-25 11:52:29 +00:00
|
|
|
}
|
|
|
|
if(!se) break;
|
|
|
|
se->tag = 1;
|
|
|
|
stb.start = se->a;
|
|
|
|
stb.finish = se->b;
|
|
|
|
stb.curve.v = se->auxA;
|
|
|
|
stb.backwards = se->auxB ? true : false;
|
|
|
|
|
|
|
|
// Find adjoining edges from the same curve; those should be
|
|
|
|
// merged into a single trim.
|
|
|
|
bool merged;
|
|
|
|
do {
|
|
|
|
merged = false;
|
|
|
|
for(se = el->l.First(); se; se = el->l.NextAfter(se)) {
|
|
|
|
if(se->tag) continue;
|
2013-08-26 20:09:15 +00:00
|
|
|
if(se->auxA != (int)stb.curve.v) continue;
|
2009-01-25 11:52:29 +00:00
|
|
|
if(( se->auxB && !stb.backwards) ||
|
|
|
|
(!se->auxB && stb.backwards)) continue;
|
|
|
|
|
|
|
|
if((se->a).Equals(stb.finish)) {
|
|
|
|
stb.finish = se->b;
|
|
|
|
se->tag = 1;
|
|
|
|
merged = true;
|
|
|
|
} else if((se->b).Equals(stb.start)) {
|
|
|
|
stb.start = se->a;
|
|
|
|
se->tag = 1;
|
|
|
|
merged = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while(merged);
|
|
|
|
|
2009-06-05 05:38:41 +00:00
|
|
|
if(asUv) {
|
|
|
|
stb.start = PointAt(stb.start.x, stb.start.y);
|
|
|
|
stb.finish = PointAt(stb.finish.x, stb.finish.y);
|
|
|
|
}
|
|
|
|
|
2009-01-25 11:52:29 +00:00
|
|
|
// And add the merged trim, with xyz (not uv like the polygon) pts
|
|
|
|
trim.Add(&stb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
static bool KeepRegion(SSurface::CombineAs type, bool opA, SShell::Class shell, SShell::Class orig)
|
2009-02-16 12:05:08 +00:00
|
|
|
{
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
bool inShell = (shell == SShell::Class::INSIDE),
|
|
|
|
inSame = (shell == SShell::Class::COINC_SAME),
|
|
|
|
inOpp = (shell == SShell::Class::COINC_OPP),
|
|
|
|
inOrig = (orig == SShell::Class::INSIDE);
|
2009-02-16 12:05:08 +00:00
|
|
|
|
|
|
|
bool inFace = inSame || inOpp;
|
|
|
|
|
|
|
|
// If these are correct, then they should be independent of inShell
|
|
|
|
// if inFace is true.
|
|
|
|
if(!inOrig) return false;
|
|
|
|
switch(type) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case SSurface::CombineAs::UNION:
|
2009-02-16 12:05:08 +00:00
|
|
|
if(opA) {
|
|
|
|
return (!inShell && !inFace);
|
|
|
|
} else {
|
|
|
|
return (!inShell && !inFace) || inSame;
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case SSurface::CombineAs::DIFFERENCE:
|
2009-02-16 12:05:08 +00:00
|
|
|
if(opA) {
|
|
|
|
return (!inShell && !inFace);
|
|
|
|
} else {
|
|
|
|
return (inShell && !inFace) || inSame;
|
|
|
|
}
|
|
|
|
|
Enable exhaustive switch coverage warnings as an error, and use them.
Specifically, this enables -Wswitch=error on GCC/Clang and its MSVC
equivalent; the exact way it is handled varies slightly, but what
they all have in common is that in a switch statement over an
enumeration, any enumerand that is not explicitly (via case:) or
implicitly (via default:) handled in the switch triggers an error.
Moreover, we also change the switch statements in three ways:
* Switch statements that ought to be extended every time a new
enumerand is added (e.g. Entity::DrawOrGetDistance(), are changed
to explicitly list every single enumerand, and not have a
default: branch.
Note that the assertions are kept because it is legal for
a enumeration to have a value unlike any of its defined
enumerands, and we can e.g. read garbage from a file, or
an uninitialized variable. This requires some rearranging if
a default: branch is undesired.
* Switch statements that ought to only ever see a few select
enumerands, are changed to always assert in the default: branch.
* Switch statements that do something meaningful for a few
enumerands, and ignore everything else, are changed to do nothing
in a default: branch, under the assumption that changing them
every time an enumerand is added or removed would just result
in noise and catch no bugs.
This commit also removes the {Request,Entity,Constraint}::UNKNOWN and
Entity::DATUM_POINT enumerands, as those were just fancy names for
zeroes. They mess up switch exhaustiveness checks and most of the time
were not the best way to implement what they did anyway.
2016-05-25 06:55:50 +00:00
|
|
|
default: ssassert(false, "Unexpected combine type");
|
2009-02-16 12:05:08 +00:00
|
|
|
}
|
|
|
|
}
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
static bool KeepEdge(SSurface::CombineAs type, bool opA,
|
|
|
|
SShell::Class indir_shell, SShell::Class outdir_shell,
|
|
|
|
SShell::Class indir_orig, SShell::Class outdir_orig)
|
2009-02-16 12:05:08 +00:00
|
|
|
{
|
2009-06-04 03:59:40 +00:00
|
|
|
bool keepIn = KeepRegion(type, opA, indir_shell, indir_orig),
|
|
|
|
keepOut = KeepRegion(type, opA, outdir_shell, outdir_orig);
|
2009-02-16 12:05:08 +00:00
|
|
|
|
|
|
|
// If the regions to the left and right of this edge are both in or both
|
|
|
|
// out, then this edge is not useful and should be discarded.
|
|
|
|
if(keepIn && !keepOut) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
static void TagByClassifiedEdge(SBspUv::Class bspclass, SShell::Class *indir, SShell::Class *outdir)
|
2009-02-16 12:05:08 +00:00
|
|
|
{
|
|
|
|
switch(bspclass) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case SBspUv::Class::INSIDE:
|
|
|
|
*indir = SShell::Class::INSIDE;
|
|
|
|
*outdir = SShell::Class::INSIDE;
|
2009-06-04 03:59:40 +00:00
|
|
|
break;
|
2009-02-16 12:05:08 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case SBspUv::Class::OUTSIDE:
|
|
|
|
*indir = SShell::Class::OUTSIDE;
|
|
|
|
*outdir = SShell::Class::OUTSIDE;
|
2009-06-04 03:59:40 +00:00
|
|
|
break;
|
2009-02-16 12:05:08 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case SBspUv::Class::EDGE_PARALLEL:
|
|
|
|
*indir = SShell::Class::INSIDE;
|
|
|
|
*outdir = SShell::Class::OUTSIDE;
|
2009-06-04 03:59:40 +00:00
|
|
|
break;
|
2009-02-16 12:05:08 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
case SBspUv::Class::EDGE_ANTIPARALLEL:
|
|
|
|
*indir = SShell::Class::OUTSIDE;
|
|
|
|
*outdir = SShell::Class::INSIDE;
|
2009-06-04 03:59:40 +00:00
|
|
|
break;
|
2009-02-16 12:05:08 +00:00
|
|
|
|
2009-06-21 20:39:42 +00:00
|
|
|
default:
|
|
|
|
dbp("TagByClassifiedEdge: fail!");
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
*indir = SShell::Class::OUTSIDE;
|
|
|
|
*outdir = SShell::Class::OUTSIDE;
|
2009-06-21 20:39:42 +00:00
|
|
|
break;
|
2009-02-16 12:05:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-19 05:36:45 +00:00
|
|
|
static void DEBUGEDGELIST(SEdgeList *sel, SSurface *surf) {
|
2009-03-08 10:59:57 +00:00
|
|
|
dbp("print %d edges", sel->l.n);
|
2009-02-17 11:17:12 +00:00
|
|
|
SEdge *se;
|
|
|
|
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
|
|
|
|
Vector mid = (se->a).Plus(se->b).ScaledBy(0.5);
|
|
|
|
Vector arrow = (se->b).Minus(se->a);
|
2015-03-27 15:43:28 +00:00
|
|
|
swap(arrow.x, arrow.y);
|
2009-02-17 11:17:12 +00:00
|
|
|
arrow.x *= -1;
|
2009-07-02 03:32:17 +00:00
|
|
|
arrow = arrow.WithMagnitude(0.01);
|
2009-02-17 11:17:12 +00:00
|
|
|
arrow = arrow.Plus(mid);
|
|
|
|
|
|
|
|
SS.nakedEdges.AddEdge(surf->PointAt(se->a.x, se->a.y),
|
|
|
|
surf->PointAt(se->b.x, se->b.y));
|
|
|
|
SS.nakedEdges.AddEdge(surf->PointAt(mid.x, mid.y),
|
|
|
|
surf->PointAt(arrow.x, arrow.y));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-27 05:53:56 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// We are given src, with at least one edge, and avoid, a list of points to
|
|
|
|
// avoid. We return a chain of edges (that share endpoints), such that no
|
|
|
|
// point within the avoid list ever occurs in the middle of a chain. And we
|
|
|
|
// delete the edges in that chain from our source list.
|
|
|
|
//-----------------------------------------------------------------------------
|
2015-03-29 00:30:52 +00:00
|
|
|
void SSurface::FindChainAvoiding(SEdgeList *src, SEdgeList *dest,
|
2009-06-27 05:53:56 +00:00
|
|
|
SPointList *avoid)
|
|
|
|
{
|
2016-05-18 22:51:36 +00:00
|
|
|
ssassert(src->l.n > 0, "Need at least one edge");
|
2009-06-27 05:53:56 +00:00
|
|
|
// Start with an arbitrary edge.
|
|
|
|
dest->l.Add(&(src->l.elem[0]));
|
|
|
|
src->l.ClearTags();
|
|
|
|
src->l.elem[0].tag = 1;
|
|
|
|
|
|
|
|
bool added;
|
|
|
|
do {
|
|
|
|
added = false;
|
|
|
|
// The start and finish of the current edge chain
|
|
|
|
Vector s = dest->l.elem[0].a,
|
|
|
|
f = dest->l.elem[dest->l.n - 1].b;
|
|
|
|
|
|
|
|
// We can attach a new edge at the start or finish, as long as that
|
|
|
|
// start or finish point isn't in the list of points to avoid.
|
|
|
|
bool startOkay = !avoid->ContainsPoint(s),
|
|
|
|
finishOkay = !avoid->ContainsPoint(f);
|
|
|
|
|
|
|
|
// Now look for an unused edge that joins at the start or finish of
|
|
|
|
// our chain (if permitted by the avoid list).
|
|
|
|
SEdge *se;
|
|
|
|
for(se = src->l.First(); se; se = src->l.NextAfter(se)) {
|
|
|
|
if(se->tag) continue;
|
|
|
|
if(startOkay && s.Equals(se->b)) {
|
|
|
|
dest->l.AddToBeginning(se);
|
|
|
|
s = se->a;
|
|
|
|
se->tag = 1;
|
|
|
|
startOkay = !avoid->ContainsPoint(s);
|
|
|
|
} else if(finishOkay && f.Equals(se->a)) {
|
|
|
|
dest->l.Add(se);
|
|
|
|
f = se->b;
|
|
|
|
se->tag = 1;
|
|
|
|
finishOkay = !avoid->ContainsPoint(f);
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
added = true;
|
|
|
|
}
|
|
|
|
} while(added);
|
|
|
|
|
|
|
|
src->l.RemoveTagged();
|
|
|
|
}
|
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
void SSurface::EdgeNormalsWithinSurface(Point2d auv, Point2d buv,
|
|
|
|
Vector *pt,
|
|
|
|
Vector *enin, Vector *enout,
|
|
|
|
Vector *surfn,
|
Use C99 integer types and C++ boolean types/values
This change comprehensively replaces the use of Microsoft-standard integer
and boolean types with their C99/C++ standard equivalents, as the latter is
more appropriate for a cross-platform application. With matter-of-course
exceptions in the Win32-specific code, the types/values have been converted
as follows:
QWORD --> uint64_t
SQWORD --> int64_t
DWORD --> uint32_t
SDWORD --> int32_t
WORD --> uint16_t
SWORD --> int16_t
BYTE --> uint8_t
BOOL --> bool
TRUE --> true
FALSE --> false
The following related changes are also included:
* Added C99 integer type definitions for Windows, as stdint.h is not
available prior to Visual Studio 2010
* Changed types of some variables in the SolveSpace class from 'int' to
'bool', as they actually represent boolean settings
* Implemented new Cnf{Freeze,Thaw}Bool() functions to support boolean
variables in the Registry
* Cnf{Freeze,Thaw}DWORD() are now Cnf{Freeze,Thaw}Int()
* TtfFont::Get{WORD,DWORD}() are now TtfFont::Get{USHORT,ULONG}() (names
inspired by the OpenType spec)
* RGB colors are packed into an integer of type uint32_t (nee DWORD), but
in a few places, these were represented by an int; these have been
corrected to uint32_t
2013-10-02 05:45:13 +00:00
|
|
|
uint32_t auxA,
|
2009-06-19 07:56:33 +00:00
|
|
|
SShell *shell, SShell *sha, SShell *shb)
|
2009-06-04 03:59:40 +00:00
|
|
|
{
|
|
|
|
// the midpoint of the edge
|
|
|
|
Point2d muv = (auv.Plus(buv)).ScaledBy(0.5);
|
|
|
|
|
|
|
|
*pt = PointAt(muv);
|
|
|
|
|
|
|
|
// If this edge just approximates a curve, then refine our midpoint so
|
|
|
|
// so that it actually lies on that curve too. Otherwise stuff like
|
|
|
|
// point-on-face tests will fail, since the point won't actually lie
|
|
|
|
// on the other face.
|
|
|
|
hSCurve hc = { auxA };
|
|
|
|
SCurve *sc = shell->curve.FindById(hc);
|
|
|
|
if(sc->isExact && sc->exact.deg != 1) {
|
|
|
|
double t;
|
|
|
|
sc->exact.ClosestPointTo(*pt, &t, false);
|
|
|
|
*pt = sc->exact.PointAt(t);
|
2009-06-10 08:04:35 +00:00
|
|
|
ClosestPointTo(*pt, &muv);
|
2009-06-19 07:56:33 +00:00
|
|
|
} else if(!sc->isExact) {
|
|
|
|
SSurface *trimmedA = sc->GetSurfaceA(sha, shb),
|
2016-05-21 05:18:00 +00:00
|
|
|
*trimmedB = sc->GetSurfaceB(sha, shb);
|
2009-06-19 07:56:33 +00:00
|
|
|
*pt = trimmedA->ClosestPointOnThisAndSurface(trimmedB, *pt);
|
|
|
|
ClosestPointTo(*pt, &muv);
|
2009-06-04 03:59:40 +00:00
|
|
|
}
|
|
|
|
|
2009-06-10 08:04:35 +00:00
|
|
|
*surfn = NormalAt(muv.x, muv.y);
|
|
|
|
|
2009-06-19 07:56:33 +00:00
|
|
|
// Compute the edge's inner normal in xyz space.
|
|
|
|
Vector ab = (PointAt(auv)).Minus(PointAt(buv)),
|
|
|
|
enxyz = (ab.Cross(*surfn)).WithMagnitude(SS.ChordTolMm());
|
|
|
|
// And based on that, compute the edge's inner normal in uv space. This
|
|
|
|
// vector is perpendicular to the edge in xyz, but not necessarily in uv.
|
|
|
|
Vector tu, tv;
|
|
|
|
TangentsAt(muv.x, muv.y, &tu, &tv);
|
|
|
|
Point2d enuv;
|
|
|
|
enuv.x = enxyz.Dot(tu) / tu.MagSquared();
|
|
|
|
enuv.y = enxyz.Dot(tv) / tv.MagSquared();
|
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
// Compute the inner and outer normals of this edge (within the srf),
|
|
|
|
// in xyz space. These are not necessarily antiparallel, if the
|
|
|
|
// surface is curved.
|
2009-06-19 07:56:33 +00:00
|
|
|
Vector pin = PointAt(muv.Minus(enuv)),
|
|
|
|
pout = PointAt(muv.Plus(enuv));
|
2009-06-04 03:59:40 +00:00
|
|
|
*enin = pin.Minus(*pt),
|
|
|
|
*enout = pout.Minus(*pt);
|
|
|
|
}
|
|
|
|
|
2009-01-25 11:52:29 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Trim this surface against the specified shell, in the way that's appropriate
|
|
|
|
// for the specified Boolean operation type (and which operand we are). We
|
|
|
|
// also need a pointer to the shell that contains our own surface, since that
|
|
|
|
// contains our original trim curves.
|
|
|
|
//-----------------------------------------------------------------------------
|
2009-06-19 07:56:33 +00:00
|
|
|
SSurface SSurface::MakeCopyTrimAgainst(SShell *parent,
|
|
|
|
SShell *sha, SShell *shb,
|
2009-02-01 05:13:43 +00:00
|
|
|
SShell *into,
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
SSurface::CombineAs type)
|
2009-01-25 11:52:29 +00:00
|
|
|
{
|
2009-06-19 07:56:33 +00:00
|
|
|
bool opA = (parent == sha);
|
|
|
|
SShell *agnst = opA ? shb : sha;
|
|
|
|
|
2009-01-25 11:52:29 +00:00
|
|
|
SSurface ret;
|
|
|
|
// The returned surface is identical, just the trim curves change
|
|
|
|
ret = *this;
|
2015-03-27 15:31:23 +00:00
|
|
|
ret.trim = {};
|
2009-01-25 11:52:29 +00:00
|
|
|
|
2009-02-01 05:13:43 +00:00
|
|
|
// First, build a list of the existing trim curves; update them to use
|
|
|
|
// the split curves.
|
|
|
|
STrimBy *stb;
|
|
|
|
for(stb = trim.First(); stb; stb = trim.NextAfter(stb)) {
|
|
|
|
STrimBy stn = *stb;
|
|
|
|
stn.curve = (parent->curve.FindById(stn.curve))->newH;
|
|
|
|
ret.trim.Add(&stn);
|
|
|
|
}
|
2009-01-25 11:52:29 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
if(type == SSurface::CombineAs::DIFFERENCE && !opA) {
|
2009-02-16 12:05:08 +00:00
|
|
|
// The second operand of a Boolean difference gets turned inside out
|
|
|
|
ret.Reverse();
|
|
|
|
}
|
|
|
|
|
2009-02-17 11:17:12 +00:00
|
|
|
// Build up our original trim polygon; remember the coordinates could
|
2009-06-04 03:59:40 +00:00
|
|
|
// be changed if we just flipped the surface normal, and we are using
|
|
|
|
// the split curves (not the original curves).
|
2015-03-27 15:31:23 +00:00
|
|
|
SEdgeList orig = {};
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
ret.MakeEdgesInto(into, &orig, MakeAs::UV);
|
2009-02-01 05:13:43 +00:00
|
|
|
ret.trim.Clear();
|
2009-02-17 11:17:12 +00:00
|
|
|
// which means that we can't necessarily use the old BSP...
|
2009-07-02 03:32:17 +00:00
|
|
|
SBspUv *origBsp = SBspUv::From(&orig, &ret);
|
2009-01-25 11:52:29 +00:00
|
|
|
|
2009-02-01 05:13:43 +00:00
|
|
|
// And now intersect the other shell against us
|
2015-03-27 15:31:23 +00:00
|
|
|
SEdgeList inter = {};
|
2009-02-01 05:13:43 +00:00
|
|
|
|
|
|
|
SSurface *ss;
|
|
|
|
for(ss = agnst->surface.First(); ss; ss = agnst->surface.NextAfter(ss)) {
|
|
|
|
SCurve *sc;
|
|
|
|
for(sc = into->curve.First(); sc; sc = into->curve.NextAfter(sc)) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
if(sc->source != SCurve::Source::INTERSECTION) continue;
|
2009-02-01 05:13:43 +00:00
|
|
|
if(opA) {
|
|
|
|
if(sc->surfA.v != h.v || sc->surfB.v != ss->h.v) continue;
|
2009-03-15 23:04:45 +00:00
|
|
|
} else {
|
|
|
|
if(sc->surfB.v != h.v || sc->surfA.v != ss->h.v) continue;
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2009-02-01 05:13:43 +00:00
|
|
|
int i;
|
|
|
|
for(i = 1; i < sc->pts.n; i++) {
|
2009-05-18 07:26:51 +00:00
|
|
|
Vector a = sc->pts.elem[i-1].p,
|
|
|
|
b = sc->pts.elem[i].p;
|
2009-02-01 05:13:43 +00:00
|
|
|
|
|
|
|
Point2d auv, buv;
|
|
|
|
ss->ClosestPointTo(a, &(auv.x), &(auv.y));
|
|
|
|
ss->ClosestPointTo(b, &(buv.x), &(buv.y));
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
SBspUv::Class c = (ss->bsp) ? ss->bsp->ClassifyEdge(auv, buv, ss) : SBspUv::Class::OUTSIDE;
|
|
|
|
if(c != SBspUv::Class::OUTSIDE) {
|
2009-02-01 05:13:43 +00:00
|
|
|
Vector ta = Vector::From(0, 0, 0);
|
|
|
|
Vector tb = Vector::From(0, 0, 0);
|
2009-02-16 12:05:08 +00:00
|
|
|
ret.ClosestPointTo(a, &(ta.x), &(ta.y));
|
|
|
|
ret.ClosestPointTo(b, &(tb.x), &(tb.y));
|
2009-02-01 05:13:43 +00:00
|
|
|
|
2009-02-16 12:05:08 +00:00
|
|
|
Vector tn = ret.NormalAt(ta.x, ta.y);
|
2009-02-01 05:13:43 +00:00
|
|
|
Vector sn = ss->NormalAt(auv.x, auv.y);
|
|
|
|
|
2009-02-17 11:17:12 +00:00
|
|
|
// We are subtracting the portion of our surface that
|
|
|
|
// lies in the shell, so the in-plane edge normal should
|
|
|
|
// point opposite to the surface normal.
|
|
|
|
bool bkwds = true;
|
2009-02-16 12:05:08 +00:00
|
|
|
if((tn.Cross(b.Minus(a))).Dot(sn) < 0) bkwds = !bkwds;
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
if(type == SSurface::CombineAs::DIFFERENCE && !opA) bkwds = !bkwds;
|
2009-02-16 12:05:08 +00:00
|
|
|
if(bkwds) {
|
2009-02-01 05:13:43 +00:00
|
|
|
inter.AddEdge(tb, ta, sc->h.v, 1);
|
2015-03-29 00:30:52 +00:00
|
|
|
} else {
|
2009-02-16 12:05:08 +00:00
|
|
|
inter.AddEdge(ta, tb, sc->h.v, 0);
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-27 05:53:56 +00:00
|
|
|
// Record all the points where more than two edges join, which I will call
|
|
|
|
// the choosing points. If two edges join at a non-choosing point, then
|
|
|
|
// they must either both be kept or both be discarded (since that would
|
|
|
|
// otherwise create an open contour).
|
2015-03-27 15:31:23 +00:00
|
|
|
SPointList choosing = {};
|
2009-06-27 05:53:56 +00:00
|
|
|
SEdge *se;
|
|
|
|
for(se = orig.l.First(); se; se = orig.l.NextAfter(se)) {
|
|
|
|
choosing.IncrementTagFor(se->a);
|
|
|
|
choosing.IncrementTagFor(se->b);
|
|
|
|
}
|
|
|
|
for(se = inter.l.First(); se; se = inter.l.NextAfter(se)) {
|
|
|
|
choosing.IncrementTagFor(se->a);
|
|
|
|
choosing.IncrementTagFor(se->b);
|
|
|
|
}
|
|
|
|
SPoint *sp;
|
|
|
|
for(sp = choosing.l.First(); sp; sp = choosing.l.NextAfter(sp)) {
|
|
|
|
if(sp->tag == 2) {
|
|
|
|
sp->tag = 1;
|
|
|
|
} else {
|
|
|
|
sp->tag = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
choosing.l.RemoveTagged();
|
|
|
|
|
|
|
|
// The list of edges to trim our new surface, a combination of edges from
|
|
|
|
// our original and intersecting edge lists.
|
2015-03-27 15:31:23 +00:00
|
|
|
SEdgeList final = {};
|
2009-02-01 05:13:43 +00:00
|
|
|
|
2009-06-27 05:53:56 +00:00
|
|
|
while(orig.l.n > 0) {
|
2015-03-27 15:31:23 +00:00
|
|
|
SEdgeList chain = {};
|
2009-06-27 05:53:56 +00:00
|
|
|
FindChainAvoiding(&orig, &chain, &choosing);
|
|
|
|
|
|
|
|
// Arbitrarily choose an edge within the chain to classify; they
|
|
|
|
// should all be the same, though.
|
|
|
|
se = &(chain.l.elem[chain.l.n/2]);
|
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
Point2d auv = (se->a).ProjectXy(),
|
|
|
|
buv = (se->b).ProjectXy();
|
2009-02-09 12:40:48 +00:00
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
Vector pt, enin, enout, surfn;
|
|
|
|
ret.EdgeNormalsWithinSurface(auv, buv, &pt, &enin, &enout, &surfn,
|
2009-06-19 07:56:33 +00:00
|
|
|
se->auxA, into, sha, shb);
|
2009-06-04 03:59:40 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
SShell::Class indir_shell, outdir_shell, indir_orig, outdir_orig;
|
2009-06-04 03:59:40 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
indir_orig = SShell::Class::INSIDE;
|
|
|
|
outdir_orig = SShell::Class::OUTSIDE;
|
2009-06-04 03:59:40 +00:00
|
|
|
|
|
|
|
agnst->ClassifyEdge(&indir_shell, &outdir_shell,
|
2015-03-29 00:30:52 +00:00
|
|
|
ret.PointAt(auv), ret.PointAt(buv), pt,
|
2009-06-04 03:59:40 +00:00
|
|
|
enin, enout, surfn);
|
2009-03-15 23:04:45 +00:00
|
|
|
|
2015-03-29 00:30:52 +00:00
|
|
|
if(KeepEdge(type, opA, indir_shell, outdir_shell,
|
2009-06-04 03:59:40 +00:00
|
|
|
indir_orig, outdir_orig))
|
|
|
|
{
|
2009-06-27 05:53:56 +00:00
|
|
|
for(se = chain.l.First(); se; se = chain.l.NextAfter(se)) {
|
|
|
|
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
|
|
|
|
}
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
2009-06-27 05:53:56 +00:00
|
|
|
chain.Clear();
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
|
2009-06-27 05:53:56 +00:00
|
|
|
while(inter.l.n > 0) {
|
2015-03-27 15:31:23 +00:00
|
|
|
SEdgeList chain = {};
|
2009-06-27 05:53:56 +00:00
|
|
|
FindChainAvoiding(&inter, &chain, &choosing);
|
|
|
|
|
|
|
|
// Any edge in the chain, same as above.
|
|
|
|
se = &(chain.l.elem[chain.l.n/2]);
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2009-02-09 12:40:48 +00:00
|
|
|
Point2d auv = (se->a).ProjectXy(),
|
|
|
|
buv = (se->b).ProjectXy();
|
2009-02-01 05:13:43 +00:00
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
Vector pt, enin, enout, surfn;
|
|
|
|
ret.EdgeNormalsWithinSurface(auv, buv, &pt, &enin, &enout, &surfn,
|
2009-06-19 07:56:33 +00:00
|
|
|
se->auxA, into, sha, shb);
|
2009-02-01 05:13:43 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
SShell::Class indir_shell, outdir_shell, indir_orig, outdir_orig;
|
2009-02-16 12:05:08 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
SBspUv::Class c_this = (origBsp) ? origBsp->ClassifyEdge(auv, buv, &ret) : SBspUv::Class::OUTSIDE;
|
2009-06-04 03:59:40 +00:00
|
|
|
TagByClassifiedEdge(c_this, &indir_orig, &outdir_orig);
|
2009-02-01 05:13:43 +00:00
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
agnst->ClassifyEdge(&indir_shell, &outdir_shell,
|
2015-03-29 00:30:52 +00:00
|
|
|
ret.PointAt(auv), ret.PointAt(buv), pt,
|
2009-06-04 03:59:40 +00:00
|
|
|
enin, enout, surfn);
|
|
|
|
|
2015-03-29 00:30:52 +00:00
|
|
|
if(KeepEdge(type, opA, indir_shell, outdir_shell,
|
2009-06-04 03:59:40 +00:00
|
|
|
indir_orig, outdir_orig))
|
|
|
|
{
|
2009-06-27 05:53:56 +00:00
|
|
|
for(se = chain.l.First(); se; se = chain.l.NextAfter(se)) {
|
|
|
|
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
|
|
|
|
}
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
2009-06-27 05:53:56 +00:00
|
|
|
chain.Clear();
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
|
2009-03-15 23:04:45 +00:00
|
|
|
// Cull extraneous edges; duplicates or anti-parallel pairs. In particular,
|
|
|
|
// we can get duplicate edges if our surface intersects the other shell
|
|
|
|
// at an edge, so that both surfaces intersect coincident (and both
|
|
|
|
// generate an intersection edge).
|
|
|
|
final.CullExtraneousEdges();
|
2009-02-17 11:17:12 +00:00
|
|
|
|
2009-02-16 12:05:08 +00:00
|
|
|
// Use our reassembled edges to trim the new surface.
|
2009-06-05 05:38:41 +00:00
|
|
|
ret.TrimFromEdgeList(&final, true);
|
2009-02-01 05:13:43 +00:00
|
|
|
|
2015-03-27 15:31:23 +00:00
|
|
|
SPolygon poly = {};
|
2009-03-15 23:04:45 +00:00
|
|
|
final.l.ClearTags();
|
|
|
|
if(!final.AssemblePolygon(&poly, NULL, true)) {
|
2009-05-30 08:49:09 +00:00
|
|
|
into->booleanFailed = true;
|
2009-06-27 05:53:56 +00:00
|
|
|
dbp("failed: I=%d, avoid=%d", I, choosing.l.n);
|
2009-03-19 17:40:11 +00:00
|
|
|
DEBUGEDGELIST(&final, &ret);
|
2009-03-15 23:04:45 +00:00
|
|
|
}
|
|
|
|
poly.Clear();
|
|
|
|
|
2009-06-27 05:53:56 +00:00
|
|
|
choosing.Clear();
|
2009-02-01 05:13:43 +00:00
|
|
|
final.Clear();
|
|
|
|
inter.Clear();
|
|
|
|
orig.Clear();
|
2009-01-25 11:52:29 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
void SShell::CopySurfacesTrimAgainst(SShell *sha, SShell *shb, SShell *into, SSurface::CombineAs type) {
|
2009-01-25 11:52:29 +00:00
|
|
|
SSurface *ss;
|
|
|
|
for(ss = surface.First(); ss; ss = surface.NextAfter(ss)) {
|
|
|
|
SSurface ssn;
|
2009-06-19 07:56:33 +00:00
|
|
|
ssn = ss->MakeCopyTrimAgainst(this, sha, shb, into, type);
|
2009-03-15 23:04:45 +00:00
|
|
|
ss->newH = into->surface.AddAndAssignId(&ssn);
|
2009-02-01 05:13:43 +00:00
|
|
|
I++;
|
2009-01-25 11:52:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-27 07:59:58 +00:00
|
|
|
void SShell::MakeIntersectionCurvesAgainst(SShell *agnst, SShell *into) {
|
|
|
|
SSurface *sa;
|
2009-03-15 23:04:45 +00:00
|
|
|
for(sa = surface.First(); sa; sa = surface.NextAfter(sa)) {
|
2009-01-27 07:59:58 +00:00
|
|
|
SSurface *sb;
|
2009-03-15 23:04:45 +00:00
|
|
|
for(sb = agnst->surface.First(); sb; sb = agnst->surface.NextAfter(sb)){
|
2009-01-27 07:59:58 +00:00
|
|
|
// Intersect every surface from our shell against every surface
|
|
|
|
// from agnst; this will add zero or more curves to the curve
|
|
|
|
// list for into.
|
2009-03-15 23:04:45 +00:00
|
|
|
sa->IntersectAgainst(sb, this, agnst, into);
|
2009-01-27 07:59:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
void SShell::CleanupAfterBoolean() {
|
2009-01-27 07:59:58 +00:00
|
|
|
SSurface *ss;
|
|
|
|
for(ss = surface.First(); ss; ss = surface.NextAfter(ss)) {
|
2009-06-04 03:59:40 +00:00
|
|
|
ss->edges.Clear();
|
2009-01-27 07:59:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-20 03:04:36 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// All curves contain handles to the two surfaces that they trim. After a
|
|
|
|
// Boolean or assembly, we must rewrite those handles to refer to the curves
|
2015-03-29 00:30:52 +00:00
|
|
|
// by their new IDs.
|
2009-05-20 03:04:36 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SShell::RewriteSurfaceHandlesForCurves(SShell *a, SShell *b) {
|
|
|
|
SCurve *sc;
|
|
|
|
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
|
2009-06-19 07:56:33 +00:00
|
|
|
sc->surfA = sc->GetSurfaceA(a, b)->newH,
|
|
|
|
sc->surfB = sc->GetSurfaceB(a, b)->newH;
|
2009-05-20 03:04:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Copy all the surfaces and curves from two different shells into a single
|
|
|
|
// shell. The only difficulty is to rewrite all of their handles; we don't
|
|
|
|
// look for any surface intersections, so if two objects interfere then the
|
|
|
|
// result is just self-intersecting. This is used for assembly, since it's
|
|
|
|
// much faster than merging as union.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SShell::MakeFromAssemblyOf(SShell *a, SShell *b) {
|
2009-05-30 08:49:09 +00:00
|
|
|
booleanFailed = false;
|
|
|
|
|
2009-05-20 03:04:36 +00:00
|
|
|
Vector t = Vector::From(0, 0, 0);
|
|
|
|
Quaternion q = Quaternion::IDENTITY;
|
|
|
|
int i = 0;
|
|
|
|
SShell *ab;
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2009-05-20 03:04:36 +00:00
|
|
|
// First, copy over all the curves. Note which shell (a or b) each curve
|
|
|
|
// came from, but assign it a new ID.
|
|
|
|
SCurve *c, cn;
|
|
|
|
for(i = 0; i < 2; i++) {
|
|
|
|
ab = (i == 0) ? a : b;
|
|
|
|
for(c = ab->curve.First(); c; c = ab->curve.NextAfter(c)) {
|
2009-12-15 12:26:22 +00:00
|
|
|
cn = SCurve::FromTransformationOf(c, t, q, 1.0);
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
cn.source = (i == 0) ? SCurve::Source::A : SCurve::Source::B;
|
2009-05-20 03:04:36 +00:00
|
|
|
// surfA and surfB are wrong now, and we can't fix them until
|
|
|
|
// we've assigned IDs to the surfaces. So we'll get that later.
|
|
|
|
c->newH = curve.AddAndAssignId(&cn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Likewise copy over all the surfaces.
|
|
|
|
SSurface *s, sn;
|
|
|
|
for(i = 0; i < 2; i++) {
|
|
|
|
ab = (i == 0) ? a : b;
|
|
|
|
for(s = ab->surface.First(); s; s = ab->surface.NextAfter(s)) {
|
2009-12-15 12:26:22 +00:00
|
|
|
sn = SSurface::FromTransformationOf(s, t, q, 1.0, true);
|
2009-05-20 03:04:36 +00:00
|
|
|
// All the trim curve IDs get rewritten; we know the new handles
|
|
|
|
// to the curves since we recorded them in the previous step.
|
|
|
|
STrimBy *stb;
|
|
|
|
for(stb = sn.trim.First(); stb; stb = sn.trim.NextAfter(stb)) {
|
|
|
|
stb->curve = ab->curve.FindById(stb->curve)->newH;
|
|
|
|
}
|
|
|
|
s->newH = surface.AddAndAssignId(&sn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, rewrite the surfaces associated with each curve to use the
|
|
|
|
// new handles.
|
|
|
|
RewriteSurfaceHandlesForCurves(a, b);
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
void SShell::MakeFromBoolean(SShell *a, SShell *b, SSurface::CombineAs type) {
|
2009-05-30 08:49:09 +00:00
|
|
|
booleanFailed = false;
|
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
a->MakeClassifyingBsps(NULL);
|
|
|
|
b->MakeClassifyingBsps(NULL);
|
2009-02-01 05:13:43 +00:00
|
|
|
|
2009-01-25 11:52:29 +00:00
|
|
|
// Copy over all the original curves, splitting them so that a
|
|
|
|
// piecwise linear segment never crosses a surface from the other
|
|
|
|
// shell.
|
2009-02-27 13:04:36 +00:00
|
|
|
a->CopyCurvesSplitAgainst(true, b, this);
|
|
|
|
b->CopyCurvesSplitAgainst(false, a, this);
|
2009-01-25 11:52:29 +00:00
|
|
|
|
|
|
|
// Generate the intersection curves for each surface in A against all
|
2009-02-01 05:13:43 +00:00
|
|
|
// the surfaces in B (which is all of the intersection curves).
|
2009-01-27 07:59:58 +00:00
|
|
|
a->MakeIntersectionCurvesAgainst(b, this);
|
2009-05-18 07:26:51 +00:00
|
|
|
|
|
|
|
SCurve *sc;
|
|
|
|
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
|
2009-06-19 07:56:33 +00:00
|
|
|
SSurface *srfA = sc->GetSurfaceA(a, b),
|
2016-05-21 05:18:00 +00:00
|
|
|
*srfB = sc->GetSurfaceB(a, b);
|
2009-06-19 07:56:33 +00:00
|
|
|
|
2009-05-18 07:26:51 +00:00
|
|
|
sc->RemoveShortSegments(srfA, srfB);
|
|
|
|
}
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
// And clean up the piecewise linear things we made as a calculation aid
|
|
|
|
a->CleanupAfterBoolean();
|
|
|
|
b->CleanupAfterBoolean();
|
|
|
|
// Remake the classifying BSPs with the split (and short-segment-removed)
|
|
|
|
// curves
|
|
|
|
a->MakeClassifyingBsps(this);
|
|
|
|
b->MakeClassifyingBsps(this);
|
|
|
|
|
2009-02-23 10:06:02 +00:00
|
|
|
if(b->surface.n == 0 || a->surface.n == 0) {
|
2009-06-19 07:56:33 +00:00
|
|
|
I = 1000000;
|
2009-02-01 05:13:43 +00:00
|
|
|
} else {
|
2009-06-04 03:59:40 +00:00
|
|
|
I = 0;
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
2009-06-19 07:56:33 +00:00
|
|
|
// Then trim and copy the surfaces
|
|
|
|
a->CopySurfacesTrimAgainst(a, b, this, type);
|
|
|
|
b->CopySurfacesTrimAgainst(a, b, this, type);
|
2009-01-27 07:59:58 +00:00
|
|
|
|
2009-03-15 23:04:45 +00:00
|
|
|
// Now that we've copied the surfaces, we know their new hSurfaces, so
|
|
|
|
// rewrite the curves to refer to the surfaces by their handles in the
|
|
|
|
// result.
|
2009-05-20 03:04:36 +00:00
|
|
|
RewriteSurfaceHandlesForCurves(a, b);
|
2009-03-15 23:04:45 +00:00
|
|
|
|
2009-01-27 07:59:58 +00:00
|
|
|
// And clean up the piecewise linear things we made as a calculation aid
|
|
|
|
a->CleanupAfterBoolean();
|
|
|
|
b->CleanupAfterBoolean();
|
2009-01-23 03:30:30 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 05:13:43 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// All of the BSP routines that we use to perform and accelerate polygon ops.
|
|
|
|
//-----------------------------------------------------------------------------
|
2009-06-04 03:59:40 +00:00
|
|
|
void SShell::MakeClassifyingBsps(SShell *useCurvesFrom) {
|
2009-02-01 05:13:43 +00:00
|
|
|
SSurface *ss;
|
|
|
|
for(ss = surface.First(); ss; ss = surface.NextAfter(ss)) {
|
2009-06-04 03:59:40 +00:00
|
|
|
ss->MakeClassifyingBsp(this, useCurvesFrom);
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-04 03:59:40 +00:00
|
|
|
void SSurface::MakeClassifyingBsp(SShell *shell, SShell *useCurvesFrom) {
|
2015-03-27 15:31:23 +00:00
|
|
|
SEdgeList el = {};
|
2009-02-01 05:13:43 +00:00
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
MakeEdgesInto(shell, &el, MakeAs::UV, useCurvesFrom);
|
2009-07-02 03:32:17 +00:00
|
|
|
bsp = SBspUv::From(&el, this);
|
2009-02-01 05:13:43 +00:00
|
|
|
el.Clear();
|
2009-06-04 03:59:40 +00:00
|
|
|
|
2015-03-27 15:31:23 +00:00
|
|
|
edges = {};
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
MakeEdgesInto(shell, &edges, MakeAs::XYZ, useCurvesFrom);
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
|
2016-05-05 05:54:05 +00:00
|
|
|
SBspUv *SBspUv::Alloc() {
|
2009-02-01 05:13:43 +00:00
|
|
|
return (SBspUv *)AllocTemporary(sizeof(SBspUv));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ByLength(const void *av, const void *bv)
|
|
|
|
{
|
|
|
|
SEdge *a = (SEdge *)av,
|
|
|
|
*b = (SEdge *)bv;
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2009-02-01 05:13:43 +00:00
|
|
|
double la = (a->a).Minus(a->b).Magnitude(),
|
|
|
|
lb = (b->a).Minus(b->b).Magnitude();
|
|
|
|
|
|
|
|
// Sort in descending order, longest first. This improves numerical
|
|
|
|
// stability for the normals.
|
|
|
|
return (la < lb) ? 1 : -1;
|
|
|
|
}
|
2016-05-21 05:18:00 +00:00
|
|
|
|
2009-07-02 03:32:17 +00:00
|
|
|
SBspUv *SBspUv::From(SEdgeList *el, SSurface *srf) {
|
2015-03-27 15:31:23 +00:00
|
|
|
SEdgeList work = {};
|
2009-02-01 05:13:43 +00:00
|
|
|
|
|
|
|
SEdge *se;
|
|
|
|
for(se = el->l.First(); se; se = el->l.NextAfter(se)) {
|
|
|
|
work.AddEdge(se->a, se->b, se->auxA, se->auxB);
|
|
|
|
}
|
|
|
|
qsort(work.l.elem, work.l.n, sizeof(work.l.elem[0]), ByLength);
|
|
|
|
|
|
|
|
SBspUv *bsp = NULL;
|
|
|
|
for(se = work.l.First(); se; se = work.l.NextAfter(se)) {
|
2016-03-25 14:16:58 +00:00
|
|
|
bsp = InsertOrCreateEdge(bsp, (se->a).ProjectXy(), (se->b).ProjectXy(), srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
work.Clear();
|
|
|
|
return bsp;
|
|
|
|
}
|
|
|
|
|
2009-07-02 03:32:17 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// The points in this BSP are in uv space, but we want to apply our tolerances
|
|
|
|
// consistently in xyz (i.e., we want to say a point is on-edge if its xyz
|
|
|
|
// distance to that edge is less than LENGTH_EPS, irrespective of its distance
|
|
|
|
// in uv). So we linearize the surface about the point we're considering and
|
|
|
|
// then do the test. That preserves point-on-line relationships, and the only
|
|
|
|
// time we care about exact correctness is when we're very close to the line,
|
|
|
|
// which is when the linearization is accurate.
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-05-21 05:18:00 +00:00
|
|
|
|
|
|
|
void SBspUv::ScalePoints(Point2d *pt, Point2d *a, Point2d *b, SSurface *srf) const {
|
2009-07-02 03:32:17 +00:00
|
|
|
Vector tu, tv;
|
|
|
|
srf->TangentsAt(pt->x, pt->y, &tu, &tv);
|
|
|
|
double mu = tu.Magnitude(), mv = tv.Magnitude();
|
|
|
|
|
|
|
|
pt->x *= mu; pt->y *= mv;
|
|
|
|
a ->x *= mu; a ->y *= mv;
|
|
|
|
b ->x *= mu; b ->y *= mv;
|
|
|
|
}
|
2016-05-21 05:18:00 +00:00
|
|
|
|
2015-03-29 00:30:52 +00:00
|
|
|
double SBspUv::ScaledSignedDistanceToLine(Point2d pt, Point2d a, Point2d b,
|
2016-05-21 05:18:00 +00:00
|
|
|
SSurface *srf) const
|
2009-07-02 03:32:17 +00:00
|
|
|
{
|
|
|
|
ScalePoints(&pt, &a, &b, srf);
|
|
|
|
|
|
|
|
Point2d n = ((b.Minus(a)).Normal()).WithMagnitude(1);
|
|
|
|
double d = a.Dot(n);
|
|
|
|
|
|
|
|
return pt.Dot(n) - d;
|
|
|
|
}
|
2016-05-21 05:18:00 +00:00
|
|
|
|
2009-07-02 03:32:17 +00:00
|
|
|
double SBspUv::ScaledDistanceToLine(Point2d pt, Point2d a, Point2d b, bool seg,
|
2016-05-21 05:18:00 +00:00
|
|
|
SSurface *srf) const
|
2009-07-02 03:32:17 +00:00
|
|
|
{
|
|
|
|
ScalePoints(&pt, &a, &b, srf);
|
|
|
|
|
|
|
|
return pt.DistanceToLine(a, b, seg);
|
|
|
|
}
|
|
|
|
|
2016-05-21 05:18:00 +00:00
|
|
|
SBspUv *SBspUv::InsertOrCreateEdge(SBspUv *where, Point2d ea, Point2d eb, SSurface *srf) {
|
2016-03-25 14:16:58 +00:00
|
|
|
if(where == NULL) {
|
2009-02-01 05:13:43 +00:00
|
|
|
SBspUv *ret = Alloc();
|
|
|
|
ret->a = ea;
|
|
|
|
ret->b = eb;
|
|
|
|
return ret;
|
|
|
|
}
|
2016-03-25 14:16:58 +00:00
|
|
|
where->InsertEdge(ea, eb, srf);
|
|
|
|
return where;
|
|
|
|
}
|
2009-02-01 05:13:43 +00:00
|
|
|
|
2016-03-25 14:16:58 +00:00
|
|
|
void SBspUv::InsertEdge(Point2d ea, Point2d eb, SSurface *srf) {
|
2009-07-02 03:32:17 +00:00
|
|
|
double dea = ScaledSignedDistanceToLine(ea, a, b, srf),
|
|
|
|
deb = ScaledSignedDistanceToLine(eb, a, b, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
|
|
|
|
if(fabs(dea) < LENGTH_EPS && fabs(deb) < LENGTH_EPS) {
|
|
|
|
// Line segment is coincident with this one, store in same node
|
|
|
|
SBspUv *m = Alloc();
|
|
|
|
m->a = ea;
|
|
|
|
m->b = eb;
|
|
|
|
m->more = more;
|
|
|
|
more = m;
|
|
|
|
} else if(fabs(dea) < LENGTH_EPS) {
|
|
|
|
// Point A lies on this lie, but point B does not
|
|
|
|
if(deb > 0) {
|
2016-03-25 14:16:58 +00:00
|
|
|
pos = InsertOrCreateEdge(pos, ea, eb, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
} else {
|
2016-03-25 14:16:58 +00:00
|
|
|
neg = InsertOrCreateEdge(neg, ea, eb, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
} else if(fabs(deb) < LENGTH_EPS) {
|
|
|
|
// Point B lies on this lie, but point A does not
|
|
|
|
if(dea > 0) {
|
2016-03-25 14:16:58 +00:00
|
|
|
pos = InsertOrCreateEdge(pos, ea, eb, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
} else {
|
2016-03-25 14:16:58 +00:00
|
|
|
neg = InsertOrCreateEdge(neg, ea, eb, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
} else if(dea > 0 && deb > 0) {
|
2016-03-25 14:16:58 +00:00
|
|
|
pos = InsertOrCreateEdge(pos, ea, eb, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
} else if(dea < 0 && deb < 0) {
|
2016-03-25 14:16:58 +00:00
|
|
|
neg = InsertOrCreateEdge(neg, ea, eb, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
} else {
|
|
|
|
// New edge crosses this one; we need to split.
|
2009-07-02 03:32:17 +00:00
|
|
|
Point2d n = ((b.Minus(a)).Normal()).WithMagnitude(1);
|
|
|
|
double d = a.Dot(n);
|
2009-02-01 05:13:43 +00:00
|
|
|
double t = (d - n.Dot(ea)) / (n.Dot(eb.Minus(ea)));
|
|
|
|
Point2d pi = ea.Plus((eb.Minus(ea)).ScaledBy(t));
|
|
|
|
if(dea > 0) {
|
2016-03-25 14:16:58 +00:00
|
|
|
pos = InsertOrCreateEdge(pos, ea, pi, srf);
|
|
|
|
neg = InsertOrCreateEdge(neg, pi, eb, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
} else {
|
2016-03-25 14:16:58 +00:00
|
|
|
neg = InsertOrCreateEdge(neg, ea, pi, srf);
|
|
|
|
pos = InsertOrCreateEdge(pos, pi, eb, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
2016-03-25 14:16:58 +00:00
|
|
|
return;
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
SBspUv::Class SBspUv::ClassifyPoint(Point2d p, Point2d eb, SSurface *srf) const {
|
2009-07-02 03:32:17 +00:00
|
|
|
double dp = ScaledSignedDistanceToLine(p, a, b, srf);
|
2009-02-01 05:13:43 +00:00
|
|
|
|
|
|
|
if(fabs(dp) < LENGTH_EPS) {
|
2016-05-21 05:18:00 +00:00
|
|
|
const SBspUv *f = this;
|
2009-02-01 05:13:43 +00:00
|
|
|
while(f) {
|
|
|
|
Point2d ba = (f->b).Minus(f->a);
|
2009-07-02 03:32:17 +00:00
|
|
|
if(ScaledDistanceToLine(p, f->a, ba, true, srf) < LENGTH_EPS) {
|
|
|
|
if(ScaledDistanceToLine(eb, f->a, ba, false, srf) < LENGTH_EPS){
|
2009-02-01 05:13:43 +00:00
|
|
|
if(ba.Dot(eb.Minus(p)) > 0) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
return Class::EDGE_PARALLEL;
|
2009-02-01 05:13:43 +00:00
|
|
|
} else {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
return Class::EDGE_ANTIPARALLEL;
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
} else {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
return Class::EDGE_OTHER;
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
f = f->more;
|
|
|
|
}
|
|
|
|
// Pick arbitrarily which side to send it down, doesn't matter
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
Class c1 = neg ? neg->ClassifyPoint(p, eb, srf) : Class::OUTSIDE;
|
|
|
|
Class c2 = pos ? pos->ClassifyPoint(p, eb, srf) : Class::INSIDE;
|
2009-02-01 13:01:28 +00:00
|
|
|
if(c1 != c2) {
|
|
|
|
dbp("MISMATCH: %d %d %08x %08x", c1, c2, neg, pos);
|
|
|
|
}
|
|
|
|
return c1;
|
2009-02-01 05:13:43 +00:00
|
|
|
} else if(dp > 0) {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
return pos ? pos->ClassifyPoint(p, eb, srf) : Class::INSIDE;
|
2009-02-01 05:13:43 +00:00
|
|
|
} else {
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
return neg ? neg->ClassifyPoint(p, eb, srf) : Class::OUTSIDE;
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:
class Foo {
enum { X = 1, Y = 2 };
int kind;
}
... foo.kind = Foo::X; ...
and convert it to this:
class Foo {
enum class Kind : uint32_t { X = 1, Y = 2 };
Kind kind;
}
... foo.kind = Foo::Kind::X;
(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)
The benefits are as follows:
* The type of the field gives a clear indication of intent, both
to humans and tools (such as binding generators).
* The compiler is able to automatically warn when a switch is not
exhaustive; but this is currently suppressed by the
default: ssassert(false, ...)
idiom.
* Integers and plain enums are weakly type checked: they implicitly
convert into each other. This can hide bugs where type conversion
is performed but not intended. Enum classes are strongly type
checked.
* Plain enums pollute parent namespaces; enum classes do not.
Almost every defined enum we have already has a kind of ad-hoc
namespacing via `NAMESPACE_`, which is now explicit.
* Plain enums do not have a well-defined ABI size, which is
important for bindings. Enum classes can have it, if specified.
We specify the base type for all enums as uint32_t, which is
a safe choice and allows us to not change the numeric values
of any variants.
This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-20 08:31:20 +00:00
|
|
|
SBspUv::Class SBspUv::ClassifyEdge(Point2d ea, Point2d eb, SSurface *srf) const {
|
|
|
|
SBspUv::Class ret = ClassifyPoint((ea.Plus(eb)).ScaledBy(0.5), eb, srf);
|
|
|
|
if(ret == Class::EDGE_OTHER) {
|
2009-03-15 23:04:45 +00:00
|
|
|
// Perhaps the edge is tangent at its midpoint (and we screwed up
|
|
|
|
// somewhere earlier and failed to split it); try a different
|
|
|
|
// point on the edge.
|
2009-07-02 03:32:17 +00:00
|
|
|
ret = ClassifyPoint(ea.Plus((eb.Minus(ea)).ScaledBy(0.294)), eb, srf);
|
2009-03-15 23:04:45 +00:00
|
|
|
}
|
|
|
|
return ret;
|
2009-02-01 05:13:43 +00:00
|
|
|
}
|
|
|
|
|
2016-05-21 05:18:00 +00:00
|
|
|
double SBspUv::MinimumDistanceToEdge(Point2d p, SSurface *srf) const {
|
2009-08-21 04:58:28 +00:00
|
|
|
|
2016-03-25 14:16:58 +00:00
|
|
|
double dn = (neg) ? neg->MinimumDistanceToEdge(p, srf) : VERY_POSITIVE;
|
|
|
|
double dp = (pos) ? pos->MinimumDistanceToEdge(p, srf) : VERY_POSITIVE;
|
2009-08-21 04:58:28 +00:00
|
|
|
|
|
|
|
Point2d as = a, bs = b;
|
|
|
|
ScalePoints(&p, &as, &bs, srf);
|
|
|
|
double d = p.DistanceToLine(as, bs.Minus(as), true);
|
|
|
|
|
|
|
|
return min(d, min(dn, dp));
|
|
|
|
}
|
|
|
|
|