2013-07-29 06:08:34 +08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Binary space partitioning tree, used to represent a volume in 3-space
|
|
|
|
// bounded by a triangle mesh. These are used to compute Boolean operations
|
|
|
|
// on meshes. These aren't used for anything relating to an SShell of
|
|
|
|
// ratpoly surfaces.
|
|
|
|
//
|
|
|
|
// Copyright 2008-2013 Jonathan Westhues.
|
|
|
|
//-----------------------------------------------------------------------------
|
2008-06-23 16:37:12 +08:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
2016-05-05 13:54:05 +08:00
|
|
|
SBsp2 *SBsp2::Alloc() { return (SBsp2 *)AllocTemporary(sizeof(SBsp2)); }
|
|
|
|
SBsp3 *SBsp3::Alloc() { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); }
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-07-22 04:27:53 +08:00
|
|
|
SBsp3 *SBsp3::FromMesh(const SMesh *m) {
|
2008-06-23 16:37:12 +08:00
|
|
|
SBsp3 *bsp3 = NULL;
|
|
|
|
int i;
|
|
|
|
|
2015-03-27 23:31:23 +08:00
|
|
|
SMesh mc = {};
|
2008-06-23 16:37:12 +08:00
|
|
|
for(i = 0; i < m->l.n; i++) {
|
|
|
|
mc.AddTriangle(&(m->l.elem[i]));
|
|
|
|
}
|
|
|
|
|
2008-02-07 17:57:59 +08:00
|
|
|
srand(0); // Let's be deterministic, at least!
|
|
|
|
int n = mc.l.n;
|
|
|
|
while(n > 1) {
|
|
|
|
int k = rand() % n;
|
|
|
|
n--;
|
2015-03-27 23:43:28 +08:00
|
|
|
swap(mc.l.elem[k], mc.l.elem[n]);
|
2008-02-07 17:57:59 +08:00
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
|
|
|
|
for(i = 0; i < mc.l.n; i++) {
|
2016-03-25 22:16:58 +08:00
|
|
|
bsp3 = InsertOrCreate(bsp3, &(mc.l.elem[i]), NULL);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mc.Clear();
|
|
|
|
return bsp3;
|
|
|
|
}
|
|
|
|
|
2016-05-21 13:18:00 +08:00
|
|
|
Vector SBsp3::IntersectionWith(Vector a, Vector b) const {
|
2008-06-23 16:37:12 +08:00
|
|
|
double da = a.Dot(n) - d;
|
|
|
|
double db = b.Dot(n) - d;
|
2016-05-19 06:51:36 +08:00
|
|
|
ssassert(da*db < 0, "Expected segment to intersect BSP node");
|
2008-06-23 16:37:12 +08:00
|
|
|
|
|
|
|
double dab = (db - da);
|
|
|
|
return (a.ScaledBy(db/dab)).Plus(b.ScaledBy(-da/dab));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SBsp3::InsertInPlane(bool pos2, STriangle *tr, SMesh *m) {
|
|
|
|
Vector tc = ((tr->a).Plus(tr->b).Plus(tr->c)).ScaledBy(1.0/3);
|
|
|
|
|
|
|
|
bool onFace = false;
|
2013-08-27 03:36:00 +08:00
|
|
|
bool sameNormal = false;
|
2008-06-23 16:37:12 +08:00
|
|
|
double maxNormalMag = -1;
|
|
|
|
|
|
|
|
Vector lln, trn = tr->Normal();
|
|
|
|
|
|
|
|
SBsp3 *ll = this;
|
|
|
|
while(ll) {
|
|
|
|
if((ll->tri).ContainsPoint(tc)) {
|
|
|
|
onFace = true;
|
|
|
|
// If the mesh contains almost-zero-area triangles, and we're
|
|
|
|
// just on the edge of one of those, then don't trust its normal.
|
|
|
|
lln = (ll->tri).Normal();
|
|
|
|
if(lln.Magnitude() > maxNormalMag) {
|
|
|
|
sameNormal = trn.Dot(lln) > 0;
|
|
|
|
maxNormalMag = lln.Magnitude();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ll = ll->more;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m->flipNormal && ((!pos2 && !onFace) ||
|
|
|
|
(onFace && !sameNormal && m->keepCoplanar)))
|
|
|
|
{
|
|
|
|
m->AddTriangle(tr->meta, tr->c, tr->b, tr->a);
|
2015-03-29 08:30:52 +08:00
|
|
|
} else if(!(m->flipNormal) && ((pos2 && !onFace) ||
|
2008-06-23 16:37:12 +08:00
|
|
|
(onFace && sameNormal && m->keepCoplanar)))
|
|
|
|
{
|
|
|
|
m->AddTriangle(tr->meta, tr->a, tr->b, tr->c);
|
|
|
|
} else {
|
|
|
|
m->atLeastOneDiscarded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 16:31:20 +08:00
|
|
|
void SBsp3::InsertHow(BspClass how, STriangle *tr, SMesh *instead) {
|
2008-06-23 16:37:12 +08:00
|
|
|
switch(how) {
|
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 16:31:20 +08:00
|
|
|
case BspClass::POS:
|
2008-06-23 16:37:12 +08:00
|
|
|
if(instead && !pos) goto alt;
|
2016-03-25 22:16:58 +08:00
|
|
|
pos = InsertOrCreate(pos, tr, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
break;
|
|
|
|
|
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 16:31:20 +08:00
|
|
|
case BspClass::NEG:
|
2008-06-23 16:37:12 +08:00
|
|
|
if(instead && !neg) goto alt;
|
2016-03-25 22:16:58 +08:00
|
|
|
neg = InsertOrCreate(neg, tr, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
break;
|
|
|
|
|
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 16:31:20 +08:00
|
|
|
case BspClass::COPLANAR: {
|
2008-06-23 16:37:12 +08:00
|
|
|
if(instead) goto alt;
|
|
|
|
SBsp3 *m = Alloc();
|
|
|
|
m->n = n;
|
|
|
|
m->d = d;
|
|
|
|
m->tri = *tr;
|
|
|
|
m->more = more;
|
|
|
|
more = m;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
alt:
|
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 16:31:20 +08:00
|
|
|
if(how == BspClass::POS && !(instead->flipNormal)) {
|
2008-06-23 16:37:12 +08:00
|
|
|
instead->AddTriangle(tr->meta, tr->a, tr->b, tr->c);
|
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 16:31:20 +08:00
|
|
|
} else if(how == BspClass::NEG && instead->flipNormal) {
|
2008-06-23 16:37:12 +08:00
|
|
|
instead->AddTriangle(tr->meta, tr->c, tr->b, tr->a);
|
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 16:31:20 +08:00
|
|
|
} else if(how == BspClass::COPLANAR) {
|
2008-06-23 16:37:12 +08:00
|
|
|
if(edges) {
|
|
|
|
edges->InsertTriangle(tr, instead, this);
|
|
|
|
} else {
|
|
|
|
// I suppose this actually is allowed to happen, if the coplanar
|
|
|
|
// face is the leaf, and all of its neighbors are earlier in tree?
|
2016-05-25 20:08:19 +08:00
|
|
|
InsertInPlane(/*pos2=*/false, tr, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
instead->atLeastOneDiscarded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
class BspUtil {
|
|
|
|
public:
|
|
|
|
SBsp3 *bsp;
|
|
|
|
|
|
|
|
size_t onc;
|
|
|
|
size_t posc;
|
|
|
|
size_t negc;
|
|
|
|
bool *isPos;
|
|
|
|
bool *isNeg;
|
|
|
|
bool *isOn;
|
|
|
|
|
|
|
|
// triangle operations
|
|
|
|
STriangle *tr;
|
|
|
|
STriangle *btri; // also as alone
|
|
|
|
STriangle *ctri;
|
|
|
|
|
|
|
|
// convex operations
|
|
|
|
Vector *on;
|
|
|
|
size_t npos;
|
|
|
|
size_t nneg;
|
|
|
|
Vector *vpos; // also as quad
|
|
|
|
Vector *vneg;
|
|
|
|
|
|
|
|
static BspUtil *Alloc() {
|
|
|
|
return (BspUtil *)AllocTemporary(sizeof(BspUtil));
|
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
void AllocOn() {
|
|
|
|
on = (Vector *)AllocTemporary(sizeof(Vector) * 2);
|
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
void AllocTriangle() {
|
|
|
|
btri = (STriangle *)AllocTemporary(sizeof(STriangle));
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-04-30 19:54:59 +08:00
|
|
|
|
|
|
|
void AllocTriangles() {
|
|
|
|
btri = (STriangle *)AllocTemporary(sizeof(STriangle) * 2);
|
|
|
|
ctri = &btri[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
void AllocQuad() {
|
|
|
|
vpos = (Vector *)AllocTemporary(sizeof(Vector) * 4);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
void AllocClassify(size_t size) {
|
|
|
|
// Allocate a one big piece is faster than a small ones.
|
|
|
|
isPos = (bool *)AllocTemporary(sizeof(bool) * size * 3);
|
|
|
|
isNeg = &isPos[size];
|
|
|
|
isOn = &isNeg[size];
|
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
void AllocVertices(size_t size) {
|
|
|
|
vpos = (Vector *)AllocTemporary(sizeof(Vector) * size * 2);
|
|
|
|
vneg = &vpos[size];
|
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
void ClassifyTriangle(STriangle *tri, SBsp3 *node) {
|
|
|
|
tr = tri;
|
|
|
|
bsp = node;
|
|
|
|
onc = 0;
|
|
|
|
posc = 0;
|
|
|
|
negc = 0;
|
|
|
|
|
|
|
|
AllocClassify(3);
|
|
|
|
|
|
|
|
double dt[3] = { (tr->a).Dot(bsp->n), (tr->b).Dot(bsp->n), (tr->c).Dot(bsp->n) };
|
|
|
|
double d = bsp->d;
|
|
|
|
// Count vertices in the plane
|
|
|
|
for(int i = 0; i < 3; i++) {
|
|
|
|
if(dt[i] > d + LENGTH_EPS) {
|
|
|
|
posc++;
|
|
|
|
isPos[i] = true;
|
|
|
|
} else if(dt[i] < d - LENGTH_EPS) {
|
|
|
|
negc++;
|
|
|
|
isNeg[i] = true;
|
|
|
|
} else {
|
|
|
|
onc++;
|
|
|
|
isOn[i] = true;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
bool ClassifyConvex(Vector *vertex, size_t cnt, SBsp3 *node, bool insertEdge) {
|
|
|
|
bsp = node;
|
|
|
|
onc = 0;
|
|
|
|
posc = 0;
|
|
|
|
negc = 0;
|
|
|
|
|
|
|
|
AllocClassify(cnt);
|
|
|
|
AllocOn();
|
|
|
|
|
|
|
|
for(size_t i = 0; i < cnt; i++) {
|
|
|
|
double dt = bsp->n.Dot(vertex[i]);
|
|
|
|
isPos[i] = isNeg[i] = isOn[i] = false;
|
|
|
|
if(fabs(dt - bsp->d) < LENGTH_EPS) {
|
|
|
|
isOn[i] = true;
|
|
|
|
if(onc < 2) {
|
|
|
|
on[onc] = vertex[i];
|
|
|
|
}
|
|
|
|
onc++;
|
|
|
|
} else if(dt > bsp->d) {
|
|
|
|
isPos[i] = true;
|
|
|
|
posc++;
|
|
|
|
} else {
|
|
|
|
isNeg[i] = true;
|
|
|
|
negc++;
|
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
if(onc != 2 && onc != 1 && onc != 0) return false;
|
|
|
|
if(onc == 2) {
|
|
|
|
if(insertEdge) {
|
|
|
|
Vector e01 = (vertex[1]).Minus(vertex[0]);
|
|
|
|
Vector e12 = (vertex[2]).Minus(vertex[1]);
|
|
|
|
Vector out = e01.Cross(e12);
|
|
|
|
SEdge se = SEdge::From(on[0], on[1]);
|
|
|
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
bool ClassifyConvexVertices(Vector *vertex, size_t cnt, bool insertEdges) {
|
|
|
|
Vector inter[2];
|
|
|
|
int inters = 0;
|
|
|
|
|
|
|
|
npos = 0;
|
|
|
|
nneg = 0;
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
// Enlarge vertices list to consider two intersections
|
|
|
|
AllocVertices(cnt + 4);
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
for(size_t i = 0; i < cnt; i++) {
|
|
|
|
size_t ip = WRAP((i + 1), cnt);
|
|
|
|
|
|
|
|
if(isPos[i]) {
|
|
|
|
vpos[npos++] = vertex[i];
|
|
|
|
}
|
|
|
|
if(isNeg[i]) {
|
|
|
|
vneg[nneg++] = vertex[i];
|
|
|
|
}
|
|
|
|
if(isOn[i]) {
|
|
|
|
vneg[nneg++] = vertex[i];
|
|
|
|
vpos[npos++] = vertex[i];
|
|
|
|
}
|
|
|
|
if((isPos[i] && isNeg[ip]) || (isNeg[i] && isPos[ip])) {
|
|
|
|
Vector vi = bsp->IntersectionWith(vertex[i], vertex[ip]);
|
|
|
|
vpos[npos++] = vi;
|
|
|
|
vneg[nneg++] = vi;
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
if(inters >= 2) return false; // triangulate: XXX shouldn't happen but does
|
|
|
|
inter[inters++] = vi;
|
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-04-30 19:54:59 +08:00
|
|
|
ssassert(npos <= cnt + 1 && nneg <= cnt + 1, "Impossible");
|
|
|
|
|
|
|
|
if(insertEdges) {
|
|
|
|
Vector e01 = (vertex[1]).Minus(vertex[0]);
|
|
|
|
Vector e12 = (vertex[2]).Minus(vertex[1]);
|
|
|
|
Vector out = e01.Cross(e12);
|
|
|
|
if(inters == 2) {
|
|
|
|
SEdge se = SEdge::From(inter[0], inter[1]);
|
|
|
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, out);
|
|
|
|
} else if(inters == 1 && onc == 1) {
|
|
|
|
SEdge se = SEdge::From(inter[0], on[0]);
|
|
|
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, out);
|
|
|
|
} else if(inters == 0 && onc == 2) {
|
|
|
|
// We already handled this on-plane existing edge
|
|
|
|
} else {
|
|
|
|
return false; //triangulate;
|
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-04-30 19:54:59 +08:00
|
|
|
if(nneg < 3 || npos < 3) return false; // triangulate; // XXX
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProcessEdgeInsert() {
|
|
|
|
ssassert(onc == 2, "Impossible");
|
|
|
|
|
|
|
|
Vector a, b;
|
|
|
|
if (!isOn[0]) { a = tr->b; b = tr->c; }
|
|
|
|
else if(!isOn[1]) { a = tr->c; b = tr->a; }
|
|
|
|
else if(!isOn[2]) { a = tr->a; b = tr->b; }
|
|
|
|
else ssassert(false, "Impossible");
|
|
|
|
|
|
|
|
SEdge se = SEdge::From(a, b);
|
|
|
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, tr->Normal());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SplitIntoTwoTriangles(bool insertEdge) {
|
|
|
|
ssassert(posc == 1 && negc == 1 && onc == 1, "Impossible");
|
|
|
|
|
|
|
|
bool bpos;
|
|
|
|
Vector a, b, c;
|
|
|
|
|
|
|
|
// Standardize so that a is on the plane
|
|
|
|
if (isOn[0]) { a = tr->a; b = tr->b; c = tr->c; bpos = isPos[1];
|
|
|
|
} else if(isOn[1]) { a = tr->b; b = tr->c; c = tr->a; bpos = isPos[2];
|
|
|
|
} else if(isOn[2]) { a = tr->c; b = tr->a; c = tr->b; bpos = isPos[0];
|
|
|
|
} else ssassert(false, "Impossible");
|
|
|
|
|
|
|
|
AllocTriangles();
|
|
|
|
Vector bPc = bsp->IntersectionWith(b, c);
|
|
|
|
*btri = STriangle::From(tr->meta, a, b, bPc);
|
|
|
|
*ctri = STriangle::From(tr->meta, c, a, bPc);
|
|
|
|
|
|
|
|
if(insertEdge) {
|
|
|
|
SEdge se = SEdge::From(a, bPc);
|
|
|
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, tr->Normal());
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
return bpos;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SplitIntoTwoPieces(bool insertEdge) {
|
|
|
|
Vector a, b, c;
|
|
|
|
if(posc == 2 && negc == 1) {
|
|
|
|
// Standardize so that a is on one side, and b and c are on the other.
|
|
|
|
if (isNeg[0]) { a = tr->a; b = tr->b; c = tr->c;
|
|
|
|
} else if(isNeg[1]) { a = tr->b; b = tr->c; c = tr->a;
|
|
|
|
} else if(isNeg[2]) { a = tr->c; b = tr->a; c = tr->b;
|
|
|
|
} else ssassert(false, "Impossible");
|
|
|
|
} else if(posc == 1 && negc == 2) {
|
|
|
|
if (isPos[0]) { a = tr->a; b = tr->b; c = tr->c;
|
|
|
|
} else if(isPos[1]) { a = tr->b; b = tr->c; c = tr->a;
|
|
|
|
} else if(isPos[2]) { a = tr->c; b = tr->a; c = tr->b;
|
|
|
|
} else ssassert(false, "Impossible");
|
|
|
|
} else ssassert(false, "Impossible");
|
|
|
|
|
|
|
|
Vector aPb = bsp->IntersectionWith(a, b);
|
|
|
|
Vector cPa = bsp->IntersectionWith(c, a);
|
|
|
|
AllocTriangle();
|
|
|
|
AllocQuad();
|
|
|
|
|
|
|
|
*btri = STriangle::From(tr->meta, a, aPb, cPa);
|
|
|
|
|
|
|
|
vpos[0] = aPb;
|
|
|
|
vpos[1] = b;
|
|
|
|
vpos[2] = c;
|
|
|
|
vpos[3] = cPa;
|
|
|
|
|
|
|
|
if(insertEdge) {
|
|
|
|
SEdge se = SEdge::From(aPb, cPa);
|
|
|
|
bsp->edges = SBsp2::InsertOrCreateEdge(bsp->edges, &se, bsp->n, btri->Normal());
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-04-30 19:54:59 +08:00
|
|
|
|
|
|
|
return posc == 2 && negc == 1;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-04-30 19:54:59 +08:00
|
|
|
|
|
|
|
static SBsp3 *Triangulate(SBsp3 *bsp, const STriMeta &meta, Vector *vertex,
|
|
|
|
size_t cnt, SMesh *instead) {
|
|
|
|
for(size_t i = 0; i < cnt - 2; i++) {
|
|
|
|
STriangle tr = STriangle::From(meta, vertex[0], vertex[i + 1], vertex[i + 2]);
|
|
|
|
bsp = SBsp3::InsertOrCreate(bsp, &tr, instead);
|
2008-02-10 21:34:32 +08:00
|
|
|
}
|
2016-04-30 19:54:59 +08:00
|
|
|
return bsp;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-04-30 19:54:59 +08:00
|
|
|
};
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
void SBsp3::InsertConvexHow(BspClass how, STriMeta meta, Vector *vertex, size_t n,
|
|
|
|
SMesh *instead) {
|
|
|
|
switch(how) {
|
|
|
|
case BspClass::POS:
|
|
|
|
if(pos) {
|
|
|
|
pos = pos->InsertConvex(meta, vertex, n, instead);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
case BspClass::NEG:
|
|
|
|
if(neg) {
|
|
|
|
neg = neg->InsertConvex(meta, vertex, n, instead);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: ssassert(false, "Unexpected BSP insert type");
|
|
|
|
}
|
|
|
|
|
|
|
|
for(size_t i = 0; i < n - 2; i++) {
|
2008-06-23 16:37:12 +08:00
|
|
|
STriangle tr = STriangle::From(meta,
|
|
|
|
vertex[0], vertex[i+1], vertex[i+2]);
|
2016-04-30 19:54:59 +08:00
|
|
|
InsertHow(how, &tr, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-04-30 19:54:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SBsp3 *SBsp3::InsertConvex(STriMeta meta, Vector *vertex, size_t cnt, SMesh *instead) {
|
|
|
|
BspUtil *u = BspUtil::Alloc();
|
|
|
|
if(u->ClassifyConvex(vertex, cnt, this, !instead)) {
|
|
|
|
if(u->posc == 0) {
|
|
|
|
InsertConvexHow(BspClass::NEG, meta, vertex, cnt, instead);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
if(u->negc == 0) {
|
|
|
|
InsertConvexHow(BspClass::POS, meta, vertex, cnt, instead);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(u->ClassifyConvexVertices(vertex, cnt, !instead)) {
|
|
|
|
InsertConvexHow(BspClass::NEG, meta, u->vneg, u->nneg, instead);
|
|
|
|
InsertConvexHow(BspClass::POS, meta, u->vpos, u->npos, instead);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't handle the special case for this; do it as triangles
|
|
|
|
return BspUtil::Triangulate(this, meta, vertex, cnt, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
2016-03-25 22:16:58 +08:00
|
|
|
SBsp3 *SBsp3::InsertOrCreate(SBsp3 *where, STriangle *tr, SMesh *instead) {
|
|
|
|
if(where == NULL) {
|
2008-06-23 16:37:12 +08:00
|
|
|
if(instead) {
|
|
|
|
if(instead->flipNormal) {
|
|
|
|
instead->atLeastOneDiscarded = true;
|
|
|
|
} else {
|
|
|
|
instead->AddTriangle(tr->meta, tr->a, tr->b, tr->c);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Brand new node; so allocate for it, and fill us in.
|
|
|
|
SBsp3 *r = Alloc();
|
|
|
|
r->n = (tr->Normal()).WithMagnitude(1);
|
|
|
|
r->d = (tr->a).Dot(r->n);
|
|
|
|
r->tri = *tr;
|
|
|
|
return r;
|
|
|
|
}
|
2016-03-25 22:16:58 +08:00
|
|
|
where->Insert(tr, instead);
|
|
|
|
return where;
|
|
|
|
}
|
2008-06-23 16:37:12 +08:00
|
|
|
|
2016-03-25 22:16:58 +08:00
|
|
|
void SBsp3::Insert(STriangle *tr, SMesh *instead) {
|
2016-04-30 19:54:59 +08:00
|
|
|
BspUtil *u = BspUtil::Alloc();
|
|
|
|
u->ClassifyTriangle(tr, this);
|
2008-06-23 16:37:12 +08:00
|
|
|
|
|
|
|
// All vertices in-plane
|
2016-04-30 19:54:59 +08:00
|
|
|
if(u->onc == 3) {
|
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 16:31:20 +08:00
|
|
|
InsertHow(BspClass::COPLANAR, tr, instead);
|
2016-03-25 22:16:58 +08:00
|
|
|
return;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// No split required
|
2016-04-30 19:54:59 +08:00
|
|
|
if(u->posc == 0 || u->negc == 0) {
|
|
|
|
if(!instead && u->onc == 2) {
|
|
|
|
u->ProcessEdgeInsert();
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
if(u->posc > 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 16:31:20 +08:00
|
|
|
InsertHow(BspClass::POS, tr, instead);
|
2008-06-23 16:37:12 +08: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 16:31:20 +08:00
|
|
|
InsertHow(BspClass::NEG, tr, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-03-25 22:16:58 +08:00
|
|
|
return;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
// The polygon must be split into two triangles, one above, one below.
|
|
|
|
if(u->posc == 1 && u->negc == 1 && u->onc == 1) {
|
|
|
|
if(u->SplitIntoTwoTriangles(!instead)) {
|
|
|
|
InsertHow(BspClass::POS, u->btri, instead);
|
|
|
|
InsertHow(BspClass::NEG, u->ctri, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
} else {
|
2016-04-30 19:54:59 +08:00
|
|
|
InsertHow(BspClass::POS, u->ctri, instead);
|
|
|
|
InsertHow(BspClass::NEG, u->btri, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-03-25 22:16:58 +08:00
|
|
|
return;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 19:54:59 +08:00
|
|
|
// The polygon must be split into two pieces: a triangle and a quad.
|
|
|
|
if(u->SplitIntoTwoPieces(!instead)) {
|
|
|
|
InsertConvexHow(BspClass::POS, tr->meta, u->vpos, 4, instead);
|
|
|
|
InsertHow(BspClass::NEG, u->btri, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
} else {
|
2016-04-30 19:54:59 +08:00
|
|
|
InsertConvexHow(BspClass::NEG, tr->meta, u->vpos, 4, instead);
|
|
|
|
InsertHow(BspClass::POS, u->btri, instead);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-21 13:18:00 +08:00
|
|
|
void SBsp3::GenerateInPaintOrder(SMesh *m) const {
|
2009-03-18 00:33:46 +08:00
|
|
|
// Doesn't matter which branch we take if the normal has zero z
|
|
|
|
// component, so don't need a separate case for that.
|
|
|
|
if(n.z < 0) {
|
2016-03-25 22:16:58 +08:00
|
|
|
if(pos) pos->GenerateInPaintOrder(m);
|
2009-03-18 00:33:46 +08:00
|
|
|
} else {
|
2016-03-25 22:16:58 +08:00
|
|
|
if(neg) neg->GenerateInPaintOrder(m);
|
2009-03-18 00:33:46 +08:00
|
|
|
}
|
|
|
|
|
2016-05-21 13:18:00 +08:00
|
|
|
const SBsp3 *flip = this;
|
2009-03-18 00:33:46 +08:00
|
|
|
while(flip) {
|
|
|
|
m->AddTriangle(&(flip->tri));
|
|
|
|
flip = flip->more;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(n.z < 0) {
|
2016-03-25 22:16:58 +08:00
|
|
|
if(neg) neg->GenerateInPaintOrder(m);
|
2009-03-18 00:33:46 +08:00
|
|
|
} else {
|
2016-03-25 22:16:58 +08:00
|
|
|
if(pos) pos->GenerateInPaintOrder(m);
|
2009-03-18 00:33:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-23 16:37:12 +08:00
|
|
|
/////////////////////////////////
|
|
|
|
|
2016-05-21 13:18:00 +08:00
|
|
|
Vector SBsp2::IntersectionWith(Vector a, Vector b) const {
|
2008-06-23 16:37:12 +08:00
|
|
|
double da = a.Dot(no) - d;
|
|
|
|
double db = b.Dot(no) - d;
|
2016-05-19 06:51:36 +08:00
|
|
|
ssassert(da*db < 0, "Expected segment to intersect BSP node");
|
2008-06-23 16:37:12 +08:00
|
|
|
|
|
|
|
double dab = (db - da);
|
|
|
|
return (a.ScaledBy(db/dab)).Plus(b.ScaledBy(-da/dab));
|
|
|
|
}
|
|
|
|
|
2016-03-25 22:16:58 +08:00
|
|
|
SBsp2 *SBsp2::InsertOrCreateEdge(SBsp2 *where, SEdge *nedge, Vector nnp, Vector out) {
|
|
|
|
if(where == NULL) {
|
2008-06-23 16:37:12 +08:00
|
|
|
// Brand new node; so allocate for it, and fill us in.
|
|
|
|
SBsp2 *r = Alloc();
|
|
|
|
r->np = nnp;
|
|
|
|
r->no = ((r->np).Cross((nedge->b).Minus(nedge->a))).WithMagnitude(1);
|
|
|
|
if(out.Dot(r->no) < 0) {
|
|
|
|
r->no = (r->no).ScaledBy(-1);
|
|
|
|
}
|
|
|
|
r->d = (nedge->a).Dot(r->no);
|
|
|
|
r->edge = *nedge;
|
|
|
|
return r;
|
|
|
|
}
|
2016-03-25 22:16:58 +08:00
|
|
|
where->InsertEdge(nedge, nnp, out);
|
|
|
|
return where;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SBsp2::InsertEdge(SEdge *nedge, Vector nnp, Vector out) {
|
2008-06-23 16:37:12 +08:00
|
|
|
|
|
|
|
double dt[2] = { (nedge->a).Dot(no), (nedge->b).Dot(no) };
|
|
|
|
|
2015-03-27 23:31:23 +08:00
|
|
|
bool isPos[2] = {}, isNeg[2] = {}, isOn[2] = {};
|
2008-06-23 16:37:12 +08:00
|
|
|
for(int i = 0; i < 2; i++) {
|
|
|
|
if(fabs(dt[i] - d) < LENGTH_EPS) {
|
|
|
|
isOn[i] = true;
|
|
|
|
} else if(dt[i] > d) {
|
|
|
|
isPos[i] = true;
|
|
|
|
} else {
|
|
|
|
isNeg[i] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((isPos[0] && isPos[1])||(isPos[0] && isOn[1])||(isOn[0] && isPos[1])) {
|
2016-03-25 22:16:58 +08:00
|
|
|
pos = InsertOrCreateEdge(pos, nedge, nnp, out);
|
|
|
|
return;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
if((isNeg[0] && isNeg[1])||(isNeg[0] && isOn[1])||(isOn[0] && isNeg[1])) {
|
2016-03-25 22:16:58 +08:00
|
|
|
neg = InsertOrCreateEdge(neg, nedge, nnp, out);
|
|
|
|
return;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
if(isOn[0] && isOn[1]) {
|
|
|
|
SBsp2 *m = Alloc();
|
|
|
|
|
|
|
|
m->np = nnp;
|
|
|
|
m->no = ((m->np).Cross((nedge->b).Minus(nedge->a))).WithMagnitude(1);
|
|
|
|
if(out.Dot(m->no) < 0) {
|
|
|
|
m->no = (m->no).ScaledBy(-1);
|
|
|
|
}
|
|
|
|
m->d = (nedge->a).Dot(m->no);
|
|
|
|
m->edge = *nedge;
|
|
|
|
|
|
|
|
m->more = more;
|
|
|
|
more = m;
|
2016-03-25 22:16:58 +08:00
|
|
|
return;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
if((isPos[0] && isNeg[1]) || (isNeg[0] && isPos[1])) {
|
|
|
|
Vector aPb = IntersectionWith(nedge->a, nedge->b);
|
|
|
|
|
|
|
|
SEdge ea = SEdge::From(nedge->a, aPb);
|
|
|
|
SEdge eb = SEdge::From(aPb, nedge->b);
|
|
|
|
|
|
|
|
if(isPos[0]) {
|
2016-03-25 22:16:58 +08:00
|
|
|
pos = InsertOrCreateEdge(pos, &ea, nnp, out);
|
|
|
|
neg = InsertOrCreateEdge(neg, &eb, nnp, out);
|
2008-06-23 16:37:12 +08:00
|
|
|
} else {
|
2016-03-25 22:16:58 +08:00
|
|
|
neg = InsertOrCreateEdge(neg, &ea, nnp, out);
|
|
|
|
pos = InsertOrCreateEdge(pos, &eb, nnp, out);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-03-25 22:16:58 +08:00
|
|
|
return;
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
2016-05-19 06:51:36 +08:00
|
|
|
ssassert(false, "Impossible");
|
2008-06-23 16:37:12 +08: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 16:31:20 +08:00
|
|
|
void SBsp2::InsertTriangleHow(BspClass how, STriangle *tr, SMesh *m, SBsp3 *bsp3) {
|
2008-06-23 16:37:12 +08:00
|
|
|
switch(how) {
|
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 16:31:20 +08:00
|
|
|
case BspClass::POS:
|
2008-06-23 16:37:12 +08:00
|
|
|
if(pos) {
|
|
|
|
pos->InsertTriangle(tr, m, bsp3);
|
|
|
|
} else {
|
2016-05-25 20:08:19 +08:00
|
|
|
bsp3->InsertInPlane(/*pos2=*/true, tr, m);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
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 16:31:20 +08:00
|
|
|
case BspClass::NEG:
|
2008-06-23 16:37:12 +08:00
|
|
|
if(neg) {
|
|
|
|
neg->InsertTriangle(tr, m, bsp3);
|
|
|
|
} else {
|
2016-05-25 20:08:19 +08:00
|
|
|
bsp3->InsertInPlane(/*pos2=*/false, tr, m);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2016-05-19 06:51:36 +08:00
|
|
|
default: ssassert(false, "Unexpected BSP insert type");
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SBsp2::InsertTriangle(STriangle *tr, SMesh *m, SBsp3 *bsp3) {
|
|
|
|
double dt[3] = { (tr->a).Dot(no), (tr->b).Dot(no), (tr->c).Dot(no) };
|
|
|
|
|
2015-03-27 23:31:23 +08:00
|
|
|
bool isPos[3] = {}, isNeg[3] = {}, isOn[3] = {};
|
2008-06-23 16:37:12 +08:00
|
|
|
int inc = 0, posc = 0, negc = 0;
|
|
|
|
for(int i = 0; i < 3; i++) {
|
|
|
|
if(fabs(dt[i] - d) < LENGTH_EPS) {
|
|
|
|
isOn[i] = true;
|
|
|
|
inc++;
|
|
|
|
} else if(dt[i] > d) {
|
|
|
|
isPos[i] = true;
|
|
|
|
posc++;
|
|
|
|
} else {
|
|
|
|
isNeg[i] = true;
|
|
|
|
negc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(inc == 3) {
|
|
|
|
// All vertices on-line; so it's a degenerate triangle, to ignore.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No split required
|
|
|
|
if(posc == 0 || negc == 0) {
|
|
|
|
if(posc > 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 16:31:20 +08:00
|
|
|
InsertTriangleHow(BspClass::POS, tr, m, bsp3);
|
2008-06-23 16:37:12 +08: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 16:31:20 +08:00
|
|
|
InsertTriangleHow(BspClass::NEG, tr, m, bsp3);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The polygon must be split into two pieces, one above, one below.
|
|
|
|
Vector a, b, c;
|
|
|
|
|
|
|
|
if(posc == 1 && negc == 1 && inc == 1) {
|
|
|
|
bool bpos;
|
|
|
|
// Standardize so that a is on the plane
|
|
|
|
if (isOn[0]) { a = tr->a; b = tr->b; c = tr->c; bpos = isPos[1];
|
|
|
|
} else if(isOn[1]) { a = tr->b; b = tr->c; c = tr->a; bpos = isPos[2];
|
|
|
|
} else if(isOn[2]) { a = tr->c; b = tr->a; c = tr->b; bpos = isPos[0];
|
2016-05-19 06:51:36 +08:00
|
|
|
} else ssassert(false, "Impossible");
|
2008-06-23 16:37:12 +08:00
|
|
|
|
|
|
|
Vector bPc = IntersectionWith(b, c);
|
|
|
|
STriangle btri = STriangle::From(tr->meta, a, b, bPc);
|
|
|
|
STriangle ctri = STriangle::From(tr->meta, c, a, bPc);
|
|
|
|
|
|
|
|
if(bpos) {
|
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 16:31:20 +08:00
|
|
|
InsertTriangleHow(BspClass::POS, &btri, m, bsp3);
|
|
|
|
InsertTriangleHow(BspClass::NEG, &ctri, m, bsp3);
|
2008-06-23 16:37:12 +08: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 16:31:20 +08:00
|
|
|
InsertTriangleHow(BspClass::POS, &ctri, m, bsp3);
|
|
|
|
InsertTriangleHow(BspClass::NEG, &btri, m, bsp3);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(posc == 2 && negc == 1) {
|
|
|
|
// Standardize so that a is on one side, and b and c are on the other.
|
|
|
|
if (isNeg[0]) { a = tr->a; b = tr->b; c = tr->c;
|
|
|
|
} else if(isNeg[1]) { a = tr->b; b = tr->c; c = tr->a;
|
|
|
|
} else if(isNeg[2]) { a = tr->c; b = tr->a; c = tr->b;
|
2016-05-19 06:51:36 +08:00
|
|
|
} else ssassert(false, "Impossible");
|
2008-06-23 16:37:12 +08:00
|
|
|
|
|
|
|
} else if(posc == 1 && negc == 2) {
|
|
|
|
if (isPos[0]) { a = tr->a; b = tr->b; c = tr->c;
|
|
|
|
} else if(isPos[1]) { a = tr->b; b = tr->c; c = tr->a;
|
|
|
|
} else if(isPos[2]) { a = tr->c; b = tr->a; c = tr->b;
|
2016-05-19 06:51:36 +08:00
|
|
|
} else ssassert(false, "Impossible");
|
|
|
|
} else ssassert(false, "Impossible");
|
2008-06-23 16:37:12 +08:00
|
|
|
|
|
|
|
Vector aPb = IntersectionWith(a, b);
|
|
|
|
Vector cPa = IntersectionWith(c, a);
|
|
|
|
|
|
|
|
STriangle alone = STriangle::From(tr->meta, a, aPb, cPa);
|
|
|
|
STriangle quad1 = STriangle::From(tr->meta, aPb, b, c );
|
|
|
|
STriangle quad2 = STriangle::From(tr->meta, aPb, c, cPa);
|
|
|
|
|
|
|
|
if(posc == 2 && negc == 1) {
|
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 16:31:20 +08:00
|
|
|
InsertTriangleHow(BspClass::POS, &quad1, m, bsp3);
|
|
|
|
InsertTriangleHow(BspClass::POS, &quad2, m, bsp3);
|
|
|
|
InsertTriangleHow(BspClass::NEG, &alone, m, bsp3);
|
2008-06-23 16:37:12 +08: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 16:31:20 +08:00
|
|
|
InsertTriangleHow(BspClass::NEG, &quad1, m, bsp3);
|
|
|
|
InsertTriangleHow(BspClass::NEG, &quad2, m, bsp3);
|
|
|
|
InsertTriangleHow(BspClass::POS, &alone, m, bsp3);
|
2008-06-23 16:37:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|