diff --git a/.github/workflows/test_sonarcloud.yml b/.github/workflows/test_sonarcloud.yml index abdd847b..279aa4d7 100644 --- a/.github/workflows/test_sonarcloud.yml +++ b/.github/workflows/test_sonarcloud.yml @@ -17,26 +17,29 @@ jobs: runs-on: ubuntu-latest steps: - - name: "Dependencies: APT" - run: | - sudo apt update - sudo apt install -y \ - qt6-base-dev \ - gcovr \ - texlive-xetex \ - cairosvg \ - imagemagick +# - name: "Dependencies: APT" +# run: | +# sudo apt update +# sudo apt install -y \ +# qt6-base-dev \ +# catch2 \ +# gcovr \ +# texlive-xetex \ +# cairosvg \ +# imagemagick # libxml2-utils + - name: 'Dependencies: Nix' + uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: Setup Nix cache + uses: DeterminateSystems/magic-nix-cache-action@v13 + - name: "Dependencies: Sonar" run: | mkdir -p /tmp/sonar - wget \ - https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${{ env.SONAR_SCANNER_VERSION }}-linux-x64.zip \ - -O /tmp/sonar/sonar-scanner.zip - unzip \ - -o /tmp/sonar/sonar-scanner.zip \ - -d /tmp/sonar/ wget \ https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip \ -O /tmp/sonar/build-wrapper-linux-x86.zip @@ -49,20 +52,17 @@ jobs: # curl https://report.ci/report.py \ # > /tmp/report.py - - name: "Dependencies: Catch2" - run: | - git clone https://github.com/catchorg/Catch2.git - cd Catch2 - cmake -Bbuild -H. -DBUILD_TESTING=OFF - sudo cmake --build build/ --target install - - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Build Nix environment + run: nix develop --no-update-lock-file --command true + - name: Configure run: | + nix develop --no-update-lock-file --command \ cmake \ -S. \ -Bbuild \ @@ -73,16 +73,20 @@ jobs: - name: Build run: | + nix develop --no-update-lock-file --command \ /tmp/sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 \ --out-dir build_wrapper_output_directory \ cmake --build build --target all unittest - name: Coverage - run: cmake --build build --target coverage + run: | + nix develop --no-update-lock-file --command \ + cmake --build build --target coverage - name: Scan run: | - /tmp/sonar/sonar-scanner-${{ env.SONAR_SCANNER_VERSION }}-linux-x64/bin/sonar-scanner \ + nix develop --no-update-lock-file --command \ + sonar-scanner \ -Dproject.settings=.sonar-project.properties \ -Dsonar.cfamily.build-wrapper-output=build_wrapper_output_directory \ -Dsonar.host.url="https://sonarcloud.io" \ @@ -123,12 +127,13 @@ jobs: - name: Produce test report run: | + nix develop --no-update-lock-file --command bash -c '\ build/test/unit/openemsh_unittest \ -r junit::out=build/test/unit/openemsh_unittest_result.xml \ - || true + || true' - name: Export test report - uses: dorny/test-reporter@v1 + uses: dorny/test-reporter@v2 with: name: Unit tests path: build/test/unit/openemsh_unittest_result.xml diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cf914fd3..9042e823 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -80,6 +80,14 @@ target_sources( openemsh_bin "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/utils/nodegraph/node.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/utils/nodegraph/container.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/utils/nodegraph/wire.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_delegate.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_dialog.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_model_global.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_model_conflict_too_close_meshline_policies.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_model_edge.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_model_interval.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_model_meshline_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_axis.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_plane.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_style.cpp" @@ -104,6 +112,7 @@ target_sources( openemsh_bin "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_scene.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_view.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/about_dialog.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/icons.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/main_window.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/style.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/resources.qrc" diff --git a/src/app/openemsh.cpp b/src/app/openemsh.cpp index cdef7659..a4f84257 100644 --- a/src/app/openemsh.cpp +++ b/src/app/openemsh.cpp @@ -9,6 +9,7 @@ #include "infra/serializers/serializer_to_plantuml.hpp" #include "infra/serializers/serializer_to_prettyprint.hpp" +#include "utils/concepts.hpp" #include "utils/unreachable.hpp" #include "openemsh.hpp" @@ -43,6 +44,27 @@ optional next(Step step) { } } +//****************************************************************************** +set that_and_after(Step step) { + set out; + + using enum Step; + switch(step) { + case DETECT_CONFLICT_EIP: out.emplace(DETECT_CONFLICT_EIP); [[fallthrough]]; + case DETECT_CONFLICT_CE: out.emplace(DETECT_CONFLICT_CE); [[fallthrough]]; + case DETECT_NON_CONFLICTING_EDGES: out.emplace(DETECT_NON_CONFLICTING_EDGES); [[fallthrough]]; + case ADD_FIXED_MLP: out.emplace(ADD_FIXED_MLP); [[fallthrough]]; + case SOLVE_ALL_EIP: out.emplace(SOLVE_ALL_EIP); [[fallthrough]]; + case SOLVE_ALL_CE: out.emplace(SOLVE_ALL_CE); [[fallthrough]]; + case DETECT_AND_SOLVE_TCMLP: out.emplace(DETECT_AND_SOLVE_TCMLP); [[fallthrough]]; + case DETECT_INTERVALS: out.emplace(DETECT_INTERVALS); [[fallthrough]]; + case MESH: out.emplace(MESH); break; + default: unreachable(); + } + + return out; +} + //****************************************************************************** OpenEMSH::OpenEMSH(Params params) : params(std::move(params)) @@ -58,10 +80,26 @@ domain::Board const& OpenEMSH::get_board() const { return *board; } +//****************************************************************************** +void OpenEMSH::set_input(std::filesystem::path const& path) { + params.input = path; +} + +//****************************************************************************** +void OpenEMSH::set_output(std::filesystem::path const& path) { + params.output = path; +} + +//****************************************************************************** +void OpenEMSH::set_output_format(Params::OutputFormat format) { + params.output_format = format; +} + //****************************************************************************** void OpenEMSH::parse() { Caretaker::singleton().reset(); board = ParserFromCsx::run(params.input, static_cast(params), params.override_from_cli); + Caretaker::singleton().remember_current_timepoint(); } //****************************************************************************** @@ -85,47 +123,23 @@ void OpenEMSH::write() const { //****************************************************************************** void OpenEMSH::run(std::set const& steps) const { - auto const annotate = [](Step step) { - Caretaker::singleton().annotate_current_timepoint(make_unique(step)); + auto const handle = [&] F>(Step step, F const& func) { + if(steps.contains(step)) { + Caretaker::singleton().annotate_current_timepoint(make_unique(step)); + func(); + } }; - if(steps.contains(Step::DETECT_CONFLICT_EIP)) { - Caretaker::singleton().remember_current_timepoint(); - annotate(Step::DETECT_CONFLICT_EIP); - board->detect_edges_in_polygons(); - } - if(steps.contains(Step::DETECT_CONFLICT_CE)) { - annotate(Step::DETECT_CONFLICT_CE); - board->detect_colinear_edges(); - } - if(steps.contains(Step::DETECT_NON_CONFLICTING_EDGES)) { - annotate(Step::DETECT_NON_CONFLICTING_EDGES); - board->detect_non_conflicting_edges(); - } - if(steps.contains(Step::ADD_FIXED_MLP)) { - annotate(Step::ADD_FIXED_MLP); - board->add_fixed_meshline_policies(); - } - if(steps.contains(Step::SOLVE_ALL_EIP)) { - annotate(Step::SOLVE_ALL_EIP); - board->auto_solve_all_edge_in_polygon(); - } - if(steps.contains(Step::SOLVE_ALL_CE)) { - annotate(Step::SOLVE_ALL_CE); - board->auto_solve_all_colinear_edges(); - } - if(steps.contains(Step::DETECT_AND_SOLVE_TCMLP)) { - annotate(Step::DETECT_AND_SOLVE_TCMLP); - board->detect_and_solve_too_close_meshline_policies(); - } - if(steps.contains(Step::DETECT_INTERVALS)) { - annotate(Step::DETECT_INTERVALS); - board->detect_intervals(); - } - if(steps.contains(Step::MESH)) { - annotate(Step::MESH); - board->mesh(); - } + using enum Step; + handle(DETECT_CONFLICT_EIP, [&] { board->detect_edges_in_polygons(); }); + handle(DETECT_CONFLICT_CE, [&] { board->detect_colinear_edges(); }); + handle(DETECT_NON_CONFLICTING_EDGES, [&] { board->detect_non_conflicting_edges(); }); + handle(ADD_FIXED_MLP, [&] { board->add_fixed_meshline_policies(); }); + handle(SOLVE_ALL_EIP, [&] { board->auto_solve_all_edge_in_polygon(); }); + handle(SOLVE_ALL_CE, [&] { board->auto_solve_all_colinear_edges(); }); + handle(DETECT_AND_SOLVE_TCMLP, [&] { board->detect_and_solve_too_close_meshline_policies(); }); + handle(DETECT_INTERVALS, [&] { board->detect_intervals(); }); + handle(MESH, [&] { board->mesh(); }); Caretaker::singleton().remember_current_timepoint(); } @@ -158,10 +172,15 @@ void OpenEMSH::run_next_step() const { } } +//****************************************************************************** +void OpenEMSH::run_from_step(Step step) const { + run(that_and_after(step)); +} + //****************************************************************************** void OpenEMSH::go_before(Step step) const { auto& c = Caretaker::singleton(); - c.go_and_remember( + c.go_without_remembering( c.find_first_ancestor_with_annotation_that( [&step](IAnnotation const* annotation) { return static_cast(annotation)->before_step == step; diff --git a/src/app/openemsh.hpp b/src/app/openemsh.hpp index f127b9af..0acc91da 100644 --- a/src/app/openemsh.hpp +++ b/src/app/openemsh.hpp @@ -57,6 +57,10 @@ class OpenEMSH { Params const& get_params() const; domain::Board const& get_board() const; + void set_input(std::filesystem::path const& path); + void set_output(std::filesystem::path const& path); + void set_output_format(Params::OutputFormat format); + // TODO implement validation checks on params here. // void check_x(); @@ -64,6 +68,7 @@ class OpenEMSH { void run(std::set const& steps) const; void run_all_steps() const; void run_next_step() const; + void run_from_step(Step step) const; void go_before(Step step) const; void go_before_previous_step() const; void write() const; @@ -85,4 +90,7 @@ class Annotation : public IAnnotation { //****************************************************************************** std::optional next(Step step); +//****************************************************************************** +std::set that_and_after(Step step); + } // namespace app diff --git a/src/domain/board.cpp b/src/domain/board.cpp index 366121ef..370c40e9 100644 --- a/src/domain/board.cpp +++ b/src/domain/board.cpp @@ -71,8 +71,8 @@ void Board::Builder::add_fixed_meshline_policy(Axis const axis, Coord const coor fixed_meshline_policy_creators[axis].emplace_back([=](Board const* board, Timepoint* t) { if(!contains_that(board->line_policy_manager->get_current_state().line_policies[axis], [&coord](shared_ptr const& policy) { - if(policy->policy == MeshlinePolicy::Policy::ONELINE - && policy->normal == MeshlinePolicy::Normal::NONE + if(policy->get_current_state().policy == MeshlinePolicy::Policy::ONELINE + && policy->get_current_state().normal == MeshlinePolicy::Normal::NONE && policy->coord == coord) return true; return false; @@ -312,7 +312,7 @@ void Board::detect_non_conflicting_edges(Plane const plane) { optional const coord = domain::coord(edge->p0(), edge->axis); optional const axis = transpose(plane, edge->axis); optional const normal = cast(edge->normal); - if(coord && axis && normal && !edge->get_current_state().conflicts.size()) { + if(coord && axis && normal && edge->get_current_state().conflicts.empty()) { auto [t, state_e] = edge->make_next_state(); state_e.meshline_policy = line_policy_manager->add_meshline_policy( { edge }, @@ -320,7 +320,7 @@ void Board::detect_non_conflicting_edges(Plane const plane) { MeshlinePolicy::Policy::THIRDS, normal.value(), coord.value(), - true, + state_e.to_mesh, t); edge->set_state(t, state_e); } diff --git a/src/domain/conflicts/conflict_too_close_meshline_policies.cpp b/src/domain/conflicts/conflict_too_close_meshline_policies.cpp index 729f0517..54a2d539 100644 --- a/src/domain/conflicts/conflict_too_close_meshline_policies.cpp +++ b/src/domain/conflicts/conflict_too_close_meshline_policies.cpp @@ -37,19 +37,22 @@ void ConflictTooCloseMeshlinePolicies::auto_solve(MeshlinePolicyManager& line_po return; auto [policy, normal] = [&]() -> tuple, optional> { - if(a->policy == MeshlinePolicy::Policy::THIRDS && b->policy == MeshlinePolicy::Policy::THIRDS) { - if(a->normal != b->normal) { + auto const& state_a = a->get_current_state(); + auto const& state_b = b->get_current_state(); + + if(state_a.policy == MeshlinePolicy::Policy::THIRDS && state_b.policy == MeshlinePolicy::Policy::THIRDS) { + if(state_a.normal != state_b.normal) { return { MeshlinePolicy::Policy::HALFS, MeshlinePolicy::Normal::NONE }; - } else if(a->normal == MeshlinePolicy::Normal::MIN - && b->normal == MeshlinePolicy::Normal::MIN) { + } else if(state_a.normal == MeshlinePolicy::Normal::MIN + && state_b.normal == MeshlinePolicy::Normal::MIN) { return { MeshlinePolicy::Policy::THIRDS, MeshlinePolicy::Normal::MIN }; - } else if(a->normal == MeshlinePolicy::Normal::MAX - && b->normal == MeshlinePolicy::Normal::MAX) { + } else if(state_a.normal == MeshlinePolicy::Normal::MAX + && state_b.normal == MeshlinePolicy::Normal::MAX) { return { MeshlinePolicy::Policy::THIRDS, MeshlinePolicy::Normal::MAX }; } - } else if((a->policy == MeshlinePolicy::Policy::HALFS && b->policy == MeshlinePolicy::Policy::HALFS) - || (a->policy == MeshlinePolicy::Policy::HALFS && b->policy == MeshlinePolicy::Policy::THIRDS) - || (a->policy == MeshlinePolicy::Policy::THIRDS && b->policy == MeshlinePolicy::Policy::HALFS)) { + } else if((state_a.policy == MeshlinePolicy::Policy::HALFS && state_b.policy == MeshlinePolicy::Policy::HALFS) + || (state_a.policy == MeshlinePolicy::Policy::HALFS && state_b.policy == MeshlinePolicy::Policy::THIRDS) + || (state_a.policy == MeshlinePolicy::Policy::THIRDS && state_b.policy == MeshlinePolicy::Policy::HALFS)) { return { MeshlinePolicy::Policy::HALFS, MeshlinePolicy::Normal::NONE }; } //else if(ONE and *) { // TODO } // TODO should not have been created ? diff --git a/src/domain/mesh/interval.cpp b/src/domain/mesh/interval.cpp index 273817c6..57135615 100644 --- a/src/domain/mesh/interval.cpp +++ b/src/domain/mesh/interval.cpp @@ -46,11 +46,11 @@ Interval::Interval(MeshlinePolicy* before, MeshlinePolicy* after, Axis axis, Glo : Originator(t, { .dmax = global_params->get_current_state().dmax, .before = Side(before, global_params->get_current_state().lmin, global_params->get_current_state().lambda, calc_h(before->coord, after->coord), [before](double d) noexcept { - switch(before->policy) { + switch(before->get_current_state().policy) { case MeshlinePolicy::Policy::ONELINE: return 0.0; case MeshlinePolicy::Policy::HALFS: return d / 2.0; case MeshlinePolicy::Policy::THIRDS: return [&] { - switch(before->normal) { + switch(before->get_current_state().normal) { case MeshlinePolicy::Normal::MAX: return 2.0/3.0 * d; case MeshlinePolicy::Normal::MIN: @@ -63,11 +63,11 @@ Interval::Interval(MeshlinePolicy* before, MeshlinePolicy* after, Axis axis, Glo } }), .after = Side(after, global_params->get_current_state().lmin, global_params->get_current_state().lambda, calc_h(before->coord, after->coord), [after](double d) noexcept { - switch(after->policy) { + switch(after->get_current_state().policy) { case MeshlinePolicy::Policy::ONELINE: return 0.0; case MeshlinePolicy::Policy::HALFS: return d / 2.0; case MeshlinePolicy::Policy::THIRDS: return [&] { - switch(after->normal) { + switch(after->get_current_state().normal) { case MeshlinePolicy::Normal::MAX: return 1.0/3.0 * d; case MeshlinePolicy::Normal::MIN: @@ -162,7 +162,7 @@ vector find_ls(double d, double lambda, double dmax, Coord s) { /// - The last space between adjacent lines should not be less than dmax/lambda. ///***************************************************************************** -bool is_ls_valid_for_dmax_lmin_lambda(vector ls, double d, double lambda, double dmax, size_t lmin) { +bool is_ls_valid_for_dmax_lmin_lambda(vector const& ls, double d, double lambda, double dmax, size_t lmin) { if(d > dmax || ls.size() < lmin || ls.empty()) @@ -405,7 +405,7 @@ vector> Interval::mesh() const { double const d_init_after = state.after.d_init(); vector> meshlines; - if(state.before.meshline_policy->policy != MeshlinePolicy::Policy::ONELINE) + if(state.before.meshline_policy->get_current_state().policy != MeshlinePolicy::Policy::ONELINE) meshlines.push_back(make_shared( state.before.meshline_policy->coord + d_init_before, this, @@ -425,7 +425,7 @@ vector> Interval::mesh() const { state.after.meshline_policy->coord - d_init_after - (*it), this, state.after.meshline_policy)); - if(state.after.meshline_policy->policy != MeshlinePolicy::Policy::ONELINE) + if(state.after.meshline_policy->get_current_state().policy != MeshlinePolicy::Policy::ONELINE) meshlines.push_back(make_shared( state.after.meshline_policy->coord - d_init_after, this, diff --git a/src/domain/mesh/interval.hpp b/src/domain/mesh/interval.hpp index 61172b8c..94b22f20 100644 --- a/src/domain/mesh/interval.hpp +++ b/src/domain/mesh/interval.hpp @@ -100,6 +100,6 @@ double find_dmax(Interval::Side const& a, Interval::Side const& b, double dmax); std::vector find_ls(double d, double lambda, double dmax, Coord s); //****************************************************************************** -bool is_ls_valid_for_dmax_lmin_lambda(std::vector ls, double d, double lambda, double dmax, size_t lmin); +bool is_ls_valid_for_dmax_lmin_lambda(std::vector const& ls, double d, double lambda, double dmax, size_t lmin); } // namespace domain diff --git a/src/domain/mesh/meshline_policy.cpp b/src/domain/mesh/meshline_policy.cpp index aa06eef1..22c84133 100644 --- a/src/domain/mesh/meshline_policy.cpp +++ b/src/domain/mesh/meshline_policy.cpp @@ -26,21 +26,21 @@ MeshlinePolicy::MeshlinePolicy( bool const is_enabled, double const res_factor) : Originator(t, { + .policy = policy, + .normal = normal, .is_enabled = is_enabled, .res_factor = res_factor, .d = global_params->get_current_state().dmax / res_factor, .origins = origins }) , axis(axis) -, policy(policy) -, normal(normal) , global_params(global_params) , coord(coord) {} //****************************************************************************** optional MeshlinePolicy::mesh() { - if(policy == Policy::ONELINE) + if(get_current_state().policy == Policy::ONELINE) return Meshline(coord, this); else return nullopt; diff --git a/src/domain/mesh/meshline_policy.hpp b/src/domain/mesh/meshline_policy.hpp index 314e7f78..67f3b1d5 100644 --- a/src/domain/mesh/meshline_policy.hpp +++ b/src/domain/mesh/meshline_policy.hpp @@ -28,16 +28,7 @@ namespace domain { class Conflict; class Meshline; -//****************************************************************************** -struct MeshlinePolicyState final -: public IConflictOriginState -, public IConflictSolutionState { - bool is_enabled; - double res_factor; // TODO useful? d directly? come from params - double d; ///< Distance betwen two lines (HALFS and THIRDS only). - std::vector origins; - std::vector meshlines; -}; +struct MeshlinePolicyState; /// This class is an interface between a mesh line and its origin because /// multiples edges can be responsible for the same lines and some lines can @@ -61,13 +52,13 @@ class MeshlinePolicy ONELINE, ///< Place one line on the coord. typically produced by ports. HALFS, ///< Apply halfs rule while meshing : when edges conflict on the direction. THIRDS ///< Apply thirds rule while meshing : normal case for edges. - } const policy; // TODO rename meshing_rule + }; enum class Normal { NONE, MIN, MAX - } const normal; + }; GlobalParams* global_params; Coord const coord; @@ -87,6 +78,19 @@ class MeshlinePolicy std::optional mesh(); }; +//****************************************************************************** +struct MeshlinePolicyState final +: public IConflictOriginState +, public IConflictSolutionState { + MeshlinePolicy::Policy policy; + MeshlinePolicy::Normal normal; + bool is_enabled; + double res_factor; // TODO useful? d directly? come from params + double d; ///< Distance betwen two lines (HALFS and THIRDS only). + std::vector origins; + std::vector meshlines; +}; + //****************************************************************************** std::optional coord(Point const& point, Segment::Axis const axis) noexcept; diff --git a/src/domain/meshline_policy_manager.cpp b/src/domain/meshline_policy_manager.cpp index 9def83ca..9015e7b8 100644 --- a/src/domain/meshline_policy_manager.cpp +++ b/src/domain/meshline_policy_manager.cpp @@ -76,7 +76,7 @@ optional> detect_closest_meshline_policies( erase_if(dimension, [](MeshlinePolicy const* a) { return (!a->get_current_state().is_enabled) - || a->policy == MeshlinePolicy::Policy::ONELINE; + || a->get_current_state().policy == MeshlinePolicy::Policy::ONELINE; }); ranges::sort(dimension, diff --git a/src/infra/serializers/serializer_to_plantuml.cpp b/src/infra/serializers/serializer_to_plantuml.cpp index abd56dd7..09d5f0ed 100644 --- a/src/infra/serializers/serializer_to_plantuml.cpp +++ b/src/infra/serializers/serializer_to_plantuml.cpp @@ -140,8 +140,8 @@ void SerializerToPlantuml::visit(ConflictColinearEdges& conflict) { if(solution) { out += - id + " : Solution.policy = " + to_string(solution->policy) + "\n" + - id + " : Solution.normal = " + to_string(solution->normal) + "\n" + + id + " : Solution.policy = " + to_string(solution->get_current_state().policy) + "\n" + + id + " : Solution.normal = " + to_string(solution->get_current_state().normal) + "\n" + id + "_out ------> " + to_string(solution->id) + "_in\n"; } @@ -200,9 +200,9 @@ void SerializerToPlantuml::visit(MeshlinePolicy& policy) { "state \"MeshlinePolicy\" as " + id + (policy.get_current_state().is_enabled ? " #green" : " #red") + " {\n" "state \" \" as " + id + "_in <>\n" "state \" \" as " + id + "_out <>\n" + - id + " : Normal = " + to_string(policy.normal) + "\n" + + id + " : Normal = " + to_string(policy.get_current_state().normal) + "\n" + id + " : Is enabled = " + (policy.get_current_state().is_enabled ? "true" : "false") + "\n" + - id + " : Policy = " + to_string(policy.policy) + "\n" + + id + " : Policy = " + to_string(policy.get_current_state().policy) + "\n" + id + " : d = " + to_string(policy.get_current_state().d) + "\n"; if(origin) diff --git a/src/infra/serializers/serializer_to_prettyprint.cpp b/src/infra/serializers/serializer_to_prettyprint.cpp index a15161de..0fed69ae 100644 --- a/src/infra/serializers/serializer_to_prettyprint.cpp +++ b/src/infra/serializers/serializer_to_prettyprint.cpp @@ -119,7 +119,7 @@ void SerializerToPrettyprint::visit(ConflictColinearEdges& conflict) { } if(solution) - out += "\tSolution: " + F_D_GREEN + to_string(solution->policy) + S_RESET; + out += "\tSolution: " + F_D_GREEN + to_string(solution->get_current_state().policy) + S_RESET; out += "\n"; } diff --git a/src/main.cpp b/src/main.cpp index 14c6d8e1..dfe311d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,7 @@ int main(int argc, char* argv[]) { setlocale(LC_NUMERIC, "C"); ui::qt::MainWindow w(oemsh); w.show(); + w.parse_and_display(); return QApplication::exec(); } diff --git a/src/ui/cli.cpp b/src/ui/cli.cpp index 7858685e..7b3b893c 100644 --- a/src/ui/cli.cpp +++ b/src/ui/cli.cpp @@ -14,6 +14,7 @@ #include #include +#include "utils/concepts.hpp" #include "utils/unreachable.hpp" #include "cli.hpp" @@ -76,6 +77,18 @@ struct FutureConditional : CLI::Validator { } }; +//****************************************************************************** +template F> +struct JustDo : CLI::Validator { + explicit JustDo(F const& func) { + name_ = "JustDo"; + func_ = [func](string const&) { + func(); + return std::string(); + }; + } +}; + //****************************************************************************** template auto make_overrider(auto& overrides_collector) { @@ -99,8 +112,9 @@ app::OpenEMSH::Params cli(int const argc, char* argv[]) { app.set_help_flag("-h,--help", "Display help and exit."); app.set_version_flag("--version", OEMSH_VERSION, "Display version and exit."); app.add_flag("-v,--verbose", params.verbose, "Verbose mode.")->capture_default_str(); - app.add_flag("-G", params.gui, "GUI mode."); - app.add_option("-i,--input", params.input, "Input CSX file.")->check(CLI::ExistingFile)->required(); + auto* g = app.add_flag("-G", params.gui, "GUI mode."); + auto* i = app.add_option("-i,--input", params.input, "Input CSX file.")->check(CLI::ExistingFile)->required(); + g->trigger_on_parse()->check(JustDo([i]() { i->required(false); })); // app.add_option("-o,--output", params.output, "Output CSX file. If different from input, will copy and extend it.")->check((!CLI::ExistingFile)|FutureConditional(params.force,"Cannot overwrite a file without --force")); app.add_option("-o,--output", params.output, "Output CSX file. If different from input, will copy and extend it.")->check(CLI::Validator((!CLI::ExistingFile)|FutureConditional(params.force,"Cannot overwrite a file without --force"), "FILE", "KO")); app.add_flag("-f,--force", params.force, "Allow overwriting a file.")->trigger_on_parse(); @@ -128,20 +142,20 @@ app::OpenEMSH::Params cli(int const argc, char* argv[]) { // app.add_flag("--step-mesh", params.with_step_mesh, "Do intervals meshing step.")->group("Processing options"); // Mesher options - app.add_option_function("--metal_res", - make_overrider<&domain::Params::metal_res>(domain_overrides), - "Desired mesh resolution for metal regions." - )->group("Mesher options"); +// app.add_option_function("--metal_res", +// make_overrider<&domain::Params::metal_res>(domain_overrides), +// "Desired mesh resolution for metal regions." +// )->group("Mesher options"); // app.add_option_function("--air_res", // make_overrider<&domain::Params::air_res>(domain_overrides), // "Desired mesh resolution for air regions." // )->group("Mesher options"); - app.add_option_function("--substrate_res", - make_overrider<&domain::Params::substrate_res>(domain_overrides), - "Desired mesh resolution for substrate / ground plane regions." - )->group("Mesher options"); +// app.add_option_function("--substrate_res", +// make_overrider<&domain::Params::substrate_res>(domain_overrides), +// "Desired mesh resolution for substrate / ground plane regions." +// )->group("Mesher options"); app.add_option_function("--proximity_limit", make_overrider<&domain::Params::proximity_limit>(domain_overrides), @@ -158,7 +172,7 @@ app::OpenEMSH::Params cli(int const argc, char* argv[]) { "Minimum line number per interval half." )->group("Mesher options"); - app.add_option_function("--lambda", + app.add_option_function("--smoothness", make_overrider<&domain::Params::lambda>(domain_overrides), "Smoothness factor ]1;2]." )->group("Mesher options")->check(BoundExclusiveInclusive(1.0, 2.0)); @@ -170,6 +184,11 @@ app::OpenEMSH::Params cli(int const argc, char* argv[]) { app.add_flag("--policy-lines", params.with_meshline_policies, "Include meshline policies in output.")->group("Output options")->default_str(to_string(params.with_meshline_policies)); // app.add_flag("--policy-lines", params.with_meshline_policies, "Include meshline policies in output.")->group("Output options")->capture_default_str(); + app.preparse_callback([g](size_t argc) { + if(argc == 0) + g->force_callback()->default_val(true); + }); + try { app.parse(argc, argv); } catch(CLI::Success const& e) { diff --git a/src/ui/qt/about_dialog.cpp b/src/ui/qt/about_dialog.cpp index 6a10773a..83a1bccb 100644 --- a/src/ui/qt/about_dialog.cpp +++ b/src/ui/qt/about_dialog.cpp @@ -46,9 +46,4 @@ AboutDialog::AboutDialog(QWidget* parent) //****************************************************************************** AboutDialog::~AboutDialog() = default; -//****************************************************************************** -void AboutDialog::on_pb_ok_clicked() { - accept(); -} - } // namespace ui::qt diff --git a/src/ui/qt/about_dialog.hpp b/src/ui/qt/about_dialog.hpp index d9a45f43..0064eac2 100644 --- a/src/ui/qt/about_dialog.hpp +++ b/src/ui/qt/about_dialog.hpp @@ -7,10 +7,11 @@ #pragma once #include -#include #include +class QAbstractButton; + namespace Ui { class AboutDialog; } // namespace Ui @@ -19,13 +20,9 @@ namespace ui::qt { //****************************************************************************** class AboutDialog : public QDialog { - Q_OBJECT private: std::unique_ptr ui; -private slots: - void on_pb_ok_clicked(); - public: explicit AboutDialog(QWidget* parent = nullptr); ~AboutDialog() override; diff --git a/src/ui/qt/about_dialog.ui b/src/ui/qt/about_dialog.ui index 416dd97c..2807f998 100644 --- a/src/ui/qt/about_dialog.ui +++ b/src/ui/qt/about_dialog.ui @@ -127,22 +127,11 @@ the GPL license version 3 or later. - - - - - Qt::Horizontal - - - - - - - OK - - - - + + + QDialogButtonBox::Ok + + @@ -150,5 +139,12 @@ the GPL license version 3 or later. - + + + dbb_ok + accepted() + Dialog + accept() + + diff --git a/src/ui/qt/edit/edit_delegate.cpp b/src/ui/qt/edit/edit_delegate.cpp new file mode 100644 index 00000000..8d0d9a01 --- /dev/null +++ b/src/ui/qt/edit/edit_delegate.cpp @@ -0,0 +1,243 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "domain/mesh/meshline_policy.hpp" +#include "infra/utils/to_string.hpp" +#include "utils/concepts.hpp" +#include "utils/unconst.hpp" +#include "utils/unreachable.hpp" + +#include "edit_delegate.hpp" + +Q_DECLARE_METATYPE(domain::MeshlinePolicy::Normal) +Q_DECLARE_METATYPE(domain::MeshlinePolicy::Policy) + +namespace ui::qt { + +//****************************************************************************** +using Normal = domain::MeshlinePolicy::Normal; +using Policy = domain::MeshlinePolicy::Policy; + +//****************************************************************************** +static auto constexpr AllNormal = std::array { + Normal::NONE, + Normal::MIN, + Normal::MAX +}; + +//****************************************************************************** +static auto constexpr AllPolicy = std::array { + Policy::ONELINE, + Policy::HALFS, + Policy::THIRDS +}; + +//****************************************************************************** +template +QString convert(E e) { + return QString::fromStdString(to_string(e)); +} + +//****************************************************************************** +template +QStringList convert(std::array const& in) { + QStringList out; + for(auto& e : in) + out.push_back(convert(e)); + return out; +} + +//****************************************************************************** +template +constexpr std::size_t key(E e, std::array const& all) { + for(std::size_t i = 0; i < all.size(); ++i) + if(all[i] == e) + return i; + unreachable(); +} + +//****************************************************************************** +static constexpr auto key(Normal normal) { return key(normal, AllNormal); } +static constexpr auto key(Policy policy) { return key(policy, AllPolicy); } + +//****************************************************************************** +static_assert(AllNormal[key(Normal::NONE)] == Normal::NONE); +static_assert(AllNormal[key(Normal::MIN)] == Normal::MIN); +static_assert(AllNormal[key(Normal::MAX)] == Normal::MAX); +static_assert(AllPolicy[key(Policy::ONELINE)] == Policy::ONELINE); +static_assert(AllPolicy[key(Policy::HALFS)] == Policy::HALFS); +static_assert(AllPolicy[key(Policy::THIRDS)] == Policy::THIRDS); + +//****************************************************************************** +EditDelegate::EditDelegate(QObject* parent) +: QStyledItemDelegate(parent) +, normal_index(QModelIndex()) // Init at first paint(). +, policy_index(QModelIndex()) // Init at first paint(). +{} + +//****************************************************************************** +QWidget* EditDelegate::createEditor(QWidget* parent, QStyleOptionViewItem const& option, QModelIndex const& index) const { + auto const type = index.data(Qt::UserRole + 1).typeId(); + + auto const handle_enum = [&](std::array const& all) { + auto* widget = new QComboBox(parent); + widget->addItems(convert(all)); + widget->setToolTip(index.data(Qt::ToolTipRole).toString()); + static_cast(widget->view())->setToolTip(index.data(Qt::ToolTipRole).toString()); + return widget; + }; + + auto const bound_normal_choice_by_current_policy = [&](auto const* cb) { + if(policy_index.isValid()) { + auto policy = policy_index.data(Qt::UserRole + 1).value(); + switch(policy) { + case Policy::ONELINE: [[fallthrough]]; + case Policy::HALFS: { + // Actually made uneditable since there is no choice, + // in enforce_coherent_normal_regarding_current_policy(). + auto const* m = static_cast(cb->model()); + m->item(key(Normal::NONE))->setEnabled(true); + m->item(key(Normal::MIN))->setEnabled(false); + m->item(key(Normal::MAX))->setEnabled(false); + } break; + case Policy::THIRDS: { + auto const* m = static_cast(cb->model()); + m->item(key(Normal::NONE))->setEnabled(false); + m->item(key(Normal::MIN))->setEnabled(true); + m->item(key(Normal::MAX))->setEnabled(true); + } break; + default: break; + } + } + }; + + if(type == qMetaTypeId()) { + auto* cb = handle_enum(AllNormal); + bound_normal_choice_by_current_policy(cb); + return cb; + } else if(type == qMetaTypeId()) { + return handle_enum(AllPolicy); + } else { + return QStyledItemDelegate::createEditor(parent, option, index); + } +} + +//****************************************************************************** +void EditDelegate::setEditorData(QWidget* editor, QModelIndex const& index) const { + auto const type = index.data(Qt::UserRole + 1).typeId(); + + auto const handle_enum = [&]() { + auto* cb = static_cast(editor); + cb->setCurrentIndex((int) key(index.data(Qt::UserRole + 1).value())); + }; + + if(type == qMetaTypeId()) { + handle_enum.operator()(); + } else if(type == qMetaTypeId()) { + handle_enum.operator()(); + } + + QStyledItemDelegate::setEditorData(editor, index); +} + +//****************************************************************************** +void EditDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, QModelIndex const& index) const { + auto const type = index.data(Qt::UserRole + 1).typeId(); + + auto const handle_enum = [&](std::array const& all) { + auto const* cb = static_cast(editor); + model->setData(index, QVariant::fromValue(all[cb->currentIndex()]), Qt::UserRole + 1); + model->setData(index, cb->currentText(), Qt::EditRole); + }; + + auto const enforce_coherent_normal_regarding_current_policy = [&]() { + if(normal_index.isValid()) { + auto policy = model->data(index, Qt::UserRole + 1).value(); + switch(policy) { + case Policy::ONELINE: [[fallthrough]]; + case Policy::HALFS: { + model->setData(normal_index, QVariant::fromValue(Normal::NONE), Qt::UserRole + 1); + auto* item = static_cast(model)->itemFromIndex(normal_index); + item->setEditable(false); + } break; + case Policy::THIRDS: { + if(model->data(normal_index, Qt::UserRole + 1).value() == Normal::NONE) { + model->setData(normal_index, QVariant::fromValue(Normal::MIN), Qt::UserRole + 1); + auto* item = static_cast(model)->itemFromIndex(normal_index); + item->setEditable(true); + } + } break; + default: break; + } + } + }; + + if(type == qMetaTypeId()) { + handle_enum(AllNormal); + } else if(type == qMetaTypeId()) { + handle_enum(AllPolicy); + enforce_coherent_normal_regarding_current_policy(); + } + + QStyledItemDelegate::setModelData(editor, model, index); +} + +//****************************************************************************** +void EditDelegate::paint(QPainter* painter, QStyleOptionViewItem const& option, QModelIndex const& index) const { + auto const type = index.data(Qt::UserRole + 1).typeId(); + + auto const handle_enum = [&]() { + auto* model = unconst(index.model()); + model->setData( + index, + convert(index.data(Qt::UserRole + 1).value()), + Qt::DisplayRole); + }; + + if(type == qMetaTypeId()) { + handle_enum.operator()(); + unconst(this)->normal_index = index; + } else if(type == qMetaTypeId()) { + handle_enum.operator()(); + unconst(this)->policy_index = index; + } + + QStyledItemDelegate::paint(painter, option, index); +} + +//****************************************************************************** +bool EditDelegate::eventFilter(QObject* object, QEvent* event) { + QWidget* editor = qobject_cast(object); + if(!editor) + return QStyledItemDelegate::eventFilter(object, event); + + if(event->type() == QEvent::KeyPress) { + switch(static_cast(event)->key()) { + case Qt::Key_Enter: [[fallthrough]]; + case Qt::Key_Return: + if(qobject_cast(editor)) { + emit commitData(editor); + emit closeEditor(editor); + return true; + } + } + } + + return QStyledItemDelegate::eventFilter(object, event); +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_delegate.hpp b/src/ui/qt/edit/edit_delegate.hpp new file mode 100644 index 00000000..b0910abf --- /dev/null +++ b/src/ui/qt/edit/edit_delegate.hpp @@ -0,0 +1,32 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include +#include + +namespace ui::qt { + +//****************************************************************************** +class EditDelegate : public QStyledItemDelegate { +public: + explicit EditDelegate(QObject* parent = nullptr); + + QWidget* createEditor(QWidget* parent, QStyleOptionViewItem const& option, QModelIndex const& index) const override; + void setEditorData(QWidget* editor, QModelIndex const& index) const override; + void setModelData(QWidget* editor, QAbstractItemModel* model, QModelIndex const& index) const override; + void paint(QPainter* painter, QStyleOptionViewItem const& option, QModelIndex const& index) const override; + +protected: + bool eventFilter(QObject* editor, QEvent* event) override; + +private: + QPersistentModelIndex normal_index; + QPersistentModelIndex policy_index; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_dialog.cpp b/src/ui/qt/edit/edit_dialog.cpp new file mode 100644 index 00000000..07fc0a87 --- /dev/null +++ b/src/ui/qt/edit/edit_dialog.cpp @@ -0,0 +1,49 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include + +#include "edit_delegate.hpp" +#include "edit_model.hpp" + +#include "ui_edit_dialog.h" +#include "edit_dialog.hpp" + +namespace ui::qt { + +using namespace std; + +//****************************************************************************** +EditDialog::EditDialog(EditModel* model, QString const& title, QWidget* parent) +: QDialog(parent, Qt::Dialog) +, ui(make_unique()) +, delegate(new EditDelegate(this)) { + ui->setupUi(this); + setWindowIcon(QPixmap(":/openemsh.ico")); + setWindowTitle(windowTitle() + " " + title); + + ui->tv_properties->setItemDelegate(delegate); + ui->tv_properties->setModel(model); + ui->tv_properties->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); +} + +//****************************************************************************** +EditDialog::~EditDialog() = default; + +//****************************************************************************** +void EditDialog::on_dbb_ok_accepted() { + QGuiApplication::setOverrideCursor(Qt::WaitCursor); + static_cast(ui->tv_properties->model())->commit(); + QGuiApplication::restoreOverrideCursor(); + accept(); +} + +//****************************************************************************** +void EditDialog::on_dbb_ok_rejected() { + reject(); +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_dialog.hpp b/src/ui/qt/edit/edit_dialog.hpp new file mode 100644 index 00000000..314b6ef8 --- /dev/null +++ b/src/ui/qt/edit/edit_dialog.hpp @@ -0,0 +1,38 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include + +#include + +namespace Ui { +class EditDialog; +} // namespace Ui + +namespace ui::qt { + +class EditDelegate; +class EditModel; + +//****************************************************************************** +class EditDialog : public QDialog { + Q_OBJECT +private: + std::unique_ptr ui; + EditDelegate* delegate; + +private slots: + void on_dbb_ok_accepted(); + void on_dbb_ok_rejected(); + +public: + explicit EditDialog(EditModel* model, QString const& title = QString(), QWidget* parent = nullptr); + ~EditDialog() override; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_dialog.ui b/src/ui/qt/edit/edit_dialog.ui new file mode 100644 index 00000000..45d6aa12 --- /dev/null +++ b/src/ui/qt/edit/edit_dialog.ui @@ -0,0 +1,36 @@ + + + EditDialog + + + Edit + + + + QLayout::SetFixedSize + + + + + + QAbstractScrollArea::AdjustToContents + + + true + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + diff --git a/src/ui/qt/edit/edit_model.cpp b/src/ui/qt/edit/edit_model.cpp new file mode 100644 index 00000000..45f39814 --- /dev/null +++ b/src/ui/qt/edit/edit_model.cpp @@ -0,0 +1,91 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include "edit_model_conflict_too_close_meshline_policies.hpp" +#include "edit_model_edge.hpp" +#include "edit_model_interval.hpp" +#include "edit_model_meshline_policy.hpp" +#include "ui/qt/user_types.hpp" +#include "ui/qt/processing_view/processing_conflict_too_close_meshline_policies.hpp" +#include "ui/qt/processing_view/processing_edge.hpp" +#include "ui/qt/processing_view/processing_interval.hpp" +#include "ui/qt/processing_view/processing_meshline_policy.hpp" +#include "utils/unconst.hpp" + +#include "edit_model.hpp" + +namespace ui::qt { + +//****************************************************************************** +bool EditModel::try_to_double(QString const& in, double& out) { + bool does_succeed = false; + auto result = in.toDouble(&does_succeed); + if(does_succeed) + out = result; + return does_succeed; +} + +//****************************************************************************** +bool EditModel::try_to_ulong(QString const& in, std::size_t& out) { + bool does_succeed = false; + auto result = in.toULong(&does_succeed); + if(does_succeed) + out = result; + return does_succeed; +} + +//****************************************************************************** +bool EditModel::try_to_bool(Qt::CheckState const in, bool& out) { + bool does_succeed = false; + switch(in) { + case Qt::Checked: + does_succeed = true; + out = true; + break; + case Qt::Unchecked: + does_succeed = true; + out = false; + break; + default: + break; + } + return does_succeed; +} + +//****************************************************************************** +EditModel* EditModel::make(nodegraph::Node* node, QObject* parent) { + switch(node->type()) { + case UserTypes::PROCESSING_EDGE: + return new EditModelEdge(unconst(static_cast(node)->edge), parent); + case UserTypes::PROCESSING_INTERVAL: + return new EditModelInterval(unconst(static_cast(node)->interval), parent); + case UserTypes::PROCESSING_MESHLINE_POLICY: + return new EditModelMeshlinePolicy(unconst(static_cast(node)->meshline_policy), parent); + case UserTypes::PROCESSING_CONFLICT_TCMLP: + return new EditModelConflictTooCloseMeshlinePolicies(unconst(static_cast(node)->conflict), parent); + default: + return nullptr; + } +} + +//****************************************************************************** +EditModel::EditModel(QObject* parent) +: QStandardItemModel(parent) +{ + static_assert(1 <= V && V <= 2, "The Value column index V must be either 1 or 2"); + + setColumnCount(V + 1); + + if constexpr(V == 2) + setHorizontalHeaderLabels({ "Property", "Old value", "New value" }); + else + setHorizontalHeaderLabels({ "Property", "Value" }); +} + +//****************************************************************************** +void EditModel::commit() {} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model.hpp b/src/ui/qt/edit/edit_model.hpp new file mode 100644 index 00000000..20b298c7 --- /dev/null +++ b/src/ui/qt/edit/edit_model.hpp @@ -0,0 +1,104 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include + +#include + +#include "app/steps.hpp" +#include "utils/concepts.hpp" + +namespace ui::qt { + +namespace nodegraph { +class Node; +} // namespace nodegraph + +//****************************************************************************** +class EditModel : public QStandardItemModel { + Q_OBJECT +public: + static EditModel* make(nodegraph::Node* node, QObject* parent = nullptr); + + explicit EditModel(QObject* parent = nullptr); + virtual void commit(); + +protected: + static auto constexpr V = 2; // Value column index. + + template + void make_row(int row, QString const& property, T const& old_value, T const& new_value, QString const& tool_tip); + void make_row(int row, QString const& property, auto const& value, QString const& tool_tip); + static bool is_true(bool const val) { return val; } + static bool try_to_double(QString const& in, double& out); + static bool try_to_ulong(QString const& in, std::size_t& out); + static bool try_to_bool(Qt::CheckState const in, bool& out); + +private: + template + static void set_content(QStandardItem* item, E e); + static void set_content(QStandardItem* item, QString const& s); + static void set_content(QStandardItem* item, bool b); + static void set_uneditable(QStandardItem* item); + +signals: + void edit_from(app::Step from, std::function const& edit); +}; + +//****************************************************************************** +template +void EditModel::set_content(QStandardItem* item, E e) { + item->setData(QVariant::fromValue(e)); +} + +//****************************************************************************** +inline void EditModel::set_content(QStandardItem* item, QString const& s) { + item->setText(s); +} + +//****************************************************************************** +inline void EditModel::set_content(QStandardItem* item, bool b) { + item->setCheckable(true); + item->setCheckState(b ? Qt::Checked : Qt::Unchecked); + set_uneditable(item); +} + +//****************************************************************************** +inline void EditModel::set_uneditable(QStandardItem* item) { + item->setFlags(item->flags() & ~Qt::ItemIsEditable); +} + +//****************************************************************************** +template +void EditModel::make_row(int row, QString const& property, T const& old_value, T const& new_value, QString const& tool_tip) { + setItem(row, 0, new QStandardItem(property)); + item(row, 0)->setToolTip(tool_tip); + set_uneditable(item(row, 0)); + + if constexpr(V == 2) { + setItem(row, 1, new QStandardItem()); + item(row, 1)->setToolTip(tool_tip); + set_uneditable(item(row, 1)); + set_content(item(row, 1), old_value); + } + + setItem(row, V, new QStandardItem()); + item(row, V)->setToolTip(tool_tip); + if constexpr(V == 2) { + set_content(item(row, V), new_value); + } else { + set_content(item(row, V), old_value); + } +} + +//****************************************************************************** +void EditModel::make_row(int row, QString const& property, auto const& value, QString const& tool_tip) { + make_row(row, property, value, value, tool_tip); +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_conflict_too_close_meshline_policies.cpp b/src/ui/qt/edit/edit_model_conflict_too_close_meshline_policies.cpp new file mode 100644 index 00000000..e3149fb4 --- /dev/null +++ b/src/ui/qt/edit/edit_model_conflict_too_close_meshline_policies.cpp @@ -0,0 +1,43 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "app/steps.hpp" +#include "domain/conflicts/conflict_too_close_meshline_policies.hpp" + +#include "edit_model_conflict_too_close_meshline_policies.hpp" + +namespace ui::qt { + +//****************************************************************************** +EditModelConflictTooCloseMeshlinePolicies::EditModelConflictTooCloseMeshlinePolicies(domain::ConflictTooCloseMeshlinePolicies* conflict, QObject* parent) +: EditModel(parent) +, conflict(conflict) +{ + auto const& state = conflict->get_current_state(); + setRowCount(1); + + make_row(0, "Enabled", state.is_enabled, "Take into account in the meshing process."); +} + +//****************************************************************************** +void EditModelConflictTooCloseMeshlinePolicies::commit() { + auto state = conflict->get_current_state(); + + std::array does_succeed = { + try_to_bool(item(0, V)->checkState(), state.is_enabled) + }; + + if(std::ranges::all_of(does_succeed, is_true)) { + emit edit_from(app::Step::DETECT_AND_SOLVE_TCMLP, [&]() { + conflict->set_next_state(state); + }); + } +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_conflict_too_close_meshline_policies.hpp b/src/ui/qt/edit/edit_model_conflict_too_close_meshline_policies.hpp new file mode 100644 index 00000000..900752a4 --- /dev/null +++ b/src/ui/qt/edit/edit_model_conflict_too_close_meshline_policies.hpp @@ -0,0 +1,27 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include "edit_model.hpp" + +namespace domain { +class ConflictTooCloseMeshlinePolicies; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class EditModelConflictTooCloseMeshlinePolicies : public EditModel { +public: + explicit EditModelConflictTooCloseMeshlinePolicies(domain::ConflictTooCloseMeshlinePolicies* conflict, QObject* parent = nullptr); + void commit() override; + +private: + domain::ConflictTooCloseMeshlinePolicies* conflict; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_edge.cpp b/src/ui/qt/edit/edit_model_edge.cpp new file mode 100644 index 00000000..a854b5c5 --- /dev/null +++ b/src/ui/qt/edit/edit_model_edge.cpp @@ -0,0 +1,43 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "app/steps.hpp" +#include "domain/geometrics/edge.hpp" + +#include "edit_model_edge.hpp" + +namespace ui::qt { + +//****************************************************************************** +EditModelEdge::EditModelEdge(domain::Edge* edge, QObject* parent) +: EditModel(parent) +, edge(edge) +{ + auto const& state = edge->get_current_state(); + setRowCount(1); + + make_row(0, "To mesh", state.to_mesh, "Take into account in the meshing process."); +} + +//****************************************************************************** +void EditModelEdge::commit() { + auto state = edge->get_current_state(); + + std::array does_succeed = { + try_to_bool(item(0, V)->checkState(), state.to_mesh) + }; + + if(std::ranges::all_of(does_succeed, is_true)) { + emit edit_from(app::Step::DETECT_CONFLICT_EIP, [&]() { + edge->set_next_state(state); + }); + } +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_edge.hpp b/src/ui/qt/edit/edit_model_edge.hpp new file mode 100644 index 00000000..31b7e356 --- /dev/null +++ b/src/ui/qt/edit/edit_model_edge.hpp @@ -0,0 +1,27 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include "edit_model.hpp" + +namespace domain { +class Edge; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class EditModelEdge : public EditModel { +public: + explicit EditModelEdge(domain::Edge* edge, QObject* parent = nullptr); + void commit() override; + +private: + domain::Edge* edge; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_global.cpp b/src/ui/qt/edit/edit_model_global.cpp new file mode 100644 index 00000000..19ab5198 --- /dev/null +++ b/src/ui/qt/edit/edit_model_global.cpp @@ -0,0 +1,61 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "app/steps.hpp" +#include "domain/global.hpp" + +#include "edit_model_global.hpp" + +namespace ui::qt { + +// https://doc.qt.io/qt-6/qitemeditorfactory.html#registerEditor +// https://www.bogotobogo.com/Qt/Qt5_QTableView_QItemDelegate_ModelView_MVC.php +// https://stackoverflow.com/questions/60767527/creating-item-with-a-integer-qstandarditem-doesnt-provide-qspinbox +// https://stackoverflow.com/questions/3135505/qstandarditem-qcombobox +//****************************************************************************** +EditModelGlobal::EditModelGlobal(domain::GlobalParams* global, QObject* parent) +: EditModel(parent) +, global(global) +{ + auto const& params = global->get_current_state(); + setRowCount(4); + +// make_row(0, "metal_res", QString::number(params.metal_res), ""); +// make_row(1, "substrate_res", QString::number(params.substrate_res), ""); + make_row(0, "Proximity limit", QString::number(params.proximity_limit), + "Distance below which two MeshlinePolicies will be merged."); + make_row(1, "Smoothness", QString::number(params.lambda), + "Smoothness factor ]1;2]. Meshing algorithm will decrease it, better to start high."); + make_row(2, "lmin", QString::number(params.lmin), + "Minimum line number per Interval half."); + make_row(3, "dmax", QString::number(params.dmax), + "Maximum distance between two adjacent lines."); +} + +//****************************************************************************** +void EditModelGlobal::commit() { + domain::Params params; + + std::array does_succeed = { +// try_to_double(item(0, V)->text(), params.metal_res), +// try_to_double(item(1, V)->text(), params.substrate_res), + try_to_double(item(0, V)->text(), params.proximity_limit), + try_to_double(item(1, V)->text(), params.lambda), + try_to_ulong(item(2, V)->text(), params.lmin), + try_to_double(item(3, V)->text(), params.dmax) + }; + + if(std::ranges::all_of(does_succeed, is_true)) { + emit edit_from(app::Step::DETECT_CONFLICT_EIP, [&]() { + global->set_next_state(params); + }); + } +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_global.hpp b/src/ui/qt/edit/edit_model_global.hpp new file mode 100644 index 00000000..e1c2f84a --- /dev/null +++ b/src/ui/qt/edit/edit_model_global.hpp @@ -0,0 +1,27 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include "edit_model.hpp" + +namespace domain { +class GlobalParams; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class EditModelGlobal : public EditModel { +public: + explicit EditModelGlobal(domain::GlobalParams* global, QObject* parent = nullptr); + void commit() override; + +private: + domain::GlobalParams* global; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_interval.cpp b/src/ui/qt/edit/edit_model_interval.cpp new file mode 100644 index 00000000..8786b781 --- /dev/null +++ b/src/ui/qt/edit/edit_model_interval.cpp @@ -0,0 +1,60 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "app/steps.hpp" +#include "domain/mesh/interval.hpp" + +#include "edit_model_interval.hpp" + +namespace ui::qt { + +//****************************************************************************** +EditModelInterval::EditModelInterval(domain::Interval* interval, QObject* parent) +: EditModel(parent) +, interval(interval) +{ + auto const& state = interval->get_current_state(); + setRowCount(5); + + make_row(0, "dmax", QString::number(state.dmax), + "Maximum distance between two adjacent lines."); + make_row(1, "Before.lmin", QString::number(state.before.lmin), + "Minimum line number in the minimal interval half. " + "Note a line will always be placed at the interval center."); + make_row(2, "Before.Smoothness", QString::number(state.before.lambda), QString("2"), + "Smoothness factor ]1;2] around the minimal side. " + "Meshing algorithm will decrease it, better to start high."); + make_row(3, "After.lmin", QString::number(state.after.lmin), + "Minimum line number in the maximal interval half. " + "Note a line will always be placed at the interval center."); + make_row(4, "After.Smoothness", QString::number(state.after.lambda), QString("2"), + "Smoothness factor ]1;2] around the maximal side. " + "Meshing algorithm will decrease it, better to start high."); +} + +//****************************************************************************** +void EditModelInterval::commit() { + auto state = interval->get_current_state(); + + std::array does_succeed = { + try_to_double(item(0, V)->text(), state.dmax), + try_to_ulong(item(1, V)->text(), state.before.lmin), + try_to_double(item(2, V)->text(), state.before.lambda), + try_to_ulong(item(3, V)->text(), state.after.lmin), + try_to_double(item(4, V)->text(), state.after.lambda) + }; + + if(std::ranges::all_of(does_succeed, is_true)) { + emit edit_from(app::Step::MESH, [&] { + interval->set_next_state(state); + }); + } +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_interval.hpp b/src/ui/qt/edit/edit_model_interval.hpp new file mode 100644 index 00000000..53693227 --- /dev/null +++ b/src/ui/qt/edit/edit_model_interval.hpp @@ -0,0 +1,27 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include "edit_model.hpp" + +namespace domain { +class Interval; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class EditModelInterval : public EditModel { +public: + explicit EditModelInterval(domain::Interval* interval, QObject* parent = nullptr); + void commit() override; + +private: + domain::Interval* interval; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_meshline_policy.cpp b/src/ui/qt/edit/edit_model_meshline_policy.cpp new file mode 100644 index 00000000..2541a2c9 --- /dev/null +++ b/src/ui/qt/edit/edit_model_meshline_policy.cpp @@ -0,0 +1,91 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "app/steps.hpp" +#include "domain/mesh/meshline_policy.hpp" +#include "infra/utils/to_string.hpp" +#include "utils/unreachable.hpp" + +#include "edit_model_meshline_policy.hpp" + +Q_DECLARE_METATYPE(domain::MeshlinePolicy::Policy) +Q_DECLARE_METATYPE(domain::MeshlinePolicy::Normal) + +namespace ui::qt { + +//****************************************************************************** +using Normal = domain::MeshlinePolicy::Normal; +using Policy = domain::MeshlinePolicy::Policy; + +//****************************************************************************** +EditModelMeshlinePolicy::EditModelMeshlinePolicy(domain::MeshlinePolicy* meshline_policy, QObject* parent) +: EditModel(parent) +, meshline_policy(meshline_policy) +{ + auto const& state = meshline_policy->get_current_state(); + setRowCount(4); + + make_row(0, "Policy", state.policy, + "ONELINE: One meshline at the policy position.
" + "HALFS: Two lines centered around the policy position.
" + "THIRDS: Two lines placed around (2d/3 in Normal direction, d/3 the other side) the policy position."); + make_row(1, "Normal", state.normal, + "Direction associated with Policy."); + make_row(2, "Enabled", state.is_enabled, + "Take into account in the meshing process."); +// make_row(3, "res_factor", QString::number(state.res_factor), ""); + make_row(3, "d", QString::number(state.d), + "Desired distance between policy lines (HALFS|THIRDS) or " + "between policy line and adjacent lines (ONELINE).
" + "Can be decreased by the meshing algorithm."); +} + +//****************************************************************************** +void EditModelMeshlinePolicy::commit() { + auto state = meshline_policy->get_current_state(); + + auto const are_policy_and_normal_compatible = [&state]() { + switch(state.policy) { + case Policy::ONELINE: [[fallthrough]]; + case Policy::HALFS: + switch(state.normal) { + case Normal::MIN: [[fallthrough]]; + case Normal::MAX: return false; + case Normal::NONE: return true; + default: unreachable(); + } + case Policy::THIRDS: + switch(state.normal) { + case Normal::MIN: [[fallthrough]]; + case Normal::MAX: return true; + case Normal::NONE: return false; + default: unreachable(); + } + default:unreachable(); + } + }; + + state.policy = item(0, V)->data().value(); + state.normal = item(1, V)->data().value(); + + std::array does_succeed = { + are_policy_and_normal_compatible(), + try_to_bool(item(2, V)->checkState(), state.is_enabled), +// try_to_double(item(3, V)->text(), state.res_factor), + try_to_double(item(3, V)->text(), state.d) + }; + + if(std::ranges::all_of(does_succeed, is_true)) { + emit edit_from(app::Step::DETECT_INTERVALS, [&]() { + meshline_policy->set_next_state(state); + }); + } +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_meshline_policy.hpp b/src/ui/qt/edit/edit_model_meshline_policy.hpp new file mode 100644 index 00000000..736c5d79 --- /dev/null +++ b/src/ui/qt/edit/edit_model_meshline_policy.hpp @@ -0,0 +1,27 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include "edit_model.hpp" + +namespace domain { +class MeshlinePolicy; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class EditModelMeshlinePolicy : public EditModel { +public: + explicit EditModelMeshlinePolicy(domain::MeshlinePolicy* meshline_policy, QObject* parent = nullptr); + void commit() override; + +private: + domain::MeshlinePolicy* meshline_policy; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/icons.cpp b/src/ui/qt/icons.cpp new file mode 100644 index 00000000..4b6200d1 --- /dev/null +++ b/src/ui/qt/icons.cpp @@ -0,0 +1,161 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include +#include +#include +#include +#include + +#include "structure_view/structure_conflict_colinear_edges.hpp" +#include "structure_view/structure_conflict_too_close_meshline_policies.hpp" +#include "structure_view/structure_interval.hpp" +#include "structure_view/structure_meshline.hpp" +#include "structure_view/structure_meshline_policy.hpp" + +#include "user_types.hpp" +#include "utils/concepts.hpp" +#include "utils/unreachable.hpp" + +#include "icons.hpp" + +namespace ui::qt { + +//****************************************************************************** +auto draw_icon_from_text(auto str) { + return [=](int size, QPainter& painter) { + painter.setFont(QFont("Arial", size / 2)); + painter.drawText(QRect(0, 0, size, size), Qt::AlignCenter, QString::fromUtf8(str)); + }; +} + +//****************************************************************************** +template Drawer> +QPixmap make_pixmap(Drawer const& draw) { + int const size = 24; + QPixmap icon(size, size); + icon.fill(Qt::transparent); + QPainter painter(&icon); + switch(QGuiApplication::styleHints()->colorScheme()) { + default: [[fallthrough]]; + case Qt::ColorScheme::Light: painter.setPen(Qt::black); break; + case Qt::ColorScheme::Dark: painter.setPen(Qt::white); break; + } + draw(size, painter); + return icon; +}; + +//****************************************************************************** +static QTransform const rotate_90_cw = []() { + QTransform t; + t.rotate(90); + return t; +} (); + +//****************************************************************************** +static QTransform const rotate_90_ccw = []() { + QTransform t; + t.rotate(-90); + return t; +} (); + +//****************************************************************************** +QPixmap crop_to_original_size(QPixmap const& to_crop, QPixmap const& orig) { + int xoffset = (to_crop.width() - orig.width()) / 2; + int yoffset = (to_crop.height() - orig.height()) / 2; + return to_crop.copy(xoffset, yoffset, orig.width(), orig.height()); +} + +//****************************************************************************** +QPixmap apply(QTransform const& transform, QPixmap const& pixmap) { + return crop_to_original_size(pixmap.transformed(transform), pixmap); +} + +//****************************************************************************** +#define PIXMAP_MAKER_DEF(NAME, FUNC) \ + QPixmap const& Icons::NAME() { \ + switch(QGuiApplication::styleHints()->colorScheme()) { \ + default: [[fallthrough]]; \ + case Qt::ColorScheme::Light: { \ + static QPixmap const light = FUNC; \ + return light; \ + } \ + case Qt::ColorScheme::Dark: { \ + static QPixmap const dark = FUNC; \ + return dark; \ + } \ + } \ + } + +//****************************************************************************** +PIXMAP_MAKER_DEF(edge, make_pixmap(draw_icon_from_text("/"))) +PIXMAP_MAKER_DEF(polygon, make_pixmap(draw_icon_from_text("▱"))) +PIXMAP_MAKER_DEF(conflict_ce_v, make_pixmap(draw_icon_from_text("┆"))) +PIXMAP_MAKER_DEF(conflict_tcmlp_v, make_pixmap(draw_icon_from_text("‖"))) +PIXMAP_MAKER_DEF(interval_v, make_pixmap(draw_icon_from_text("▥"))) +PIXMAP_MAKER_DEF(meshline_v, make_pixmap(draw_icon_from_text("|"))) +PIXMAP_MAKER_DEF(meshline_policy_v, make_pixmap(draw_icon_from_text("⟊"))) +PIXMAP_MAKER_DEF(conflict_ce_h, apply(rotate_90_cw, conflict_ce_v())) +PIXMAP_MAKER_DEF(conflict_tcmlp_h, apply(rotate_90_cw, conflict_tcmlp_v())) +PIXMAP_MAKER_DEF(interval_h, apply(rotate_90_cw, interval_v())) +PIXMAP_MAKER_DEF(meshline_h, apply(rotate_90_cw, meshline_v())) +PIXMAP_MAKER_DEF(meshline_policy_h, apply(rotate_90_cw, meshline_policy_v())) + +//****************************************************************************** +QPixmap const& Icons::select(QGraphicsItem const* item) { + using namespace UserTypes; + + switch(item->type()) { + case PROCESSING_EDGE: [[fallthrough]]; + case STRUCTURE_EDGE: return edge(); + case PROCESSING_POLYGON: [[fallthrough]]; + case STRUCTURE_POLYGON: return polygon(); + case PROCESSING_INTERVAL: return interval_v(); + case STRUCTURE_INTERVAL: + switch(static_cast(item)->axis) { + case domain::ViewAxis::H: return interval_h(); + case domain::ViewAxis::V: return interval_v(); + default: unreachable(); + } + case PROCESSING_MESHLINE: return meshline_v(); + case STRUCTURE_MESHLINE: + switch(static_cast(item)->axis) { + case domain::ViewAxis::H: return meshline_h(); + case domain::ViewAxis::V: return meshline_v(); + default: unreachable(); + } + case PROCESSING_MESHLINE_POLICY: return meshline_policy_v(); + case STRUCTURE_MESHLINE_POLICY: + switch(static_cast(item)->axis) { + case domain::ViewAxis::H: return meshline_policy_h(); + case domain::ViewAxis::V: return meshline_policy_v(); + default: unreachable(); + } + case PROCESSING_CONFLICT_CE: return conflict_ce_v(); + case STRUCTURE_CONFLICT_CE: + switch(static_cast(item)->axis) { + case domain::ViewAxis::H: return conflict_ce_h(); + case domain::ViewAxis::V: return conflict_ce_v(); + default: unreachable(); + } + case PROCESSING_CONFLICT_TCMLP: return conflict_tcmlp_v(); + case STRUCTURE_CONFLICT_TCMLP: + switch(static_cast(item)->axis) { + case domain::ViewAxis::H: return conflict_tcmlp_h(); + case domain::ViewAxis::V: return conflict_tcmlp_v(); + default: unreachable(); + } + case PROCESSING_CONFLICT_EIP: [[fallthrough]]; + case PROCESSING_AXIS: [[fallthrough]]; + case PROCESSING_PLANE: [[fallthrough]]; + default: + static auto const empty = QPixmap(); + return empty; + } +} + +} // namespace ui::qt diff --git a/src/ui/qt/icons.hpp b/src/ui/qt/icons.hpp new file mode 100644 index 00000000..5e044122 --- /dev/null +++ b/src/ui/qt/icons.hpp @@ -0,0 +1,35 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include + +class QGraphicsItem; + +namespace ui::qt { + +//****************************************************************************** +struct Icons { + Icons() = delete; + + static QPixmap const& select(QGraphicsItem const* item); + + static QPixmap const& edge(); + static QPixmap const& polygon(); + static QPixmap const& interval_h(); + static QPixmap const& interval_v(); + static QPixmap const& meshline_policy_h(); + static QPixmap const& meshline_policy_v(); + static QPixmap const& conflict_ce_h(); + static QPixmap const& conflict_ce_v(); + static QPixmap const& conflict_tcmlp_h(); + static QPixmap const& conflict_tcmlp_v(); + static QPixmap const& meshline_h(); + static QPixmap const& meshline_v(); +}; + +} // namespace ui::qt diff --git a/src/ui/qt/main_window.cpp b/src/ui/qt/main_window.cpp index 80dc0362..f57157e6 100644 --- a/src/ui/qt/main_window.cpp +++ b/src/ui/qt/main_window.cpp @@ -5,12 +5,19 @@ ///***************************************************************************** #include +#include +#include #include +#include #include "domain/geometrics/space.hpp" +#include "edit/edit_dialog.hpp" +#include "edit/edit_model.hpp" +#include "edit/edit_model_global.hpp" #include "processing_view/processing_view.hpp" #include "structure_view/structure_view.hpp" #include "utils/state_management.hpp" +#include "utils/unreachable.hpp" #include "about_dialog.hpp" #include "ui_main_window.h" @@ -18,17 +25,25 @@ namespace ui::qt { +//****************************************************************************** +using DisplayMode = ProcessingScene::DisplayMode; +using MeshVisibility = StructureScene::MeshVisibility; + //****************************************************************************** MainWindow::MainWindow(app::OpenEMSH& oemsh, QWidget* parent) : QMainWindow(parent) , ui(std::make_unique()) , oemsh(oemsh) , dock_layout_order(false) +, csx_file(oemsh.get_params().input.empty() + ? QString() + : QString::fromStdString(oemsh.get_params().input.generic_string())) { setWindowState(Qt::WindowMaximized); - setWindowIcon(QPixmap(":/openemsh.ico")); ui->setupUi(this); + // TODO Init StructureView & ProcessingView stuff from buttons default values + for(auto const& style : Style::available_styles) { auto* const action = new QAction(style.name, ui->ag_styles); action->setCheckable(true); @@ -38,23 +53,35 @@ MainWindow::MainWindow(app::OpenEMSH& oemsh, QWidget* parent) } ui->m_style->addAction(action); } +} - oemsh.parse(); - oemsh.run_all_steps(); +//****************************************************************************** +MainWindow::~MainWindow() = default; +//****************************************************************************** +void MainWindow::parse_and_display() { + QGuiApplication::setOverrideCursor(Qt::WaitCursor); + update_title(); + oemsh.parse(); ui->structure_view->init(&oemsh.get_board()); ui->processing_view->init(&oemsh.get_board()); - handle_edition(); + run(); + QGuiApplication::restoreOverrideCursor(); +} - ui->structure_view->set_display_plane(domain::XY); - ui->processing_view->get_current_state().scene->set_display_plane(domain::XY); - ui->processing_view->get_current_state().scene->set_display_view_axes({ true, true }); -// ui->structure_view->setup_scale_max(ui->structure_view->scenes[domain::XY].polygons->boundingRect()); -// on_tb_reset_clicked(); +//****************************************************************************** +void MainWindow::update_title() { + static QString const base_title(windowTitle()); + + if(!csx_file.isEmpty()) + setWindowTitle(base_title + " - " + csx_file); } //****************************************************************************** -MainWindow::~MainWindow() = default; +void MainWindow::clear() { + ui->structure_view->clear(); + ui->processing_view->clear(); +} //****************************************************************************** void MainWindow::set_style(Style const& style) { @@ -83,27 +110,21 @@ void MainWindow::on_ag_styles_triggered(QAction* const action) { } //****************************************************************************** -void MainWindow::on_rb_plane_xy_toggled(bool const is_checked) { - if(is_checked) { - ui->structure_view->set_display_plane(domain::XY); - ui->processing_view->get_current_state().scene->set_display_plane(domain::XY); - } +void MainWindow::on_tb_plane_xy_clicked() { + ui->structure_view->set_display_plane(domain::XY); + ui->processing_view->set_display_plane(domain::XY); } //****************************************************************************** -void MainWindow::on_rb_plane_yz_toggled(bool const is_checked) { - if(is_checked) { - ui->structure_view->set_display_plane(domain::YZ); - ui->processing_view->get_current_state().scene->set_display_plane(domain::YZ); - } +void MainWindow::on_tb_plane_yz_clicked() { + ui->structure_view->set_display_plane(domain::YZ); + ui->processing_view->set_display_plane(domain::YZ); } //****************************************************************************** -void MainWindow::on_rb_plane_zx_toggled(bool const is_checked) { - if(is_checked) { - ui->structure_view->set_display_plane(domain::ZX); - ui->processing_view->get_current_state().scene->set_display_plane(domain::ZX); - } +void MainWindow::on_tb_plane_zx_clicked() { + ui->structure_view->set_display_plane(domain::ZX); + ui->processing_view->set_display_plane(domain::ZX); } //****************************************************************************** @@ -116,7 +137,7 @@ void MainWindow::on_tb_anchor_clicked(bool const is_checked) { } //****************************************************************************** -void MainWindow::on_a_reset_triggered() { +void MainWindow::on_a_fit_triggered() { ui->processing_view->get_current_state().scene->fit_containers(); ui->processing_view->get_current_state().scene->fit_scene(); ui->processing_view->fit(); @@ -151,58 +172,58 @@ void MainWindow::on_a_vertical_layout_triggered() { //****************************************************************************** void MainWindow::on_tb_show_all_mesh_clicked() { - ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::FULL); - ui->processing_view->get_current_state().scene->set_display_view_axes({ true, true }); + ui->structure_view->set_mesh_visibility(MeshVisibility::FULL); + ui->processing_view->set_display_view_axes({ true, true }); ui->processing_view->fit(); } //****************************************************************************** void MainWindow::on_tb_show_horizontal_mesh_clicked() { - ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::HORIZONTAL); - ui->processing_view->get_current_state().scene->set_display_view_axes({ true, false }); + ui->structure_view->set_mesh_visibility(MeshVisibility::HORIZONTAL); + ui->processing_view->set_display_view_axes({ true, false }); ui->processing_view->fit(); } //****************************************************************************** void MainWindow::on_tb_show_vertical_mesh_clicked() { - ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::VERTICAL); - ui->processing_view->get_current_state().scene->set_display_view_axes({ false, true }); + ui->structure_view->set_mesh_visibility(MeshVisibility::VERTICAL); + ui->processing_view->set_display_view_axes({ false, true }); ui->processing_view->fit(); } //****************************************************************************** void MainWindow::on_tb_show_no_mesh_clicked() { - ui->structure_view->set_mesh_visibility(StructureScene::MeshVisibility::NONE); - ui->processing_view->get_current_state().scene->set_display_view_axes({ false, false }); + ui->structure_view->set_mesh_visibility(MeshVisibility::NONE); + ui->processing_view->set_display_view_axes({ false, false }); ui->processing_view->fit(); } //****************************************************************************** void MainWindow::on_tb_show_selected_clicked() { - ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::SELECTED_CHAIN); + ui->processing_view->set_display_mode(DisplayMode::SELECTED_CHAIN); ui->processing_view->fit(); } //****************************************************************************** void MainWindow::on_tb_show_displayed_clicked() { - ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::STRUCTURE_VIEW); + ui->processing_view->set_display_mode(DisplayMode::STRUCTURE_VIEW); ui->processing_view->fit(); } //****************************************************************************** void MainWindow::on_tb_show_everything_clicked() { - ui->processing_view->get_current_state().scene->set_display(ProcessingScene::DisplayMode::EVERYTHING); + ui->processing_view->set_display_mode(DisplayMode::EVERYTHING); ui->processing_view->fit(); } //****************************************************************************** void MainWindow::on_tb_curved_wires_clicked() { - ui->processing_view->get_current_state().scene->set_wire_style(nodegraph::Wire::Style::CURVED); + ui->processing_view->set_wire_style(nodegraph::Wire::Style::CURVED); } //****************************************************************************** void MainWindow::on_tb_direct_wires_clicked() { - ui->processing_view->get_current_state().scene->set_wire_style(nodegraph::Wire::Style::DIRECT); + ui->processing_view->set_wire_style(nodegraph::Wire::Style::DIRECT); } //****************************************************************************** @@ -235,37 +256,119 @@ void MainWindow::on_tb_processing_zoom_out_clicked() { ui->processing_view->scale(1 / 1.2, 1 / 1.2); } +//****************************************************************************** +static QString const format_filter_csx("OpenEMS CSX file (*.csx *.xml)"); + +//****************************************************************************** +void MainWindow::on_a_file_open_triggered() { + QFileDialog dialog(this, ui->a_file_open->toolTip()); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setNameFilter(format_filter_csx); + dialog.setDirectory(csx_file.isEmpty() ? QString(".") : QFileInfo(csx_file).path()); + if(dialog.exec()) { + QGuiApplication::setOverrideCursor(Qt::WaitCursor); + csx_file = dialog.selectedFiles().first(); + + clear(); + oemsh.set_input(csx_file.toStdString()); + parse_and_display(); + + on_a_fit_triggered(); + QGuiApplication::restoreOverrideCursor(); + } +} + +//****************************************************************************** +void MainWindow::on_a_file_save_triggered() { + QGuiApplication::setOverrideCursor(Qt::WaitCursor); + + if(oemsh.get_params().output.empty()) + oemsh.set_output(csx_file.toStdString()); + + // TODO deduce from csx_file suffix + oemsh.set_output_format(app::OpenEMSH::Params::OutputFormat::CSX); + + // TODO warn for overwrite? + + // TODO be sure in this mode, the XML file is edited and stuff like comments won't be discarded + oemsh.write(); + + QGuiApplication::restoreOverrideCursor(); +} + +//****************************************************************************** +void MainWindow::on_a_file_save_as_triggered() { + QFileDialog dialog(this, ui->a_file_save_as->toolTip()); + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilter(format_filter_csx); + dialog.setDefaultSuffix(".csx"); + dialog.setDirectory(csx_file.isEmpty() ? QString(".") : QFileInfo(csx_file).path()); + if(dialog.exec()) { + QGuiApplication::setOverrideCursor(Qt::WaitCursor); + csx_file = dialog.selectedFiles().first(); + update_title(); + + // TODO deduce from filter selected by user + // dialog.selectedNameFilter(); // TODO check actual suffix with that ? + oemsh.set_output_format(app::OpenEMSH::Params::OutputFormat::CSX); + oemsh.set_output(csx_file.toStdString()); + oemsh.write(); + + QGuiApplication::restoreOverrideCursor(); + } +} + +//****************************************************************************** +void MainWindow::on_a_edit_triggered() { + auto* widget = static_cast(ui->toolBar->widgetForAction(ui->a_edit)); + widget->setDown(true); + ui->processing_view->get_current_state().scene->edit_selected_nodes(widget->mapToGlobal(widget->rect().bottomLeft())); + widget->setDown(false); +} + +//****************************************************************************** +void MainWindow::edit_global_params() { + EditModelGlobal model(oemsh.get_board().global_params.get()); + EditDialog edit(&model, "global parameters"); + connect( + &model, &EditModel::edit_from, + this, &MainWindow::handle_edition_from); + edit.exec(); +} + //****************************************************************************** void MainWindow::on_a_mesh_prev_triggered() { - setCursor(Qt::WaitCursor); + QGuiApplication::setOverrideCursor(Qt::WaitCursor); oemsh.go_before_previous_step(); go_to_or_make_current_state(); - unsetCursor(); + QGuiApplication::restoreOverrideCursor(); } // TODO require some processing fit() //****************************************************************************** void MainWindow::on_a_mesh_next_triggered() { - setCursor(Qt::WaitCursor); + QGuiApplication::setOverrideCursor(Qt::WaitCursor); oemsh.run_next_step(); go_to_or_make_current_state(); - unsetCursor(); + QGuiApplication::restoreOverrideCursor(); } //****************************************************************************** void MainWindow::on_a_undo_triggered() { - setCursor(Qt::WaitCursor); + QGuiApplication::setOverrideCursor(Qt::WaitCursor); Caretaker::singleton().undo(); go_to_or_make_current_state(); - unsetCursor(); + QGuiApplication::restoreOverrideCursor(); } //****************************************************************************** void MainWindow::on_a_redo_triggered() { - setCursor(Qt::WaitCursor); + QGuiApplication::setOverrideCursor(Qt::WaitCursor); Caretaker::singleton().redo(); go_to_or_make_current_state(); - unsetCursor(); + QGuiApplication::restoreOverrideCursor(); } //****************************************************************************** @@ -282,7 +385,8 @@ void MainWindow::go_to_or_make_current_state() { void MainWindow::go_to_current_state() { ui->structure_view->go_to_current_state(); ui->processing_view->go_to_current_state(); - update_navigation_visibility(); + update_navigation_buttons_visibility(); + update_show_buttons_pressing(); // TODO handle passing selection from a scene to its own future couterpart } @@ -302,26 +406,123 @@ void MainWindow::make_current_state_view() { ui->processing_view->states[t].scene, &ProcessingScene::select_counterparts); } - update_navigation_visibility(); -} + connect( + ui->processing_view->states[t].scene, &ProcessingScene::edit_global_params, + this, &MainWindow::edit_global_params); -//****************************************************************************** -void MainWindow::handle_edition(std::set const& to_redo) { -// Caretaker::singleton().remember_current_timepoint(); + connect( + ui->processing_view->states[t].scene, &ProcessingScene::edit_from, + this, &MainWindow::handle_edition_from); -// if(ui->a_mesh_auto->is_checked()) // TODO may not be that useful since editing at once two things from different steps will discard newer objects edits?? - oemsh.run(to_redo); - Caretaker::singleton().remember_current_timepoint(); + update_navigation_buttons_visibility(); +} +//****************************************************************************** +void MainWindow::run(app::Step from) { + oemsh.run_from_step(from); make_current_state_view(); } //****************************************************************************** -void MainWindow::update_navigation_visibility() { +void MainWindow::handle_edition_from(app::Step from, std::function const& edit) { + oemsh.go_before(from); + edit(); + run(from); +} + +//****************************************************************************** +void MainWindow::update_navigation_buttons_visibility() { ui->a_undo->setEnabled(Caretaker::singleton().can_undo()); ui->a_redo->setEnabled(Caretaker::singleton().can_redo()); ui->a_mesh_prev->setEnabled(oemsh.can_go_before()); ui->a_mesh_next->setEnabled(oemsh.can_run_a_next_step()); }; +//****************************************************************************** +void MainWindow::update_show_buttons_pressing() { + switch(ui->structure_view->get_mesh_visibility()) { + case MeshVisibility::NONE: ui->tb_show_no_mesh->setChecked(true); break; + case MeshVisibility::VERTICAL: ui->tb_show_vertical_mesh->setChecked(true); break; + case MeshVisibility::HORIZONTAL: ui->tb_show_horizontal_mesh->setChecked(true); break; + case MeshVisibility::FULL: ui->tb_show_all_mesh->setChecked(true); break; + default: unreachable(); + } + + switch(ui->processing_view->get_display_mode()) { + case DisplayMode::EVERYTHING: ui->tb_show_everything->setChecked(true); break; + case DisplayMode::STRUCTURE_VIEW: ui->tb_show_displayed->setChecked(true); break; + case DisplayMode::SELECTED_CHAIN: ui->tb_show_selected->setChecked(true); break; + default: unreachable(); + } +} + +//****************************************************************************** +void MainWindow::keyPressEvent(QKeyEvent* event) { + if(event->key() == Qt::Key_E || event->key() == Qt::Key_Space) { + on_a_edit_triggered(); + } else if(event->key() == Qt::Key_F) { + on_a_fit_triggered(); + } else if(event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_O) { + on_a_file_open_triggered(); + } else if(event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_S) { + if(event->modifiers() & Qt::ShiftModifier) { + on_a_file_save_as_triggered(); + } else { + on_a_file_save_triggered(); + } + } else if(event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Z) { + if(event->modifiers() & Qt::ShiftModifier) { + on_a_redo_triggered(); + } else { + on_a_undo_triggered(); + } + } else if(event->key() == Qt::Key_Greater) { + on_a_mesh_next_triggered(); + } else if(event->key() == Qt::Key_Less) { + on_a_mesh_prev_triggered(); + } else if(event->key() == Qt::Key_1) { + ui->tb_show_selected->click(); + } else if(event->key() == Qt::Key_2) { + ui->tb_show_displayed->click(); + } else if(event->key() == Qt::Key_3) { + ui->tb_show_everything->click(); + } else if(event->key() == Qt::Key_C) { + ui->tb_curved_wires->click(); + } else if(event->key() == Qt::Key_D) { + ui->tb_direct_wires->click(); + } else if(event->key() == Qt::Key_X) { + ui->tb_show_all_mesh->click(); + } else if(event->key() == Qt::Key_V) { + ui->tb_show_vertical_mesh->click(); + } else if(event->key() == Qt::Key_H) { + ui->tb_show_horizontal_mesh->click(); + } else if(event->key() == Qt::Key_Period) { + ui->tb_show_no_mesh->click(); + } else if(event->key() == Qt::Key_PageUp) { + if(auto const* b = ui->bg_plane->checkedButton() + ; b == ui->tb_plane_xy) { + ui->tb_plane_zx->click(); + } else if(b == ui->tb_plane_zx) { + ui->tb_plane_yz->click(); + } else if(b == ui->tb_plane_yz) { + ui->tb_plane_xy->click(); + } + } else if(event->key() == Qt::Key_PageDown) { + if(auto const* b = ui->bg_plane->checkedButton() + ; b == ui->tb_plane_xy) { + ui->tb_plane_yz->click(); + } else if(b == ui->tb_plane_zx) { + ui->tb_plane_xy->click(); + } else if(b == ui->tb_plane_yz) { + ui->tb_plane_zx->click(); + } + } else if(event->key() == Qt::Key_Escape) { + // Will be forwarded to the 3 StructureScenes + if(auto* scene = ui->processing_view->scene(); scene) + scene->clearSelection(); + } else { + QWidget::keyPressEvent(event); + } +} + } // namespace ui::qt diff --git a/src/ui/qt/main_window.hpp b/src/ui/qt/main_window.hpp index da7ba873..adec0955 100644 --- a/src/ui/qt/main_window.hpp +++ b/src/ui/qt/main_window.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include @@ -28,23 +29,27 @@ class MainWindow : public QMainWindow { app::OpenEMSH& oemsh; bool dock_layout_order; + QString csx_file; void set_style(Style const& style); - void update_navigation_visibility(); + void update_title(); + void update_navigation_buttons_visibility(); + void update_show_buttons_pressing(); void go_to_current_state(); void make_current_state_view(); void go_to_or_make_current_state(); + void run(app::Step from = app::Step::DETECT_CONFLICT_EIP); private slots: void on_a_about_triggered(); void on_a_doc_oems_meshing_triggered() const; void on_ag_styles_triggered(QAction* const action); - void on_rb_plane_xy_toggled(bool const is_checked); - void on_rb_plane_yz_toggled(bool const is_checked); - void on_rb_plane_zx_toggled(bool const is_checked); + void on_tb_plane_xy_clicked(); + void on_tb_plane_yz_clicked(); + void on_tb_plane_zx_clicked(); void on_tb_anchor_clicked(bool const is_checked); - void on_a_reset_triggered(); + void on_a_fit_triggered(); void on_a_horizontal_layout_triggered(); void on_a_vertical_layout_triggered(); void on_tb_show_all_mesh_clicked(); @@ -62,17 +67,27 @@ private slots: void on_tb_structure_zoom_out_clicked(); void on_tb_processing_zoom_in_clicked(); void on_tb_processing_zoom_out_clicked(); + void on_a_file_open_triggered(); + void on_a_file_save_triggered(); + void on_a_file_save_as_triggered(); + void on_a_edit_triggered(); void on_a_mesh_prev_triggered(); void on_a_mesh_next_triggered(); void on_a_undo_triggered(); void on_a_redo_triggered(); - void handle_edition(std::set const& to_redo = {}); // TODO handle_edition / on_edition + void edit_global_params(); + void handle_edition_from(app::Step from, std::function const& edit); public: MainWindow(app::OpenEMSH& oemsh, QWidget* parent = nullptr); ~MainWindow() override; + void parse_and_display(); + void clear(); + +protected: + void keyPressEvent(QKeyEvent* event) override; }; } // namespace ui::qt diff --git a/src/ui/qt/main_window.ui b/src/ui/qt/main_window.ui index 80e41ded..29163c5e 100644 --- a/src/ui/qt/main_window.ui +++ b/src/ui/qt/main_window.ui @@ -13,6 +13,9 @@ OpenEMSH + + :/openemsh.ico + Qt::WindowMaximized @@ -46,6 +49,15 @@ true + + true + + + + 0 + 0 + + @@ -59,6 +71,25 @@ true + + true + + + + 0 + 0 + + + + + + + + QFrame::Shape::HLine + + + QFrame::Shadow::Sunken + @@ -69,6 +100,24 @@ Show selected chain only + + true + + + true + + + true + + + + 0 + 0 + + + + bg_show_processing + @@ -79,6 +128,21 @@ Show axes/plane currently displayed only + + true + + + true + + + + 0 + 0 + + + + bg_show_processing + @@ -89,6 +153,31 @@ Show everything + + true + + + true + + + + 0 + 0 + + + + bg_show_processing + + + + + + + QFrame::Shape::HLine + + + QFrame::Shadow::Sunken + @@ -99,6 +188,24 @@ Curved wires + + true + + + true + + + true + + + + 0 + 0 + + + + bg_wires + @@ -109,6 +216,21 @@ Direct wires + + true + + + true + + + + 0 + 0 + + + + bg_wires + @@ -157,6 +279,15 @@ true + + true + + + + 0 + 0 + + @@ -170,6 +301,15 @@ true + + true + + + + 0 + 0 + + @@ -183,6 +323,15 @@ true + + true + + + + 0 + 0 + + @@ -196,6 +345,15 @@ true + + true + + + + 0 + 0 + + @@ -209,6 +367,25 @@ true + + true + + + + 0 + 0 + + + + + + + + QFrame::Shape::HLine + + + QFrame::Shadow::Sunken + @@ -219,6 +396,24 @@ Show mesh + + true + + + true + + + true + + + + 0 + 0 + + + + bg_show_mesh + @@ -229,6 +424,21 @@ Show vertical meshlines only + + true + + + true + + + + 0 + 0 + + + + bg_show_mesh + @@ -239,6 +449,21 @@ Show horizontal meshlines only + + true + + + true + + + + 0 + 0 + + + + bg_show_mesh + @@ -249,49 +474,109 @@ Don't show mesh + + true + + + true + + + + 0 + 0 + + + + bg_show_mesh + - - + + + QFrame::Shape::HLine + + + QFrame::Shadow::Sunken + + + + + YZ View YZ plane - - Qt::NoFocus + + true + + true + + + + 0 + 0 + + + + bg_plane + - + ZX View ZX plane - - Qt::NoFocus + + true + + true + + + + 0 + 0 + + + + bg_plane + - + XY View XY plane - - Qt::NoFocus + + true true + + true + + + + 0 + 0 + + + + bg_plane + @@ -350,10 +635,14 @@ + + + + - + @@ -384,12 +673,59 @@ Horizontal layout - + - Reset view + Fit view + + + + + + + + 🗋 + + + Open CSX file + + + + + + + + 🗎 + + + Save mesh overwriting input CSX file + + + + + + + + 🗎 + + + Save mesh as... + + + + + + + + 🖉 + + + Edit parameters + + + @@ -399,6 +735,9 @@ Run the next meshing step + + + @@ -407,6 +746,9 @@ Go back to previous meshing step + + + @@ -415,6 +757,9 @@ Undo + + + @@ -423,8 +768,17 @@ Redo + + + + + + + + + ui::qt::StructureView @@ -437,6 +791,8 @@
ui/qt/processing_view/processing_view.hpp
- + + + diff --git a/src/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.hpp b/src/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.hpp index fc813eb4..c4d35e07 100644 --- a/src/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.hpp +++ b/src/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.hpp @@ -17,6 +17,7 @@ class ConflictTooCloseMeshlinePolicies; namespace ui::qt { +class EditModel; class ProcessingMeshlinePolicy; //****************************************************************************** @@ -40,6 +41,8 @@ class ProcessingConflictTooCloseMeshlinePolicies : public nodegraph::Node { std::size_t count_tcmlp_mlp_deepness() const; private: + friend EditModel; + domain::ConflictTooCloseMeshlinePolicies const* const conflict; }; diff --git a/src/ui/qt/processing_view/processing_edge.hpp b/src/ui/qt/processing_view/processing_edge.hpp index 3aaec559..116759f4 100644 --- a/src/ui/qt/processing_view/processing_edge.hpp +++ b/src/ui/qt/processing_view/processing_edge.hpp @@ -17,6 +17,8 @@ class Edge; namespace ui::qt { +class EditModel; + //****************************************************************************** class ProcessingEdge : public nodegraph::Node { public: @@ -39,6 +41,8 @@ class ProcessingEdge : public nodegraph::Node { int type() const override; private: + friend EditModel; + domain::Edge const* const edge; }; diff --git a/src/ui/qt/processing_view/processing_interval.cpp b/src/ui/qt/processing_view/processing_interval.cpp index 0fa4de85..8dbafa2e 100644 --- a/src/ui/qt/processing_view/processing_interval.cpp +++ b/src/ui/qt/processing_view/processing_interval.cpp @@ -69,10 +69,10 @@ ProcessingInterval::ProcessingInterval(domain::Interval const* interval, QGraphi }; QString dmax("dmax: "); - QString before_lmin ("before.lmin: "); - QString before_lambda ("before.lambda: "); - QString after_lmin("after.lmin: "); - QString after_lambda("after.lambda: "); + QString before_lmin ("Before.lmin: "); + QString before_lambda ("Before.Smoothness: "); + QString after_lmin("After.lmin: "); + QString after_lambda("After.Smoothness: "); if(interval) { auto const& state = interval->get_current_state(); dmax += QString::number(state.dmax); diff --git a/src/ui/qt/processing_view/processing_interval.hpp b/src/ui/qt/processing_view/processing_interval.hpp index dfe55d92..f2623a80 100644 --- a/src/ui/qt/processing_view/processing_interval.hpp +++ b/src/ui/qt/processing_view/processing_interval.hpp @@ -17,6 +17,8 @@ class Interval; namespace ui::qt { +class EditModel; + //****************************************************************************** class ProcessingInterval : public nodegraph::Node { public: @@ -36,6 +38,8 @@ class ProcessingInterval : public nodegraph::Node { int type() const override; private: + friend EditModel; + domain::Interval const* const interval; }; diff --git a/src/ui/qt/processing_view/processing_meshline_policy.cpp b/src/ui/qt/processing_view/processing_meshline_policy.cpp index d4ca9a47..eb5b1f34 100644 --- a/src/ui/qt/processing_view/processing_meshline_policy.cpp +++ b/src/ui/qt/processing_view/processing_meshline_policy.cpp @@ -79,9 +79,9 @@ ProcessingMeshlinePolicy::ProcessingMeshlinePolicy(domain::MeshlinePolicy const* QString policy("Policy: "); QString d("d: "); if(meshline_policy) { - normal += QString::fromStdString(to_string(meshline_policy->normal)); + normal += QString::fromStdString(to_string(meshline_policy->get_current_state().normal)); is_enabled += (meshline_policy->get_current_state().is_enabled ? "true" : "false"); - policy += QString::fromStdString(to_string(meshline_policy->policy)); + policy += QString::fromStdString(to_string(meshline_policy->get_current_state().policy)); d += QString::number(meshline_policy->get_current_state().d); } diff --git a/src/ui/qt/processing_view/processing_meshline_policy.hpp b/src/ui/qt/processing_view/processing_meshline_policy.hpp index ed62d740..540df3d7 100644 --- a/src/ui/qt/processing_view/processing_meshline_policy.hpp +++ b/src/ui/qt/processing_view/processing_meshline_policy.hpp @@ -17,6 +17,7 @@ class MeshlinePolicy; namespace ui::qt { +class EditModel; class ProcessingConflictTooCloseMeshlinePolicies; //****************************************************************************** @@ -44,6 +45,8 @@ class ProcessingMeshlinePolicy : public nodegraph::Node { std::size_t count_mlp_tcmlp_deepness() const; private: + friend EditModel; + domain::MeshlinePolicy const* const meshline_policy; }; diff --git a/src/ui/qt/processing_view/processing_scene.cpp b/src/ui/qt/processing_view/processing_scene.cpp index 925a3e02..c2c132b7 100644 --- a/src/ui/qt/processing_view/processing_scene.cpp +++ b/src/ui/qt/processing_view/processing_scene.cpp @@ -4,6 +4,9 @@ /// @author Thomas Lepoix ///***************************************************************************** +#include +#include + #include "domain/conflicts/conflict_colinear_edges.hpp" #include "domain/conflicts/conflict_edge_in_polygon.hpp" #include "domain/conflicts/conflict_too_close_meshline_policies.hpp" @@ -14,6 +17,10 @@ #include "domain/mesh/meshline.hpp" #include "domain/mesh/meshline_policy.hpp" #include "ui/qt/data_keys.hpp" +#include "ui/qt/icons.hpp" +#include "ui/qt/edit/edit_dialog.hpp" +#include "ui/qt/edit/edit_model.hpp" +#include "ui/qt/utils/qlist_utils.hpp" #include "utils/unreachable.hpp" #include "processing_axis.hpp" #include "processing_conflict_colinear_edges.hpp" @@ -54,7 +61,7 @@ ProcessingScene::~ProcessingScene() { //****************************************************************************** void ProcessingScene::init() { - set_display(display_mode); + set_display_mode(display_mode); } //****************************************************************************** @@ -335,7 +342,7 @@ void ProcessingScene::set_display_plane(domain::Plane plane) { } //****************************************************************************** -void ProcessingScene::set_display(DisplayMode mode) { +void ProcessingScene::set_display_mode(DisplayMode mode) { display_mode = mode; switch(display_mode) { case DisplayMode::EVERYTHING: @@ -354,6 +361,11 @@ void ProcessingScene::set_display(DisplayMode mode) { } } +//****************************************************************************** +ProcessingScene::DisplayMode ProcessingScene::get_display_mode() const { + return display_mode; +} + //****************************************************************************** void ProcessingScene::display_structure_view() { reset_visibility(); @@ -384,6 +396,7 @@ void ProcessingScene::display_selected_chain() { auto const selected = selected_nodes(); auto const highlighted = highlighted_nodes(); reset_visibility(false); + clearSelection(); for(auto const& list : { selected, highlighted }) for(auto* node : list) @@ -430,4 +443,68 @@ void ProcessingScene::select_counterparts(QList foreign_items) { } } +//****************************************************************************** +void ProcessingScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) { + event->accept(); + edit(dynamic_to_qlist(QGraphicsScene::items(event->scenePos())), event->screenPos()); +} + +//****************************************************************************** +void ProcessingScene::edit_selected_nodes(QPoint const& pos) { + edit(selected_nodes(), pos); +} + +//****************************************************************************** +void ProcessingScene::edit(QList nodes, QPoint const& pos) { + static QList const type_index = { + UserTypes::PROCESSING_EDGE, + UserTypes::PROCESSING_INTERVAL, + UserTypes::PROCESSING_MESHLINE_POLICY, + UserTypes::PROCESSING_CONFLICT_CE, + UserTypes::PROCESSING_CONFLICT_EIP, + UserTypes::PROCESSING_CONFLICT_TCMLP + }; + +// items.removeIf([](auto const it) { return it->type() <= QGraphicsItem::UserType; }); // Wire::Type == UserType + nodes.removeIf([](auto const it) { return !type_index.contains(it->type()); }); + + // TODO isolate in own file + auto const make_title = [](QGraphicsItem const* item) { + QString title(item->data(DataKeys::TYPE).toString() + " - " + item->data(DataKeys::ID).toString()); + if(item->type() == ProcessingPolygon::Type) + title.append(" - " + item->data(DataKeys::NAME).toString()); + return title; + }; + + auto const edit_node = [this](nodegraph::Node* node, QString const& title = QString()) { + if(auto* model = EditModel::make(node); model) { + EditDialog edit(model, title); + model->setParent(&edit); + connect( + model, &EditModel::edit_from, + this, &ProcessingScene::edit_from); + edit.exec(); + } + }; + + if(nodes.isEmpty()) { + clearSelection(); + emit edit_global_params(); + } else if(nodes.size() == 1) { + edit_node(nodes.first(), make_title(nodes.first())); + } else { + QMenu menu; + for(auto* node : nodes) { +// // TODO add entity icon + auto const title = make_title(node); + auto* action = new QAction(Icons::select(node), title, &menu); + menu.addAction(action); + QObject::connect(action, &QAction::triggered, [&edit_node, node, title]() { + edit_node(node, title); + }); + } + menu.exec(pos); + } +} + } // namespace ui::qt diff --git a/src/ui/qt/processing_view/processing_scene.hpp b/src/ui/qt/processing_view/processing_scene.hpp index 759dbb06..0e4ec3ea 100644 --- a/src/ui/qt/processing_view/processing_scene.hpp +++ b/src/ui/qt/processing_view/processing_scene.hpp @@ -11,8 +11,11 @@ #include #include +#include #include +#include +#include "app/steps.hpp" #include "domain/geometrics/space.hpp" #include "ui/qt/utils/nodegraph/wire.hpp" #include "utils/concepts.hpp" @@ -45,6 +48,7 @@ class ProcessingScene : public QGraphicsScene { explicit ProcessingScene(ProcessingStyleSelector& style_selector, QObject* parent = nullptr); ~ProcessingScene() override; + void init(); void set_wire_style(nodegraph::Wire::Style style) const; void fit_containers() const; @@ -70,10 +74,12 @@ class ProcessingScene : public QGraphicsScene { QList selected_nodes() const; QList highlighted_nodes() const; void reset_visibility(bool are_visible = true) const; - void set_display(DisplayMode mode); + DisplayMode get_display_mode() const; + void set_display_mode(DisplayMode mode); void set_display_view_axes(domain::ViewAxisSpace const& axes); void set_display_plane(domain::Plane plane); - void init(); + + void edit_selected_nodes(QPoint const& pos); ProcessingStyleSelector& style_selector; @@ -100,6 +106,9 @@ private slots: signals: void selection_changed(QList items); void requires_fit(); + void edit_global_params(); + void edit_from(app::Step from, std::function const& edit); + public slots: void select_counterparts(QList foreign_items); @@ -120,6 +129,10 @@ public slots: void display_structure_view(); void display_selected_chain(); + void edit(QList nodes, QPoint const& pos); + +protected: + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) override; }; } // namespace ui::qt diff --git a/src/ui/qt/processing_view/processing_view.cpp b/src/ui/qt/processing_view/processing_view.cpp index 15e023bb..26b2a810 100644 --- a/src/ui/qt/processing_view/processing_view.cpp +++ b/src/ui/qt/processing_view/processing_view.cpp @@ -20,6 +20,9 @@ ProcessingView::ProcessingView(QWidget* parent) : QGraphicsView(parent) , board(nullptr) , current_timepoint(nullptr) +, wire_style(nodegraph::Wire::Style::CURVED) +, plane_displayed_on_structure_view(domain::XY) +, axes_displayed_on_structure_view({ true, true }) { setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); @@ -33,6 +36,16 @@ ProcessingView::ProcessingView(QWidget* parent) void ProcessingView::init(domain::Board const* _board) { board = _board; } + +//****************************************************************************** +void ProcessingView::clear() { + for(auto [t, state] : states) + delete state.scene; + states.clear(); + board = nullptr; + current_timepoint = nullptr; +} + //****************************************************************************** void ProcessingView::wheelEvent(QWheelEvent* event) { if(event->modifiers() & Qt::ControlModifier) { @@ -58,6 +71,35 @@ void ProcessingView::fit() { fitInView(get_current_state().scene->sceneRect(), Qt::KeepAspectRatio); } +//****************************************************************************** +ProcessingScene::DisplayMode ProcessingView::get_display_mode() { + return get_current_state().scene->get_display_mode(); +} + +//****************************************************************************** +void ProcessingView::set_display_mode(ProcessingScene::DisplayMode mode) { + get_current_state().scene->set_display_mode(mode); +} + +//****************************************************************************** +void ProcessingView::set_display_view_axes(domain::ViewAxisSpace const& axes) { + axes_displayed_on_structure_view = axes; + get_current_state().scene->set_display_view_axes(axes); +} + +//****************************************************************************** +void ProcessingView::set_display_plane(domain::Plane plane) { + plane_displayed_on_structure_view = plane; + get_current_state().scene->set_display_plane(plane); +} + +//****************************************************************************** +void ProcessingView::set_wire_style(nodegraph::Wire::Style style) { + wire_style = style; + for(auto const& [t, state] : states) + state.scene->set_wire_style(style); +} + //****************************************************************************** ProcessingState& ProcessingView::get_current_state() { return states.at(current_timepoint); @@ -76,6 +118,11 @@ void ProcessingView::make_current_state() { populate(scene); scene->init(); + if(auto const* current_scene = static_cast(this->scene()); current_scene) + scene->set_display_mode(current_scene->get_display_mode()); + scene->set_display_view_axes(axes_displayed_on_structure_view); + scene->set_display_plane(plane_displayed_on_structure_view); + scene->set_wire_style(wire_style); states.emplace(Caretaker::singleton().get_current_timepoint(), scene); go_to_current_state(); diff --git a/src/ui/qt/processing_view/processing_view.hpp b/src/ui/qt/processing_view/processing_view.hpp index a35bf834..7466a6df 100644 --- a/src/ui/qt/processing_view/processing_view.hpp +++ b/src/ui/qt/processing_view/processing_view.hpp @@ -28,6 +28,7 @@ class ProcessingView : public QGraphicsView { public: explicit ProcessingView(QWidget* parent = nullptr); void init(domain::Board const* _board); + void clear(); ProcessingStyleSelector style_selector; std::map states; @@ -36,6 +37,12 @@ class ProcessingView : public QGraphicsView { void make_current_state(); void go_to_current_state(); + ProcessingScene::DisplayMode get_display_mode(); + void set_display_mode(ProcessingScene::DisplayMode mode); + void set_display_view_axes(domain::ViewAxisSpace const& axes); + void set_display_plane(domain::Plane plane); + void set_wire_style(nodegraph::Wire::Style style); + public slots: void fit(); @@ -46,6 +53,10 @@ public slots: domain::Board const* board; Timepoint* current_timepoint; + nodegraph::Wire::Style wire_style; + domain::Plane plane_displayed_on_structure_view; + domain::ViewAxisSpace axes_displayed_on_structure_view; + void populate(ProcessingScene* scene); }; diff --git a/src/ui/qt/structure_view/structure_interval.hpp b/src/ui/qt/structure_view/structure_interval.hpp index 3715662d..099a9d50 100644 --- a/src/ui/qt/structure_view/structure_interval.hpp +++ b/src/ui/qt/structure_view/structure_interval.hpp @@ -38,12 +38,12 @@ class StructureInterval : public QGraphicsRectItem { int type() const override; + domain::ViewAxis const axis; + protected: void paint(QPainter* painter, QStyleOptionGraphicsItem const* option, QWidget* widget = nullptr) override; QVariant itemChange(GraphicsItemChange change, QVariant const& value) override; - domain::ViewAxis const axis; - private: domain::Interval const* const interval; }; diff --git a/src/ui/qt/structure_view/structure_meshline_policy.cpp b/src/ui/qt/structure_view/structure_meshline_policy.cpp index 19bf687f..72875f16 100644 --- a/src/ui/qt/structure_view/structure_meshline_policy.cpp +++ b/src/ui/qt/structure_view/structure_meshline_policy.cpp @@ -43,11 +43,11 @@ static std::array convert_policy_lines(domain::ViewAxis axis, domain: auto const offset = [&]() -> std::array { auto const d = meshline_policy->get_current_state().d; - switch(meshline_policy->policy) { + switch(meshline_policy->get_current_state().policy) { case domain::MeshlinePolicy::Policy::ONELINE: return { 0.0, 0.0 }; case domain::MeshlinePolicy::Policy::HALFS: return { d / 2.0, -d / 2.0 }; case domain::MeshlinePolicy::Policy::THIRDS: - switch(meshline_policy->normal) { + switch(meshline_policy->get_current_state().normal) { case domain::MeshlinePolicy::Normal::MAX: return { 2.0 / 3.0 * d, -1.0 / 3.0 * d }; case domain::MeshlinePolicy::Normal::MIN: diff --git a/src/ui/qt/structure_view/structure_scene.cpp b/src/ui/qt/structure_view/structure_scene.cpp index 9934e563..d3522541 100644 --- a/src/ui/qt/structure_view/structure_scene.cpp +++ b/src/ui/qt/structure_view/structure_scene.cpp @@ -22,6 +22,7 @@ #include "domain/mesh/meshline_policy.hpp" #include "utils/unreachable.hpp" #include "ui/qt/data_keys.hpp" +#include "ui/qt/icons.hpp" #include "ui/qt/user_types.hpp" #include "structure_conflict_colinear_edges.hpp" #include "structure_conflict_too_close_meshline_policies.hpp" @@ -63,6 +64,7 @@ StructureScene::StructureScene(StructureStyleSelector& style_selector, QObject* , intervals{{ new StructureGroup(), new StructureGroup() }} , meshlines{{ new StructureGroup(), new StructureGroup() }} , meshline_policies{{ new StructureGroup(), new StructureGroup() }} +, mesh_visibility_on_view(MeshVisibility::FULL) { // Adding order matters. addItem(edges); @@ -258,6 +260,7 @@ void StructureScene::clear_all() { //****************************************************************************** void StructureScene::set_mesh_visibility(MeshVisibility mesh_visibility) { + mesh_visibility_on_view = mesh_visibility; switch(mesh_visibility) { case MeshVisibility::NONE: meshlines[domain::H]->setVisible(false); @@ -280,6 +283,11 @@ void StructureScene::set_mesh_visibility(MeshVisibility mesh_visibility) { } } +//****************************************************************************** +StructureScene::MeshVisibility StructureScene::get_mesh_visibility() const { + return mesh_visibility_on_view; +} + // TODO use simple click + double click to select / deselect //****************************************************************************** void StructureScene::mousePressEvent(QGraphicsSceneMouseEvent* event) { @@ -317,7 +325,7 @@ void StructureScene::mousePressEvent(QGraphicsSceneMouseEvent* event) { if(item->type() == StructurePolygon::Type) title.append(" - " + item->data(DataKeys::NAME).toString()); - auto* action = new QAction(title, &menu); + auto* action = new QAction(Icons::select(item), title, &menu); menu.addAction(action); QObject::connect(action, &QAction::triggered, [item]() { item->setSelected(true); diff --git a/src/ui/qt/structure_view/structure_scene.hpp b/src/ui/qt/structure_view/structure_scene.hpp index 2d0f04e5..17733b56 100644 --- a/src/ui/qt/structure_view/structure_scene.hpp +++ b/src/ui/qt/structure_view/structure_scene.hpp @@ -73,6 +73,7 @@ class StructureScene : public QGraphicsScene { void clear_all(); void set_mesh_visibility(MeshVisibility mesh_visibility); + MeshVisibility get_mesh_visibility() const; StructureStyleSelector& style_selector; //private: //TODO @@ -96,6 +97,7 @@ public slots: void select_counterparts(QList foreign_items); private: bool is_select_counterparts_locked = false; + MeshVisibility mesh_visibility_on_view; protected: void mousePressEvent(QGraphicsSceneMouseEvent* event) override; diff --git a/src/ui/qt/structure_view/structure_view.cpp b/src/ui/qt/structure_view/structure_view.cpp index f91da8bf..24685a88 100644 --- a/src/ui/qt/structure_view/structure_view.cpp +++ b/src/ui/qt/structure_view/structure_view.cpp @@ -43,11 +43,11 @@ static QPainterPath create_repair() { //****************************************************************************** StructureView::StructureView(QWidget* parent) : QGraphicsView(parent) +, board(nullptr) +, current_timepoint(nullptr) , repair(std::make_unique(create_repair())) , rotation(0) , displayed_plane(domain::XY) -, board(nullptr) -, current_timepoint(nullptr) { setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); @@ -64,6 +64,16 @@ void StructureView::init(domain::Board const* _board) { board = _board; } +//****************************************************************************** +void StructureView::clear() { + for(auto [t, state] : states) + for(auto* ptr : state.scenes) + delete ptr; + states.clear(); + board = nullptr; + current_timepoint = nullptr; +} + //****************************************************************************** void StructureView::drawForeground(QPainter* painter, QRectF const& rect) { QGraphicsView::drawForeground(painter, rect); @@ -137,6 +147,11 @@ void StructureView::fit() { fitInView(static_cast(scene())->polygons->boundingRect() + QMarginsF(5, 5, 5, 5), Qt::KeepAspectRatio); } +//****************************************************************************** +StructureScene::MeshVisibility StructureView::get_mesh_visibility() { + return get_current_state().scenes.front()->get_mesh_visibility(); +} + //****************************************************************************** void StructureView::set_mesh_visibility(StructureScene::MeshVisibility mesh_visibility) { for(auto const plane : domain::AllPlane) @@ -182,6 +197,9 @@ void StructureView::make_current_state() { std::make_unique(style_selector, this).release() }}; populate(scenes); + if(auto const* current_scene = static_cast(scene()); current_scene) + for(auto* scene : scenes) + scene->set_mesh_visibility(current_scene->get_mesh_visibility()); states.try_emplace(Caretaker::singleton().get_current_timepoint(), scenes); diff --git a/src/ui/qt/structure_view/structure_view.hpp b/src/ui/qt/structure_view/structure_view.hpp index debaed96..82fb8047 100644 --- a/src/ui/qt/structure_view/structure_view.hpp +++ b/src/ui/qt/structure_view/structure_view.hpp @@ -37,12 +37,14 @@ class StructureView : public QGraphicsView { explicit StructureView(QWidget* parent = nullptr); ~StructureView() override; void init(domain::Board const* _board); + void clear(); void fit(); void rotate_view(qreal angle); void reset_rotation(); qreal get_rotation() const; + StructureScene::MeshVisibility get_mesh_visibility(); void set_mesh_visibility(StructureScene::MeshVisibility mesh_visibility); void set_display_plane(domain::Plane plane); @@ -65,13 +67,14 @@ class StructureView : public QGraphicsView { // + public set_scene() that wrap axis QStrings or repair // qreal scale_max; + domain::Board const* board; + Timepoint* current_timepoint; + std::unique_ptr const repair; using QGraphicsView::rotate; qreal rotation; domain::Plane displayed_plane; - domain::Board const* board; - Timepoint* current_timepoint; void populate(domain::PlaneSpace scenes); }; diff --git a/src/ui/qt/utils/qlist_utils.hpp b/src/ui/qt/utils/qlist_utils.hpp new file mode 100644 index 00000000..536d6cd7 --- /dev/null +++ b/src/ui/qt/utils/qlist_utils.hpp @@ -0,0 +1,40 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include + +#include + +namespace ui::qt { + +// Downcast +//****************************************************************************** +template +requires std::is_base_of_v< + std::remove_reference_t>, + std::remove_reference_t>> +QList dynamic_to_qlist(QList const& list_i) { + QList list_o; + for(I i : list_i) + if(O o = dynamic_cast(i); o) + list_o.emplace_back(o); + return list_o; +} + +// Upcast +//****************************************************************************** +template +//requires std::is_base_of_v< +// std::remove_reference_t>, +// std::remove_reference_t>> +QList to_qlist(QList const& list_i) { + QList list_o; + for(I i : list_i) + list_o.emplace_back(static_cast(i)); + return list_o; +} + +} // namespace ui::qt diff --git a/test/unit/app/test_openemsh.cpp b/test/unit/app/test_openemsh.cpp index 16dbef74..49a0bca6 100644 --- a/test/unit/app/test_openemsh.cpp +++ b/test/unit/app/test_openemsh.cpp @@ -9,6 +9,7 @@ #include "app/openemsh.hpp" /// @test optional next(Step step) +/// @test set that_and_after(Step step) ///***************************************************************************** using namespace app; @@ -78,3 +79,106 @@ SCENARIO("optional next(Step step)", "[app][openemsh]") { } } } + +//****************************************************************************** +SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { + WHEN("Running for DETECT_CONFLICT_EIP") { + THEN("Should return all Steps except those coming before DETECT_CONFLICT_EIP") { + REQUIRE(that_and_after(Step::DETECT_CONFLICT_EIP) == std::set { + Step::DETECT_CONFLICT_EIP, + Step::DETECT_CONFLICT_CE, + Step::DETECT_NON_CONFLICTING_EDGES, + Step::ADD_FIXED_MLP, + Step::SOLVE_ALL_EIP, + Step::SOLVE_ALL_CE, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for DETECT_CONFLICT_CE") { + THEN("Should return all Steps except those coming before DETECT_CONFLICT_CE") { + REQUIRE(that_and_after(Step::DETECT_CONFLICT_CE) == std::set { + Step::DETECT_CONFLICT_CE, + Step::DETECT_NON_CONFLICTING_EDGES, + Step::ADD_FIXED_MLP, + Step::SOLVE_ALL_EIP, + Step::SOLVE_ALL_CE, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for DETECT_NON_CONFLICTING_EDGES") { + THEN("Should return all Steps except those coming before DETECT_NON_CONFLICTING_EDGES") { + REQUIRE(that_and_after(Step::DETECT_NON_CONFLICTING_EDGES) == std::set { + Step::DETECT_NON_CONFLICTING_EDGES, + Step::ADD_FIXED_MLP, + Step::SOLVE_ALL_EIP, + Step::SOLVE_ALL_CE, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for ADD_FIXED_MLP") { + THEN("Should return all Steps except those coming before ADD_FIXED_MLP") { + REQUIRE(that_and_after(Step::ADD_FIXED_MLP) == std::set { + Step::ADD_FIXED_MLP, + Step::SOLVE_ALL_EIP, + Step::SOLVE_ALL_CE, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for SOLVE_ALL_EIP") { + THEN("Should return all Steps except those coming before SOLVE_ALL_EIP") { + REQUIRE(that_and_after(Step::SOLVE_ALL_EIP) == std::set { + Step::SOLVE_ALL_EIP, + Step::SOLVE_ALL_CE, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for SOLVE_ALL_CE") { + THEN("Should return all Steps except those coming before SOLVE_ALL_CE") { + REQUIRE(that_and_after(Step::SOLVE_ALL_CE) == std::set { + Step::SOLVE_ALL_CE, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for DETECT_AND_SOLVE_TCMLP") { + THEN("Should return all Steps except those coming before DETECT_AND_SOLVE_TCMLP") { + REQUIRE(that_and_after(Step::DETECT_AND_SOLVE_TCMLP) == std::set { + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for DETECT_INTERVALS") { + THEN("Should return all Steps except those coming before DETECT_INTERVALS") { + REQUIRE(that_and_after(Step::DETECT_INTERVALS) == std::set { + Step::DETECT_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for MESH") { + THEN("Should return all Steps except those coming before MESH") { + REQUIRE(that_and_after(Step::MESH) == std::set { + Step::MESH + }); + } + } +} diff --git a/test/unit/domain/conflicts/test_conflict_colinear_edges.cpp b/test/unit/domain/conflicts/test_conflict_colinear_edges.cpp index 45851e72..ed29d9e7 100644 --- a/test/unit/domain/conflicts/test_conflict_colinear_edges.cpp +++ b/test/unit/domain/conflicts/test_conflict_colinear_edges.cpp @@ -55,8 +55,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[X][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[X][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[X][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[X][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().is_enabled); } @@ -82,8 +82,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[X][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[X][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[X][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[X][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().is_enabled); } @@ -109,8 +109,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[X][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[X][0]->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(mpm.get_current_state().line_policies[X][0]->normal == MeshlinePolicy::Normal::MIN); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().normal == MeshlinePolicy::Normal::MIN); REQUIRE(mpm.get_current_state().line_policies[X][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().is_enabled); } @@ -136,8 +136,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[X][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[X][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[X][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[X][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().is_enabled); } @@ -163,8 +163,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[X][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[X][0]->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(mpm.get_current_state().line_policies[X][0]->normal == MeshlinePolicy::Normal::MAX); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().normal == MeshlinePolicy::Normal::MAX); REQUIRE(mpm.get_current_state().line_policies[X][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().is_enabled); } @@ -206,8 +206,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); } @@ -233,8 +233,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); } @@ -260,8 +260,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::MIN); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::MIN); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); } @@ -287,8 +287,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); } @@ -314,8 +314,8 @@ SCENARIO("void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_pol REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == cce.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &cce); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::MAX); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::MAX); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); } diff --git a/test/unit/domain/conflicts/test_conflict_too_close_meshline_policies.cpp b/test/unit/domain/conflicts/test_conflict_too_close_meshline_policies.cpp index eb054110..9986e3b0 100644 --- a/test/unit/domain/conflicts/test_conflict_too_close_meshline_policies.cpp +++ b/test/unit/domain/conflicts/test_conflict_too_close_meshline_policies.cpp @@ -45,8 +45,8 @@ SCENARIO("void ConflictTooCloseMeshlinePolicies::auto_solve(MeshlinePolicyManage REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == x.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &x); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); REQUIRE(x.get_current_state().is_solved); @@ -79,15 +79,15 @@ SCENARIO("void ConflictTooCloseMeshlinePolicies::auto_solve(MeshlinePolicyManage REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == x.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &x); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); REQUIRE(mpm.get_current_state().line_policies[Y][1].get() == y.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().origins[0] == &y); - REQUIRE(mpm.get_current_state().line_policies[Y][1]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[Y][1]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[Y][1]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().is_enabled); REQUIRE(x.get_current_state().is_solved); @@ -136,15 +136,15 @@ SCENARIO("void ConflictTooCloseMeshlinePolicies::auto_solve(MeshlinePolicyManage REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == x.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &x); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); REQUIRE(mpm.get_current_state().line_policies[X][0].get() == y.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins[0] == &y); - REQUIRE(mpm.get_current_state().line_policies[X][0]->policy == MeshlinePolicy::Policy::HALFS); - REQUIRE(mpm.get_current_state().line_policies[X][0]->normal == MeshlinePolicy::Normal::NONE); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().policy == MeshlinePolicy::Policy::HALFS); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().normal == MeshlinePolicy::Normal::NONE); REQUIRE(mpm.get_current_state().line_policies[X][0]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().is_enabled); REQUIRE(x.get_current_state().is_solved); @@ -225,29 +225,29 @@ SCENARIO("void ConflictTooCloseMeshlinePolicies::auto_solve(MeshlinePolicyManage REQUIRE(mpm.get_current_state().line_policies[Y][0].get() == w.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().origins[0] == &w); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(mpm.get_current_state().line_policies[Y][0]->normal == MeshlinePolicy::Normal::MIN); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().normal == MeshlinePolicy::Normal::MIN); REQUIRE(mpm.get_current_state().line_policies[Y][0]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[Y][0]->get_current_state().is_enabled); REQUIRE(mpm.get_current_state().line_policies[Y][1].get() == x.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().origins[0] == &x); - REQUIRE(mpm.get_current_state().line_policies[Y][1]->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(mpm.get_current_state().line_policies[Y][1]->normal == MeshlinePolicy::Normal::MAX); + REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().normal == MeshlinePolicy::Normal::MAX); REQUIRE(mpm.get_current_state().line_policies[Y][1]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[Y][1]->get_current_state().is_enabled); REQUIRE(mpm.get_current_state().line_policies[X][0].get() == y.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().origins[0] == &y); - REQUIRE(mpm.get_current_state().line_policies[X][0]->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(mpm.get_current_state().line_policies[X][0]->normal == MeshlinePolicy::Normal::MIN); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().normal == MeshlinePolicy::Normal::MIN); REQUIRE(mpm.get_current_state().line_policies[X][0]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[X][0]->get_current_state().is_enabled); REQUIRE(mpm.get_current_state().line_policies[X][1].get() == z.get_current_state().solution); REQUIRE(mpm.get_current_state().line_policies[X][1]->get_current_state().origins.size() == 1); REQUIRE(mpm.get_current_state().line_policies[X][1]->get_current_state().origins[0] == &z); - REQUIRE(mpm.get_current_state().line_policies[X][1]->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(mpm.get_current_state().line_policies[X][1]->normal == MeshlinePolicy::Normal::MAX); + REQUIRE(mpm.get_current_state().line_policies[X][1]->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(mpm.get_current_state().line_policies[X][1]->get_current_state().normal == MeshlinePolicy::Normal::MAX); REQUIRE(mpm.get_current_state().line_policies[X][1]->coord == 10.5); REQUIRE(mpm.get_current_state().line_policies[X][1]->get_current_state().is_enabled); REQUIRE(w.get_current_state().is_solved); diff --git a/test/unit/domain/mesh/test_interval.cpp b/test/unit/domain/mesh/test_interval.cpp index 103ece44..2c37de98 100644 --- a/test/unit/domain/mesh/test_interval.cpp +++ b/test/unit/domain/mesh/test_interval.cpp @@ -18,7 +18,7 @@ /// @test Coord Interval::s(Interval::Side const& side) const @todo /// @test Coord Interval::s(Interval::Side const& side, double d) const @todo /// @test std::vector find_ls(double d, double lambda, double dmax, Coord s) -/// @test bool is_ls_valid_for_dmax_lmin_lambda(std::vector ls, double d, double lambda, double dmax, size_t lmin) +/// @test bool is_ls_valid_for_dmax_lmin_lambda(std::vector const& ls, double d, double lambda, double dmax, size_t lmin) /// @test void Interval::update_ls() @todo /// @test void Interval::update_ls(Interval::Side& side) @todo /// @test double find_dmax(Interval::Side const& side, double dmax) @@ -246,7 +246,7 @@ SCENARIO("std::vector find_ls(double d, double lambda, double dmax, Coord } //****************************************************************************** -SCENARIO("bool is_ls_valid_for_dmax_lmin_lambda(std::vector ls, double d, double lambda, double dmax, size_t lmin)", "[interval]") { +SCENARIO("bool is_ls_valid_for_dmax_lmin_lambda(std::vector const& ls, double d, double lambda, double dmax, size_t lmin)", "[interval]") { GIVEN("An empty ls vector") { THEN("Should not be valid, disregarding lmin") { REQUIRE_FALSE(is_ls_valid_for_dmax_lmin_lambda({}, 1.0, 2.0, 3.0, 2)); diff --git a/test/unit/domain/test_meshline_policy_manager.cpp b/test/unit/domain/test_meshline_policy_manager.cpp index 97748a27..b9b236b3 100644 --- a/test/unit/domain/test_meshline_policy_manager.cpp +++ b/test/unit/domain/test_meshline_policy_manager.cpp @@ -92,8 +92,8 @@ bool const is_enabled)", "[meshline_policy_manager]") { REQUIRE(m->get_current_state().origins.size() == 1); REQUIRE(m->get_current_state().origins[0] == &e); REQUIRE(m->axis == X); - REQUIRE(m->policy == MeshlinePolicy::Policy::THIRDS); - REQUIRE(m->normal == MeshlinePolicy::Normal::MAX); + REQUIRE(m->get_current_state().policy == MeshlinePolicy::Policy::THIRDS); + REQUIRE(m->get_current_state().normal == MeshlinePolicy::Normal::MAX); REQUIRE(m->coord == 1); REQUIRE(m->get_current_state().is_enabled); }