diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 398c5838..96c31b47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,10 +21,12 @@ target_sources( openemsh "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/point.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/segment.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/edge.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/angle.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/range.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/polygon.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/conflicts/conflict.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/conflicts/conflict_colinear_edges.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/domain/conflicts/conflict_diagonal_or_circular_zone.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/conflicts/conflict_edge_in_polygon.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/conflicts/conflict_too_close_meshline_policies.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/mesh/interval.cpp" @@ -94,6 +96,8 @@ target_sources( openemsh_bin "${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_angle.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/edit/edit_model_conflict_diagonal_or_circular_zone.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" @@ -103,7 +107,9 @@ target_sources( openemsh_bin "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_style.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_polygon.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_edge.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_angle.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_conflict_colinear_edges.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_conflict_diagonal_or_circular_zone.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_conflict_edge_in_polygon.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_meshline_policy.cpp" @@ -112,7 +118,9 @@ target_sources( openemsh_bin "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_scene.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/processing_view/processing_view.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_edge.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_angle.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_conflict_colinear_edges.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_conflict_diagonal_or_circular_zone.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_conflict_too_close_meshline_policies.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_meshline_policy.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ui/qt/structure_view/structure_meshline.cpp" diff --git a/src/app/openemsh.cpp b/src/app/openemsh.cpp index e58c0f52..eedcea8a 100644 --- a/src/app/openemsh.cpp +++ b/src/app/openemsh.cpp @@ -23,6 +23,12 @@ using namespace std; optional next(Step step) { switch(step) { case Step::ADJUST_EDGE_TO_MATERIAL: + return Step::DETECT_DIAG_ANGLES; + case Step::DETECT_DIAG_ANGLES: + return Step::DETECT_DIAG_ZONES; + case Step::DETECT_DIAG_ZONES: + return Step::SOLVE_DIAG_ZONES_ANGLES; + case Step::SOLVE_DIAG_ZONES_ANGLES: return Step::DETECT_CONFLICT_EIP; case Step::DETECT_CONFLICT_EIP: return Step::DETECT_CONFLICT_CE; @@ -39,6 +45,10 @@ optional next(Step step) { case Step::DETECT_AND_SOLVE_TCMLP: return Step::DETECT_INTERVALS; case Step::DETECT_INTERVALS: + return Step::DETECT_INTERVALS_PER_DIAG_ZONES; + case Step::DETECT_INTERVALS_PER_DIAG_ZONES: + return Step::SOLVE_DIAG_ZONES_INTERVALS; + case Step::SOLVE_DIAG_ZONES_INTERVALS: return Step::MESH; case Step::MESH: return nullopt; @@ -53,16 +63,21 @@ set that_and_after(Step step) { using enum Step; switch(step) { - case ADJUST_EDGE_TO_MATERIAL: out.emplace(ADJUST_EDGE_TO_MATERIAL); [[fallthrough]]; - case DETECT_CONFLICT_EIP: out.emplace(DETECT_CONFLICT_EIP); [[fallthrough]]; - case DETECT_CONFLICT_CE: out.emplace(DETECT_CONFLICT_CE); [[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_INDIVIDUAL_EDGES: out.emplace(DETECT_INDIVIDUAL_EDGES); [[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; + case ADJUST_EDGE_TO_MATERIAL: out.emplace(ADJUST_EDGE_TO_MATERIAL); [[fallthrough]]; + case DETECT_DIAG_ANGLES: out.emplace(DETECT_DIAG_ANGLES); [[fallthrough]]; + case DETECT_DIAG_ZONES: out.emplace(DETECT_DIAG_ZONES); [[fallthrough]]; + case SOLVE_DIAG_ZONES_ANGLES: out.emplace(SOLVE_DIAG_ZONES_ANGLES); [[fallthrough]]; + case DETECT_CONFLICT_EIP: out.emplace(DETECT_CONFLICT_EIP); [[fallthrough]]; + case DETECT_CONFLICT_CE: out.emplace(DETECT_CONFLICT_CE); [[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_INDIVIDUAL_EDGES: out.emplace(DETECT_INDIVIDUAL_EDGES); [[fallthrough]]; + case DETECT_AND_SOLVE_TCMLP: out.emplace(DETECT_AND_SOLVE_TCMLP); [[fallthrough]]; + case DETECT_INTERVALS: out.emplace(DETECT_INTERVALS); [[fallthrough]]; + case DETECT_INTERVALS_PER_DIAG_ZONES: out.emplace(DETECT_INTERVALS_PER_DIAG_ZONES); [[fallthrough]]; + case SOLVE_DIAG_ZONES_INTERVALS: out.emplace(SOLVE_DIAG_ZONES_INTERVALS); [[fallthrough]]; + case MESH: out.emplace(MESH); break; default: ::unreachable(); } @@ -151,16 +166,21 @@ void OpenEMSH::run(std::set const& steps) const { }; using enum Step; - handle(ADJUST_EDGE_TO_MATERIAL, [&] { board->adjust_edges_to_materials(); }); - handle(DETECT_CONFLICT_EIP, [&] { board->detect_edges_in_polygons(); }); - handle(DETECT_CONFLICT_CE, [&] { board->detect_colinear_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_INDIVIDUAL_EDGES, [&] { board->detect_individual_edges(); }); - handle(DETECT_AND_SOLVE_TCMLP, [&] { board->detect_and_solve_too_close_meshline_policies(); }); - handle(DETECT_INTERVALS, [&] { board->detect_intervals(); }); - handle(MESH, [&] { board->mesh(); }); + handle(ADJUST_EDGE_TO_MATERIAL, [&] { board->adjust_edges_to_materials(); }); + handle(DETECT_DIAG_ANGLES, [&] { board->detect_diagonal_angles(); }); + handle(DETECT_DIAG_ZONES, [&] { board->detect_diagonal_zones(); }); + handle(SOLVE_DIAG_ZONES_ANGLES, [&] { board->solve_diagonal_zones_angles(); }); + handle(DETECT_CONFLICT_EIP, [&] { board->detect_edges_in_polygons(); }); + handle(DETECT_CONFLICT_CE, [&] { board->detect_colinear_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_INDIVIDUAL_EDGES, [&] { board->detect_individual_edges(); }); + handle(DETECT_AND_SOLVE_TCMLP, [&] { board->detect_and_solve_too_close_meshline_policies(); }); + handle(DETECT_INTERVALS, [&] { board->detect_intervals(); }); + handle(DETECT_INTERVALS_PER_DIAG_ZONES, [&] { board->detect_intervals_per_diagonal_zones(); }); + handle(SOLVE_DIAG_ZONES_INTERVALS, [&] { board->solve_diagonal_zones_intervals(); }); + handle(MESH, [&] { board->mesh(); }); Caretaker::singleton().remember_current_timepoint(); } @@ -169,6 +189,9 @@ void OpenEMSH::run(std::set const& steps) const { void OpenEMSH::run_all_steps() const { run({ Step::ADJUST_EDGE_TO_MATERIAL, + Step::DETECT_DIAG_ANGLES, + Step::DETECT_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_ANGLES, Step::DETECT_CONFLICT_EIP, Step::DETECT_CONFLICT_CE, Step::ADD_FIXED_MLP, @@ -177,6 +200,8 @@ void OpenEMSH::run_all_steps() const { Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } diff --git a/src/app/steps.hpp b/src/app/steps.hpp index e9d25361..a55f31e6 100644 --- a/src/app/steps.hpp +++ b/src/app/steps.hpp @@ -15,6 +15,9 @@ namespace app { //****************************************************************************** enum class Step { ADJUST_EDGE_TO_MATERIAL, + DETECT_DIAG_ANGLES, + DETECT_DIAG_ZONES, + SOLVE_DIAG_ZONES_ANGLES, DETECT_CONFLICT_EIP, DETECT_CONFLICT_CE, ADD_FIXED_MLP, @@ -23,6 +26,8 @@ enum class Step { DETECT_INDIVIDUAL_EDGES, DETECT_AND_SOLVE_TCMLP, DETECT_INTERVALS, + DETECT_INTERVALS_PER_DIAG_ZONES, + SOLVE_DIAG_ZONES_INTERVALS, MESH }; @@ -33,15 +38,20 @@ inline std::size_t index(std::optional step) { switch(step.value()) { case Step::ADJUST_EDGE_TO_MATERIAL: return 1; - case Step::DETECT_CONFLICT_EIP: return 2; - case Step::DETECT_CONFLICT_CE: return 3; - case Step::ADD_FIXED_MLP: return 4; - case Step::SOLVE_ALL_EIP: return 5; - case Step::SOLVE_ALL_CE: return 6; - case Step::DETECT_INDIVIDUAL_EDGES: return 7; - case Step::DETECT_AND_SOLVE_TCMLP: return 8; - case Step::DETECT_INTERVALS: return 9; - case Step::MESH: return 10; + case Step::DETECT_DIAG_ANGLES: return 2; + case Step::DETECT_DIAG_ZONES: return 3; + case Step::SOLVE_DIAG_ZONES_ANGLES: return 4; + case Step::DETECT_CONFLICT_EIP: return 5; + case Step::DETECT_CONFLICT_CE: return 6; + case Step::ADD_FIXED_MLP: return 7; + case Step::SOLVE_ALL_EIP: return 8; + case Step::SOLVE_ALL_CE: return 9; + case Step::DETECT_INDIVIDUAL_EDGES: return 10; + case Step::DETECT_AND_SOLVE_TCMLP: return 11; + case Step::DETECT_INTERVALS: return 12; + case Step::DETECT_INTERVALS_PER_DIAG_ZONES: return 13; + case Step::SOLVE_DIAG_ZONES_INTERVALS: return 14; + case Step::MESH: return 15; default: ::unreachable(); } } diff --git a/src/domain/board.cpp b/src/domain/board.cpp index d0df575f..8555e5b5 100644 --- a/src/domain/board.cpp +++ b/src/domain/board.cpp @@ -5,8 +5,10 @@ ///***************************************************************************** #include +#include #include +#include "geometrics/bounding.hpp" #include "infra/utils/to_string.hpp" #include "utils/progress.hpp" #include "utils/signum.hpp" @@ -239,6 +241,66 @@ void Board::adjust_edges_to_materials(Plane const plane) { bar.complete(); } +//****************************************************************************** +void Board::detect_diagonal_angles(Plane plane) { + auto [t, state] = make_next_state(); + + auto [bar, found, k] = Progress::Bar::build( + /*state.edges[plane].size() // As many Edges as Polygon::Point + +*/ ((state.edges[plane].size() * state.edges[plane].size()) - state.edges[plane].size()) / 2, // AB/BA deduplicated, AA dismissed. + "["s + to_string(plane) + "] Detecting diagonal Angles "); + +// TODO calculate Normals (easy in first case, uneasy in second case) + + // Angles of polygons, involving a diagonal edge. + for(auto const& polygon : state.polygons[plane]) { + size_t p = polygon->edges.size() - 1; + for(size_t i = 0; i < polygon->edges.size(); ++i, ++k) { + if(polygon->edges[p]->axis == Segment::Axis::DIAGONAL + || polygon->edges[i]->axis == Segment::Axis::DIAGONAL) { + ++found; + state.angles[plane].emplace_back(make_shared(*(polygon->points[p]), polygon->edges[p].get(), polygon->edges[i].get(), t)); + } + p = i; + } + bar.tick(found, k); + } + + // TODO also inside polygon, except itself, previous and next + + // Crosses between any diagonal edge and any other edge. + for(size_t i = 0; i < state.polygons[plane].size(); ++i) { + for(size_t l = 0; l < state.polygons[plane][i]->edges.size(); ++l) { + auto& edge_a = state.polygons[plane][i]->edges[l]; + + for(size_t j = i + 1; j < state.polygons[plane].size(); ++j) { + for(size_t m = 0; m < state.polygons[plane][j]->edges.size(); ++m, ++k) { + auto& edge_b = state.polygons[plane][j]->edges[m]; + + if(edge_a->axis != Segment::Axis::DIAGONAL + && edge_b->axis != Segment::Axis::DIAGONAL) + continue; + + if(!does_overlap_strict(bounding(*edge_a), bounding(*edge_b))) + continue; + + relation::SegmentSegment rel = edge_a->relation_to(*edge_b); + if(rel == relation::SegmentSegment::CROSSING) { + if(optional p = intersection(*edge_a, *edge_b)) { + ++found; + state.angles[plane].emplace_back(make_shared(p.value(), edge_a.get(), edge_b.get(), t)); + } + } + } + } + bar.tick(found, k); + } + } + + set_state(t, state); + bar.complete(); +} + /// Detect all EDGE_IN_POLYGON. Will also detect some COLINEAR_EDGES. /// Overlapping edges should be EDGE_IN_POLYGON and not COLINEAR_EDGES. ///***************************************************************************** @@ -388,9 +450,12 @@ void Board::detect_colinear_edges(Plane const plane) { "["s + to_string(plane) + "] Detecting COLINEAR_EDGES conflicts "); for(size_t i = 0; i < s.edges[plane].size(); ++i) { - if(s.edges[plane][i]->axis == Segment::Axis::DIAGONAL) + if(s.edges[plane][i]->axis == Segment::Axis::DIAGONAL) { // || !edges[i]->to_mesh) + k += (s.edges[plane].size() - i - 1); + bar.tick(found, k); continue; + } for(size_t j = i + 1; j < s.edges[plane].size(); ++j, ++k) { if(s.edges[plane][j]->axis != s.edges[plane][i]->axis) @@ -415,11 +480,14 @@ void Board::detect_colinear_edges(Plane const plane) { //****************************************************************************** void Board::detect_individual_edges(Plane const plane) { + auto const& state = get_current_state(); + auto [bar, found, i] = Progress::Bar::build( - get_current_state().edges[plane].size(), - "["s + to_string(plane) + "] Adding fixed meshline policies "); + state.edges[plane].size() + + state.angles[plane].size(), + "["s + to_string(plane) + "] Detecting individual Edges "); - for(Edge* edge : get_current_state().edges[plane]) { + for(Edge* edge : state.edges[plane]) { optional const coord = domain::coord(edge->p0(), edge->axis); optional const axis = transpose(plane, edge->axis); Normal const normal = edge->get_current_state().to_reverse @@ -443,6 +511,89 @@ void Board::detect_individual_edges(Plane const plane) { } bar.tick(found, ++i); } + + for(shared_ptr const& angle : state.angles[plane]) { + if(angle->get_current_state().conflicts.empty() + || ranges::none_of(angle->get_current_state().conflicts, [](auto const& conflict) { return conflict ? conflict->kind == Conflict::Kind::COLINEAR_EDGES : false; })) { + ++found; + for(ViewAxis axis : AllViewAxis) { + auto [t, state_a] = angle->make_next_state(); + state_a.meshline_policy = line_policy_manager->add_meshline_policy( + { angle.get() }, + Axes[plane][axis], + MeshlinePolicy::Policy::HALFS, + MeshlinePolicy::Normal::NONE, + coord(angle->p, axis), + state_a.to_mesh[axis], + t); + angle->set_state(t, state_a); + } + } + bar.tick(found, ++i); + } + bar.complete(); +} + +//****************************************************************************** +void Board::detect_diagonal_zones(Plane plane) { + auto const& state = get_current_state(); + + auto angles = create_view(state.angles[plane]); + + auto [bar, found, k] = Progress::Bar::build( + (angles.size() - (angles.size() > 1 ? 1 : 0)) * 2, // Intervals between Angles. + "["s + to_string(plane) + "] Detecting diagonal zones "); + + auto diagonal_edges = state.edges[plane] + | views::filter([](Edge const* edge) { return edge->get_current_state().to_mesh && edge->axis == Segment::Axis::DIAGONAL; }); + + struct Range { + Bounding1D bounding; + Coord mid; + array angles; + set edges; + Range(ViewAxis axis, array angles) // angles must be sorted by axis coord + : bounding({ coord(angles[0]->p, axis), coord(angles[1]->p, axis) }) + , mid(domain::mid(coord(angles[0]->p, axis), coord(angles[1]->p, axis))) + , angles(angles) + {} + }; + + for(ViewAxis view_axis : AllViewAxis) { + ranges::sort(angles, [view_axis](Angle const* a, Angle const* b) { + return coord(a->p, view_axis) < coord(b->p, view_axis); + }); + + std::vector angles_ranges; + for(size_t i = 1; i < angles.size(); ++i, ++k) { + auto& range = angles_ranges.emplace_back(Range(view_axis, { angles[i-1], angles[i] })); + + for(Edge* edge : diagonal_edges) { + if(does_overlap(cast(view_axis, bounding(*edge)), range.mid)) { + range.edges.emplace(edge); + } + } + bar.tick(found, k); + } + + auto subranges = find_consecutive_matches(angles_ranges, [](Range const& range) { return !range.edges.empty(); }); + found += subranges.size(); + bar.tick(found, k); + for(auto const& subrange : subranges) { + auto subrange_angles = subrange + | views::transform([](auto const& range) { return range.angles; }) + | views::join + | ranges::to>(); + auto [b, e] = ranges::unique(subrange_angles); + subrange_angles.erase(b, e); + + conflict_manager->add_diagonal_or_circular_zone( + Axes[plane][view_axis], + subrange_angles, + global_params.get() + ); + } + } bar.complete(); } @@ -450,7 +601,7 @@ void Board::detect_individual_edges(Plane const plane) { void Board::add_fixed_meshline_policies(Axis axis) { auto [bar, i, _] = Progress::Bar::build( fixed_meshline_policy_creators[axis].size(), - "["s + to_string(axis) + "] Adding fixed meshline policies "); + "["s + to_string(axis) + "] Adding fixed Meshline Policies "); auto* t = next_timepoint(); for(auto const& create_meshline_policy : fixed_meshline_policy_creators[axis]) { @@ -466,6 +617,30 @@ void Board::adjust_edges_to_materials() { adjust_edges_to_materials(plane); } +//****************************************************************************** +void Board::detect_diagonal_angles() { + for(auto const& plane : AllPlane) + detect_diagonal_angles(plane); +} + +//****************************************************************************** +void Board::detect_diagonal_zones() { + for(auto const& plane : AllPlane) + detect_diagonal_zones(plane); +} + +//****************************************************************************** +void Board::solve_diagonal_zones_angles() { + for(auto const& axis : AllAxis) + conflict_manager->auto_solve_all_diagonal_angles(axis); +} + +//****************************************************************************** +void Board::solve_diagonal_zones_intervals() { + for(auto const& axis : AllAxis) + conflict_manager->auto_solve_all_diagonal_zones(axis); +} + //****************************************************************************** void Board::detect_edges_in_polygons() { for(auto const& plane : AllPlane) @@ -516,6 +691,12 @@ void Board::detect_intervals() { line_policy_manager->detect_intervals(axis); } +//****************************************************************************** +void Board::detect_intervals_per_diagonal_zones() { + for(auto const& axis : AllAxis) + line_policy_manager->detect_intervals_per_diagonal_zones(axis); +} + //****************************************************************************** void Board::mesh() { for(auto const& axis : AllAxis) @@ -542,6 +723,11 @@ vector> const& Board::get_intervals(Axis axis) const { return line_policy_manager->get_intervals(axis); } +//****************************************************************************** +vector> const& Board::get_angles(Plane plane) const { + return get_current_state().angles[plane]; +} + //****************************************************************************** vector> const& Board::get_polygons(Plane plane) const { return get_current_state().polygons[plane]; @@ -562,6 +748,11 @@ vector> const& Board::get_conflicts return conflict_manager->get_too_close_meshline_policies(axis); } +//****************************************************************************** +vector> const& Board::get_conflicts_diagonal_or_circular_zones(Axis const axis) const { + return conflict_manager->get_diagonal_or_circular_zones(axis); +} + //****************************************************************************** size_t Board::get_mesh_cell_number() const { return line_policy_manager->get_mesh_cell_number(); diff --git a/src/domain/board.hpp b/src/domain/board.hpp index ced0b468..3d783455 100644 --- a/src/domain/board.hpp +++ b/src/domain/board.hpp @@ -14,6 +14,7 @@ #include #include "conflicts/conflict.hpp" +#include "geometrics/angle.hpp" #include "geometrics/edge.hpp" #include "geometrics/point.hpp" #include "geometrics/polygon.hpp" @@ -37,6 +38,7 @@ namespace domain { struct BoardState final { PlaneSpace>> polygons; PlaneSpace> edges; + PlaneSpace>> angles; explicit BoardState(PlaneSpace>>&& polygons); }; @@ -84,9 +86,15 @@ class Board void detect_edges_in_polygons(Plane const plane); void detect_colinear_edges(Plane plane); void detect_individual_edges(Plane const plane); + void detect_diagonal_angles(Plane plane); + void detect_diagonal_zones(Plane plane); void add_fixed_meshline_policies(Axis axis); void adjust_edges_to_materials(); + void detect_diagonal_angles(); + void detect_diagonal_zones(); + void solve_diagonal_zones_angles(); + void solve_diagonal_zones_intervals(); void detect_edges_in_polygons(); void detect_colinear_edges(); void detect_individual_edges(); @@ -98,6 +106,7 @@ class Board void auto_solve_all_colinear_edges(); void detect_and_solve_too_close_meshline_policies(); void detect_intervals(); + void detect_intervals_per_diagonal_zones(); void mesh(); std::vector> get_meshline_policies_meshlines(Axis axis) const; @@ -105,9 +114,11 @@ class Board std::vector> const& get_meshline_policies(Axis axis) const; std::vector> const& get_intervals(Axis axis) const; std::vector> const& get_polygons(Plane plane) const; + std::vector> const& get_angles(Plane plane) const; std::vector> const& get_conflicts_edge_in_polygons(Plane const plane) const; std::vector> const& get_conflicts_colinear_edges(Axis const axis) const; std::vector> const& get_conflicts_too_close_meshline_policies(Axis const axis) const; + std::vector> const& get_conflicts_diagonal_or_circular_zones(Axis const axis) const; std::size_t get_mesh_cell_number() const; private: diff --git a/src/domain/conflict_manager.cpp b/src/domain/conflict_manager.cpp index d38a437d..3750d240 100644 --- a/src/domain/conflict_manager.cpp +++ b/src/domain/conflict_manager.cpp @@ -4,6 +4,9 @@ /// @author Thomas Lepoix ///***************************************************************************** +#include + +#include "geometrics/angle.hpp" #include "geometrics/edge.hpp" #include "geometrics/polygon.hpp" #include "mesh/meshline_policy.hpp" @@ -199,6 +202,67 @@ ConflictTooCloseMeshlinePolicies* ConflictManager::add_too_close_meshline_polici return conflict.get(); } +// TODO merge if two DOCZ in the same axis overlap, coming from two different planes +//****************************************************************************** +void ConflictManager::add_diagonal_or_circular_zone(Axis axis, vector const& angles, GlobalParams* global_params) { + auto [t, state] = make_next_state(); + + if(angles.empty()) + return; + + Plane plane = angles.front()->plane; + if(!ranges::all_of(angles, [&plane](Angle const* angle) { + return angle->plane == plane; + })) + return; + + optional view_axis = transpose(plane, axis); + if(!view_axis.has_value()) + return; + + auto sorted_angles = angles; + ranges::sort(sorted_angles, [&view_axis](Angle const* a, Angle const* b) { + return coord(a->p, view_axis.value()).value() < coord(b->p, view_axis.value()).value(); + }); + + // TODO find overlapping & merge + // TODO uneasy merge if the current overlaps with two (or more) other zones + // is popping the old ones out safe/fine? + + auto const& conflict = state.all_diagonal_or_circular_zone[axis].emplace_back( + make_shared(axis, sorted_angles, global_params, t)); + + set_state(t, state); +} + +//****************************************************************************** +void ConflictManager::auto_solve_all_diagonal_angles(Axis const axis) { + auto [bar, i, _] = Progress::Bar::build( + get_current_state().all_diagonal_or_circular_zone[axis].size(), + "["s + to_string(axis) + "] Solving ANGLE part of DIAGONAL_ZONE conflicts "); + + for(auto const& conflict : get_current_state().all_diagonal_or_circular_zone[axis]) { + conflict->solve_angles(); + bar.tick(i++); + } + + bar.complete(); +} + +//****************************************************************************** +void ConflictManager::auto_solve_all_diagonal_zones(Axis const axis) { + auto [bar, i, _] = Progress::Bar::build( + get_current_state().all_diagonal_or_circular_zone[axis].size(), + "["s + to_string(axis) + "] Solving INTERVAL part of DIAGONAL_ZONE conflicts "); + + for(auto const& conflict : get_current_state().all_diagonal_or_circular_zone[axis]) { + conflict->solve_intervals(); + bar.tick(i++); + } + + bar.complete(); +} + //****************************************************************************** void ConflictManager::auto_solve_all_edge_in_polygon(Plane const plane) { auto [bar, i, _] = Progress::Bar::build( @@ -240,4 +304,9 @@ vector> const& ConflictManager::get return get_current_state().all_too_close_meshline_policies[axis]; } +//****************************************************************************** +vector> const& ConflictManager::get_diagonal_or_circular_zones(Axis const axis) const { + return get_current_state().all_diagonal_or_circular_zone[axis]; +} + } // namespace domain diff --git a/src/domain/conflict_manager.hpp b/src/domain/conflict_manager.hpp index 88b3065a..1946263a 100644 --- a/src/domain/conflict_manager.hpp +++ b/src/domain/conflict_manager.hpp @@ -14,16 +14,19 @@ #include "conflicts/conflict_colinear_edges.hpp" #include "conflicts/conflict_edge_in_polygon.hpp" #include "conflicts/conflict_too_close_meshline_policies.hpp" +#include "conflicts/conflict_diagonal_or_circular_zone.hpp" #include "geometrics/space.hpp" #include "utils/state_management.hpp" namespace domain { +class Angle; class Edge; class MeshlinePolicyManager; class MeshlinePolicy; class Polygon; class Range; +class GlobalParams; #ifdef UNITTEST #define private public @@ -34,6 +37,7 @@ struct ConflictManagerState final { PlaneSpace>> all_edge_in_polygons; AxisSpace>> all_colinear_edges; AxisSpace>> all_too_close_meshline_policies; + AxisSpace>> all_diagonal_or_circular_zone; }; /// Create / append conflicts regarding already existing conflicts @@ -54,8 +58,12 @@ class ConflictManager void add_edge_in_polygon(Edge* a, Polygon* polygon, Range const range, std::optional b = std::nullopt); ConflictTooCloseMeshlinePolicies* add_too_close_meshline_policies(MeshlinePolicy* a, MeshlinePolicy* b) noexcept; + void add_diagonal_or_circular_zone(Axis axis, std::vector const& angles, GlobalParams* global_params); + // void add_user_will(Edge* a); // TODO + void auto_solve_all_diagonal_angles(Axis const axis); + void auto_solve_all_diagonal_zones(Axis const axis); void auto_solve_all_edge_in_polygon(Plane const plane); void auto_solve_all_colinear_edges(Axis const axis); // Conflict* find(std::vector const&); @@ -63,6 +71,7 @@ class ConflictManager std::vector> const& get_colinear_edges(Axis const axis) const; std::vector> const& get_edge_in_polygons(Plane const plane) const; std::vector> const& get_too_close_meshline_policies(Axis const axis) const; + std::vector> const& get_diagonal_or_circular_zones(Axis const axis) const; }; #ifdef UNITTEST diff --git a/src/domain/conflicts/conflict.hpp b/src/domain/conflicts/conflict.hpp index 32e12d57..3a2c6276 100644 --- a/src/domain/conflicts/conflict.hpp +++ b/src/domain/conflicts/conflict.hpp @@ -35,7 +35,8 @@ class Conflict EDGE_IN_POLYGON, // OVERLAPPING_EDGES, // TODO this or EDGE_IN_POLYGON subcase? try EOP first COLINEAR_EDGES, - TOO_CLOSE_MESHLINE_POLICIES + TOO_CLOSE_MESHLINE_POLICIES, + DIAGONAL_OR_CIRCULAR_ZONE } kind; // MeshlinePolicy* solution; diff --git a/src/domain/conflicts/conflict_diagonal_or_circular_zone.cpp b/src/domain/conflicts/conflict_diagonal_or_circular_zone.cpp new file mode 100644 index 00000000..07a8902c --- /dev/null +++ b/src/domain/conflicts/conflict_diagonal_or_circular_zone.cpp @@ -0,0 +1,98 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include + +#include "domain/geometrics/angle.hpp" +#include "domain/mesh/interval.hpp" + +#include "conflict_diagonal_or_circular_zone.hpp" + +namespace domain { + +using namespace std; + +// Assume sorted angles by axis-relevant coord. +//****************************************************************************** +ConflictDiagonalOrCircularZone::ConflictDiagonalOrCircularZone(Axis axis, vector const& angles, GlobalParams* global_params, Timepoint* t) +: Originator(t, { + .dmax = global_params->get_current_state().diagonal_dmax, + .lmin = global_params->get_current_state().lmin, + .minimal_angle = global_params->get_current_state().consecutive_diagonal_minimal_angle, + .angles = angles }) +, Conflict(Kind::DIAGONAL_OR_CIRCULAR_ZONE) +, global_params(global_params) +, axis(axis) +{} + +//****************************************************************************** +void ConflictDiagonalOrCircularZone::append(vector const& intervals, Timepoint* t) { + auto state = get_current_state(); + state.intervals.insert(state.intervals.end(), intervals.begin(), intervals.end()); + set_given_or_next_state(state, t); +} + +// Assume sorted angles. +//****************************************************************************** +Bounding1D ConflictDiagonalOrCircularZone::bounding() const { + auto state = get_current_state(); + + auto const get_coord = [this](Angle const* angle) { + if(auto view_axis = transpose(angle->plane, axis) + ; view_axis.has_value()) + return coord(angle->p, view_axis.value()); + return Coord(numeric_limits::signaling_NaN()); + }; + + return { get_coord(state.angles.front()), get_coord(state.angles.back()) }; +} + +//****************************************************************************** +void ConflictDiagonalOrCircularZone::auto_solve(MeshlinePolicyManager& line_policy_manager) { +} + +// Assume sorted angles +//****************************************************************************** +void ConflictDiagonalOrCircularZone::solve_angles() { + auto [t, state] = make_next_state(); + + // Always enable extremities + for(Angle* angle : { state.angles.front(), state.angles.back() }) { + if(auto view_axis = transpose(angle->plane, axis) + ; view_axis.has_value()) { + auto state_a = angle->get_current_state(); + state_a.to_mesh[view_axis.value()] = true; + angle->set_state(t, state_a); + } + } + + // Enable inner angles if acute enough + for(Angle* angle : state.angles | views::drop(1) | views::reverse | views::drop(1) | views::reverse) { + if(auto view_axis = transpose(angle->plane, axis) + ; view_axis.has_value()) { + auto state_a = angle->get_current_state(); + state_a.to_mesh[view_axis.value()] = angle->angle >= global_params->get_current_state().consecutive_diagonal_minimal_angle; + angle->set_state(t, state_a); + } + } +} + +//****************************************************************************** +void ConflictDiagonalOrCircularZone::solve_intervals() { + auto [t, state] = make_next_state(); + + // TODO lmin for extremities + // front()->before & back()->after + + for(Interval* interval : state.intervals) { + auto state_i = interval->get_current_state(); + state_i.dmax = state.dmax; + interval->set_state(t, state_i); + } +} + + +} // namespace domain diff --git a/src/domain/conflicts/conflict_diagonal_or_circular_zone.hpp b/src/domain/conflicts/conflict_diagonal_or_circular_zone.hpp new file mode 100644 index 00000000..03a96c4a --- /dev/null +++ b/src/domain/conflicts/conflict_diagonal_or_circular_zone.hpp @@ -0,0 +1,54 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include + +#include "domain/global.hpp" +#include "domain/geometrics/bounding.hpp" +#include "domain/geometrics/space.hpp" +#include "utils/state_management.hpp" +#include "conflict.hpp" + +namespace domain { + +class Angle; +class Interval; + +//****************************************************************************** +struct ConflictDiagonalOrCircularZoneState final : public ConflictState { + double dmax; + std::size_t lmin; + double minimal_angle; + std::vector angles; + std::vector intervals; +}; + +//****************************************************************************** +class ConflictDiagonalOrCircularZone +: public Originator +, public Visitable +, public Conflict { +private: + GlobalParams* global_params; + +public: + Axis const axis; + + ConflictDiagonalOrCircularZone(Axis axis, std::vector const& angles, GlobalParams* global_params, Timepoint* t); + + void append(std::vector const& intervals, Timepoint* t = nullptr); + + Bounding1D bounding() const; + + // TODO Refactor to Avoid that + void auto_solve(MeshlinePolicyManager& line_policy_manager) override; + void solve_angles(); + void solve_intervals(); +}; + +} // namespace domain diff --git a/src/domain/geometrics/angle.cpp b/src/domain/geometrics/angle.cpp new file mode 100644 index 00000000..fd17810d --- /dev/null +++ b/src/domain/geometrics/angle.cpp @@ -0,0 +1,23 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include "edge.hpp" + +#include "angle.hpp" + +namespace domain { + +//****************************************************************************** +Angle::Angle(Point const& p, Edge* e0, Edge* e1, Timepoint* t) +: Originator(t) +, plane(e0->plane) +, p(p) +, e0(e0) +, e1(e1) +, angle(domain::angle(e0->vec, e1->vec)) +{} + +} // namespace domain diff --git a/src/domain/geometrics/angle.hpp b/src/domain/geometrics/angle.hpp new file mode 100644 index 00000000..700d28f9 --- /dev/null +++ b/src/domain/geometrics/angle.hpp @@ -0,0 +1,50 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include "domain/conflicts/i_conflict_origin.hpp" +#include "domain/mesh/i_meshline_origin.hpp" +#include "domain/utils/entity_visitor.hpp" +#include "utils/entity.hpp" +#include "utils/state_management.hpp" +//#include "normal.hpp" +#include "point.hpp" +#include "space.hpp" + +namespace domain { + +class Edge; + +//****************************************************************************** +struct AngleState final +: public IConflictOriginState +, public IMeshLineOriginState { + ViewAxisSpace to_mesh = { false, false }; +}; + +// TODO IMeshLineOrigin allow 1 MLP while Angle will end in 2 MLPs !!! + +//****************************************************************************** +class Angle +: public Originator +, public Visitable +, public Entity +, public IConflictOrigin +, public IMeshLineOrigin { +public: + + Plane const plane; + Point const p; + Edge* const e0; + Edge* const e1; + Coord const angle; // In degree. +// ViewAxisSpace normals; // from e0 & e1, assuming not colinear : if H or V -> take, else -> NONE -> HALFS + + Angle(Point const& p, Edge* e0, Edge* e1, Timepoint* t); +}; + +} // namespace domain diff --git a/src/domain/geometrics/bounding.cpp b/src/domain/geometrics/bounding.cpp index a4898820..dd7dc6bd 100644 --- a/src/domain/geometrics/bounding.cpp +++ b/src/domain/geometrics/bounding.cpp @@ -4,21 +4,49 @@ /// @author Thomas Lepoix ///***************************************************************************** +#include + +#include "utils/unreachable.hpp" + #include "bounding.hpp" namespace domain { +using namespace std; + +///***************************************************************************** +bool does_overlap(Bounding1D const& a, Coord const& b) noexcept { + return b >= a[XMIN] && b <= a[XMAX]; +} + +/// Check if two bounding boxes overlap or just touch each other. +///***************************************************************************** +bool does_overlap(Bounding1D const& a, Bounding1D const& b) noexcept { + return min(a[XMAX], b[XMAX]) >= max(a[XMIN], b[XMIN]); +} + /// Check if two bounding boxes overlap or just touch each other. ///***************************************************************************** bool does_overlap(Bounding2D const& a, Bounding2D const& b) noexcept { - return((b[XMIN] >= a[XMIN] && b[XMIN] <= a[XMAX]) - || (b[XMAX] >= a[XMIN] && b[XMAX] <= a[XMAX]) - || (a[XMIN] >= b[XMIN] && a[XMIN] <= b[XMAX]) - || (a[XMAX] >= b[XMIN] && a[XMAX] <= b[XMAX])) - &&((b[YMIN] >= a[YMIN] && b[YMIN] <= a[YMAX]) - || (b[YMAX] >= a[YMIN] && b[YMAX] <= a[YMAX]) - || (a[YMIN] >= b[YMIN] && a[YMIN] <= b[YMAX]) - || (a[YMAX] >= b[YMIN] && a[YMAX] <= b[YMAX])); + return min(a[XMAX], b[XMAX]) >= max(a[XMIN], b[XMIN]) + && min(a[YMAX], b[YMAX]) >= max(a[YMIN], b[YMIN]); +} + +/// Check if two bounding boxes overlap. +///***************************************************************************** +bool does_overlap_strict(Bounding2D const& a, Bounding2D const& b) noexcept { + return min(a[XMAX], b[XMAX]) > max(a[XMIN], b[XMIN]) + && min(a[YMAX], b[YMAX]) > max(a[YMIN], b[YMIN]); +} + +//****************************************************************************** +Bounding1D cast(ViewAxis axis, Bounding2D const& a) noexcept { + switch(axis) { + case H: return { a[XMIN], a[XMAX] }; + case V: return { a[YMIN], a[YMAX] }; + default: ::unreachable(); + } } + } // namespace domain diff --git a/src/domain/geometrics/bounding.hpp b/src/domain/geometrics/bounding.hpp index ca25a835..50de50a1 100644 --- a/src/domain/geometrics/bounding.hpp +++ b/src/domain/geometrics/bounding.hpp @@ -8,15 +8,29 @@ #include +#include "space.hpp" #include "coord.hpp" namespace domain { //****************************************************************************** +using Bounding1D = std::array; using Bounding2D = std::array; enum BoundingIndex { XMIN, XMAX, YMIN, YMAX }; +//****************************************************************************** +bool does_overlap(Bounding1D const& a, Coord const& b) noexcept; + +//****************************************************************************** +bool does_overlap(Bounding1D const& a, Bounding1D const& b) noexcept; + //****************************************************************************** bool does_overlap(Bounding2D const& a, Bounding2D const& b) noexcept; +//****************************************************************************** +bool does_overlap_strict(Bounding2D const& a, Bounding2D const& b) noexcept; + +//****************************************************************************** +Bounding1D cast(ViewAxis axis, Bounding2D const& a) noexcept; + } // namespace domain diff --git a/src/domain/geometrics/edge.cpp b/src/domain/geometrics/edge.cpp index eed3ecc3..081e803d 100644 --- a/src/domain/geometrics/edge.cpp +++ b/src/domain/geometrics/edge.cpp @@ -5,7 +5,8 @@ ///***************************************************************************** #include -//#include +#include +#include #include "point.hpp" #include "polygon.hpp" @@ -65,4 +66,23 @@ bool operator==(Edge const& a, Range const& b) noexcept { || (a.p0() == b.p1() && a.p1() == b.p0())); } +// Returns the acute side of the angle. +//****************************************************************************** +Coord angle(Point const& vec_a, Point const& vec_b) noexcept { + // Cross and dot products. + auto cross = double (vec_a.x * vec_b.y - vec_a.y * vec_b.x); + auto dot = double (vec_a.x * vec_b.x + vec_a.y * vec_b.y); + + // In radians between [-pi, +pi] + double angle_rad = atan2(fabs(cross), dot); + + // Smaller angle in degree between [0, 180] + double angle_deg = fabs(angle_rad) * 180.0 / numbers::pi; + + if (angle_deg > 180.0) + angle_deg = 360.0 - angle_deg; + + return angle_deg; +} + } // namespace domain diff --git a/src/domain/geometrics/edge.hpp b/src/domain/geometrics/edge.hpp index 03adb328..cbdc3865 100644 --- a/src/domain/geometrics/edge.hpp +++ b/src/domain/geometrics/edge.hpp @@ -100,4 +100,7 @@ std::optional merge(Edge const& a, Edge const& b) = delete; bool operator==(Range const& a, Edge const& b) noexcept; bool operator==(Edge const& a, Range const& b) noexcept; +//****************************************************************************** +Coord angle(Point const& vec_a, Point const& vec_b) noexcept; + } // namespace domain diff --git a/src/domain/geometrics/point.cpp b/src/domain/geometrics/point.cpp index 8dd4ab2b..72e89e64 100644 --- a/src/domain/geometrics/point.cpp +++ b/src/domain/geometrics/point.cpp @@ -4,6 +4,8 @@ /// @author Thomas Lepoix ///***************************************************************************** +#include "utils/unreachable.hpp" + #include "point.hpp" namespace domain { @@ -42,4 +44,16 @@ Point mid(Point const& a, Point const& b) noexcept { return Point(mid(a.x, b.x), mid(a.y, b.y)); } +/// Here, @param axis describe the axis of the selected coord of the @param point. +/// H : H axis : x coord +/// V : V axis : y coord +///***************************************************************************** +Coord coord(Point const& point, ViewAxis const axis) noexcept { + switch(axis) { + case H: return point.x; + case V: return point.y; + default: unreachable(); + } +} + } // namespace domain diff --git a/src/domain/geometrics/point.hpp b/src/domain/geometrics/point.hpp index d5218894..99a00b59 100644 --- a/src/domain/geometrics/point.hpp +++ b/src/domain/geometrics/point.hpp @@ -6,6 +6,8 @@ #pragma once +#include "space.hpp" + #include "coord.hpp" // TODO use std::complex instead of Point? @@ -48,4 +50,7 @@ Point operator*(Point const& p, T const& n) noexcept { //****************************************************************************** Point mid(Point const& a, Point const& b) noexcept; +//****************************************************************************** +Coord coord(Point const& point, ViewAxis const axis) noexcept; + } // namespace domain diff --git a/src/domain/geometrics/polygon.cpp b/src/domain/geometrics/polygon.cpp index cbecf11f..a00c87a3 100644 --- a/src/domain/geometrics/polygon.cpp +++ b/src/domain/geometrics/polygon.cpp @@ -46,7 +46,7 @@ vector> detect_edges(vector> const& poi vector> edges; Point const* prev = points.back().get(); - for(auto const & point : points) { + for(auto const& point : points) { edges.push_back(make_shared(plane, prev, point.get(), t)); prev = point.get(); } diff --git a/src/domain/geometrics/segment.cpp b/src/domain/geometrics/segment.cpp index 29e2ec2d..534e0d24 100644 --- a/src/domain/geometrics/segment.cpp +++ b/src/domain/geometrics/segment.cpp @@ -237,4 +237,34 @@ optional transpose(Plane const plane, Segment::Axis const axis) noexcept { } } +//****************************************************************************** +optional cast(Segment::Axis const axis) noexcept { + switch(axis) { + case Segment::Axis::H: return H; + case Segment::Axis::V: return V; + default: return nullopt; + } +} + +//****************************************************************************** +Segment::Axis cast(ViewAxis const axis) noexcept { + switch(axis) { + case H: return Segment::Axis::H; + case V: return Segment::Axis::V; + default: ::unreachable(); + } +} + +/// Here, @param axis describe the orientation of the @param segment itself. +/// H : - : y coord +/// V : | : x coord +///***************************************************************************** +optional coord(Point const& point, Segment::Axis const axis) noexcept { + if(auto view_axis = cast(axis) + ; view_axis.has_value()) + return coord(point, reverse(view_axis.value())); + else + return nullopt; +} + } // namespace domain diff --git a/src/domain/geometrics/segment.hpp b/src/domain/geometrics/segment.hpp index e7d458b6..1e23e44f 100644 --- a/src/domain/geometrics/segment.hpp +++ b/src/domain/geometrics/segment.hpp @@ -60,4 +60,13 @@ std::optional overlap(Segment const& a, Segment const& b); // TODO -> Bou //****************************************************************************** std::optional transpose(Plane const plane, Segment::Axis const axis) noexcept; +//****************************************************************************** +std::optional cast(Segment::Axis const axis) noexcept; + +//****************************************************************************** +Segment::Axis cast(ViewAxis const axis) noexcept; + +//****************************************************************************** +std::optional coord(Point const& point, Segment::Axis const axis) noexcept; + } // namespace domain diff --git a/src/domain/global.hpp b/src/domain/global.hpp index be533e25..b716906e 100644 --- a/src/domain/global.hpp +++ b/src/domain/global.hpp @@ -19,6 +19,10 @@ struct Params { double smoothness = 2; std::size_t lmin = 10; double dmax = 2.5; + + std::size_t diagonal_lmin = 2; + double diagonal_dmax = 0.2; + double consecutive_diagonal_minimal_angle = 20; // Limite between acute / obtuse angles. }; //****************************************************************************** diff --git a/src/domain/mesh/interval.hpp b/src/domain/mesh/interval.hpp index 7b8e48cd..885a8c25 100644 --- a/src/domain/mesh/interval.hpp +++ b/src/domain/mesh/interval.hpp @@ -12,6 +12,7 @@ #include #include +#include "domain/conflicts/i_conflict_origin.hpp" #include "domain/geometrics/coord.hpp" #include "domain/geometrics/space.hpp" #include "domain/utils/entity_visitor.hpp" @@ -82,7 +83,8 @@ class Interval }; //****************************************************************************** -struct IntervalState final { +struct IntervalState final +: public IConflictOriginState { double dmax; ///< Maximum distance between two adjacent meshlines. Interval::Side before; Interval::Side after; diff --git a/src/domain/mesh/meshline_policy.cpp b/src/domain/mesh/meshline_policy.cpp index f02db3df..eb6d4da4 100644 --- a/src/domain/mesh/meshline_policy.cpp +++ b/src/domain/mesh/meshline_policy.cpp @@ -46,15 +46,6 @@ optional MeshlinePolicy::mesh() { return nullopt; } -//****************************************************************************** -optional coord(Point const& point, Segment::Axis const axis) noexcept { - switch(axis) { - case Segment::Axis::H: return point.y; - case Segment::Axis::V: return point.x; - default: return nullopt; - } -} - //****************************************************************************** MeshlinePolicy::Normal cast(Normal const normal) noexcept { switch(normal) { diff --git a/src/domain/mesh/meshline_policy.hpp b/src/domain/mesh/meshline_policy.hpp index 67f3b1d5..d118b9e3 100644 --- a/src/domain/mesh/meshline_policy.hpp +++ b/src/domain/mesh/meshline_policy.hpp @@ -14,7 +14,6 @@ #include "domain/conflicts/i_conflict_origin.hpp" #include "domain/conflicts/i_conflict_solution.hpp" #include "domain/geometrics/coord.hpp" -#include "domain/geometrics/segment.hpp" #include "domain/geometrics/normal.hpp" #include "domain/geometrics/space.hpp" #include "domain/utils/entity_visitor.hpp" @@ -91,9 +90,6 @@ struct MeshlinePolicyState final std::vector meshlines; }; -//****************************************************************************** -std::optional coord(Point const& point, Segment::Axis const axis) noexcept; - //****************************************************************************** MeshlinePolicy::Normal cast(Normal const normal) noexcept; diff --git a/src/domain/meshline_policy_manager.cpp b/src/domain/meshline_policy_manager.cpp index 8e92106a..338ebc4f 100644 --- a/src/domain/meshline_policy_manager.cpp +++ b/src/domain/meshline_policy_manager.cpp @@ -161,6 +161,33 @@ void MeshlinePolicyManager::detect_intervals(Axis const axis) { bar.complete(); } +//****************************************************************************** +void MeshlinePolicyManager::detect_intervals_per_diagonal_zones(Axis const axis) { + auto [t, state] = make_next_state(); + + auto [bar, found, i] = Progress::Bar::build( + conflict_manager->get_diagonal_or_circular_zones(axis).size() * state.intervals[axis].size(), + "["s + to_string(axis) + "] Detecting Intervals per diagonal zones"); + + for(auto& conflict : conflict_manager->get_diagonal_or_circular_zones(axis)) { + Bounding1D const bounding = conflict->bounding(); + vector intervals; + for(auto const& interval : state.intervals[axis]) { + ++i; + if(does_overlap(bounding, interval->m)) { + ++found; + intervals.emplace_back(interval.get()); + auto state_i = interval->get_current_state(); + state_i.conflicts.emplace_back(conflict.get()); + interval->set_state(t, state_i); + } + } + conflict->append(intervals, t); + bar.tick(found, i); + } + bar.complete(); +} + //****************************************************************************** void MeshlinePolicyManager::mesh(Axis const axis) { auto [t, state] = make_next_state(); diff --git a/src/domain/meshline_policy_manager.hpp b/src/domain/meshline_policy_manager.hpp index 61822053..71888e2e 100644 --- a/src/domain/meshline_policy_manager.hpp +++ b/src/domain/meshline_policy_manager.hpp @@ -59,6 +59,7 @@ class MeshlinePolicyManager // TODO MeshlineManager void detect_and_solve_too_close_meshline_policies(Axis const axis); void detect_intervals(Axis const axis); + void detect_intervals_per_diagonal_zones(Axis const axis); void mesh(Axis const axis); void detect_and_solve_too_close_meshline_policies() { for(auto const& axis : AllAxis) detect_and_solve_too_close_meshline_policies(axis); }; diff --git a/src/domain/utils/entity_visitor.hpp b/src/domain/utils/entity_visitor.hpp index 900c3cc3..cc312b22 100644 --- a/src/domain/utils/entity_visitor.hpp +++ b/src/domain/utils/entity_visitor.hpp @@ -9,9 +9,11 @@ namespace domain { class Board; +class Angle; class Edge; class Polygon; class ConflictColinearEdges; +class ConflictDiagonalOrCircularZone; class ConflictEdgeInPolygon; class ConflictTooCloseMeshlinePolicies; class MeshlinePolicy; @@ -22,9 +24,11 @@ class Meshline; class EntityVisitor { public: virtual void visit([[maybe_unused]] Board& board) {}; + virtual void visit([[maybe_unused]] Angle& angle) {}; virtual void visit([[maybe_unused]] Edge& edge) {}; virtual void visit([[maybe_unused]] Polygon& polygon) {}; virtual void visit([[maybe_unused]] ConflictColinearEdges& conflict) {}; + virtual void visit([[maybe_unused]] ConflictDiagonalOrCircularZone& conflict) {}; virtual void visit([[maybe_unused]] ConflictEdgeInPolygon& conflict) {}; virtual void visit([[maybe_unused]] ConflictTooCloseMeshlinePolicies& conflict) {}; virtual void visit([[maybe_unused]] MeshlinePolicy& policy) {}; diff --git a/src/ui/cli/cli.cpp b/src/ui/cli/cli.cpp index eff48099..0c4fdf1c 100644 --- a/src/ui/cli/cli.cpp +++ b/src/ui/cli/cli.cpp @@ -165,6 +165,21 @@ app::OpenEMSH::Params cli(int const argc, char* argv[]) { "Smoothness factor ]1;2]." )->group("Mesher options")->check(BoundExclusiveInclusive(1.0, 2.0)); + app.add_option_function("--diag-dmax", + make_overrider<&domain::Params::diagonal_dmax>(domain_overrides), + "Maximum distance between two adjacent lines in diagonal zones." + )->group("Mesher options"); + + app.add_option_function("--diag-lmin", + make_overrider<&domain::Params::diagonal_lmin>(domain_overrides), + "Minimum line number per Interval half, at extremities of diagonal zones." + )->group("Mesher options"); + + app.add_option_function("--diag-minimal-angle", + make_overrider<&domain::Params::consecutive_diagonal_minimal_angle>(domain_overrides), + "Angle threshold, above which angles between diagonal edges will generate MeshlinePolicies." + )->group("Mesher options"); + app.add_flag("--no-x", [¶ms](size_t) { params.with_axis_x = false; }, "Don't include X axis meshlines in output.")->group("Output options"); app.add_flag("--no-y", [¶ms](size_t) { params.with_axis_y = false; }, "Don't include Y axis meshlines in output.")->group("Output options"); app.add_flag("--no-z", [¶ms](size_t) { params.with_axis_z = false; }, "Don't include Z axis meshlines in output.")->group("Output options"); diff --git a/src/ui/qt/edit/edit_model.cpp b/src/ui/qt/edit/edit_model.cpp index 45f39814..5363dfde 100644 --- a/src/ui/qt/edit/edit_model.cpp +++ b/src/ui/qt/edit/edit_model.cpp @@ -4,11 +4,15 @@ /// @author Thomas Lepoix ///***************************************************************************** +#include "edit_model_angle.hpp" +#include "edit_model_conflict_diagonal_or_circular_zone.hpp" #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_angle.hpp" +#include "ui/qt/processing_view/processing_conflict_diagonal_or_circular_zone.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" @@ -58,12 +62,16 @@ bool EditModel::try_to_bool(Qt::CheckState const in, bool& out) { //****************************************************************************** EditModel* EditModel::make(nodegraph::Node* node, QObject* parent) { switch(node->type()) { + case UserTypes::PROCESSING_ANGLE: + return new EditModelAngle(unconst(static_cast(node)->angle), parent); 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_DOCZ: + return new EditModelConflictDiagonalOrCircularZone(unconst(static_cast(node)->conflict), parent); case UserTypes::PROCESSING_CONFLICT_TCMLP: return new EditModelConflictTooCloseMeshlinePolicies(unconst(static_cast(node)->conflict), parent); default: diff --git a/src/ui/qt/edit/edit_model_angle.cpp b/src/ui/qt/edit/edit_model_angle.cpp new file mode 100644 index 00000000..92feb1ae --- /dev/null +++ b/src/ui/qt/edit/edit_model_angle.cpp @@ -0,0 +1,45 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "app/steps.hpp" +#include "domain/geometrics/angle.hpp" + +#include "edit_model_angle.hpp" + +namespace ui::qt { + +//****************************************************************************** +EditModelAngle::EditModelAngle(domain::Angle* angle, QObject* parent) +: EditModel(parent) +, angle(angle) +{ + auto const& state = angle->get_current_state(); + setRowCount(2); + + make_row(0, "To mesh[H]", state.to_mesh[domain::H], "Take into account in the meshing process of the horizontal axis."); + make_row(1, "To mesh[V]", state.to_mesh[domain::V], "Take into account in the meshing process of the vertical axis."); +} + +//****************************************************************************** +void EditModelAngle::commit() { + auto state = angle->get_current_state(); + + std::array does_succeed = { + try_to_bool(item(0, V)->checkState(), state.to_mesh[domain::H]), + try_to_bool(item(1, V)->checkState(), state.to_mesh[domain::V]) + }; + + if(std::ranges::all_of(does_succeed, is_true)) { + emit edit_from(app::Step::DETECT_CONFLICT_EIP, [&]() { + angle->set_next_state(state); + }); + } +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_angle.hpp b/src/ui/qt/edit/edit_model_angle.hpp new file mode 100644 index 00000000..3e3273d4 --- /dev/null +++ b/src/ui/qt/edit/edit_model_angle.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 Angle; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class EditModelAngle : public EditModel { +public: + explicit EditModelAngle(domain::Angle* angle, QObject* parent = nullptr); + void commit() override; + +private: + domain::Angle* angle; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_conflict_diagonal_or_circular_zone.cpp b/src/ui/qt/edit/edit_model_conflict_diagonal_or_circular_zone.cpp new file mode 100644 index 00000000..d717f136 --- /dev/null +++ b/src/ui/qt/edit/edit_model_conflict_diagonal_or_circular_zone.cpp @@ -0,0 +1,52 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "app/steps.hpp" +#include "domain/conflicts/conflict_diagonal_or_circular_zone.hpp" + +#include "edit_model_conflict_diagonal_or_circular_zone.hpp" + +namespace ui::qt { + +//****************************************************************************** +EditModelConflictDiagonalOrCircularZone::EditModelConflictDiagonalOrCircularZone(domain::ConflictDiagonalOrCircularZone* conflict, QObject* parent) +: EditModel(parent) +, conflict(conflict) +{ + auto const& state = conflict->get_current_state(); + setRowCount(3); + + make_row(0, "lmin", QString::number(state.lmin), + "Minimum line number per Interval half, at extremities of the diagonal zone."); + make_row(1, "dmax", QString::number(state.dmax), + "Maximum distance between two adjacent lines."); + make_row(2, "Minimal angle", QString::number(state.minimal_angle), + "Angle threshold, above which angles between diagonal edges will generate MeshlinePolicies."); +} + +//****************************************************************************** +void EditModelConflictDiagonalOrCircularZone::commit() { + auto state = conflict->get_current_state(); + + std::array does_succeed = { + try_to_ulong(item(0, V)->text(), state.lmin), + try_to_double(item(1, V)->text(), state.dmax), + try_to_double(item(2, V)->text(), state.minimal_angle) + }; + + if(std::ranges::all_of(does_succeed, is_true)) { + emit edit_from((state.minimal_angle != conflict->get_current_state().minimal_angle + ? app::Step::SOLVE_DIAG_ZONES_ANGLES + : app::Step::SOLVE_DIAG_ZONES_INTERVALS), [&]() { + conflict->set_next_state(state); + }); + } +} + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_conflict_diagonal_or_circular_zone.hpp b/src/ui/qt/edit/edit_model_conflict_diagonal_or_circular_zone.hpp new file mode 100644 index 00000000..e33fe090 --- /dev/null +++ b/src/ui/qt/edit/edit_model_conflict_diagonal_or_circular_zone.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 ConflictDiagonalOrCircularZone; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class EditModelConflictDiagonalOrCircularZone : public EditModel { +public: + explicit EditModelConflictDiagonalOrCircularZone(domain::ConflictDiagonalOrCircularZone* conflict, QObject* parent = nullptr); + void commit() override; + +private: + domain::ConflictDiagonalOrCircularZone* conflict; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/edit/edit_model_edge.cpp b/src/ui/qt/edit/edit_model_edge.cpp index bc386e9e..bf29a63f 100644 --- a/src/ui/qt/edit/edit_model_edge.cpp +++ b/src/ui/qt/edit/edit_model_edge.cpp @@ -23,7 +23,7 @@ EditModelEdge::EditModelEdge(domain::Edge* edge, QObject* parent) setRowCount(2); make_row(0, "To mesh", state.to_mesh, "Take into account in the meshing process."); - make_row(1, "To reverse", state.to_mesh, "Swap in-side and out-side."); + make_row(1, "To reverse", state.to_reverse, "Swap in-side and out-side."); } //****************************************************************************** diff --git a/src/ui/qt/edit/edit_model_global.cpp b/src/ui/qt/edit/edit_model_global.cpp index dc30be2b..52fa7f7a 100644 --- a/src/ui/qt/edit/edit_model_global.cpp +++ b/src/ui/qt/edit/edit_model_global.cpp @@ -34,6 +34,12 @@ EditModelGlobal::EditModelGlobal(domain::GlobalParams* global, QObject* parent) "Minimum line number per Interval half."); make_row(3, "dmax", QString::number(params.dmax), "Maximum distance between two adjacent lines."); + make_row(4, "Minimal angle", QString::number(params.consecutive_diagonal_minimal_angle), + "Angle threshold, above which angles between diagonal edges will generate MeshlinePolicies."); + make_row(5, "Diagonal dmax", QString::number(params.diagonal_dmax), + "Maximum distance between two adjacent lines in diagonal zones."); + make_row(6, "Diagonal lmin", QString::number(params.diagonal_lmin), + "Minimum line number per Interval half, at extremities of diagonal zones."); } //****************************************************************************** @@ -44,11 +50,14 @@ void EditModelGlobal::commit() { try_to_double(item(0, V)->text(), params.proximity_limit), try_to_double(item(1, V)->text(), params.smoothness), try_to_ulong(item(2, V)->text(), params.lmin), - try_to_double(item(3, V)->text(), params.dmax) + try_to_double(item(3, V)->text(), params.dmax), + try_to_double(item(4, V)->text(), params.consecutive_diagonal_minimal_angle), + try_to_double(item(5, V)->text(), params.diagonal_dmax), + try_to_ulong(item(6, V)->text(), params.diagonal_lmin) }; if(std::ranges::all_of(does_succeed, is_true)) { - emit edit_from(app::Step::DETECT_CONFLICT_EIP, [&]() { + emit edit_from(app::Step::DETECT_DIAG_ZONES, [&]() { global->set_next_state(params); }); } diff --git a/src/ui/qt/icons.cpp b/src/ui/qt/icons.cpp index 43c01f07..3a18fb81 100644 --- a/src/ui/qt/icons.cpp +++ b/src/ui/qt/icons.cpp @@ -13,6 +13,7 @@ #include #include "structure_view/structure_conflict_colinear_edges.hpp" +#include "structure_view/structure_conflict_diagonal_or_circular_zone.hpp" #include "structure_view/structure_conflict_too_close_meshline_policies.hpp" #include "structure_view/structure_interval.hpp" #include "structure_view/structure_meshline.hpp" @@ -105,14 +106,17 @@ QPixmap apply(QTransform const& transform, QPixmap const& pixmap) { #endif //****************************************************************************** +PIXMAP_MAKER_DEF(angle, make_pixmap(draw_icon_from_text("∠"))) 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_docz_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_docz_h, apply(rotate_90_cw, conflict_docz_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())) @@ -123,6 +127,8 @@ QPixmap const& Icons::select(QGraphicsItem const* item) { using namespace UserTypes; switch(item->type()) { + case PROCESSING_ANGLE: [[fallthrough]]; + case STRUCTURE_ANGLE: return angle(); case PROCESSING_EDGE: [[fallthrough]]; case STRUCTURE_EDGE: return edge(); case PROCESSING_POLYGON: [[fallthrough]]; @@ -155,6 +161,13 @@ QPixmap const& Icons::select(QGraphicsItem const* item) { case domain::ViewAxis::V: return conflict_ce_v(); default: unreachable(); } + case PROCESSING_CONFLICT_DOCZ: return conflict_docz_v(); + case STRUCTURE_CONFLICT_DOCZ: + switch(static_cast(item)->axis) { + case domain::ViewAxis::H: return conflict_docz_h(); + case domain::ViewAxis::V: return conflict_docz_v(); + default: unreachable(); + } case PROCESSING_CONFLICT_TCMLP: return conflict_tcmlp_v(); case STRUCTURE_CONFLICT_TCMLP: switch(static_cast(item)->axis) { diff --git a/src/ui/qt/icons.hpp b/src/ui/qt/icons.hpp index 5e044122..85dadbf3 100644 --- a/src/ui/qt/icons.hpp +++ b/src/ui/qt/icons.hpp @@ -18,6 +18,7 @@ struct Icons { static QPixmap const& select(QGraphicsItem const* item); + static QPixmap const& angle(); static QPixmap const& edge(); static QPixmap const& polygon(); static QPixmap const& interval_h(); @@ -26,6 +27,8 @@ struct Icons { static QPixmap const& meshline_policy_v(); static QPixmap const& conflict_ce_h(); static QPixmap const& conflict_ce_v(); + static QPixmap const& conflict_docz_h(); + static QPixmap const& conflict_docz_v(); static QPixmap const& conflict_tcmlp_h(); static QPixmap const& conflict_tcmlp_v(); static QPixmap const& meshline_h(); diff --git a/src/ui/qt/processing_view/processing_angle.cpp b/src/ui/qt/processing_view/processing_angle.cpp new file mode 100644 index 00000000..f0d3b3ac --- /dev/null +++ b/src/ui/qt/processing_view/processing_angle.cpp @@ -0,0 +1,145 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include +#include + +#include "domain/geometrics/angle.hpp" +#include "domain/geometrics/edge.hpp" +#include "ui/qt/data_keys.hpp" +#include "ui/qt/utils/nodegraph/text.hpp" + +#include "processing_angle.hpp" + +namespace ui::qt { + +//****************************************************************************** +ProcessingAngle::ProcessingAngle(domain::Angle const* angle, QGraphicsItem* parent) +: nodegraph::Node("Angle - " + (angle ? QString::number(angle->id) : QString()), parent) +, locate_processing_angle_params(default_locator) +, angle(angle) +{ + QList to_wire; + + locate_node_params = [this]() -> auto& { + return locate_processing_angle_params().node; + }; + + title->locate_text_params = [this]() -> auto& { + return locate_processing_angle_params().title; + }; + + auto* h_box = new QGraphicsLinearLayout(Qt::Horizontal, layout()); + auto* v_box1 = new QGraphicsLinearLayout(Qt::Vertical, h_box); + auto* v_box2 = new QGraphicsLinearLayout(Qt::Vertical, h_box); + auto* v_box3 = new QGraphicsLinearLayout(Qt::Vertical, h_box); + layout()->addItem(h_box); + h_box->addItem(v_box1); + h_box->addItem(v_box2); + h_box->addItem(v_box3); + v_box1->addStretch(); + + nodegraph::Port* edge0_port = add_input_port(); + edge0_port->setFlag(QGraphicsItem::ItemIsSelectable); + edge0_port->setAcceptedMouseButtons(Qt::NoButton); + edge0_port->locate_port_params = [this]() -> auto& { + return locate_processing_angle_params().port; + }; + v_box1->addItem(edge0_port); + v_box1->addStretch(); + to_wire.emplace_back(DataKeys::set_to_wire(angle->e0, edge0_port)); + + nodegraph::Port* edge1_port = add_input_port(); + edge1_port->setFlag(QGraphicsItem::ItemIsSelectable); + edge1_port->setAcceptedMouseButtons(Qt::NoButton); + edge1_port->locate_port_params = [this]() -> auto& { + return locate_processing_angle_params().port; + }; + v_box1->addItem(edge1_port); + v_box1->addStretch(); + to_wire.emplace_back(DataKeys::set_to_wire(angle->e1, edge1_port)); + + nodegraph::Port* output_port = add_output_port(); + output_port->setFlag(QGraphicsItem::ItemIsSelectable); + output_port->setAcceptedMouseButtons(Qt::NoButton); + output_port->locate_port_params = [this]() -> auto& { + return locate_processing_angle_params().port; + }; + + QString angle_val("Angle (°): "); + QString to_mesh_h("To mesh [H]: "); + QString to_mesh_v("To mesh [V]: "); + if(angle) { + angle_val += QString::number(angle->angle.value()); + to_mesh_h += (angle->get_current_state().to_mesh[domain::H] ? "true" : "false"); + to_mesh_v += (angle->get_current_state().to_mesh[domain::V] ? "true" : "false"); + } + + auto* text_angle = new nodegraph::Text(angle_val, this); + text_angle->setFlag(QGraphicsItem::ItemIsSelectable); + text_angle->setAcceptedMouseButtons(Qt::NoButton); + text_angle->locate_text_params = [this]() -> auto& { + return locate_processing_angle_params().main; + }; + + auto* text_to_mesh_h = new nodegraph::Text(to_mesh_h, this); + text_to_mesh_h->setFlag(QGraphicsItem::ItemIsSelectable); + text_to_mesh_h->setAcceptedMouseButtons(Qt::NoButton); + if(angle) { + if(angle->get_current_state().to_mesh[domain::H]) + text_to_mesh_h->locate_text_params = [this]() -> auto& { + return locate_processing_angle_params().enabled; + }; + else + text_to_mesh_h->locate_text_params = [this]() -> auto& { + return locate_processing_angle_params().disabled; + }; + } else { + text_to_mesh_h->locate_text_params = [this]() -> auto& { + return locate_processing_angle_params().main; + }; + } + + auto* text_to_mesh_v = new nodegraph::Text(to_mesh_v, this); + text_to_mesh_v->setFlag(QGraphicsItem::ItemIsSelectable); + text_to_mesh_v->setAcceptedMouseButtons(Qt::NoButton); + if(angle) { + if(angle->get_current_state().to_mesh[domain::V]) + text_to_mesh_v->locate_text_params = [this]() -> auto& { + return locate_processing_angle_params().enabled; + }; + else + text_to_mesh_v->locate_text_params = [this]() -> auto& { + return locate_processing_angle_params().disabled; + }; + } else { + text_to_mesh_v->locate_text_params = [this]() -> auto& { + return locate_processing_angle_params().main; + }; + } + + v_box2->addItem(text_angle); + v_box2->addItem(text_to_mesh_h); + v_box2->addItem(text_to_mesh_v); + v_box3->addStretch(); + v_box3->addItem(output_port); + v_box3->addStretch(); + v_box3->setAlignment(output_port, Qt::AlignRight | Qt::AlignVCenter); + + setData(DataKeys::TYPE, "Angle"); + setData(DataKeys::ID, (qulonglong) angle->id); + setData(DataKeys::ENTITY, DataKeys::set_entity(angle)); + setData(DataKeys::TO_WIRE, to_wire); + retrieve_highlightable_children(); +} + +//****************************************************************************** +int ProcessingAngle::type() const { + return Type; +} + +} // namespace ui::qt diff --git a/src/ui/qt/processing_view/processing_angle.hpp b/src/ui/qt/processing_view/processing_angle.hpp new file mode 100644 index 00000000..a5db3908 --- /dev/null +++ b/src/ui/qt/processing_view/processing_angle.hpp @@ -0,0 +1,48 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include "ui/qt/user_types.hpp" +#include "ui/qt/utils/nodegraph/node.hpp" +#include "ui/qt/utils/nodegraph/text.hpp" +#include "utils/default_locator.hpp" + +namespace domain { +class Angle; +} // namespace domain + +namespace ui::qt { + +class EditModel; + +//****************************************************************************** +class ProcessingAngle : public nodegraph::Node { +public: + enum { Type = UserTypes::PROCESSING_ANGLE }; + + struct Params final { + nodegraph::Node::Params const& node = default_locator(); + nodegraph::Port::Params const& port = default_locator(); + nodegraph::Text::Params const& title = default_locator(); + nodegraph::Text::Params const& main = default_locator(); + nodegraph::Text::Params const& enabled = default_locator(); + nodegraph::Text::Params const& disabled = default_locator(); + }; + + std::function locate_processing_angle_params; + + explicit ProcessingAngle(domain::Angle const* angle, QGraphicsItem* parent = nullptr); + + int type() const override; + +private: + friend EditModel; + + domain::Angle const* const angle; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/processing_view/processing_axis.cpp b/src/ui/qt/processing_view/processing_axis.cpp index 0a82b3e9..c72bc5c7 100644 --- a/src/ui/qt/processing_view/processing_axis.cpp +++ b/src/ui/qt/processing_view/processing_axis.cpp @@ -29,6 +29,7 @@ ProcessingAxis::ProcessingAxis(domain::Axis axis, QGraphicsItem* parent) // Can be optimized by splitting count() -> compute()/get() case UserTypes::PROCESSING_MESHLINE_POLICY: return 1 + static_cast(item)->count_mlp_tcmlp_deepness(); case UserTypes::PROCESSING_CONFLICT_TCMLP: return 2 + static_cast(item)->count_tcmlp_mlp_deepness(); + case UserTypes::PROCESSING_CONFLICT_DOCZ: return std::numeric_limits::max() - 2; case UserTypes::PROCESSING_INTERVAL: return std::numeric_limits::max() - 1; case UserTypes::PROCESSING_MESHLINE: return std::numeric_limits::max(); default: return 0; diff --git a/src/ui/qt/processing_view/processing_conflict_diagonal_or_circular_zone.cpp b/src/ui/qt/processing_view/processing_conflict_diagonal_or_circular_zone.cpp new file mode 100644 index 00000000..1472572b --- /dev/null +++ b/src/ui/qt/processing_view/processing_conflict_diagonal_or_circular_zone.cpp @@ -0,0 +1,111 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "domain/geometrics/angle.hpp" +#include "domain/conflicts/conflict_diagonal_or_circular_zone.hpp" +#include "ui/qt/data_keys.hpp" + +#include "processing_conflict_diagonal_or_circular_zone.hpp" + +namespace ui::qt { + +//****************************************************************************** +ProcessingConflictDiagonalOrCircularZone::ProcessingConflictDiagonalOrCircularZone(domain::ConflictDiagonalOrCircularZone const* conflict, QGraphicsItem* parent) +: nodegraph::Node("ConflictDiagonalOrCircularZone - " + (conflict ? QString::number(conflict->id) : QString()), parent) +, locate_processing_conflict_docz_params(default_locator) +, conflict(conflict) +{ + QList to_wire; + + locate_node_params = [this]() -> auto& { + return locate_processing_conflict_docz_params().node; + }; + + title->locate_text_params = [this]() -> auto& { + return locate_processing_conflict_docz_params().title; + }; + + auto* h_box = new QGraphicsLinearLayout(Qt::Horizontal, layout()); + auto* v_box1 = new QGraphicsLinearLayout(Qt::Vertical, h_box); + auto* v_box2 = new QGraphicsLinearLayout(Qt::Vertical, h_box); + auto* v_box3 = new QGraphicsLinearLayout(Qt::Vertical, h_box); + layout()->addItem(h_box); + h_box->addItem(v_box1); + h_box->addItem(v_box2); + h_box->addItem(v_box3); + + nodegraph::Port* in = add_input_port(" "); + in->setFlag(QGraphicsItem::ItemIsSelectable); + in->setAcceptedMouseButtons(Qt::NoButton); + in->locate_port_params = [this]() -> auto& { + return locate_processing_conflict_docz_params().port; + }; + v_box1->addItem(in); + + nodegraph::Port* out = add_output_port(); + out->setFlag(QGraphicsItem::ItemIsSelectable); + out->setAcceptedMouseButtons(Qt::NoButton); + out->locate_port_params = [this]() -> auto& { + return locate_processing_conflict_docz_params().port; + }; + + QString dmax("dmax: "); + QString lmin("lmin: "); + QString minimal_angle ("Minimal angle (°): "); + if(conflict) { + auto const& state = conflict->get_current_state(); + dmax += QString::number(state.dmax); + lmin += QString::number(state.lmin); + minimal_angle += QString::number(state.minimal_angle); + for(auto const* angle : state.angles) + to_wire.emplace_back(DataKeys::set_to_wire(angle, in)); + } + + auto* text_dmax = new nodegraph::Text(dmax, this); + text_dmax->setFlag(QGraphicsItem::ItemIsSelectable); + text_dmax->setAcceptedMouseButtons(Qt::NoButton); + text_dmax->locate_text_params = [this]() -> auto& { + return locate_processing_conflict_docz_params().main; + }; + + auto* text_lmin = new nodegraph::Text(lmin, this); + text_lmin->setFlag(QGraphicsItem::ItemIsSelectable); + text_lmin->setAcceptedMouseButtons(Qt::NoButton); + text_lmin->locate_text_params = [this]() -> auto& { + return locate_processing_conflict_docz_params().main; + }; + + auto* text_minimal_angle = new nodegraph::Text(minimal_angle, this); + text_minimal_angle->setFlag(QGraphicsItem::ItemIsSelectable); + text_minimal_angle->setAcceptedMouseButtons(Qt::NoButton); + text_minimal_angle->locate_text_params = [this]() -> auto& { + return locate_processing_conflict_docz_params().main; + }; + + v_box2->addItem(text_dmax); + v_box2->addItem(text_lmin); + v_box2->addItem(text_minimal_angle); + v_box3->addStretch(); + v_box3->addItem(out); + v_box3->addStretch(); + v_box3->setAlignment(out, Qt::AlignRight | Qt::AlignVCenter); + + setData(DataKeys::TYPE, "ConflictDiagonalOrCircularZone"); + setData(DataKeys::ID, (qulonglong) conflict->id); + setData(DataKeys::ENTITY, DataKeys::set_entity(conflict)); + setData(DataKeys::TO_WIRE, to_wire); + retrieve_highlightable_children(); +} + +//****************************************************************************** +int ProcessingConflictDiagonalOrCircularZone::type() const { + return Type; +} + +} // namespace ui::qt diff --git a/src/ui/qt/processing_view/processing_conflict_diagonal_or_circular_zone.hpp b/src/ui/qt/processing_view/processing_conflict_diagonal_or_circular_zone.hpp new file mode 100644 index 00000000..2ff286c1 --- /dev/null +++ b/src/ui/qt/processing_view/processing_conflict_diagonal_or_circular_zone.hpp @@ -0,0 +1,46 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include "ui/qt/user_types.hpp" +#include "ui/qt/utils/nodegraph/node.hpp" +#include "ui/qt/utils/nodegraph/text.hpp" +#include "utils/default_locator.hpp" + +namespace domain { +class ConflictDiagonalOrCircularZone; +} // namespace domain + +namespace ui::qt { + +class EditModel; + +//****************************************************************************** +class ProcessingConflictDiagonalOrCircularZone : public nodegraph::Node { +public: + enum { Type = UserTypes::PROCESSING_CONFLICT_DOCZ }; + + struct Params final { + nodegraph::Node::Params const& node = default_locator(); + nodegraph::Text::Params const& title = default_locator(); + nodegraph::Port::Params const& port = default_locator(); + nodegraph::Text::Params const& main = default_locator(); + }; + + std::function locate_processing_conflict_docz_params; + + explicit ProcessingConflictDiagonalOrCircularZone(domain::ConflictDiagonalOrCircularZone const* conflict, QGraphicsItem* parent = nullptr); + + int type() const override; + +private: + friend EditModel; + + domain::ConflictDiagonalOrCircularZone const* const conflict; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/processing_view/processing_interval.cpp b/src/ui/qt/processing_view/processing_interval.cpp index cf883f08..e455b103 100644 --- a/src/ui/qt/processing_view/processing_interval.cpp +++ b/src/ui/qt/processing_view/processing_interval.cpp @@ -8,6 +8,7 @@ #include #include +#include "domain/conflicts/conflict_diagonal_or_circular_zone.hpp" #include "domain/mesh/interval.hpp" #include "domain/mesh/meshline_policy.hpp" #include "ui/qt/data_keys.hpp" @@ -52,6 +53,26 @@ ProcessingInterval::ProcessingInterval(domain::Interval const* interval, QGraphi v_box1->addItem(before_port); v_box1->addStretch(); + if(interval) { + nodegraph::Port* docz_port = nullptr; + auto const& state = interval->get_current_state(); + for(domain::Conflict* conflict : state.conflicts) { + if(auto const* conflict_docz = dynamic_cast(conflict); conflict_docz) { + if(!docz_port) { + docz_port = add_input_port(" "); + docz_port->setFlag(QGraphicsItem::ItemIsSelectable); + docz_port->setAcceptedMouseButtons(Qt::NoButton); + docz_port->locate_port_params = [this]() -> auto& { + return locate_processing_interval_params().port; + }; + v_box1->addItem(docz_port); + v_box1->addStretch(); + } + to_wire.emplace_back(DataKeys::set_to_wire(conflict_docz, docz_port)); + } + } + } + nodegraph::Port* after_port = add_input_port(" "); after_port->setFlag(QGraphicsItem::ItemIsSelectable); after_port->setAcceptedMouseButtons(Qt::NoButton); @@ -69,8 +90,8 @@ ProcessingInterval::ProcessingInterval(domain::Interval const* interval, QGraphi }; QString dmax("dmax: "); - QString before_lmin ("Before.lmin: "); - QString before_smoothness ("Before.Smoothness: "); + QString before_lmin("Before.lmin: "); + QString before_smoothness("Before.Smoothness: "); QString after_lmin("After.lmin: "); QString after_smoothness("After.Smoothness: "); if(interval) { diff --git a/src/ui/qt/processing_view/processing_meshline_policy.cpp b/src/ui/qt/processing_view/processing_meshline_policy.cpp index ee27412c..fb446032 100644 --- a/src/ui/qt/processing_view/processing_meshline_policy.cpp +++ b/src/ui/qt/processing_view/processing_meshline_policy.cpp @@ -8,6 +8,7 @@ #include #include +#include "domain/geometrics/angle.hpp" #include "domain/geometrics/edge.hpp" #include "domain/conflicts/conflict_colinear_edges.hpp" #include "domain/conflicts/conflict_too_close_meshline_policies.hpp" @@ -59,6 +60,7 @@ ProcessingMeshlinePolicy::ProcessingMeshlinePolicy(domain::MeshlinePolicy const* // Downcast from IMeshLineOrigin is mandatory to upcast to Entity. if(auto const* entity = down_up_cast(origin) ; entity) diff --git a/src/ui/qt/processing_view/processing_plane.cpp b/src/ui/qt/processing_view/processing_plane.cpp index d81fbce0..9e654fba 100644 --- a/src/ui/qt/processing_view/processing_plane.cpp +++ b/src/ui/qt/processing_view/processing_plane.cpp @@ -23,6 +23,7 @@ ProcessingPlane::ProcessingPlane(domain::Plane plane, QGraphicsItem* parent) switch(item->type()) { case UserTypes::PROCESSING_CONFLICT_EIP: return 0; case UserTypes::PROCESSING_POLYGON: return 1; + case UserTypes::PROCESSING_ANGLE: return 2; default: return 0; } }; diff --git a/src/ui/qt/processing_view/processing_scene.cpp b/src/ui/qt/processing_view/processing_scene.cpp index c2c132b7..da1199b2 100644 --- a/src/ui/qt/processing_view/processing_scene.cpp +++ b/src/ui/qt/processing_view/processing_scene.cpp @@ -8,8 +8,10 @@ #include #include "domain/conflicts/conflict_colinear_edges.hpp" +#include "domain/conflicts/conflict_diagonal_or_circular_zone.hpp" #include "domain/conflicts/conflict_edge_in_polygon.hpp" #include "domain/conflicts/conflict_too_close_meshline_policies.hpp" +#include "domain/geometrics/angle.hpp" #include "domain/geometrics/edge.hpp" #include "domain/geometrics/polygon.hpp" #include "domain/geometrics/space.hpp" @@ -24,8 +26,10 @@ #include "utils/unreachable.hpp" #include "processing_axis.hpp" #include "processing_conflict_colinear_edges.hpp" +#include "processing_conflict_diagonal_or_circular_zone.hpp" #include "processing_conflict_edge_in_polygon.hpp" #include "processing_conflict_too_close_meshline_policies.hpp" +#include "processing_angle.hpp" #include "processing_edge.hpp" #include "processing_interval.hpp" #include "processing_meshline.hpp" @@ -204,6 +208,17 @@ ProcessingEdge* ProcessingScene::add(domain::Edge* edge, ProcessingPolygon* to_p return processing_edge; } +//****************************************************************************** +ProcessingAngle* ProcessingScene::add(domain::Angle* angle, ProcessingPlane* to_plane) { + auto* processing_angle = add_node(angle, to_plane); + angles.append(processing_angle); + processing_angle->locate_processing_angle_params = [this]() -> auto& { + return style_selector.get_angle(); + }; + processing_angle->updateGeometry(); + return processing_angle; +} + //****************************************************************************** ProcessingConflictColinearEdges* ProcessingScene::add(domain::ConflictColinearEdges* conflict, ProcessingAxis* to_axis) { auto* processing_conflict = add_node(conflict, to_axis); @@ -215,6 +230,17 @@ ProcessingConflictColinearEdges* ProcessingScene::add(domain::ConflictColinearEd return processing_conflict; } +//****************************************************************************** +ProcessingConflictDiagonalOrCircularZone* ProcessingScene::add(domain::ConflictDiagonalOrCircularZone* conflict, ProcessingAxis* to_axis) { + auto* processing_conflict = add_node(conflict, to_axis); + conflict_diagonal_or_circular_zones.append(processing_conflict); + processing_conflict->locate_processing_conflict_docz_params = [this]() -> auto& { + return style_selector.get_conflict_docz(); + }; + processing_conflict->updateGeometry(); + return processing_conflict; +} + //****************************************************************************** ProcessingConflictEdgeInPolygon* ProcessingScene::add(domain::ConflictEdgeInPolygon* conflict, ProcessingPlane* to_plane) { auto* processing_conflict = add_node(conflict, to_plane); @@ -457,11 +483,12 @@ void ProcessingScene::edit_selected_nodes(QPoint const& pos) { //****************************************************************************** void ProcessingScene::edit(QList nodes, QPoint const& pos) { static QList const type_index = { + UserTypes::PROCESSING_ANGLE, UserTypes::PROCESSING_EDGE, UserTypes::PROCESSING_INTERVAL, UserTypes::PROCESSING_MESHLINE_POLICY, UserTypes::PROCESSING_CONFLICT_CE, - UserTypes::PROCESSING_CONFLICT_EIP, + UserTypes::PROCESSING_CONFLICT_DOCZ, UserTypes::PROCESSING_CONFLICT_TCMLP }; diff --git a/src/ui/qt/processing_view/processing_scene.hpp b/src/ui/qt/processing_view/processing_scene.hpp index 0e4ec3ea..8e3d1b2e 100644 --- a/src/ui/qt/processing_view/processing_scene.hpp +++ b/src/ui/qt/processing_view/processing_scene.hpp @@ -23,13 +23,28 @@ class Entity; +namespace domain { +class Polygon; +class Edge; +class Angle; +class ConflictColinearEdges; +class ConflictDiagonalOrCircularZone; +class ConflictEdgeInPolygon; +class ConflictTooCloseMeshlinePolicies; +class MeshlinePolicy; +class Interval; +class Meshline; +} // namespace domain + namespace ui::qt { class ProcessingAxis; class ProcessingPlane; class ProcessingPolygon; class ProcessingEdge; +class ProcessingAngle; class ProcessingConflictColinearEdges; +class ProcessingConflictDiagonalOrCircularZone; class ProcessingConflictEdgeInPolygon; class ProcessingConflictTooCloseMeshlinePolicies; class ProcessingMeshlinePolicy; @@ -60,7 +75,9 @@ class ProcessingScene : public QGraphicsScene { ProcessingAxis* add(domain::Axis axis); ProcessingPolygon* add(domain::Polygon* polygon, ProcessingPlane* to_plane); ProcessingEdge* add(domain::Edge* edge, ProcessingPolygon* to_polygon); + ProcessingAngle* add(domain::Angle* angle, ProcessingPlane* to_plane); ProcessingConflictColinearEdges* add(domain::ConflictColinearEdges* conflict, ProcessingAxis* to_axis); + ProcessingConflictDiagonalOrCircularZone* add(domain::ConflictDiagonalOrCircularZone* conflict, ProcessingAxis* to_axis); ProcessingConflictEdgeInPolygon* add(domain::ConflictEdgeInPolygon* conflict, ProcessingPlane* to_plane); ProcessingConflictTooCloseMeshlinePolicies* add(domain::ConflictTooCloseMeshlinePolicies* conflict, ProcessingAxis* to_axis); ProcessingMeshlinePolicy* add(domain::MeshlinePolicy* policy, ProcessingAxis* to_axis); @@ -91,10 +108,12 @@ class ProcessingScene : public QGraphicsScene { domain::AxisSpace axes; QList polygons; QList edges; + QList angles; QList meshlines; QList meshline_policies; QList intervals; QList conflict_colinear_edges; + QList conflict_diagonal_or_circular_zones; QList conflict_edge_in_polygons; QList conflict_too_close_meshline_policies; diff --git a/src/ui/qt/processing_view/processing_style.cpp b/src/ui/qt/processing_view/processing_style.cpp index 5262d421..e2a81b30 100644 --- a/src/ui/qt/processing_view/processing_style.cpp +++ b/src/ui/qt/processing_view/processing_style.cpp @@ -21,6 +21,7 @@ ProcessingStyleSelector::ProcessingStyleSelector() , text_enabled(make_text_enabled(style)) , text_enabled_for_sure(make_text_enabled_for_sure(style)) , text_disabled(make_text_disabled(style)) +, angle(make_angle()) , edge(make_edge()) , polygon(make_polygon()) , plane(make_plane()) @@ -30,6 +31,7 @@ ProcessingStyleSelector::ProcessingStyleSelector() , meshline(make_meshline()) , conflict_ce(make_conflict_ce()) , conflict_eip(make_conflict_eip()) +, conflict_docz(make_conflict_docz()) , conflict_tcmlp(make_conflict_tcmlp()) {} @@ -47,6 +49,7 @@ ProcessingStyleSelector::ProcessingStyleSelector(ProcessingStyle style) , text_enabled(make_text_enabled(style)) , text_enabled_for_sure(make_text_enabled_for_sure(style)) , text_disabled(make_text_disabled(style)) +, angle(make_angle()) , edge(make_edge()) , polygon(make_polygon()) , plane(make_plane()) @@ -56,6 +59,7 @@ ProcessingStyleSelector::ProcessingStyleSelector(ProcessingStyle style) , meshline(make_meshline()) , conflict_ce(make_conflict_ce()) , conflict_eip(make_conflict_eip()) +, conflict_docz(make_conflict_docz()) , conflict_tcmlp(make_conflict_tcmlp()) {} @@ -283,6 +287,18 @@ MAKER_DEF(ProcessingStyleSelector, text_disabled, ProcessingStyle const& style) }; } +//****************************************************************************** +MAKER_DEF(ProcessingStyleSelector, angle) { + return { + .node = get_node(), + .port = get_port_normal(), + .title = get_title(), + .main = get_text_normal(), + .enabled = get_text_enabled(), + .disabled = get_text_disabled() + }; +} + //****************************************************************************** MAKER_DEF(ProcessingStyleSelector, edge) { return { @@ -381,6 +397,16 @@ MAKER_DEF(ProcessingStyleSelector, conflict_eip) { }; } +//****************************************************************************** +MAKER_DEF(ProcessingStyleSelector, conflict_docz) { + return { + .node = get_node(), + .title = get_title(), + .port = get_port_normal(), + .main = get_text_normal() + }; +} + //****************************************************************************** MAKER_DEF(ProcessingStyleSelector, conflict_tcmlp) { return { diff --git a/src/ui/qt/processing_view/processing_style.hpp b/src/ui/qt/processing_view/processing_style.hpp index 7af98c17..24c0af5d 100644 --- a/src/ui/qt/processing_view/processing_style.hpp +++ b/src/ui/qt/processing_view/processing_style.hpp @@ -12,9 +12,11 @@ #include "ui/qt/utils/nodegraph/rect.hpp" #include "ui/qt/utils/nodegraph/wire.hpp" #include "utils/class_utils.hpp" +#include "processing_angle.hpp" #include "processing_axis.hpp" #include "processing_conflict_colinear_edges.hpp" #include "processing_conflict_edge_in_polygon.hpp" +#include "processing_conflict_diagonal_or_circular_zone.hpp" #include "processing_conflict_too_close_meshline_policies.hpp" #include "processing_edge.hpp" #include "processing_interval.hpp" @@ -161,6 +163,7 @@ class ProcessingStyleSelector { nodegraph::Text::Params text_enabled; nodegraph::Text::Params text_enabled_for_sure; nodegraph::Text::Params text_disabled; + ProcessingAngle::Params const angle; ProcessingEdge::Params const edge; ProcessingPolygon::Params const polygon; ProcessingPlane::Params const plane; @@ -170,6 +173,7 @@ class ProcessingStyleSelector { ProcessingMeshline::Params const meshline; ProcessingConflictColinearEdges::Params const conflict_ce; ProcessingConflictEdgeInPolygon::Params const conflict_eip; + ProcessingConflictDiagonalOrCircularZone::Params const conflict_docz; ProcessingConflictTooCloseMeshlinePolicies::Params const conflict_tcmlp; MAKER_DECL(wire, ProcessingStyle const& style); @@ -184,6 +188,7 @@ class ProcessingStyleSelector { MAKER_DECL(text_enabled_for_sure, ProcessingStyle const& style); MAKER_DECL(text_disabled, ProcessingStyle const& style); + MAKER_DECL(angle); MAKER_DECL(edge); MAKER_DECL(polygon); MAKER_DECL(plane); @@ -193,6 +198,7 @@ class ProcessingStyleSelector { MAKER_DECL(meshline); MAKER_DECL(conflict_ce); MAKER_DECL(conflict_eip); + MAKER_DECL(conflict_docz); MAKER_DECL(conflict_tcmlp); public: @@ -208,6 +214,7 @@ class ProcessingStyleSelector { GETTER(text_enabled) GETTER(text_enabled_for_sure) GETTER(text_disabled) + GETTER(angle) GETTER(edge) GETTER(polygon) GETTER(plane) @@ -217,6 +224,7 @@ class ProcessingStyleSelector { GETTER(meshline) GETTER(conflict_ce) GETTER(conflict_eip) + GETTER(conflict_docz) GETTER(conflict_tcmlp) ProcessingStyleSelector(); diff --git a/src/ui/qt/processing_view/processing_view.cpp b/src/ui/qt/processing_view/processing_view.cpp index 26b2a810..eb21e23e 100644 --- a/src/ui/qt/processing_view/processing_view.cpp +++ b/src/ui/qt/processing_view/processing_view.cpp @@ -159,6 +159,9 @@ void ProcessingView::populate(ProcessingScene* scene) { for(auto const& conflict : board->get_conflicts_edge_in_polygons(plane)) scene->add(conflict.get(), processing_plane); + for(auto const& angle : board->get_angles(plane)) + scene->add(angle.get(), processing_plane); + processing_plane->fit(); } @@ -174,6 +177,9 @@ void ProcessingView::populate(ProcessingScene* scene) { for(auto const& policy : board->get_meshline_policies(axis)) scene->add(policy.get(), processing_axis); + for(auto const& conflict : board->get_conflicts_diagonal_or_circular_zones(axis)) + scene->add(conflict.get(), processing_axis); + for(auto const& interval : board->get_intervals(axis)) scene->add(interval.get(), processing_axis); @@ -186,6 +192,9 @@ void ProcessingView::populate(ProcessingScene* scene) { for(auto* edge : scene->edges) scene->wire_to_destination_first_output_port(edge); + for(auto* angle : scene->angles) + scene->wire_to_destination_first_output_port(angle); + for(auto* conflict : scene->conflict_colinear_edges) scene->wire_to_destination_first_output_port(conflict); @@ -195,6 +204,9 @@ void ProcessingView::populate(ProcessingScene* scene) { for(auto* conflict : scene->conflict_edge_in_polygons) scene->wire_to_destination_first_output_port(conflict); + for(auto* conflict : scene->conflict_diagonal_or_circular_zones) + scene->wire_to_destination_first_output_port(conflict); + for(auto* policy : scene->meshline_policies) scene->wire_to_destination_first_output_port(policy); diff --git a/src/ui/qt/structure_view/structure_angle.cpp b/src/ui/qt/structure_view/structure_angle.cpp new file mode 100644 index 00000000..0e7975cb --- /dev/null +++ b/src/ui/qt/structure_view/structure_angle.cpp @@ -0,0 +1,106 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include +#include + +#include "domain/geometrics/angle.hpp" +#include "ui/qt/data_keys.hpp" +#include "utils/default_locator.hpp" + +#include "structure_angle.hpp" + +namespace ui::qt { + +static qreal constexpr diameter = 5; + +//****************************************************************************** +static QRectF convert(domain::Angle const* angle) { + return QRectF(angle->p.x.value() - diameter/2, angle->p.y.value() - diameter/2, diameter, diameter); +} + +//****************************************************************************** +static domain::ViewAxisSpace convert_cross_lines(domain::Angle const* angle) { + return { + QLineF( // V line -> H axis + angle->p.x.value(), angle->p.y.value() + diameter/2, + angle->p.x.value(), angle->p.y.value() - diameter/2), + QLineF( // H line -> V axis + angle->p.x.value() + diameter/2, angle->p.y.value(), + angle->p.x.value() - diameter/2, angle->p.y.value()) + }; +} + +//****************************************************************************** +StructureAngle::StructureAngle(domain::Angle const* angle, QGraphicsItem* parent) +: QGraphicsEllipseItem(convert(angle), parent) +, locate_structure_angle_params(default_locator) +, angle(angle) +, cross_lines(convert_cross_lines(angle)) +{ + setFlags(ItemIsSelectable); + setAcceptHoverEvents(true); + setAcceptTouchEvents(true); + setData(DataKeys::TYPE, "Angle"); + setData(DataKeys::ID, (qulonglong) angle->id); + setData(DataKeys::ENTITY, DataKeys::set_entity(angle)); +} + +//****************************************************************************** +int StructureAngle::type() const { + return Type; +} + +//****************************************************************************** +void StructureAngle::paint(QPainter* painter, QStyleOptionGraphicsItem const* option, QWidget* /*widget*/) { + Params const& params = locate_structure_angle_params(); + + if(option->state & QStyle::State_Selected) { + if(option->state & QStyle::State_MouseOver) + painter->setPen(params.h_line_selected_hovered); + else + painter->setPen(params.h_line_selected); + } else { + if(option->state & QStyle::State_MouseOver) + painter->setPen(params.h_line_regular_hovered); + else + painter->setPen(params.h_line_regular); + } + + painter->drawLine(cross_lines[domain::H]); + + if(option->state & QStyle::State_Selected) { + if(option->state & QStyle::State_MouseOver) + painter->setPen(params.v_line_selected_hovered); + else + painter->setPen(params.v_line_selected); + } else { + if(option->state & QStyle::State_MouseOver) + painter->setPen(params.v_line_regular_hovered); + else + painter->setPen(params.v_line_regular); + } + + painter->drawLine(cross_lines[domain::V]); + + + if(option->state & QStyle::State_Selected) { + if(option->state & QStyle::State_MouseOver) + painter->setPen(params.circle_selected_hovered); + else + painter->setPen(params.circle_selected); + } else { + if(option->state & QStyle::State_MouseOver) + painter->setPen(params.circle_regular_hovered); + else + painter->setPen(params.circle_regular); + } + + painter->drawEllipse(rect()); +} + +} // namespace ui::qt diff --git a/src/ui/qt/structure_view/structure_angle.hpp b/src/ui/qt/structure_view/structure_angle.hpp new file mode 100644 index 00000000..6c8d6cf5 --- /dev/null +++ b/src/ui/qt/structure_view/structure_angle.hpp @@ -0,0 +1,56 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include +#include + +#include + +#include "domain/geometrics/space.hpp" +#include "ui/qt/user_types.hpp" + +namespace domain { +class Angle; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class StructureAngle : public QGraphicsEllipseItem { +public: + enum { Type = UserTypes::STRUCTURE_ANGLE }; + + struct Params final { +// qreal radius = 2; // TODO + QPen circle_regular = QPen(Qt::NoPen); + QPen circle_selected = QPen(Qt::blue, 0.1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); + QPen circle_regular_hovered = circle_regular; + QPen circle_selected_hovered = circle_selected; + QPen h_line_regular = QPen(Qt::NoPen); + QPen h_line_selected = QPen(Qt::blue, 0.1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); + QPen h_line_regular_hovered = h_line_regular; + QPen h_line_selected_hovered = h_line_selected; + QPen v_line_regular = QPen(Qt::NoPen); + QPen v_line_selected = QPen(Qt::blue, 0.1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); + QPen v_line_regular_hovered = v_line_regular; + QPen v_line_selected_hovered = v_line_selected; + }; + + std::function locate_structure_angle_params; + + explicit StructureAngle(domain::Angle const* angle, QGraphicsItem* parent = nullptr); + + int type() const override; + void paint(QPainter* painter, QStyleOptionGraphicsItem const* option, QWidget* widget = nullptr) override; + +private: + domain::Angle const* const angle; + domain::ViewAxisSpace const cross_lines; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/structure_view/structure_conflict_diagonal_or_circular_zone.cpp b/src/ui/qt/structure_view/structure_conflict_diagonal_or_circular_zone.cpp new file mode 100644 index 00000000..da3009c0 --- /dev/null +++ b/src/ui/qt/structure_view/structure_conflict_diagonal_or_circular_zone.cpp @@ -0,0 +1,90 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include +#include + +#include "domain/geometrics/angle.hpp" +#include "domain/conflicts/conflict_diagonal_or_circular_zone.hpp" +#include "utils/default_locator.hpp" +#include "utils/unreachable.hpp" +#include "ui/qt/data_keys.hpp" + +#include "structure_conflict_diagonal_or_circular_zone.hpp" + +namespace ui::qt { + +//****************************************************************************** +static QRectF convert(domain::ViewAxis axis, domain::ConflictDiagonalOrCircularZone const* conflict, QRectF scene_rect) { + qreal side = qMax(scene_rect.width(), scene_rect.height()); + scene_rect += QMarginsF(side, side, side, side) * 2; + auto bounding = conflict->bounding(); + + switch(axis) { + case domain::ViewAxis::H: + return QRectF( + QPointF(scene_rect.left(), bounding[domain::XMIN].value()), + QPointF(scene_rect.right(), bounding[domain::XMAX].value())); + case domain::ViewAxis::V: + return QRectF( + QPointF(bounding[domain::XMIN].value(), scene_rect.bottom()), + QPointF(bounding[domain::XMAX].value(), scene_rect.top())); + default: + unreachable(); + } +} + +//****************************************************************************** +StructureConflictDiagonalOrCircularZone::StructureConflictDiagonalOrCircularZone(domain::ViewAxis axis, domain::ConflictDiagonalOrCircularZone const* conflict, QRectF const& scene_rect, QGraphicsItem* parent) +: QGraphicsRectItem(convert(axis, conflict, scene_rect), parent) +, locate_structure_conflict_docz_params(default_locator) +, axis(axis) +, conflict(conflict) +{ + setFlags(ItemIsSelectable); + + setData(DataKeys::TYPE, "ConflictDiagonalOrCircularZone"); + setData(DataKeys::ID, (qulonglong) conflict->id); + setData(DataKeys::ENTITY, DataKeys::set_entity(conflict)); +// setData(DataKeys::NAME, QString::fromStdString(conflict->name)); +} + +//****************************************************************************** +int StructureConflictDiagonalOrCircularZone::type() const { + return Type; +} + +//****************************************************************************** +QVariant StructureConflictDiagonalOrCircularZone::itemChange(GraphicsItemChange change, QVariant const& value) { + if(change == ItemSelectedChange) { + // StructureConflictDiagonalOrCircularZone is almost always zoomed enough to disable repaint trigger. + prepareGeometryChange(); + update(); + } + return QGraphicsItem::itemChange(change, value); +} + +//****************************************************************************** +void StructureConflictDiagonalOrCircularZone::paint(QPainter* painter, QStyleOptionGraphicsItem const* option, QWidget* /*widget*/) { + Params const& params = locate_structure_conflict_docz_params(); + + if(option->state & QStyle::State_Selected) { + if(option->state & QStyle::State_MouseOver) + painter->setBrush(params.selected_hovered); + else + painter->setBrush(params.selected); + } else { + if(option->state & QStyle::State_MouseOver) + painter->setBrush(params.regular_hovered); + else + painter->setBrush(params.regular); + } + + painter->setPen(Qt::NoPen); + painter->drawRect(rect()); +} + +} // namespace ui::qt diff --git a/src/ui/qt/structure_view/structure_conflict_diagonal_or_circular_zone.hpp b/src/ui/qt/structure_view/structure_conflict_diagonal_or_circular_zone.hpp new file mode 100644 index 00000000..d1d686ef --- /dev/null +++ b/src/ui/qt/structure_view/structure_conflict_diagonal_or_circular_zone.hpp @@ -0,0 +1,51 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include +#include + +#include + +#include "domain/geometrics/space.hpp" +#include "ui/qt/user_types.hpp" + +namespace domain { +class ConflictDiagonalOrCircularZone; +} // namespace domain + +namespace ui::qt { + +//****************************************************************************** +class StructureConflictDiagonalOrCircularZone : public QGraphicsRectItem { +public: + enum { Type = UserTypes::STRUCTURE_CONFLICT_DOCZ }; + + struct Params final { + QBrush regular = Qt::transparent; + QBrush selected = QColor(255, 0, 0, 100); + QBrush regular_hovered = regular; + QBrush selected_hovered = selected; + }; + + std::function locate_structure_conflict_docz_params; + + StructureConflictDiagonalOrCircularZone(domain::ViewAxis axis, domain::ConflictDiagonalOrCircularZone const* conflict, QRectF const& scene_rect, QGraphicsItem* parent = nullptr); + + 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; + +private: + domain::ConflictDiagonalOrCircularZone const* const conflict; +}; + +} // namespace ui::qt diff --git a/src/ui/qt/structure_view/structure_scene.cpp b/src/ui/qt/structure_view/structure_scene.cpp index e6a58dd5..47e91107 100644 --- a/src/ui/qt/structure_view/structure_scene.cpp +++ b/src/ui/qt/structure_view/structure_scene.cpp @@ -14,9 +14,11 @@ #include #include "domain/conflicts/conflict_colinear_edges.hpp" +#include "domain/conflicts/conflict_diagonal_or_circular_zone.hpp" #include "domain/conflicts/conflict_too_close_meshline_policies.hpp" #include "domain/geometrics/polygon.hpp" #include "domain/geometrics/edge.hpp" +#include "domain/geometrics/angle.hpp" #include "domain/mesh/interval.hpp" #include "domain/mesh/meshline.hpp" #include "domain/mesh/meshline_policy.hpp" @@ -24,7 +26,9 @@ #include "ui/qt/data_keys.hpp" #include "ui/qt/icons.hpp" #include "ui/qt/user_types.hpp" +#include "structure_angle.hpp" #include "structure_conflict_colinear_edges.hpp" +#include "structure_conflict_diagonal_or_circular_zone.hpp" #include "structure_conflict_too_close_meshline_policies.hpp" #include "structure_edge.hpp" #include "structure_interval.hpp" @@ -59,7 +63,9 @@ StructureScene::StructureScene(StructureStyleSelector& style_selector, QObject* , style_selector(style_selector) , edges(new StructureGroup()) , polygons(new StructureGroup()) +, angles(new StructureGroup()) , conflict_colinear_edges{{ new StructureGroup(), new StructureGroup() }} +, conflict_diagonal_or_circular_zones{{ new StructureGroup(), new StructureGroup() }} , conflict_too_close_meshline_policies{{ new StructureGroup(), new StructureGroup() }} , intervals{{ new StructureGroup(), new StructureGroup() }} , meshlines{{ new StructureGroup(), new StructureGroup() }} @@ -69,8 +75,10 @@ StructureScene::StructureScene(StructureStyleSelector& style_selector, QObject* // Adding order matters. addItem(edges); addItem(polygons); + addItem(angles); for(auto const& list : { meshlines, + conflict_diagonal_or_circular_zones, intervals, meshline_policies, conflict_colinear_edges, @@ -80,8 +88,11 @@ StructureScene::StructureScene(StructureStyleSelector& style_selector, QObject* addItem(group); polygons->stackBefore(edges); + polygons->stackBefore(angles); + angles->stackBefore(edges); for(auto const& list : { meshlines, + conflict_diagonal_or_circular_zones, intervals, meshline_policies, conflict_colinear_edges, @@ -102,6 +113,33 @@ StructureScene::~StructureScene() { this, &StructureScene::on_selectionChanged); } +//****************************************************************************** +StructureAngle* StructureScene::add(domain::Angle const* angle) { + auto* item = new StructureAngle(angle, angles); + index[angle] = item; + auto const& state_a = angle->get_current_state(); + if(state_a.to_mesh[domain::H] && state_a.to_mesh[domain::V]) { + item->locate_structure_angle_params = [this]() -> auto& { + return style_selector.get_angle_hv_enabled(); + }; + } else if(state_a.to_mesh[domain::H] && !(state_a.to_mesh[domain::V])) { + item->locate_structure_angle_params = [this]() -> auto& { + return style_selector.get_angle_h_enabled(); + }; + } else if(!(state_a.to_mesh[domain::H]) && state_a.to_mesh[domain::V]) { + item->locate_structure_angle_params = [this]() -> auto& { + return style_selector.get_angle_v_enabled(); + }; + } else if(!(state_a.to_mesh[domain::H]) && !(state_a.to_mesh[domain::V])) { + item->locate_structure_angle_params = [this]() -> auto& { + return style_selector.get_angle_hv_disabled(); + }; + } else { + unreachable(); + } + return item; +} + //****************************************************************************** StructureEdge* StructureScene::add(domain::Edge const* edge) { auto* item = new StructureEdge(edge, edges); @@ -162,6 +200,17 @@ StructureConflictColinearEdges* StructureScene::add(domain::ConflictColinearEdge return item; } +//****************************************************************************** +StructureConflictDiagonalOrCircularZone* StructureScene::add(domain::ConflictDiagonalOrCircularZone const* conflict, domain::ViewAxis view_axis, QRectF const& scene_rect) { + auto const meshline_axis = reverse(view_axis); // Let stick to meshline axis definition. + auto* item = new StructureConflictDiagonalOrCircularZone(meshline_axis, conflict, scene_rect, conflict_diagonal_or_circular_zones[meshline_axis]); + index[conflict] = item; + item->locate_structure_conflict_docz_params = [this]() ->auto& { + return style_selector.get_conflict_docz(); + }; + return item; +} + //****************************************************************************** StructureConflictTooCloseMeshlinePolicies* StructureScene::add(domain::ConflictTooCloseMeshlinePolicies const* conflict, domain::ViewAxis view_axis, QRectF const& scene_rect) { auto const meshline_axis = reverse(view_axis); // Let stick to meshline axis definition. @@ -224,6 +273,7 @@ void StructureScene::clear_edges() { addItem(edges); polygons->stackBefore(edges); + angles->stackBefore(edges); for(auto const* group : meshlines) edges->stackBefore(group); } @@ -240,6 +290,7 @@ void StructureScene::clear_polygons() { addItem(polygons); polygons->stackBefore(edges); + polygons->stackBefore(angles); } //****************************************************************************** @@ -304,6 +355,7 @@ void StructureScene::mousePressEvent(QGraphicsSceneMouseEvent* event) { static QList const ordered_type_index = { UserTypes::STRUCTURE_EDGE, UserTypes::STRUCTURE_POLYGON, + UserTypes::STRUCTURE_ANGLE, UserTypes::STRUCTURE_MESHLINE }; diff --git a/src/ui/qt/structure_view/structure_scene.hpp b/src/ui/qt/structure_view/structure_scene.hpp index 17733b56..d3cded96 100644 --- a/src/ui/qt/structure_view/structure_scene.hpp +++ b/src/ui/qt/structure_view/structure_scene.hpp @@ -17,7 +17,9 @@ class Entity; namespace domain { +class Angle; class ConflictColinearEdges; +class ConflictDiagonalOrCircularZone; class ConflictTooCloseMeshlinePolicies; class Edge; class Interval; @@ -28,7 +30,9 @@ class Polygon; namespace ui::qt { +class StructureAngle; class StructureConflictColinearEdges; +class StructureConflictDiagonalOrCircularZone; class StructureConflictTooCloseMeshlinePolicies; class StructureEdge; class StructureInterval; @@ -59,9 +63,11 @@ class StructureScene : public QGraphicsScene { explicit StructureScene(StructureStyleSelector& style_selector, QObject* parent = nullptr); ~StructureScene() override; + StructureAngle* add(domain::Angle const* angle); StructureEdge* add(domain::Edge const* edge); StructurePolygon* add(domain::Polygon const* polygon); StructureConflictColinearEdges* add(domain::ConflictColinearEdges const* conflict, domain::ViewAxis view_axis, QRectF const& scene_rect); + StructureConflictDiagonalOrCircularZone* add(domain::ConflictDiagonalOrCircularZone const* conflict, domain::ViewAxis view_axis, QRectF const& scene_rect); StructureConflictTooCloseMeshlinePolicies* add(domain::ConflictTooCloseMeshlinePolicies const* conflict, domain::ViewAxis view_axis, QRectF const& scene_rect); StructureInterval* add(domain::Interval const* interval, domain::ViewAxis view_axis, QRectF const& scene_rect); StructureMeshline* add(domain::Meshline const* meshline, domain::ViewAxis view_axis, QRectF const& scene_rect); @@ -80,7 +86,9 @@ class StructureScene : public QGraphicsScene { // TODO structure item layer + z value StructureGroup* edges; StructureGroup* polygons; + StructureGroup* angles; domain::ViewAxisSpace conflict_colinear_edges; + domain::ViewAxisSpace conflict_diagonal_or_circular_zones; domain::ViewAxisSpace conflict_too_close_meshline_policies; domain::ViewAxisSpace intervals; domain::ViewAxisSpace meshlines; diff --git a/src/ui/qt/structure_view/structure_style.cpp b/src/ui/qt/structure_view/structure_style.cpp index fdd52732..8e5cefd9 100644 --- a/src/ui/qt/structure_view/structure_style.cpp +++ b/src/ui/qt/structure_view/structure_style.cpp @@ -10,7 +10,11 @@ namespace ui::qt { //****************************************************************************** StructureStyleSelector::StructureStyleSelector() -: edge(make_edge(style)) +: angle_hv_enabled(make_angle_hv_enabled(style)) +, angle_h_enabled(make_angle_h_enabled(style)) +, angle_v_enabled(make_angle_v_enabled(style)) +, angle_hv_disabled(make_angle_hv_disabled(style)) +, edge(make_edge(style)) , polygon_shape(make_polygon_shape(style)) , polygon_port(make_polygon_port(style)) , polygon_ground(make_polygon_ground(style)) @@ -20,12 +24,17 @@ StructureStyleSelector::StructureStyleSelector() , meshline_policy_disabled(make_meshline_policy_disabled(style)) , interval(make_interval(style)) , conflict_ce(make_conflict_ce(style)) +, conflict_docz(make_conflict_docz(style)) , conflict_tcmlp(make_conflict_tcmlp(style)) {} //****************************************************************************** StructureStyleSelector::StructureStyleSelector(StructureStyle style) : style(std::move(style)) +, angle_hv_enabled(make_angle_hv_enabled(style)) +, angle_h_enabled(make_angle_h_enabled(style)) +, angle_v_enabled(make_angle_v_enabled(style)) +, angle_hv_disabled(make_angle_hv_disabled(style)) , edge(make_edge(style)) , polygon_shape(make_polygon_shape(style)) , polygon_port(make_polygon_port(style)) @@ -36,12 +45,17 @@ StructureStyleSelector::StructureStyleSelector(StructureStyle style) , meshline_policy_disabled(make_meshline_policy_disabled(style)) , interval(make_interval(style)) , conflict_ce(make_conflict_ce(style)) +, conflict_docz(make_conflict_docz(style)) , conflict_tcmlp(make_conflict_tcmlp(style)) {} //****************************************************************************** StructureStyleSelector& StructureStyleSelector::operator=(StructureStyle const& style) { this->style = style; + angle_hv_enabled = make_angle_hv_enabled(style); + angle_h_enabled = make_angle_h_enabled(style); + angle_v_enabled = make_angle_v_enabled(style); + angle_hv_disabled = make_angle_hv_disabled(style); edge = make_edge(style); polygon_shape = make_polygon_shape(style); polygon_port = make_polygon_port(style); @@ -52,6 +66,7 @@ StructureStyleSelector& StructureStyleSelector::operator=(StructureStyle const& meshline_policy_disabled = make_meshline_policy_disabled(style); interval = make_interval(style); conflict_ce = make_conflict_ce(style); + conflict_docz = make_conflict_docz(style); conflict_tcmlp = make_conflict_tcmlp(style); return *this; } @@ -59,6 +74,10 @@ StructureStyleSelector& StructureStyleSelector::operator=(StructureStyle const& //****************************************************************************** StructureStyleSelector& StructureStyleSelector::operator=(StructureStyle&& style) { this->style = std::move(style); + angle_hv_enabled = make_angle_hv_enabled(style); + angle_h_enabled = make_angle_h_enabled(style); + angle_v_enabled = make_angle_v_enabled(style); + angle_hv_disabled = make_angle_hv_disabled(style); edge = make_edge(style); polygon_shape = make_polygon_shape(style); polygon_port = make_polygon_port(style); @@ -69,10 +88,83 @@ StructureStyleSelector& StructureStyleSelector::operator=(StructureStyle&& style meshline_policy_disabled = make_meshline_policy_disabled(style); interval = make_interval(style); conflict_ce = make_conflict_ce(style); + conflict_docz = make_conflict_docz(style); conflict_tcmlp = make_conflict_tcmlp(style); return *this; } +//****************************************************************************** +MAKER_DEF(StructureStyleSelector, angle_hv_enabled, StructureStyle const& style) { + return { + .circle_regular = QPen(style.angle_circle_regular, 0.1, Qt::SolidLine), + .circle_selected = QPen(style.angle_circle_selected, 0.1, Qt::SolidLine), + .circle_regular_hovered = QPen(style.angle_circle_regular_hovered, 0.1, Qt::SolidLine), + .circle_selected_hovered = QPen(style.angle_circle_selected_hovered, 0.1, Qt::SolidLine), + .h_line_regular = QPen(style.angle_cross_line_enabled_regular, 0.1, Qt::SolidLine), + .h_line_selected = QPen(style.angle_cross_line_enabled_selected, 0.1, Qt::SolidLine), + .h_line_regular_hovered = QPen(style.angle_cross_line_enabled_regular_hovered, 0.1, Qt::SolidLine), + .h_line_selected_hovered = QPen(style.angle_cross_line_enabled_selected_hovered, 0.1, Qt::SolidLine), + .v_line_regular = QPen(style.angle_cross_line_enabled_regular, 0.1, Qt::SolidLine), + .v_line_selected = QPen(style.angle_cross_line_enabled_selected, 0.1, Qt::SolidLine), + .v_line_regular_hovered = QPen(style.angle_cross_line_enabled_regular_hovered, 0.1, Qt::SolidLine), + .v_line_selected_hovered = QPen(style.angle_cross_line_enabled_selected_hovered, 0.1, Qt::SolidLine) + }; +} + +//****************************************************************************** +MAKER_DEF(StructureStyleSelector, angle_h_enabled, StructureStyle const& style) { + return { + .circle_regular = QPen(style.angle_circle_regular, 0.1, Qt::SolidLine), + .circle_selected = QPen(style.angle_circle_selected, 0.1, Qt::SolidLine), + .circle_regular_hovered = QPen(style.angle_circle_regular_hovered, 0.1, Qt::SolidLine), + .circle_selected_hovered = QPen(style.angle_circle_selected_hovered, 0.1, Qt::SolidLine), + .h_line_regular = QPen(style.angle_cross_line_enabled_regular, 0.1, Qt::SolidLine), + .h_line_selected = QPen(style.angle_cross_line_enabled_selected, 0.1, Qt::SolidLine), + .h_line_regular_hovered = QPen(style.angle_cross_line_enabled_regular_hovered, 0.1, Qt::SolidLine), + .h_line_selected_hovered = QPen(style.angle_cross_line_enabled_selected_hovered, 0.1, Qt::SolidLine), + .v_line_regular = QPen(style.angle_cross_line_disabled_regular, 0.1, Qt::SolidLine), + .v_line_selected = QPen(style.angle_cross_line_disabled_selected, 0.1, Qt::SolidLine), + .v_line_regular_hovered = QPen(style.angle_cross_line_disabled_regular_hovered, 0.1, Qt::SolidLine), + .v_line_selected_hovered = QPen(style.angle_cross_line_disabled_selected_hovered, 0.1, Qt::SolidLine) + }; +} + +//****************************************************************************** +MAKER_DEF(StructureStyleSelector, angle_v_enabled, StructureStyle const& style) { + return { + .circle_regular = QPen(style.angle_circle_regular, 0.1, Qt::SolidLine), + .circle_selected = QPen(style.angle_circle_selected, 0.1, Qt::SolidLine), + .circle_regular_hovered = QPen(style.angle_circle_regular_hovered, 0.1, Qt::SolidLine), + .circle_selected_hovered = QPen(style.angle_circle_selected_hovered, 0.1, Qt::SolidLine), + .h_line_regular = QPen(style.angle_cross_line_disabled_regular, 0.1, Qt::SolidLine), + .h_line_selected = QPen(style.angle_cross_line_disabled_selected, 0.1, Qt::SolidLine), + .h_line_regular_hovered = QPen(style.angle_cross_line_disabled_regular_hovered, 0.1, Qt::SolidLine), + .h_line_selected_hovered = QPen(style.angle_cross_line_disabled_selected_hovered, 0.1, Qt::SolidLine), + .v_line_regular = QPen(style.angle_cross_line_enabled_regular, 0.1, Qt::SolidLine), + .v_line_selected = QPen(style.angle_cross_line_enabled_selected, 0.1, Qt::SolidLine), + .v_line_regular_hovered = QPen(style.angle_cross_line_enabled_regular_hovered, 0.1, Qt::SolidLine), + .v_line_selected_hovered = QPen(style.angle_cross_line_enabled_selected_hovered, 0.1, Qt::SolidLine) + }; +} + +//****************************************************************************** +MAKER_DEF(StructureStyleSelector, angle_hv_disabled, StructureStyle const& style) { + return { + .circle_regular = QPen(style.angle_circle_regular, 0.1, Qt::SolidLine), + .circle_selected = QPen(style.angle_circle_selected, 0.1, Qt::SolidLine), + .circle_regular_hovered = QPen(style.angle_circle_regular_hovered, 0.1, Qt::SolidLine), + .circle_selected_hovered = QPen(style.angle_circle_selected_hovered, 0.1, Qt::SolidLine), + .h_line_regular = QPen(style.angle_cross_line_disabled_regular, 0.1, Qt::SolidLine), + .h_line_selected = QPen(style.angle_cross_line_disabled_selected, 0.1, Qt::SolidLine), + .h_line_regular_hovered = QPen(style.angle_cross_line_disabled_regular_hovered, 0.1, Qt::SolidLine), + .h_line_selected_hovered = QPen(style.angle_cross_line_disabled_selected_hovered, 0.1, Qt::SolidLine), + .v_line_regular = QPen(style.angle_cross_line_disabled_regular, 0.1, Qt::SolidLine), + .v_line_selected = QPen(style.angle_cross_line_disabled_selected, 0.1, Qt::SolidLine), + .v_line_regular_hovered = QPen(style.angle_cross_line_disabled_regular_hovered, 0.1, Qt::SolidLine), + .v_line_selected_hovered = QPen(style.angle_cross_line_disabled_selected_hovered, 0.1, Qt::SolidLine) + }; +} + //****************************************************************************** MAKER_DEF(StructureStyleSelector, edge, StructureStyle const& style) { return { @@ -197,6 +289,16 @@ MAKER_DEF(StructureStyleSelector, conflict_ce, StructureStyle const& style) { }; } +//****************************************************************************** +MAKER_DEF(StructureStyleSelector, conflict_docz, StructureStyle const& style) { + return { + .regular = QBrush(style.conflict_docz_regular), + .selected = QBrush(style.conflict_docz_selected), + .regular_hovered = QBrush(style.conflict_docz_regular_hovered), + .selected_hovered = QBrush(style.conflict_docz_selected_hovered) + }; +} + //****************************************************************************** MAKER_DEF(StructureStyleSelector, conflict_tcmlp, StructureStyle const& style) { return { diff --git a/src/ui/qt/structure_view/structure_style.hpp b/src/ui/qt/structure_view/structure_style.hpp index 6aa3e11f..4d8fff97 100644 --- a/src/ui/qt/structure_view/structure_style.hpp +++ b/src/ui/qt/structure_view/structure_style.hpp @@ -9,7 +9,9 @@ #include #include "utils/class_utils.hpp" +#include "structure_angle.hpp" #include "structure_conflict_colinear_edges.hpp" +#include "structure_conflict_diagonal_or_circular_zone.hpp" #include "structure_conflict_too_close_meshline_policies.hpp" #include "structure_edge.hpp" #include "structure_interval.hpp" @@ -35,6 +37,22 @@ struct StructureStyle { QColor edge_selected_hovered = edge_selected; + QColor angle_circle_regular = Qt::transparent; + QColor angle_circle_selected = Qt::red; + QColor angle_circle_regular_hovered = angle_circle_regular; + QColor angle_circle_selected_hovered = angle_circle_selected; + + QColor angle_cross_line_enabled_regular = Qt::transparent; + QColor angle_cross_line_enabled_selected = Qt::green; + QColor angle_cross_line_enabled_regular_hovered = angle_cross_line_enabled_regular; + QColor angle_cross_line_enabled_selected_hovered = angle_cross_line_enabled_selected; + + QColor angle_cross_line_disabled_regular = Qt::transparent; + QColor angle_cross_line_disabled_selected = Qt::red; + QColor angle_cross_line_disabled_regular_hovered = angle_cross_line_disabled_regular; + QColor angle_cross_line_disabled_selected_hovered = angle_cross_line_disabled_selected; + + QColor polygon_shape_contour_regular = Qt::black; QColor polygon_shape_contour_selected = polygon_shape_contour_regular; QColor polygon_shape_contour_regular_hovered = polygon_shape_contour_regular; @@ -115,6 +133,12 @@ struct StructureStyle { QColor conflict_ce_selected_hovered = conflict_ce_selected; + QColor conflict_docz_regular = Qt::transparent; + QColor conflict_docz_selected = QColor(255, 0, 0, 100); + QColor conflict_docz_regular_hovered = conflict_ce_regular; + QColor conflict_docz_selected_hovered = conflict_ce_selected; + + QColor conflict_tcmlp_solution_line_regular = Qt::transparent; QColor conflict_tcmlp_solution_line_selected = Qt::green; QColor conflict_tcmlp_solution_line_regular_hovered = conflict_tcmlp_solution_line_regular; @@ -129,6 +153,10 @@ struct StructureStyle { class StructureStyleSelector { StructureStyle style; + StructureAngle::Params angle_hv_enabled; + StructureAngle::Params angle_h_enabled; + StructureAngle::Params angle_v_enabled; + StructureAngle::Params angle_hv_disabled; StructureEdge::Params edge; StructurePolygon::Params polygon_shape; StructurePolygon::Params polygon_port; @@ -139,8 +167,13 @@ class StructureStyleSelector { StructureMeshlinePolicy::Params meshline_policy_disabled; StructureInterval::Params interval; StructureConflictColinearEdges::Params conflict_ce; + StructureConflictDiagonalOrCircularZone::Params conflict_docz; StructureConflictTooCloseMeshlinePolicies::Params conflict_tcmlp; + MAKER_DECL(angle_hv_enabled, StructureStyle const& style); + MAKER_DECL(angle_h_enabled, StructureStyle const& style); + MAKER_DECL(angle_v_enabled, StructureStyle const& style); + MAKER_DECL(angle_hv_disabled, StructureStyle const& style); MAKER_DECL(edge, StructureStyle const& style); MAKER_DECL(polygon_shape, StructureStyle const& style); MAKER_DECL(polygon_port, StructureStyle const& style); @@ -151,10 +184,15 @@ class StructureStyleSelector { MAKER_DECL(meshline_policy_disabled, StructureStyle const& style); MAKER_DECL(interval, StructureStyle const& style); MAKER_DECL(conflict_ce, StructureStyle const& style); + MAKER_DECL(conflict_docz, StructureStyle const& style); MAKER_DECL(conflict_tcmlp, StructureStyle const& style); public: GETTER(style) + GETTER(angle_hv_enabled) + GETTER(angle_h_enabled) + GETTER(angle_v_enabled) + GETTER(angle_hv_disabled) GETTER(edge) GETTER(polygon_shape) GETTER(polygon_port) @@ -165,6 +203,7 @@ class StructureStyleSelector { GETTER(meshline_policy_disabled) GETTER(interval) GETTER(conflict_ce) + GETTER(conflict_docz) GETTER(conflict_tcmlp) StructureStyleSelector(); diff --git a/src/ui/qt/structure_view/structure_view.cpp b/src/ui/qt/structure_view/structure_view.cpp index 24685a88..833adccc 100644 --- a/src/ui/qt/structure_view/structure_view.cpp +++ b/src/ui/qt/structure_view/structure_view.cpp @@ -232,6 +232,9 @@ void StructureView::populate(domain::PlaneSpace scenes) { scenes[plane]->add(edge.get()); } + for(auto const& angle : board->get_angles(plane)) + scenes[plane]->add(angle.get()); + QRectF const scene_rect(scenes[plane]->sceneRect()); for(domain::Axis const axis : domain::Axes[plane]) { @@ -248,6 +251,9 @@ void StructureView::populate(domain::PlaneSpace scenes) { for(auto const& conflict : board->get_conflicts_colinear_edges(axis)) scenes[plane]->add(conflict.get(), view_axis.value(), scene_rect); + for(auto const& conflict : board->get_conflicts_diagonal_or_circular_zones(axis)) + scenes[plane]->add(conflict.get(), view_axis.value(), scene_rect); + for(auto const& conflict : board->get_conflicts_too_close_meshline_policies(axis)) scenes[plane]->add(conflict.get(), view_axis.value(), scene_rect); } diff --git a/src/ui/qt/user_types.hpp b/src/ui/qt/user_types.hpp index be653cc1..005fd69e 100644 --- a/src/ui/qt/user_types.hpp +++ b/src/ui/qt/user_types.hpp @@ -15,19 +15,23 @@ namespace ui::qt { namespace UserTypes { enum UserTypes { STRUCTURE_EDGE = QGraphicsItem::UserType + 1, + STRUCTURE_ANGLE, STRUCTURE_POLYGON, STRUCTURE_INTERVAL, STRUCTURE_MESHLINE, STRUCTURE_MESHLINE_POLICY, STRUCTURE_CONFLICT_CE, + STRUCTURE_CONFLICT_DOCZ, STRUCTURE_CONFLICT_TCMLP, PROCESSING_EDGE, + PROCESSING_ANGLE, PROCESSING_POLYGON, PROCESSING_INTERVAL, PROCESSING_MESHLINE, PROCESSING_MESHLINE_POLICY, PROCESSING_CONFLICT_CE, PROCESSING_CONFLICT_EIP, + PROCESSING_CONFLICT_DOCZ, PROCESSING_CONFLICT_TCMLP, PROCESSING_AXIS, PROCESSING_PLANE diff --git a/src/utils/vector_utils.hpp b/src/utils/vector_utils.hpp index c6b1f2f3..c2c81515 100644 --- a/src/utils/vector_utils.hpp +++ b/src/utils/vector_utils.hpp @@ -49,3 +49,27 @@ bool contains_that(std::vector const& vector, P&& predicate) noexcept { return std::ranges::find_if(vector, std::forward(predicate)) != std::end(vector); } + +// TODO T = PointerLike or reference +//****************************************************************************** +template +std::vector> +find_consecutive_matches(std::vector const& original, P const& predicate) { + std::vector> result; + + bool does_prev_matched = false; + for(auto const& it : original) { + if(predicate(it)) { + if(does_prev_matched) { + result.back().emplace_back(it); + } else { + result.push_back({ it }); + } + does_prev_matched = true; + } else { + does_prev_matched = false; + } + } + + return result; +} diff --git a/test/MStest.csx b/test/MStest.csx new file mode 100644 index 00000000..cc40375d --- /dev/null +++ b/test/MStest.csx @@ -0,0 +1,545 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.714196,12.857024,15.000000,17.487449,18.752007,19.394613,19.721164,19.887106,19.971432,20.014284,20.057140,20.100000,20.142860,20.185716,20.228568,20.311647,20.472717,20.784991,21.390415,22.564183,24.838700,26.947199,28.108294,28.746893,29.098120,29.291294,29.397540,29.455974,29.488113,29.520255,29.552400,29.582401,29.612403,29.642397,29.688091,29.757701,29.863700,29.952356,30.040964,30.129518,30.300192,30.629141,31.263140,32.485077,34.838700,37.094174,38.314635,38.974834,39.331963,39.525149,39.629651,39.734176,39.838700,39.936689,40.034680,40.132660,40.233969,40.338700,40.434184,40.529668,40.625132,40.771392,40.995475,41.338700,41.664989,41.991257,42.317487,42.685317,43.100000,43.528595,43.957161,44.385678,45.019054,45.955223,47.338700,48.752353,49.619546,50.151322,50.477417,50.677383,50.877392,51.077400,51.277408,51.477417,51.677383,52.069593,52.838700,53.506891,53.861669,54.050008,54.149992,54.249996,54.350000,54.443796,54.537541,54.631229,54.799137,55.100000,55.400863,55.568771,55.662459,55.756204,55.850000,55.957149,56.064290,56.171420,56.373705,56.755669,57.476908,58.838700,60.356388,61.357383,62.017434,62.677889,63.338700,64.119804,64.627383,64.957161,65.171420,65.385702,65.600000,65.800008,66.000017,66.199983,66.535875,67.100000,67.528595,67.957161,68.385678,69.059568,70.119332,71.785926,74.405700,77.108292,79.810699 + -107.478109,-103.343972,-99.209550,-94.647291,-92.171892,-90.829225,-90.100956,-89.705939,-89.491680,-89.277398,-89.063100,-88.848802,-88.634520,-88.420261,-88.071139,-87.502265,-86.575600,-85.648935,-85.080061,-84.730939,-84.516680,-84.302398,-84.088100,-83.873802,-83.659520,-83.445261,-83.056787,-82.352441,-81.075600,-79.856671,-79.192748,-78.831298,-78.634520,-78.527390,-78.420249,-78.313100,-78.219304,-78.125559,-78.031871,-77.863963,-77.563100,-77.262237,-77.094329,-77.000641,-76.906896,-76.813100,-76.705951,-76.598810,-76.491680,-76.292387,-75.921638,-75.231930,-73.948860,-71.563100,-69.026525,-67.624019,-66.848778,-66.420261,-65.991695,-65.563100,-65.134505,-64.705939,-64.277422,-63.491565,-62.050386,-59.407412,-54.563100,-49.791581,-47.225440,-45.846024,-45.104527,-44.705939,-44.491680,-44.277398,-44.063100,-43.833142,-43.625559,-43.438183,-43.250692,-43.063100,-42.875508,-42.688017,-42.500641,-42.293058,-42.063100,-41.833142,-41.625559,-41.438183,-41.250692,-41.063100,-40.875508,-40.688017,-40.500641,-40.293058,-40.063100,-39.848802,-39.634520,-39.420261,-39.027333,-38.306743,-36.985256,-34.563100,-32.140944,-30.819457,-30.098867,-29.705939,-29.491680,-29.277398,-29.063100,-28.848802,-28.634520,-28.420261,-28.029019,-27.314600,-26.010051,-23.627910,-19.281550,-15.303523,-11.325769 + -0.928580,-0.714298,-0.500000,-0.285702,-0.071420 + + + diff --git a/test/diagonal.csx b/test/diagonal.csx new file mode 100644 index 00000000..b54b0b7c --- /dev/null +++ b/test/diagonal.csx @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/unit/app/test_openemsh.cpp b/test/unit/app/test_openemsh.cpp index c7c4f848..4df48184 100644 --- a/test/unit/app/test_openemsh.cpp +++ b/test/unit/app/test_openemsh.cpp @@ -17,9 +17,32 @@ using namespace app; //****************************************************************************** SCENARIO("optional next(Step step)", "[app][openemsh]") { WHEN("Running for ADJUST_EDGE_TO_MATERIAL") { - THEN("Should return DETECT_CONFLICT_EIP") { + THEN("Should return DETECT_DIAG_ANGLES") { std::optional a = next(Step::ADJUST_EDGE_TO_MATERIAL); REQUIRE(a.has_value()); + REQUIRE(a.value() == Step::DETECT_DIAG_ANGLES); + } + } + WHEN("Running for DETECT_DIAG_ANGLES") { + THEN("Should return DETECT_DIAG_ZONES") { + std::optional a = next(Step::DETECT_DIAG_ANGLES); + REQUIRE(a.has_value()); + REQUIRE(a.value() == Step::DETECT_DIAG_ZONES); + } + } + + WHEN("Running for DETECT_DIAG_ZONES") { + THEN("Should return SOLVE_DIAG_ZONES_ANGLES") { + std::optional a = next(Step::DETECT_DIAG_ZONES); + REQUIRE(a.has_value()); + REQUIRE(a.value() == Step::SOLVE_DIAG_ZONES_ANGLES); + } + } + + WHEN("Running for SOLVE_DIAG_ZONES_ANGLES") { + THEN("Should return DETECT_CONFLICT_EIP") { + std::optional a = next(Step::SOLVE_DIAG_ZONES_ANGLES); + REQUIRE(a.has_value()); REQUIRE(a.value() == Step::DETECT_CONFLICT_EIP); } } @@ -76,6 +99,20 @@ SCENARIO("optional next(Step step)", "[app][openemsh]") { THEN("Should return MESH") { std::optional a = next(Step::DETECT_INTERVALS); REQUIRE(a.has_value()); + REQUIRE(a.value() == Step::DETECT_INTERVALS_PER_DIAG_ZONES); + } + } + WHEN("Running for DETECT_INTERVALS_PER_DIAG_ZONES") { + THEN("Should return SOLVE_DIAG_ZONES_INTERVALS") { + std::optional a = next(Step::DETECT_INTERVALS_PER_DIAG_ZONES); + REQUIRE(a.has_value()); + REQUIRE(a.value() == Step::SOLVE_DIAG_ZONES_INTERVALS); + } + } + WHEN("Running for SOLVE_DIAG_ZONES_INTERVALS") { + THEN("Should return MESH") { + std::optional a = next(Step::SOLVE_DIAG_ZONES_INTERVALS); + REQUIRE(a.has_value()); REQUIRE(a.value() == Step::MESH); } } @@ -93,6 +130,29 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { THEN("Should return all Steps except those coming before ADJUST_EDGE_TO_MATERIAL") { REQUIRE(that_and_after(Step::ADJUST_EDGE_TO_MATERIAL) == std::set { Step::ADJUST_EDGE_TO_MATERIAL, + Step::DETECT_DIAG_ANGLES, + Step::DETECT_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_ANGLES, + Step::DETECT_CONFLICT_EIP, + Step::DETECT_CONFLICT_CE, + Step::ADD_FIXED_MLP, + Step::SOLVE_ALL_EIP, + Step::SOLVE_ALL_CE, + Step::DETECT_INDIVIDUAL_EDGES, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for DETECT_DIAG_ANGLES") { + THEN("Should return all Steps except those coming before DETECT_DIAG_ANGLES") { + REQUIRE(that_and_after(Step::DETECT_DIAG_ANGLES) == std::set { + Step::DETECT_DIAG_ANGLES, + Step::DETECT_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_ANGLES, Step::DETECT_CONFLICT_EIP, Step::DETECT_CONFLICT_CE, Step::ADD_FIXED_MLP, @@ -101,6 +161,45 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for DETECT_DIAG_ZONES") { + THEN("Should return all Steps except those coming before DETECT_DIAG_ZONES") { + REQUIRE(that_and_after(Step::DETECT_DIAG_ZONES) == std::set { + Step::DETECT_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_ANGLES, + Step::DETECT_CONFLICT_EIP, + Step::DETECT_CONFLICT_CE, + Step::ADD_FIXED_MLP, + Step::SOLVE_ALL_EIP, + Step::SOLVE_ALL_CE, + Step::DETECT_INDIVIDUAL_EDGES, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for SOLVE_DIAG_ZONES_ANGLES") { + THEN("Should return all Steps except those coming before SOLVE_DIAG_ZONES_ANGLES") { + REQUIRE(that_and_after(Step::SOLVE_DIAG_ZONES_ANGLES) == std::set { + Step::SOLVE_DIAG_ZONES_ANGLES, + Step::DETECT_CONFLICT_EIP, + Step::DETECT_CONFLICT_CE, + Step::ADD_FIXED_MLP, + Step::SOLVE_ALL_EIP, + Step::SOLVE_ALL_CE, + Step::DETECT_INDIVIDUAL_EDGES, + Step::DETECT_AND_SOLVE_TCMLP, + Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } @@ -116,6 +215,8 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } @@ -130,6 +231,8 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } @@ -143,6 +246,8 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } @@ -155,6 +260,8 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } @@ -166,6 +273,8 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } @@ -176,6 +285,8 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } @@ -185,6 +296,8 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { REQUIRE(that_and_after(Step::DETECT_AND_SOLVE_TCMLP) == std::set { Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } @@ -193,6 +306,25 @@ SCENARIO("set that_and_after(Step step)", "[app][openemsh]") { THEN("Should return all Steps except those coming before DETECT_INTERVALS") { REQUIRE(that_and_after(Step::DETECT_INTERVALS) == std::set { Step::DETECT_INTERVALS, + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for DETECT_INTERVALS_PER_DIAG_ZONES") { + THEN("Should return all Steps except those coming before DETECT_INTERVALS_PER_DIAG_ZONES") { + REQUIRE(that_and_after(Step::DETECT_INTERVALS_PER_DIAG_ZONES) == std::set { + Step::DETECT_INTERVALS_PER_DIAG_ZONES, + Step::SOLVE_DIAG_ZONES_INTERVALS, + Step::MESH + }); + } + } + WHEN("Running for SOLVE_DIAG_ZONES_INTERVALS") { + THEN("Should return all Steps except those coming before SOLVE_DIAG_ZONES_INTERVALS") { + REQUIRE(that_and_after(Step::SOLVE_DIAG_ZONES_INTERVALS) == std::set { + Step::SOLVE_DIAG_ZONES_INTERVALS, Step::MESH }); } diff --git a/test/unit/domain/geometrics/test_bounding.cpp b/test/unit/domain/geometrics/test_bounding.cpp index acd64a58..38391b8e 100644 --- a/test/unit/domain/geometrics/test_bounding.cpp +++ b/test/unit/domain/geometrics/test_bounding.cpp @@ -8,13 +8,116 @@ #include "domain/geometrics/bounding.hpp" -/// @test bool does_overlap(Bounding2D const& a, Bounding2D const& b) +/// @test bool does_overlap(Bounding1D const& a, Coord const& b) noexcept +/// @test bool does_overlap(Bounding1D const& a, Bounding1D const& b) noexcept +/// @test bool does_overlap(Bounding2D const& a, Bounding2D const& b) noexcept +/// @test bool does_overlap_strict(Bounding2D const& a, Bounding2D const& b) noexcept +/// @test Bounding1D cast(ViewAxis axis, Bounding2D const& a) noexcept ///***************************************************************************** using namespace domain; //****************************************************************************** -SCENARIO("bool does_overlap(Bounding2D const& a, Bounding2D const& b)", "[bounding]") { +SCENARIO("bool does_overlap(Bounding1D const& a, Coord const& b) noexcept", "[bounding]") { + GIVEN("A bounding box") { + Bounding1D a; + a[XMIN] = 1; + a[XMAX] = 4; + WHEN("A coord is not in the bounding box") { + Coord b(5); + THEN("Should not be detected as overlapping") { + REQUIRE_FALSE(does_overlap(a, b)); + } + } + WHEN("A coord is inside the bounding box") { + Coord b(3); + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap(a, b)); + } + } + WHEN("A coord is at the extremity of the bounding box") { + Coord b(4); + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap(a, b)); + } + } + } +} + +//****************************************************************************** +SCENARIO("bool does_overlap(Bounding1D const& a, Bounding1D const& b) noexcept", "[bounding]") { + GIVEN("Two bounding boxes that do not overlap") { + Bounding1D a; + a[XMIN] = 1; + a[XMAX] = 4; + Bounding1D b; + b[XMIN] = 5; + b[XMAX] = 6; + THEN("Should not be detected as overlapping") { + REQUIRE_FALSE(does_overlap(a, b)); + REQUIRE_FALSE(does_overlap(b, a)); + } + } + + GIVEN("Two bounding boxes that overlap") { + Bounding1D a; + a[XMIN] = 1; + a[XMAX] = 4; + Bounding1D b; + b[XMIN] = 2; + b[XMAX] = 5; + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap(a, b)); + REQUIRE(does_overlap(b, a)); + } + } + + GIVEN("A bounding box that is totally inside an other") { + Bounding1D a; + a[XMIN] = 1; + a[XMAX] = 4; + Bounding1D b; + b[XMIN] = 2; + b[XMAX] = 3; + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap(a, b)); + REQUIRE(does_overlap(b, a)); + } + } + + GIVEN("Two bounding boxes that just touch each other by an extremity") { + Bounding1D a; + a[XMIN] = 1; + a[XMAX] = 4; + Bounding1D b; + b[XMIN] = 4; + b[XMAX] = 5; + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap(a, b)); + REQUIRE(does_overlap(b, a)); + } + } +} + +//****************************************************************************** +SCENARIO("bool does_overlap(Bounding2D const& a, Bounding2D const& b) noexcept", "[bounding]") { + GIVEN("Two bounding boxes that are strictly the same") { + Bounding2D a; + a[XMIN] = 1; + a[XMAX] = 4; + a[YMIN] = 2; + a[YMAX] = 4; + Bounding2D b; + b[XMIN] = 1; + b[XMAX] = 4; + b[YMIN] = 2; + b[YMAX] = 4; + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap(a, b)); + REQUIRE(does_overlap(b, a)); + } + } + GIVEN("Two bounding boxes that do not overlap") { Bounding2D a; a[XMIN] = 1; @@ -83,3 +186,116 @@ SCENARIO("bool does_overlap(Bounding2D const& a, Bounding2D const& b)", "[boundi } } } + +//****************************************************************************** +SCENARIO("bool does_overlap_strict(Bounding2D const& a, Bounding2D const& b) noexcept", "[bounding]") { + GIVEN("Two bounding boxes that are strictly the same") { + Bounding2D a; + a[XMIN] = 1; + a[XMAX] = 4; + a[YMIN] = 2; + a[YMAX] = 4; + Bounding2D b; + b[XMIN] = 1; + b[XMAX] = 4; + b[YMIN] = 2; + b[YMAX] = 4; + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap_strict(a, b)); + REQUIRE(does_overlap_strict(b, a)); + } + } + + GIVEN("Two bounding boxes that do not overlap") { + Bounding2D a; + a[XMIN] = 1; + a[XMAX] = 4; + a[YMIN] = 2; + a[YMAX] = 4; + Bounding2D b; + b[XMIN] = 5; + b[XMAX] = 6; + b[YMIN] = 1; + b[YMAX] = 3; + THEN("Should not be detected as overlapping") { + REQUIRE_FALSE(does_overlap_strict(a, b)); + REQUIRE_FALSE(does_overlap_strict(b, a)); + } + } + + GIVEN("Two bounding boxes that overlap") { + Bounding2D a; + a[XMIN] = 1; + a[XMAX] = 4; + a[YMIN] = 2; + a[YMAX] = 4; + Bounding2D b; + b[XMIN] = 2; + b[XMAX] = 5; + b[YMIN] = 1; + b[YMAX] = 3; + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap_strict(a, b)); + REQUIRE(does_overlap_strict(b, a)); + } + } + + GIVEN("A bounding box that is totally inside an other") { + Bounding2D a; + a[XMIN] = 1; + a[XMAX] = 4; + a[YMIN] = 2; + a[YMAX] = 4; + Bounding2D b; + b[XMIN] = 2; + b[XMAX] = 3; + b[YMIN] = 2.5; + b[YMAX] = 3.5; + THEN("Should be detected as overlapping") { + REQUIRE(does_overlap_strict(a, b)); + REQUIRE(does_overlap_strict(b, a)); + } + } + + GIVEN("Two bounding boxes that just touch each other by a corner") { + Bounding2D a; + a[XMIN] = 1; + a[XMAX] = 4; + a[YMIN] = 2; + a[YMAX] = 4; + Bounding2D b; + b[XMIN] = 4; + b[XMAX] = 5; + b[YMIN] = 4; + b[YMAX] = 5; + THEN("Should not be detected as overlapping") { + REQUIRE_FALSE(does_overlap_strict(a, b)); + REQUIRE_FALSE(does_overlap_strict(b, a)); + } + } +} + +//****************************************************************************** +SCENARIO("Bounding1D cast(ViewAxis axis, Bounding2D const& a) noexcept", "[bounding]") { + GIVEN("A 2D Bounding box") { + Bounding2D a; + a[XMIN] = 1; + a[XMAX] = 4; + a[YMIN] = 3; + a[YMAX] = 5; + WHEN("Casting to 1D Bounding according to ViewAxis::H") { + Bounding1D b = cast(ViewAxis::H, a); + THEN("Should return the X part of the 2D Bounding box") { + REQUIRE(b[XMIN] == a[XMIN]); + REQUIRE(b[XMAX] == a[XMAX]); + } + } + WHEN("Casting to 1D Bounding according to ViewAxis::V") { + Bounding1D b = cast(ViewAxis::V, a); + THEN("Should return the Y part of the 2D Bounding box") { + REQUIRE(b[XMIN] == a[YMIN]); + REQUIRE(b[XMAX] == a[YMAX]); + } + } + } +} diff --git a/test/unit/domain/geometrics/test_edge.cpp b/test/unit/domain/geometrics/test_edge.cpp index 5f633d9a..bd51397b 100644 --- a/test/unit/domain/geometrics/test_edge.cpp +++ b/test/unit/domain/geometrics/test_edge.cpp @@ -59,6 +59,40 @@ SCENARIO("relation::SegmentSegment Segment::relation_to(Segment const* segment) } } + WHEN("A vertical edge and an horizontal edge are touching by just an extremity") { + Point a0(1, 1), a1(3, 1); + Point b0(1, 1), b1(1, 3); + Edge a(XY, &a0, &a1, &t), b(XY, &b0, &b1, &t); + Edge c(XY, &a1, &a0, &t), d(XY, &b1, &b0, &t); + THEN("Should be detected as CROSSING") { + REQUIRE(a.axis == Segment::Axis::H); + REQUIRE(b.axis == Segment::Axis::V); + REQUIRE(a.relation_to(b) == relation::SegmentSegment::CROSSING); + REQUIRE(b.relation_to(a) == relation::SegmentSegment::CROSSING); + REQUIRE(c.axis == Segment::Axis::H); + REQUIRE(d.axis == Segment::Axis::V); + REQUIRE(c.relation_to(d) == relation::SegmentSegment::CROSSING); + REQUIRE(d.relation_to(c) == relation::SegmentSegment::CROSSING); + } + } + + WHEN("Two diagonal edges are touching by just an extremity") { + Point a0(1, 1), a1(2, 3); + Point b0(2, 3), b1(3, 1); + Edge a(XY, &a0, &a1, &t), b(XY, &b0, &b1, &t); + Edge c(XY, &a1, &a0, &t), d(XY, &b1, &b0, &t); + THEN("Should be detected as CROSSING") { + REQUIRE(a.axis == Segment::Axis::DIAGONAL); + REQUIRE(b.axis == Segment::Axis::DIAGONAL); + REQUIRE(a.relation_to(b) == relation::SegmentSegment::CROSSING); + REQUIRE(b.relation_to(a) == relation::SegmentSegment::CROSSING); + REQUIRE(c.axis == Segment::Axis::DIAGONAL); + REQUIRE(d.axis == Segment::Axis::DIAGONAL); + REQUIRE(c.relation_to(d) == relation::SegmentSegment::CROSSING); + REQUIRE(d.relation_to(c) == relation::SegmentSegment::CROSSING); + } + } + WHEN("Two vertical edges are colinear") { Point a0(1, 1), a1(1, 2); Point b0(1, 3), b1(1, 4); diff --git a/test/unit/domain/geometrics/test_point.cpp b/test/unit/domain/geometrics/test_point.cpp index 668b5098..b10ef8a7 100644 --- a/test/unit/domain/geometrics/test_point.cpp +++ b/test/unit/domain/geometrics/test_point.cpp @@ -10,12 +10,13 @@ #include "domain/geometrics/point.hpp" -/// @test Point operator-(Point const& a, Point const& b) -/// @test Point operator+(Point const& a, Point const& b) -/// @test Point operator==(Point const& a, Point const& b) -/// @test template Point operator*(T const& n, Point const& p) -/// @test template Point operator*(Point const& p, T const& n) -/// @test Point mid(Point const& a, Point const& b) +/// @test Point operator-(Point const& a, Point const& b) noexcept +/// @test Point operator+(Point const& a, Point const& b) noexcept +/// @test Point operator==(Point const& a, Point const& b) noexcept +/// @test template Point operator*(T const& n, Point const& p) noexcept +/// @test template Point operator*(Point const& p, T const& n) noexcept +/// @test Point mid(Point const& a, Point const& b) noexcept +/// @test Coord coord(Point const& point, ViewAxis const axis) noexcept ///***************************************************************************** using namespace domain; @@ -143,3 +144,20 @@ SCENARIO("Point mid(Point const& a, Point const& b)", "[point]") { } } } + +//****************************************************************************** +SCENARIO("Coord coord(Point const& point, ViewAxis const axis) noexcept", "[point]") { + GIVEN("A Point and a ViewAxis enum") { + Point p(1, 3); + WHEN("ViewAxis::H") { + THEN("Should return X coord (horizontal axis)") { + REQUIRE(coord(p, ViewAxis::H) == p.x); + } + } + WHEN("ViewAxis::V") { + THEN("Should return Y coord (vertical axis)") { + REQUIRE(coord(p, ViewAxis::V) == p.y); + } + } + } +} diff --git a/test/unit/domain/geometrics/test_segment.cpp b/test/unit/domain/geometrics/test_segment.cpp index e24cf723..d0ef78c4 100644 --- a/test/unit/domain/geometrics/test_segment.cpp +++ b/test/unit/domain/geometrics/test_segment.cpp @@ -14,6 +14,9 @@ /// @test Segment::Axis axis(Point const& vector) noexcept /// @test Segment::Axis axis(Point const& p0, Point const& p1) noexcept /// @test std::optional transpose(Plane const plane, Segment::Axis const axis) noexcept +/// @test std::optional cast(Segment::Axis const axis) noexcept +/// @test Segment::Axis cast(ViewAxis const axis) noexcept +/// @test std::optional coord(Point const& point, Segment::Axis const axis) noexcept ///***************************************************************************** using namespace domain; @@ -175,3 +178,84 @@ SCENARIO("std::optional transpose(Plane const plane, Segment::Axis const a } } } + +//****************************************************************************** +SCENARIO("std::optional cast(Segment::Axis const axis) noexcept", "[segment]") { + GIVEN("A Segment::Axis enum class") { + WHEN("Segment::Axis::H") { + THEN("Should return ViewAxis::H") { + std::optional a(cast(Segment::Axis::H)); + REQUIRE(a.has_value()); + REQUIRE(a.value() == ViewAxis::H); + } + } + WHEN("Segment::Axis::V") { + THEN("Should return ViewAxis::V") { + std::optional a(cast(Segment::Axis::V)); + REQUIRE(a.has_value()); + REQUIRE(a.value() == ViewAxis::V); + } + } + WHEN("Segment::Axis::DIAGONAL") { + THEN("Should not return anything") { + std::optional a(cast(Segment::Axis::DIAGONAL)); + REQUIRE_FALSE(a.has_value()); + } + } + WHEN("Segment::Axis::H") { + THEN("Should return ViewAxis::H") { + std::optional a(cast(Segment::Axis::POINT)); + REQUIRE_FALSE(a.has_value()); + } + } + } +} + +//****************************************************************************** +SCENARIO("Segment::Axis cast(ViewAxis const axis) noexcept", "[segment]") { + GIVEN("A ViewAxis enum") { + WHEN("ViewAxis::H") { + THEN("Should return Segment::Axis::H") { + REQUIRE(cast(ViewAxis::H) == Segment::Axis::H); + } + } + WHEN("ViewAxis::V") { + THEN("Should return Segment::Axis::V") { + REQUIRE(cast(ViewAxis::V) == Segment::Axis::V); + } + } + } +} + +//****************************************************************************** +SCENARIO("std::optional coord(Point const& point, Segment::Axis const axis) noexcept", "[segment]") { + GIVEN("A Point and a Segment::Axis enum class") { + Point p(1, 3); + WHEN("Segment::Axis::H") { + THEN("Should return Y coord") { + std::optional a(coord(p, Segment::Axis::H)); + REQUIRE(a.has_value()); + REQUIRE(a.value() == p.y); + } + } + WHEN("Segment::Axis::V") { + THEN("Should return X coord") { + std::optional a(coord(p, Segment::Axis::V)); + REQUIRE(a.has_value()); + REQUIRE(a.value() == p.x); + } + } + WHEN("Segment::Axis::DIAGONAL") { + THEN("Should not return anything") { + std::optional a(coord(p, Segment::Axis::DIAGONAL)); + REQUIRE_FALSE(a.has_value()); + } + } + WHEN("Segment::Axis::POINT") { + THEN("Should not return anything") { + std::optional a(coord(p, Segment::Axis::POINT)); + REQUIRE_FALSE(a.has_value()); + } + } + } +} diff --git a/test/unit/domain/mesh/test_meshline_policy.cpp b/test/unit/domain/mesh/test_meshline_policy.cpp index 7aa21cde..ccd24931 100644 --- a/test/unit/domain/mesh/test_meshline_policy.cpp +++ b/test/unit/domain/mesh/test_meshline_policy.cpp @@ -6,53 +6,13 @@ #include -#include "domain/geometrics/point.hpp" -#include "domain/geometrics/segment.hpp" - #include "domain/mesh/meshline_policy.hpp" -/// @test std::optional coord(Point const& point, Segment::Axis const axis) noexcept /// @test MeshlinePolicy::Normal cast(Normal const normal) noexcept ///***************************************************************************** using namespace domain; -//****************************************************************************** -SCENARIO("std::optional coord(Point const& point, Segment::Axis const axis) noexcept", "[meshline_policy]") { - GIVEN("A Point and a Segment::Axis enum class") { - Point p(1, 3); - WHEN("Segment::Axis::H") { - THEN("Should return Y coord") { - std::optional a(coord(p, Segment::Axis::H)); - REQUIRE(a.has_value()); - REQUIRE(a.value() == p.y); - } - } - - WHEN("Segment::Axis::V") { - THEN("Should return X coord") { - std::optional a(coord(p, Segment::Axis::V)); - REQUIRE(a.has_value()); - REQUIRE(a.value() == p.x); - } - } - - WHEN("Segment::Axis::DIAGONAL") { - THEN("Should not return anything") { - std::optional a(coord(p, Segment::Axis::DIAGONAL)); - REQUIRE_FALSE(a.has_value()); - } - } - - WHEN("Segment::Axis::POINT") { - THEN("Should not return anything") { - std::optional a(coord(p, Segment::Axis::POINT)); - REQUIRE_FALSE(a.has_value()); - } - } - } -} - //****************************************************************************** SCENARIO("MeshlinePolicy::Normal cast(Normal const normal) noexcept", "[meshline_policy]") { GIVEN("A Normal enum class") {