NFC: Performance. For step-and-repeat groups, create the copies first (in parallel) and then combine them using unions of equal size shells to reduce the total time spent on booleans.

This commit is contained in:
phkahler 2020-09-01 19:36:39 -04:00
parent 7c766c72f4
commit 0a061b6f9e

View File

@ -106,25 +106,28 @@ void SMesh::RemapFaces(Group *g, int remap) {
template<class T> template<class T>
void Group::GenerateForStepAndRepeat(T *steps, T *outs, Group::CombineAs forWhat) { void Group::GenerateForStepAndRepeat(T *steps, T *outs, Group::CombineAs forWhat) {
T workA, workB;
workA = {};
workB = {};
T *soFar = &workA, *scratch = &workB;
int n = (int)valA, a0 = 0; int n = (int)valA, a0 = 0;
if(subtype == Subtype::ONE_SIDED && skipFirst) { if(subtype == Subtype::ONE_SIDED && skipFirst) {
a0++; n++; a0++; n++;
} }
int a;
for(a = a0; a < n; a++) {
int ap = a*2 - (subtype == Subtype::ONE_SIDED ? 0 : (n-1));
int remap = (a == (n - 1)) ? REMAP_LAST : a;
T transd = {}; int a;
// create all the transformed copies
std::vector <T> transd(n);
std::vector <T> workA(n);
workA[0] = {};
// first generate a shell/mesh with each transformed copy
#pragma omp parallel for
for(a = a0; a < n; a++) {
transd[a] = {};
workA[a] = {};
int ap = a*2 - (subtype == Subtype::ONE_SIDED ? 0 : (n-1));
if(type == Type::TRANSLATE) { if(type == Type::TRANSLATE) {
Vector trans = Vector::From(h.param(0), h.param(1), h.param(2)); Vector trans = Vector::From(h.param(0), h.param(1), h.param(2));
trans = trans.ScaledBy(ap); trans = trans.ScaledBy(ap);
transd.MakeFromTransformationOf(steps, transd[a].MakeFromTransformationOf(steps,
trans, Quaternion::IDENTITY, 1.0); trans, Quaternion::IDENTITY, 1.0);
} else { } else {
Vector trans = Vector::From(h.param(0), h.param(1), h.param(2)); Vector trans = Vector::From(h.param(0), h.param(1), h.param(2));
@ -133,29 +136,45 @@ void Group::GenerateForStepAndRepeat(T *steps, T *outs, Group::CombineAs forWhat
Vector axis = Vector::From(h.param(4), h.param(5), h.param(6)); Vector axis = Vector::From(h.param(4), h.param(5), h.param(6));
Quaternion q = Quaternion::From(c, s*axis.x, s*axis.y, s*axis.z); Quaternion q = Quaternion::From(c, s*axis.x, s*axis.y, s*axis.z);
// Rotation is centered at t; so A(x - t) + t = Ax + (t - At) // Rotation is centered at t; so A(x - t) + t = Ax + (t - At)
transd.MakeFromTransformationOf(steps, transd[a].MakeFromTransformationOf(steps,
trans.Minus(q.Rotate(trans)), q, 1.0); trans.Minus(q.Rotate(trans)), q, 1.0);
} }
}
for(a = a0; a < n; a++) {
// We need to rewrite any plane face entities to the transformed ones. // We need to rewrite any plane face entities to the transformed ones.
transd.RemapFaces(this, remap); int remap = (a == (n - 1)) ? REMAP_LAST : a;
transd[a].RemapFaces(this, remap);
}
// And tack this transformed copy on to the return. std::vector<T> *soFar = &transd;
if(soFar->IsEmpty()) { std::vector<T> *scratch = &workA;
scratch->MakeFromCopyOf(&transd); // do the boolean operations on pairs of equal size
while(n > 1) {
for(a = 0; a < n; a+=2) {
scratch->at(a/2).Clear();
// combine a pair of shells
if((a==0) && (a0==1)) { // if the first was skipped just copy the 2nd
scratch->at(a/2).MakeFromCopyOf(&(soFar->at(a+1)));
(soFar->at(a+1)).Clear();
a0 = 0;
} else if (a == n-1) { // for an odd number just copy the last one
scratch->at(a/2).MakeFromCopyOf(&(soFar->at(a)));
(soFar->at(a)).Clear();
} else if(forWhat == CombineAs::ASSEMBLE) { } else if(forWhat == CombineAs::ASSEMBLE) {
scratch->MakeFromAssemblyOf(soFar, &transd); scratch->at(a/2).MakeFromAssemblyOf(&(soFar->at(a)), &(soFar->at(a+1)));
(soFar->at(a)).Clear();
(soFar->at(a+1)).Clear();
} else { } else {
scratch->MakeFromUnionOf(soFar, &transd); scratch->at(a/2).MakeFromUnionOf(&(soFar->at(a)), &(soFar->at(a+1)));
(soFar->at(a)).Clear();
(soFar->at(a+1)).Clear();
}
} }
swap(scratch, soFar); swap(scratch, soFar);
scratch->Clear(); n = (n+1)/2;
transd.Clear();
} }
outs->Clear(); outs->Clear();
*outs = *soFar; *outs = soFar->at(0);
} }
template<class T> template<class T>