diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cbda8d..fce70d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Changelog 3.0 --- +New sketch features: + * Extrude, lathe, translate and rotate groups can now use the "assembly" + boolean operation, to increase performance. + New export/import features: * Three.js: allow configuring projection for exported model, and initially use the current viewport projection. diff --git a/src/groupmesh.cpp b/src/groupmesh.cpp index a890195..3c68d41 100644 --- a/src/groupmesh.cpp +++ b/src/groupmesh.cpp @@ -103,7 +103,7 @@ void SMesh::RemapFaces(Group *g, int remap) { } template -void Group::GenerateForStepAndRepeat(T *steps, T *outs) { +void Group::GenerateForStepAndRepeat(T *steps, T *outs, Group::CombineAs forWhat) { T workA, workB; workA = {}; workB = {}; @@ -141,6 +141,8 @@ void Group::GenerateForStepAndRepeat(T *steps, T *outs) { // And tack this transformed copy on to the return. if(soFar->IsEmpty()) { scratch->MakeFromCopyOf(&transd); + } else if (forWhat == CombineAs::ASSEMBLE) { + scratch->MakeFromAssemblyOf(soFar, &transd); } else { scratch->MakeFromUnionOf(soFar, &transd); } @@ -202,8 +204,8 @@ void Group::GenerateShellAndMesh() { srcg = SK.GetGroup(opA); if(!srcg->suppress) { - GenerateForStepAndRepeat(&(srcg->thisShell), &thisShell); - GenerateForStepAndRepeat (&(srcg->thisMesh), &thisMesh); + GenerateForStepAndRepeat(&(srcg->thisShell), &thisShell, srcg->meshCombine); + GenerateForStepAndRepeat (&(srcg->thisMesh), &thisMesh, srcg->meshCombine); } } else if(type == Type::EXTRUDE && haveSrc) { Group *src = SK.GetGroup(opA); diff --git a/src/sketch.h b/src/sketch.h index 7af9c8f..f4f8e42 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -268,7 +268,7 @@ public: bool IsMeshGroup(); void GenerateShellAndMesh(); - template void GenerateForStepAndRepeat(T *steps, T *outs); + template void GenerateForStepAndRepeat(T *steps, T *outs, Group::CombineAs forWhat); template void GenerateForBoolean(T *a, T *b, T *o, Group::CombineAs how); void GenerateDisplayItems(); diff --git a/src/textscreens.cpp b/src/textscreens.cpp index 1d2613d..7f05c75 100644 --- a/src/textscreens.cpp +++ b/src/textscreens.cpp @@ -352,12 +352,11 @@ void TextWindow::ShowGroupInfo() { bool un = (g->meshCombine == Group::CombineAs::UNION); bool diff = (g->meshCombine == Group::CombineAs::DIFFERENCE); bool asy = (g->meshCombine == Group::CombineAs::ASSEMBLE); - bool asa = (g->type == Group::Type::LINKED); Printf(false, " %Ftsolid model as"); Printf(false, "%Ba %f%D%Lc%Fd%s union%E " "%f%D%Lc%Fd%s difference%E " - "%f%D%Lc%Fd%s%s%E ", + "%f%D%Lc%Fd%s assemble%E ", &TextWindow::ScreenChangeGroupOption, Group::CombineAs::UNION, un ? RADIO_TRUE : RADIO_FALSE, @@ -366,8 +365,7 @@ void TextWindow::ShowGroupInfo() { diff ? RADIO_TRUE : RADIO_FALSE, &TextWindow::ScreenChangeGroupOption, Group::CombineAs::ASSEMBLE, - asa ? (asy ? RADIO_TRUE : RADIO_FALSE) : " ", - asa ? " assemble" : ""); + (asy ? RADIO_TRUE : RADIO_FALSE)); if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 40b7436..97f374d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -52,7 +52,9 @@ set(testsuite_SOURCES request/cubic_periodic/test.cpp request/datum_point/test.cpp request/line_segment/test.cpp - request/ttf_text/test.cpp) + request/ttf_text/test.cpp + group/translate_asy/test.cpp +) add_executable(solvespace_testsuite ${testsuite_SOURCES}) diff --git a/test/group/translate_asy/normal.png b/test/group/translate_asy/normal.png new file mode 100644 index 0000000..c889c07 Binary files /dev/null and b/test/group/translate_asy/normal.png differ diff --git a/test/group/translate_asy/normal.slvs b/test/group/translate_asy/normal.slvs new file mode 100644 index 0000000..2f013bc Binary files /dev/null and b/test/group/translate_asy/normal.slvs differ diff --git a/test/group/translate_asy/test.cpp b/test/group/translate_asy/test.cpp new file mode 100644 index 0000000..9263013 --- /dev/null +++ b/test/group/translate_asy/test.cpp @@ -0,0 +1,22 @@ +#include "harness.h" + +TEST_CASE(normal_roundtrip) { + CHECK_LOAD("normal.slvs"); + CHECK_RENDER_ISO("normal.png"); + CHECK_SAVE("normal.slvs"); +} + +TEST_CASE(normal_inters) { + CHECK_LOAD("normal.slvs"); + + Group *g = SK.GetGroup(SS.GW.activeGroup); + SMesh *m = &g->displayMesh; + + SEdgeList el = {}; + bool inters, leaks; + SKdNode::From(m)->MakeCertainEdgesInto(&el, + EdgeKind::SELF_INTER, /*coplanarIsInter=*/false, &inters, &leaks); + + // The assembly is supposed to interfere. + CHECK_TRUE(inters); +} diff --git a/test/harness.cpp b/test/harness.cpp index a5fe01e..2ebfd00 100644 --- a/test/harness.cpp +++ b/test/harness.cpp @@ -260,6 +260,18 @@ bool Test::Helper::CheckRender(const char *file, int line, const char *reference } } +bool Test::Helper::CheckRenderXY(const char *file, int line, const char *fixture) { + SS.GW.projRight = Vector::From(1, 0, 0); + SS.GW.projUp = Vector::From(0, 1, 0); + return CheckRender(file, line, fixture); +} + +bool Test::Helper::CheckRenderIso(const char *file, int line, const char *fixture) { + SS.GW.projRight = Vector::From(0.707, 0.000, -0.707); + SS.GW.projUp = Vector::From(-0.408, 0.816, -0.408); + return CheckRender(file, line, fixture); +} + // Avoid global constructors; using a global static vector instead of a local one // breaks MinGW for some obscure reason. static std::vector *testCasesPtr; diff --git a/test/harness.h b/test/harness.h index f3e7928..74798e0 100644 --- a/test/harness.h +++ b/test/harness.h @@ -25,6 +25,8 @@ public: bool CheckLoad(const char *file, int line, const char *fixture); bool CheckSave(const char *file, int line, const char *reference); bool CheckRender(const char *file, int line, const char *fixture); + bool CheckRenderXY(const char *file, int line, const char *fixture); + bool CheckRenderIso(const char *file, int line, const char *fixture); }; class Case { @@ -54,4 +56,6 @@ using namespace SolveSpace; #define CHECK_SAVE(fixture) \ do { if(!helper->CheckSave(__FILE__, __LINE__, fixture)) return; } while(0) #define CHECK_RENDER(reference) \ - do { if(!helper->CheckRender(__FILE__, __LINE__, reference)) return; } while(0) + do { if(!helper->CheckRenderXY(__FILE__, __LINE__, reference)) return; } while(0) +#define CHECK_RENDER_ISO(reference) \ + do { if(!helper->CheckRenderIso(__FILE__, __LINE__, reference)) return; } while(0)