diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c7659224..0d168d11 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources( openemsh "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/relation.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/bounding.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/coord.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/normal.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/point.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/segment.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/geometrics/edge.cpp" @@ -28,6 +29,7 @@ target_sources( openemsh "${CMAKE_CURRENT_SOURCE_DIR}/domain/mesh/interval.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/mesh/meshline.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/mesh/meshline_policy.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/domain/material.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/meshline_policy_manager.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/conflict_manager.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/domain/board.cpp" diff --git a/src/app/openemsh.cpp b/src/app/openemsh.cpp index a4f84257..8d367499 100644 --- a/src/app/openemsh.cpp +++ b/src/app/openemsh.cpp @@ -21,17 +21,19 @@ using namespace std; //****************************************************************************** optional next(Step step) { switch(step) { + case Step::ADJUST_EDGE_TO_MATERIAL: + return Step::DETECT_CONFLICT_EIP; case Step::DETECT_CONFLICT_EIP: return Step::DETECT_CONFLICT_CE; case Step::DETECT_CONFLICT_CE: - return Step::DETECT_NON_CONFLICTING_EDGES; - case Step::DETECT_NON_CONFLICTING_EDGES: return Step::ADD_FIXED_MLP; case Step::ADD_FIXED_MLP: return Step::SOLVE_ALL_EIP; case Step::SOLVE_ALL_EIP: return Step::SOLVE_ALL_CE; case Step::SOLVE_ALL_CE: + return Step::DETECT_INDIVIDUAL_EDGES; + case Step::DETECT_INDIVIDUAL_EDGES: return Step::DETECT_AND_SOLVE_TCMLP; case Step::DETECT_AND_SOLVE_TCMLP: return Step::DETECT_INTERVALS; @@ -40,7 +42,7 @@ optional next(Step step) { case Step::MESH: return nullopt; default: - unreachable(); + ::unreachable(); } } @@ -50,16 +52,17 @@ set that_and_after(Step step) { using enum Step; switch(step) { - case DETECT_CONFLICT_EIP: out.emplace(DETECT_CONFLICT_EIP); [[fallthrough]]; - case DETECT_CONFLICT_CE: out.emplace(DETECT_CONFLICT_CE); [[fallthrough]]; - case DETECT_NON_CONFLICTING_EDGES: out.emplace(DETECT_NON_CONFLICTING_EDGES); [[fallthrough]]; - case ADD_FIXED_MLP: out.emplace(ADD_FIXED_MLP); [[fallthrough]]; - case SOLVE_ALL_EIP: out.emplace(SOLVE_ALL_EIP); [[fallthrough]]; - case SOLVE_ALL_CE: out.emplace(SOLVE_ALL_CE); [[fallthrough]]; - case DETECT_AND_SOLVE_TCMLP: out.emplace(DETECT_AND_SOLVE_TCMLP); [[fallthrough]]; - case DETECT_INTERVALS: out.emplace(DETECT_INTERVALS); [[fallthrough]]; - case MESH: out.emplace(MESH); break; - default: unreachable(); + 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; + default: ::unreachable(); } return out; @@ -117,7 +120,7 @@ void OpenEMSH::write() const { cerr << SerializerToPrettyprint::run(*board); break; default: - unreachable(); + ::unreachable(); }; } @@ -131,15 +134,16 @@ void OpenEMSH::run(std::set const& steps) const { }; using enum Step; - handle(DETECT_CONFLICT_EIP, [&] { board->detect_edges_in_polygons(); }); - handle(DETECT_CONFLICT_CE, [&] { board->detect_colinear_edges(); }); - handle(DETECT_NON_CONFLICTING_EDGES, [&] { board->detect_non_conflicting_edges(); }); - handle(ADD_FIXED_MLP, [&] { board->add_fixed_meshline_policies(); }); - handle(SOLVE_ALL_EIP, [&] { board->auto_solve_all_edge_in_polygon(); }); - handle(SOLVE_ALL_CE, [&] { board->auto_solve_all_colinear_edges(); }); - handle(DETECT_AND_SOLVE_TCMLP, [&] { board->detect_and_solve_too_close_meshline_policies(); }); - handle(DETECT_INTERVALS, [&] { board->detect_intervals(); }); - handle(MESH, [&] { board->mesh(); }); + 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(); }); Caretaker::singleton().remember_current_timepoint(); } @@ -147,12 +151,13 @@ void OpenEMSH::run(std::set const& steps) const { //****************************************************************************** void OpenEMSH::run_all_steps() const { run({ + Step::ADJUST_EDGE_TO_MATERIAL, Step::DETECT_CONFLICT_EIP, Step::DETECT_CONFLICT_CE, - Step::DETECT_NON_CONFLICTING_EDGES, Step::ADD_FIXED_MLP, Step::SOLVE_ALL_EIP, Step::SOLVE_ALL_CE, + Step::DETECT_INDIVIDUAL_EDGES, Step::DETECT_AND_SOLVE_TCMLP, Step::DETECT_INTERVALS, Step::MESH @@ -168,7 +173,7 @@ void OpenEMSH::run_next_step() const { ; step) run({ step.value() }); } else { - run({ Step::DETECT_CONFLICT_EIP }); + run({ Step::ADJUST_EDGE_TO_MATERIAL }); } } diff --git a/src/app/openemsh.hpp b/src/app/openemsh.hpp index 0acc91da..dc7890be 100644 --- a/src/app/openemsh.hpp +++ b/src/app/openemsh.hpp @@ -40,11 +40,12 @@ class OpenEMSH { PRETTYPRINT } output_format = OutputFormat::CSX; + bool with_step_adjust_edges_to_material = true; bool with_step_detect_edges_in_polygons = true; bool with_step_detect_colinear_edges = true; - bool with_step_detect_non_conflicting_edges = true; bool with_step_auto_solve_all_edge_in_polygon = true; bool with_step_auto_solve_all_colinear_edges = true; + bool with_step_detect_individual_edges = true; bool with_step_detect_and_solve_too_close_meshline_policies = true; bool with_step_detect_intervals = true; bool with_step_mesh = true; diff --git a/src/app/steps.hpp b/src/app/steps.hpp index 02043206..3cef9456 100644 --- a/src/app/steps.hpp +++ b/src/app/steps.hpp @@ -10,12 +10,13 @@ namespace app { //****************************************************************************** enum class Step { + ADJUST_EDGE_TO_MATERIAL, DETECT_CONFLICT_EIP, DETECT_CONFLICT_CE, - DETECT_NON_CONFLICTING_EDGES, ADD_FIXED_MLP, SOLVE_ALL_EIP, SOLVE_ALL_CE, + DETECT_INDIVIDUAL_EDGES, DETECT_AND_SOLVE_TCMLP, DETECT_INTERVALS, MESH diff --git a/src/domain/board.cpp b/src/domain/board.cpp index 370c40e9..e85453f6 100644 --- a/src/domain/board.cpp +++ b/src/domain/board.cpp @@ -88,24 +88,24 @@ void Board::Builder::add_fixed_meshline_policy(Axis const axis, Coord const coor } //****************************************************************************** -void Board::Builder::add_polygon(Plane const plane, Polygon::Type const type, string const& name, initializer_list points) { - polygons[plane].push_back(make_shared(plane, type, name, from_init_list(points), Caretaker::singleton().get_history_root())); +void Board::Builder::add_polygon(Plane plane, shared_ptr const& material, string const& name, size_t priority, Polygon::RangeZ const& z_placement, initializer_list points) { + polygons[plane].push_back(make_shared(plane, material, name, priority, z_placement, from_init_list(points), Caretaker::singleton().get_history_root())); } //****************************************************************************** -void Board::Builder::add_polygon(Plane const plane, Polygon::Type const type, string const& name, vector>&& points) { - polygons[plane].push_back(make_shared(plane, type, name, std::move(points), Caretaker::singleton().get_history_root())); +void Board::Builder::add_polygon(Plane plane, shared_ptr const& material, string const& name, size_t priority, Polygon::RangeZ const& z_placement, vector>&& points) { + polygons[plane].push_back(make_shared(plane, material, name, priority, z_placement, std::move(points), Caretaker::singleton().get_history_root())); } //****************************************************************************** -void Board::Builder::add_polygon_from_box(Plane const plane, Polygon::Type const type, string const& name, Point const p1, Point const p3) { +void Board::Builder::add_polygon_from_box(Plane plane, shared_ptr const& material, string const& name, size_t priority, Polygon::RangeZ const& z_placement, Point const p1, Point const p3) { vector> points(4); points[0] = make_unique(p1.x, p1.y); points[1] = make_unique(p1.x, p3.y); points[2] = make_unique(p3.x, p3.y); points[3] = make_unique(p3.x, p1.y); - polygons[plane].push_back(make_shared(plane, type, name, std::move(points), Caretaker::singleton().get_history_root())); + polygons[plane].push_back(make_shared(plane, material, name, priority, z_placement, std::move(points), Caretaker::singleton().get_history_root())); } //****************************************************************************** @@ -160,6 +160,76 @@ Board::Board( get_caretaker().take_care_of(polygon); } +//****************************************************************************** +shared_ptr Board::find_ambient_material(Plane plane, Segment const& segment) const { + return find_ambient_material(plane, segment, nullptr).first; +} + +/// Check among all Polygons that match segment and current_polygon->z_placement. +/// Choose Material following this rule: CONDUCTOR>DIELECTRIC>AIR +///***************************************************************************** +pair, remove_const_t> Board::find_ambient_material(Plane plane, Segment const& segment, shared_ptr const& current_polygon) const { + Bounding2D const segment_bounding = bounding(segment); + + vector, remove_const_t>> materials; + for(shared_ptr const& polygon : get_current_state().polygons[plane]) { + if(polygon->material + && (!current_polygon // Bypass self & z_overlap checks if not relevant. + || (polygon != current_polygon + && does_overlap(polygon->z_placement, current_polygon->z_placement))) + && does_overlap(polygon->bounding, segment_bounding)) + materials.emplace_back(shared_ptr(polygon->material), polygon->priority); + } + + ranges::sort(materials, [](auto const& a, auto const& b) { + auto const& [material_a, priority_a] = a; + auto const& [material_b, priority_b] = b; + return priority_a != priority_b + ? priority_a < priority_b + : *material_a < *material_b; + }); + + if(!materials.empty()) + return materials.back(); + else + // TODO if no material return Board::background_material + return {}; +} + +//****************************************************************************** +void Board::adjust_edges_to_materials(Plane const plane) { + for(shared_ptr const& polygon : get_current_state().polygons[plane]) { + for(shared_ptr const& edge : polygon->edges) { + auto const& inner_material = polygon->material; + auto const& [immediate_ambient_outer_material, outer_priority] = [&]() -> pair, remove_const_t> { + Point const translate_x(2 * equality_tolerance, 0); + Point const translate_y(0, 2 * equality_tolerance); + switch(edge->normal) { + case Normal::NONE: + return {}; + case Normal::XMIN: + return find_ambient_material(plane, Range(edge->p0() - translate_x, edge->p1() - translate_x), polygon); + case Normal::XMAX: + return find_ambient_material(plane, Range(edge->p0() + translate_x, edge->p1() + translate_x), polygon); + case Normal::YMIN: + return find_ambient_material(plane, Range(edge->p0() - translate_y, edge->p1() - translate_y), polygon); + case Normal::YMAX: + return find_ambient_material(plane, Range(edge->p0() + translate_y, edge->p1() + translate_y), polygon); + default: + ::unreachable(); + } + } (); + + if(immediate_ambient_outer_material + && *immediate_ambient_outer_material > *inner_material) { + auto state = edge->get_current_state(); + state.to_reverse = true; + edge->set_next_state(state); + } + } + } +} + /// Detect all EDGE_IN_POLYGON. Will also detect some COLINEAR_EDGES. /// Overlapping edges should be EDGE_IN_POLYGON and not COLINEAR_EDGES. ///***************************************************************************** @@ -169,6 +239,13 @@ void Board::detect_edges_in_polygons(Plane const plane) { if(poly_b == poly_a) continue; + // Same priority : no reason to dismiss one. + if(poly_a->priority > poly_b->priority) + continue; + + if(!does_overlap(poly_b->z_placement, poly_a->z_placement)) + continue; + for(auto const& edge_a : poly_a->edges) { struct RangeBtwIntersections { @@ -307,18 +384,23 @@ void Board::detect_colinear_edges(Plane const plane) { } //****************************************************************************** -void Board::detect_non_conflicting_edges(Plane const plane) { +void Board::detect_individual_edges(Plane const plane) { for(Edge* edge : get_current_state().edges[plane]) { optional const coord = domain::coord(edge->p0(), edge->axis); optional const axis = transpose(plane, edge->axis); - optional const normal = cast(edge->normal); - if(coord && axis && normal && edge->get_current_state().conflicts.empty()) { + Normal const normal = edge->get_current_state().to_reverse + ? reverse(edge->normal) + : edge->normal; + if(coord && axis + && (edge->get_current_state().conflicts.empty() + || ranges::none_of(edge->get_current_state().conflicts, [](auto const& conflict) { return conflict ? conflict->kind == Conflict::Kind::COLINEAR_EDGES : false; })) + && edge->get_current_state().to_mesh) { auto [t, state_e] = edge->make_next_state(); state_e.meshline_policy = line_policy_manager->add_meshline_policy( { edge }, axis.value(), MeshlinePolicy::Policy::THIRDS, - normal.value(), + cast(normal), coord.value(), state_e.to_mesh, t); @@ -334,6 +416,12 @@ void Board::add_fixed_meshline_policies(Axis axis) { create_meshline_policy(this, t); } +//****************************************************************************** +void Board::adjust_edges_to_materials() { + for(auto const& plane : AllPlane) + adjust_edges_to_materials(plane); +} + //****************************************************************************** void Board::detect_edges_in_polygons() { for(auto const& plane : AllPlane) @@ -347,9 +435,9 @@ void Board::detect_colinear_edges() { } //****************************************************************************** -void Board::detect_non_conflicting_edges() { +void Board::detect_individual_edges() { for(auto const& plane : AllPlane) - detect_non_conflicting_edges(plane); + detect_individual_edges(plane); } //****************************************************************************** diff --git a/src/domain/board.hpp b/src/domain/board.hpp index 4e29ca7d..1d406178 100644 --- a/src/domain/board.hpp +++ b/src/domain/board.hpp @@ -9,6 +9,8 @@ #include //#include #include +#include +#include #include #include "conflicts/conflict.hpp" @@ -56,9 +58,9 @@ class Board public: void add_fixed_meshline_policy(Axis axis, Coord coord); - void add_polygon(Plane plane, Polygon::Type type, std::string const& name, std::initializer_list points); - void add_polygon(Plane plane, Polygon::Type type, std::string const& name, std::vector>&& points); - void add_polygon_from_box(Plane plane, Polygon::Type type, std::string const& name, Point const p1, Point const p3); + void add_polygon(Plane plane, std::shared_ptr const& material, std::string const& name, std::size_t priority, Polygon::RangeZ const& z_placement, std::initializer_list points); + void add_polygon(Plane plane, std::shared_ptr const& material, std::string const& name, std::size_t priority, Polygon::RangeZ const& z_placement, std::vector>&& points); + void add_polygon_from_box(Plane plane, std::shared_ptr const& material, std::string const& name, std::size_t priority, Polygon::RangeZ const& z_placement, Point const p1, Point const p3); [[nodiscard]] std::shared_ptr build(Params&& params = Params()); @@ -78,14 +80,16 @@ class Board /// Mesh resolution independant detection tasks ///************************************************************************* + void adjust_edges_to_materials(Plane const plane); void detect_edges_in_polygons(Plane const plane); void detect_colinear_edges(Plane plane); - void detect_non_conflicting_edges(Plane const plane); + void detect_individual_edges(Plane const plane); void add_fixed_meshline_policies(Axis axis); + void adjust_edges_to_materials(); void detect_edges_in_polygons(); void detect_colinear_edges(); - void detect_non_conflicting_edges(); + void detect_individual_edges(); void add_fixed_meshline_policies(); /// Mesh resolution dependant detection tasks @@ -104,6 +108,10 @@ class Board 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; + +private: + std::shared_ptr find_ambient_material(Plane plane, Segment const& segment) const; + std::pair, std::remove_const_t> find_ambient_material(Plane plane, Segment const& segment, std::shared_ptr const& current_polygon) const; }; #ifdef UNITTEST diff --git a/src/domain/conflicts/conflict_colinear_edges.cpp b/src/domain/conflicts/conflict_colinear_edges.cpp index dbff1cba..c481b768 100644 --- a/src/domain/conflicts/conflict_colinear_edges.cpp +++ b/src/domain/conflicts/conflict_colinear_edges.cpp @@ -40,7 +40,11 @@ void ConflictColinearEdges::auto_solve(MeshlinePolicyManager& line_policy_manage if(!edge->get_current_state().to_mesh) continue; - switch(edge->normal) { + Normal const normal = edge->get_current_state().to_reverse + ? reverse(edge->normal) + : edge->normal; + + switch(normal) { case Normal::XMIN: case Normal::YMIN: case Normal::ZMIN: diff --git a/src/domain/geometrics/edge.hpp b/src/domain/geometrics/edge.hpp index b5980d4c..03adb328 100644 --- a/src/domain/geometrics/edge.hpp +++ b/src/domain/geometrics/edge.hpp @@ -42,6 +42,7 @@ struct EdgeState final , public IConflictSolutionState , public IMeshLineOriginState { bool to_mesh = true; + bool to_reverse = false; }; //****************************************************************************** diff --git a/src/domain/geometrics/normal.cpp b/src/domain/geometrics/normal.cpp new file mode 100644 index 00000000..f58329a9 --- /dev/null +++ b/src/domain/geometrics/normal.cpp @@ -0,0 +1,27 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include "utils/unreachable.hpp" + +#include "normal.hpp" + +namespace domain { + +//****************************************************************************** +Normal reverse(Normal normal) noexcept { + switch(normal) { + case Normal::XMIN: return Normal::XMAX; + case Normal::XMAX: return Normal::XMIN; + case Normal::YMIN: return Normal::YMAX; + case Normal::YMAX: return Normal::YMIN; + case Normal::ZMIN: return Normal::ZMAX; + case Normal::ZMAX: return Normal::ZMIN; + case Normal::NONE: return Normal::NONE; + default: ::unreachable(); + } +} + +} // namespace domain diff --git a/src/domain/geometrics/normal.hpp b/src/domain/geometrics/normal.hpp index d26433aa..cee6f4b5 100644 --- a/src/domain/geometrics/normal.hpp +++ b/src/domain/geometrics/normal.hpp @@ -21,4 +21,7 @@ enum class Normal { NONE }; +//****************************************************************************** +Normal reverse(Normal normal) noexcept; + } // namespace domain diff --git a/src/domain/geometrics/polygon.cpp b/src/domain/geometrics/polygon.cpp index 5b4813f5..cbecf11f 100644 --- a/src/domain/geometrics/polygon.cpp +++ b/src/domain/geometrics/polygon.cpp @@ -15,10 +15,18 @@ namespace domain { using namespace std; //****************************************************************************** -Polygon::Polygon(Plane const plane, Type const type, string const& name, vector>&& points, Timepoint* t) +Polygon::RangeZ::RangeZ(Coord const& a, Coord const& b) +: min(a < b ? a : b) +, max(a > b ? a : b) +{} + +//****************************************************************************** +Polygon::Polygon(Plane const plane, shared_ptr const& material, string const& name, size_t priority, RangeZ const& z_placement, vector>&& points, Timepoint* t) : Originator(t) , rotation(detect_rotation(points)) -, type(type) +, z_placement(z_placement) +, priority(priority) +, material(material) , plane(plane) , bounding(detect_bounding(points)) , name(name) @@ -74,7 +82,7 @@ Polygon::Rotation detect_rotation(T const& points) noexcept { else if(area < 0) return Polygon::Rotation::CW; else - unreachable(); + ::unreachable(); } //****************************************************************************** @@ -193,4 +201,13 @@ relation::PolygonPoint Polygon::relation_to(Point const& point) const noexcept { return relation::PolygonPoint::OUT; } +/// Check if two Z ranges overlap or just touch each other. +///***************************************************************************** +bool does_overlap(Polygon::RangeZ const& a, Polygon::RangeZ const& b) noexcept { + return (b.min >= a.min && b.min <= a.max) + || (b.max >= a.min && b.max <= a.max) + || (a.min >= b.min && a.min <= b.max) + || (a.max >= b.min && a.max <= b.max); +} + } // namespace domain diff --git a/src/domain/geometrics/polygon.hpp b/src/domain/geometrics/polygon.hpp index 83b17abd..f1c6296a 100644 --- a/src/domain/geometrics/polygon.hpp +++ b/src/domain/geometrics/polygon.hpp @@ -14,6 +14,7 @@ #include "domain/conflicts/i_conflict_origin.hpp" #include "domain/mesh/i_meshline_origin.hpp" #include "domain/utils/entity_visitor.hpp" +#include "domain/material.hpp" #include "utils/entity.hpp" #include "utils/state_management.hpp" #include "bounding.hpp" @@ -48,13 +49,14 @@ class Polygon COLINEAR } const rotation; - enum class Type { - SHAPE, - PORT, - GROUND, - SUBSTRATE - } const type; + struct RangeZ { + Coord min; + Coord max; + RangeZ(Coord const& a, Coord const& b); + } const z_placement; + std::size_t const priority; /// At 3D overlap, the higher is selected. + std::shared_ptr material; Plane const plane; Bounding2D const bounding; std::string const name; @@ -66,7 +68,7 @@ class Polygon ///************************************************************************* std::vector> const edges; - Polygon(Plane plane, Type type, std::string const& name, std::vector>&& points, Timepoint* t); + Polygon(Plane plane, std::shared_ptr const& material, std::string const& name, std::size_t priority, RangeZ const& z_placement, std::vector>&& points, Timepoint* t); ~Polygon() override; // relation::PolygonEdge relation_to(Edge const* edge); @@ -85,4 +87,7 @@ Bounding2D detect_bounding(std::vector> const& poin //****************************************************************************** std::vector> detect_edges(std::vector> const& points, Plane plane, Timepoint* t); +//****************************************************************************** +bool does_overlap(Polygon::RangeZ const& a, Polygon::RangeZ const& b) noexcept; + } // namespace domain diff --git a/src/domain/geometrics/relation.cpp b/src/domain/geometrics/relation.cpp index 19a70cf0..4075c30a 100644 --- a/src/domain/geometrics/relation.cpp +++ b/src/domain/geometrics/relation.cpp @@ -17,7 +17,7 @@ PolygonPoint cast(PolygonSegment const a) { case PolygonSegment::IN: return PolygonPoint::IN; case PolygonSegment::ON: return PolygonPoint::ON; case PolygonSegment::OUT: return PolygonPoint::OUT; - default: unreachable(); + default: ::unreachable(); } } @@ -27,7 +27,7 @@ PolygonSegment cast(PolygonPoint const a) { case PolygonPoint::IN: return PolygonSegment::IN; case PolygonPoint::ON: return PolygonSegment::ON; case PolygonPoint::OUT: return PolygonSegment::OUT; - default: unreachable(); + default: ::unreachable(); } } diff --git a/src/domain/geometrics/segment.cpp b/src/domain/geometrics/segment.cpp index acc88632..29e2ec2d 100644 --- a/src/domain/geometrics/segment.cpp +++ b/src/domain/geometrics/segment.cpp @@ -223,14 +223,14 @@ optional transpose(Plane const plane, Segment::Axis const axis) noexcept { case YZ: return Z; case ZX: return X; case XY: return Y; - default: unreachable(); + default: ::unreachable(); } case Segment::Axis::V: switch(plane) { case YZ: return Y; case ZX: return Z; case XY: return X; - default: unreachable(); + default: ::unreachable(); } default: return nullopt; diff --git a/src/domain/geometrics/space.cpp b/src/domain/geometrics/space.cpp index 45263ff7..1a7ad888 100644 --- a/src/domain/geometrics/space.cpp +++ b/src/domain/geometrics/space.cpp @@ -28,24 +28,24 @@ optional transpose(Plane const plane, Axis const axis) noexcept { case X: return nullopt; case Y: return H; case Z: return V; - default: unreachable(); + default: ::unreachable(); } case ZX: switch(axis) { case X: return V; case Y: return nullopt; case Z: return H; - default: unreachable(); + default: ::unreachable(); } case XY: switch(axis) { case X: return H; case Y: return V; case Z: return nullopt; - default: unreachable(); + default: ::unreachable(); } default: - unreachable(); + ::unreachable(); } } @@ -57,17 +57,17 @@ Axis transpose(Plane const plane, ViewAxis const axis) noexcept { case YZ: return Y; case ZX: return Z; case XY: return X; - default: unreachable(); + default: ::unreachable(); } case V: switch(plane) { case YZ: return Z; case ZX: return X; case XY: return Y; - default: unreachable(); + default: ::unreachable(); } default: - unreachable(); + ::unreachable(); } } @@ -76,7 +76,7 @@ ViewAxis reverse(ViewAxis const axis) noexcept { switch(axis) { case H: return V; case V: return H; - default: unreachable(); + default: ::unreachable(); } } diff --git a/src/domain/material.cpp b/src/domain/material.cpp new file mode 100644 index 00000000..4f0f887b --- /dev/null +++ b/src/domain/material.cpp @@ -0,0 +1,66 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#include "utils/unreachable.hpp" + +#include "material.hpp" + +using namespace std; + +namespace domain { + +/// Simplified deduction. +///***************************************************************************** +Material::Type Material::deduce_type(double epsilon, double mue, double kappa) { + if(epsilon == default_epsilon && mue == default_mue && kappa == default_kappa) return Material::Type::AIR; + else if(epsilon > default_epsilon && mue >= default_mue && kappa == default_kappa) return Material::Type::DIELECTRIC; + else if(epsilon == default_epsilon && mue == default_mue && kappa > default_kappa) return Material::Type::CONDUCTOR; + else return Material::Type::DIELECTRIC; +} + +//****************************************************************************** +Material::Material(Type type, string const& name) +: type(type) +, name(name) +{} + +//****************************************************************************** +Material::Material(Type type, string const& name, optional const& fill_color, optional const& edge_color) +: type(type) +, name(name) +, fill_color(fill_color) +, edge_color(edge_color) +{} + +//****************************************************************************** +strong_ordering Material::operator<=>(Material const& other) const noexcept { + switch(type) { + case Type::CONDUCTOR: + switch(other.type) { + case Type::CONDUCTOR: return strong_ordering::equivalent; + case Type::DIELECTRIC: return strong_ordering::greater; + case Type::AIR: return strong_ordering::greater; + default: ::unreachable(); + } + case Type::DIELECTRIC: + switch(other.type) { + case Type::CONDUCTOR: return strong_ordering::less; + case Type::DIELECTRIC: return strong_ordering::equivalent; + case Type::AIR: return strong_ordering::greater; + default: ::unreachable(); + } + case Type::AIR: + switch(other.type) { + case Type::CONDUCTOR: return strong_ordering::less; + case Type::DIELECTRIC: return strong_ordering::less; + case Type::AIR: return strong_ordering::equivalent; + default: ::unreachable(); + } + default: ::unreachable(); + } +} + +} // namespace domain diff --git a/src/domain/material.hpp b/src/domain/material.hpp new file mode 100644 index 00000000..a7eeb63f --- /dev/null +++ b/src/domain/material.hpp @@ -0,0 +1,55 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +#include +#include +#include + +namespace domain { + +//****************************************************************************** +class Material { +public: + + enum class Type { +// DUMP, +// PEC, + CONDUCTOR, + DIELECTRIC, + AIR + } const type; + + // https://github.com/thliebig/CSXCAD/blob/master/src/CSProperties.h#L61 + struct Color { + unsigned char r, g, b, a; + }; + + std::strong_ordering operator<=>(Material const& other) const noexcept; + + Material(Type type, std::string const& name); + Material(Type type, std::string const& name, std::optional const& fill_color, std::optional const& edge_color); + + // https://wiki.openems.de/index.php/Material_Property.html + // Epsilon: relative electric permittivity (must be >=1) + // Mue: relative magnetic permeability (must be >=1) + // Kappa: electric conductivity (must be >=0) + // Sigma: magnetic conductivity (non-physical property, must be >=0) + // Values from CSXCAD. + static double constexpr default_epsilon = 1; + static double constexpr default_mue = 1; + static double constexpr default_kappa = 0; + static double constexpr default_sigma = 0; + + static Type deduce_type(double epsilon, double mue, double kappa); + + std::string const name; + std::optional const fill_color; + std::optional const edge_color; +}; + +} // namespace domain diff --git a/src/domain/mesh/interval.cpp b/src/domain/mesh/interval.cpp index 57135615..d5b0c52a 100644 --- a/src/domain/mesh/interval.cpp +++ b/src/domain/mesh/interval.cpp @@ -59,7 +59,7 @@ Interval::Interval(MeshlinePolicy* before, MeshlinePolicy* after, Axis axis, Glo return d; } } (); - default: unreachable(); + default: ::unreachable(); } }), .after = Side(after, global_params->get_current_state().lmin, global_params->get_current_state().lambda, calc_h(before->coord, after->coord), [after](double d) noexcept { @@ -76,7 +76,7 @@ Interval::Interval(MeshlinePolicy* before, MeshlinePolicy* after, Axis axis, Glo return d; } } (); - default: unreachable(); + default: ::unreachable(); } }) }) diff --git a/src/domain/mesh/meshline_policy.cpp b/src/domain/mesh/meshline_policy.cpp index 22c84133..f02db3df 100644 --- a/src/domain/mesh/meshline_policy.cpp +++ b/src/domain/mesh/meshline_policy.cpp @@ -69,7 +69,7 @@ MeshlinePolicy::Normal cast(Normal const normal) noexcept { case Normal::NONE: return MeshlinePolicy::Normal::NONE; default: - unreachable(); + ::unreachable(); } } diff --git a/src/infra/parsers/csxcad_layer/point_3d.cpp b/src/infra/parsers/csxcad_layer/point_3d.cpp index 848ec3a9..4f22519b 100644 --- a/src/infra/parsers/csxcad_layer/point_3d.cpp +++ b/src/infra/parsers/csxcad_layer/point_3d.cpp @@ -24,7 +24,7 @@ Point Point3D::get_projection(Plane plane) const { case YZ: return { y, z }; case ZX: return { z, x }; case XY: return { x, y }; - default: unreachable(); + default: ::unreachable(); } } diff --git a/src/infra/parsers/parser_from_csx.cpp b/src/infra/parsers/parser_from_csx.cpp index be808ac5..d850ef7b 100644 --- a/src/infra/parsers/parser_from_csx.cpp +++ b/src/infra/parsers/parser_from_csx.cpp @@ -5,10 +5,12 @@ ///***************************************************************************** #include +#include #include #include +#include "domain/material.hpp" #include "domain/geometrics/bounding.hpp" #include "domain/geometrics/polygon.hpp" #include "domain/geometrics/space.hpp" @@ -51,14 +53,13 @@ class ParserFromCsx::Pimpl { Pimpl(ParserFromCsx::Params const& params); - void parse_property(pugi::xml_node const& node); + shared_ptr parse_property(pugi::xml_node const& node); - void parse_primitive(pugi::xml_node const& node); - void parse_primitive_box(pugi::xml_node const& node, std::string name); - void parse_primitive_linpoly(pugi::xml_node const& node, std::string name); + bool parse_primitive(pugi::xml_node const& node, shared_ptr const& material); + void parse_primitive_box(pugi::xml_node const& node, shared_ptr const& material, std::string name); + void parse_primitive_linpoly(pugi::xml_node const& node, shared_ptr const& material, std::string name); private: - optional which_material_is(pugi::xml_node const& primitive_node); }; //****************************************************************************** @@ -67,22 +68,41 @@ ParserFromCsx::Pimpl::Pimpl(ParserFromCsx::Params const& params) {} //****************************************************************************** -void ParserFromCsx::Pimpl::parse_property(pugi::xml_node const& node) { - cerr << node.name() << endl; - - // TODO try to guess kind TRACK GROUND SUBSTRATE to disable EIP detection +shared_ptr ParserFromCsx::Pimpl::parse_property(pugi::xml_node const& node) { string name(node.attribute("Name").as_string()); + auto const parse_color = [](pugi::xml_node const& node) -> optional { + if(node) + return Material::Color { + static_cast(node.attribute("R").as_uint()), + static_cast(node.attribute("G").as_uint()), + static_cast(node.attribute("B").as_uint()), + static_cast(node.attribute("a").as_uint()) + }; + else + return nullopt; + }; + + auto fill = parse_color(node.child("FillColor")); + auto edge = parse_color(node.child("EdgeColor")); + if(node.name() == "Material"s) { + // https://github.com/thliebig/openEMS-Project/discussions/347 + // Currently do not take care of Isotropy=false + // as_double() selects the first term and ditch the part after + bool isotropy = node.attribute("Isotropy").as_bool(); pugi::xml_node property = node.child("Property"); - double epsilon = node.attribute("Epsilon").as_double(); // TODO optional - double mue = node.attribute("Mue").as_double(); // TODO optional - double kappa = node.attribute("Kappa").as_double(); // TODO optional - double sigma = node.attribute("Sigma").as_double(); // TODO optional + double epsilon = property.attribute("Epsilon").as_double(Material::default_epsilon); + double mue = property.attribute("Mue").as_double(Material::default_mue); + double kappa = property.attribute("Kappa").as_double(Material::default_kappa); + double sigma = property.attribute("Sigma").as_double(Material::default_sigma); + return make_shared(Material::deduce_type(epsilon, mue, kappa), name, fill, edge); } else if(node.name() == "Metal"s) { + return make_shared(Material::Type::CONDUCTOR, name, fill, edge); } else if(node.name() == "ConductingSheet"s) { double conductivity = node.attribute("Conductivity").as_double(); double thickness = node.attribute("Thickness").as_double(); + return make_shared(Material::Type::CONDUCTOR, name, fill, edge); } else if(node.name() == "LumpedElement"s) { } else if(node.name() == "Excitation"s) { } else if(node.name() == "ProbeBox"s) { @@ -93,67 +113,39 @@ void ParserFromCsx::Pimpl::parse_property(pugi::xml_node const& node) { } else if(node.name() == "Unknown"s) { } else if(node.name() == "DiscMaterial"s) { } + + return shared_ptr(); } //****************************************************************************** -void ParserFromCsx::Pimpl::parse_primitive(pugi::xml_node const& node) { - cerr << node.name() << endl; +bool ParserFromCsx::Pimpl::parse_primitive(pugi::xml_node const& node, shared_ptr const& material) { string property_name(node.parent().parent().attribute("Name").as_string()); string name(property_name + "::" + to_string(primitives_ids.at(node))); using pugi::char_t; - if(node.name() == "Box"s) - parse_primitive_box(node, name); - else if(node.name() == "LinPoly"s) - parse_primitive_linpoly(node, name); - else if(node.name() == "Polyhedron"s) {} - else if(node.name() == "Polygon"s) {} - else if(node.name() == "RotPoly"s) {} - else if(node.name() == "Sphere"s) {} - else if(node.name() == "Cylinder"s) {} - else if(node.name() == "Wire"s) {} - else if(node.name() == "CylindricalShell"s) {} - else if(node.name() == "User-Defined"s) {} - else if(node.name() == "Curve"s) {} - -} - -//****************************************************************************** -optional ParserFromCsx::Pimpl::which_material_is(pugi::xml_node const& primitive_node) { - string property(primitive_node.parent().parent().name()); - string property_name(primitive_node.parent().parent().attribute("Name").as_string()); - - if(contains(params.grounds, property_name)) { - return Polygon::Type::GROUND; - } else { - if(property == "Material") { - return Polygon::Type::SUBSTRATE; - } else if(property == "Metal" - || property == "ConductingSheet") { - return Polygon::Type::SHAPE; - } else if(property == "LumpedElement") { - } else if(property == "Excitation") { - } else if(property == "ProbeBox") { - } else if(property == "DumpBox") { - } else if(property == "DebyeMaterial") { - } else if(property == "LorentzMaterial") { - } else if(property == "ResBox") { - } else if(property == "Unknown") { - } else if(property == "DiscMaterial") { - } + if(node.name() == "Box"s) { + parse_primitive_box(node, material, name); + return true; + } else if(node.name() == "LinPoly"s) { + parse_primitive_linpoly(node, material, name); + return true; + } else if(node.name() == "Polyhedron"s) { + } else if(node.name() == "Polygon"s) { + } else if(node.name() == "RotPoly"s) { + } else if(node.name() == "Sphere"s) { + } else if(node.name() == "Cylinder"s) { + } else if(node.name() == "Wire"s) { + } else if(node.name() == "CylindricalShell"s) { + } else if(node.name() == "User-Defined"s) { + } else if(node.name() == "Curve"s) { } - - return nullopt; + return false; } //****************************************************************************** -void ParserFromCsx::Pimpl::parse_primitive_box(pugi::xml_node const& node, string name) { - auto const type = which_material_is(node); -// if(!type.has_value() || type.value() != Polygon::Type::SHAPE) // TODO - if(!type.has_value() || type.value() == Polygon::Type::SUBSTRATE) // TODO - return; - +void ParserFromCsx::Pimpl::parse_primitive_box(pugi::xml_node const& node, shared_ptr const& material, string name) { + size_t priority = node.attribute("Priority").as_uint(); pugi::xml_node node_p1 = node.child("P1"); pugi::xml_node node_p2 = node.child("P2"); Point3D p1( @@ -165,21 +157,17 @@ void ParserFromCsx::Pimpl::parse_primitive_box(pugi::xml_node const& node, strin node_p2.attribute("Y").as_double(), node_p2.attribute("Z").as_double()); if(params.with_yz) - board.add_polygon_from_box(YZ, type.value(), name, { p1.y, p1.z }, { p2.y, p2.z }); + board.add_polygon_from_box(YZ, material, name, priority, { p1.x, p2.x }, { p1.y, p1.z }, { p2.y, p2.z }); if(params.with_zx) - board.add_polygon_from_box(ZX, type.value(), name, { p1.z, p1.x }, { p2.z, p2.x }); + board.add_polygon_from_box(ZX, material, name, priority, { p1.y, p2.y }, { p1.z, p1.x }, { p2.z, p2.x }); if(params.with_xy) - board.add_polygon_from_box(XY, type.value(), name, { p1.x, p1.y }, { p2.x, p2.y }); + board.add_polygon_from_box(XY, material, name, priority, { p1.z, p2.z }, { p1.x, p1.y }, { p2.x, p2.y }); // TODO if property == ConductingSheet : add_fixed_meshline_policy() } //****************************************************************************** -void ParserFromCsx::Pimpl::parse_primitive_linpoly(pugi::xml_node const& node, string name) { - auto const type = which_material_is(node); -// if(!type.has_value() || type.value() != Polygon::Type::SHAPE) // TODO - if(!type.has_value() || type.value() == Polygon::Type::SUBSTRATE) // TODO - return; - +void ParserFromCsx::Pimpl::parse_primitive_linpoly(pugi::xml_node const& node, shared_ptr const& material, string name) { + size_t priority = node.attribute("Priority").as_uint(); double elevation = node.attribute("Elevation").as_double(); // offset in normdir double length = node.attribute("Length").as_double(); // height in normdir size_t normdir = node.attribute("NormDir").as_uint(); // (0->x, 1->y, 2->z) @@ -196,9 +184,9 @@ void ParserFromCsx::Pimpl::parse_primitive_linpoly(pugi::xml_node const& node, s Bounding2D bounding(detect_bounding(points)); - board.add_polygon(plane.value(), type.value(), name, std::move(points)); + board.add_polygon(plane.value(), material, name, priority, { elevation, elevation + length }, std::move(points)); if(length == 0) { - board.add_fixed_meshline_policy(normal.value(), elevation); +// board.add_fixed_meshline_policy(normal.value(), elevation); // switch(plane.value()) { // case YZ: // board.add_fixed_meshline_policy(Y, elevation); @@ -213,45 +201,49 @@ void ParserFromCsx::Pimpl::parse_primitive_linpoly(pugi::xml_node const& node, s // board.add_fixed_meshline_policy(Y, elevation); // break; // default: -// unreachable(); +// ::unreachable(); // } } else { -/* switch(plane.value()) { case YZ: if(params.with_zx) - board.add_polygon_from_box(ZX, name, + board.add_polygon_from_box(ZX, material, name, priority, + { bounding[XMIN], bounding[XMAX] }, { bounding[YMIN], elevation }, { bounding[YMAX], elevation + length }); if(params.with_xy) - board.add_polygon_from_box(XY, name, + board.add_polygon_from_box(XY, material, name, priority, + { bounding[YMIN], bounding[YMAX] }, { elevation, bounding[XMIN] }, { elevation + length, bounding[XMAX] }); break; case ZX: if(params.with_xy) - board.add_polygon_from_box(XY, name, + board.add_polygon_from_box(XY, material, name, priority, + { bounding[XMIN], bounding[XMAX] }, { bounding[YMIN], elevation }, { bounding[YMAX], elevation + length }); if(params.with_yz) - board.add_polygon_from_box(YZ, name, + board.add_polygon_from_box(YZ, material, name, priority, + { bounding[YMIN], bounding[YMAX] }, { elevation, bounding[XMIN] }, { elevation + length, bounding[XMAX] }); break; case XY: if(params.with_yz) - board.add_polygon_from_box(YZ, name, + board.add_polygon_from_box(YZ, material, name, priority, + { bounding[XMIN], bounding[XMAX] }, { bounding[YMIN], elevation }, { bounding[YMAX], elevation + length }); if(params.with_zx) - board.add_polygon_from_box(ZX, name, + board.add_polygon_from_box(ZX, material, name, priority, + { bounding[YMIN], bounding[YMAX] }, { elevation, bounding[XMIN] }, { elevation + length, bounding[XMAX] }); break; default: - unreachable(); + ::unreachable(); } -*/ } } @@ -316,11 +308,13 @@ void ParserFromCsx::parse() { pugi::xpath_node properties = doc.select_node("/openEMS/ContinuousStructure/Properties"); for(auto const& node : properties.node().children()) { - pimpl->parse_property(node); + auto material = pimpl->parse_property(node); pugi::xml_node primitives = node.child("Primitives"); - for(auto const& node : primitives.children()) - pimpl->parse_primitive(node); + for(auto const& node : primitives.children()) { + if(material) + pimpl->parse_primitive(node, material); + } } } diff --git a/src/infra/serializers/serializer_to_csx.cpp b/src/infra/serializers/serializer_to_csx.cpp index 69e18b7f..319a730c 100644 --- a/src/infra/serializers/serializer_to_csx.cpp +++ b/src/infra/serializers/serializer_to_csx.cpp @@ -23,7 +23,7 @@ string to_xml_node(Axis const axis) noexcept { case X: return "XLines"; case Y: return "YLines"; case Z: return "ZLines"; - default: unreachable(); + default: ::unreachable(); } } diff --git a/src/infra/utils/to_string.cpp b/src/infra/utils/to_string.cpp index c436fadd..30de71fb 100644 --- a/src/infra/utils/to_string.cpp +++ b/src/infra/utils/to_string.cpp @@ -19,7 +19,7 @@ string to_string(Edge::Direction const direction) noexcept { case Edge::Direction::YMIN: return "YMIN"; case Edge::Direction::YMAX: return "YMAX"; case Edge::Direction::NONE: return "NONE"; - default: unreachable(); + default: ::unreachable(); } } @@ -33,7 +33,7 @@ string to_string(Normal const normal) noexcept { case Normal::ZMIN: return "ZMIN"; case Normal::ZMAX: return "ZMAX"; case Normal::NONE: return "NONE"; - default: unreachable(); + default: ::unreachable(); } } @@ -43,7 +43,7 @@ string to_string(MeshlinePolicy::Normal const normal) noexcept { case MeshlinePolicy::Normal::MIN: return "MIN"; case MeshlinePolicy::Normal::MAX: return "MAX"; case MeshlinePolicy::Normal::NONE: return "NONE"; - default: unreachable(); + default: ::unreachable(); } } @@ -53,7 +53,7 @@ string to_string(MeshlinePolicy::Policy const policy) noexcept { case MeshlinePolicy::Policy::ONELINE: return "ONELINE"; case MeshlinePolicy::Policy::HALFS: return "HALFS"; case MeshlinePolicy::Policy::THIRDS: return "THIRDS"; - default: unreachable(); + default: ::unreachable(); } } @@ -63,7 +63,7 @@ string to_string(Polygon::Rotation const rotation) noexcept { case Polygon::Rotation::CW: return "CW"; case Polygon::Rotation::CCW: return "CCW"; case Polygon::Rotation::COLINEAR: return "COLINEAR"; - default: unreachable(); + default: ::unreachable(); } } @@ -74,7 +74,7 @@ string to_string(Segment::Axis const axis) noexcept { case Segment::Axis::V: return "V"; case Segment::Axis::DIAGONAL: return "DIAGONAL"; case Segment::Axis::POINT: return "POINT"; - default: unreachable(); + default: ::unreachable(); } } @@ -84,7 +84,7 @@ string to_string(Axis const axis) noexcept { case X: return "X"; case Y: return "Y"; case Z: return "Z"; - default: unreachable(); + default: ::unreachable(); } } @@ -94,6 +94,16 @@ string to_string(Plane const plane) noexcept { case YZ: return "YZ"; case ZX: return "ZX"; case XY: return "XY"; - default: unreachable(); + default: ::unreachable(); + } +} + +//****************************************************************************** +string to_string(domain::Material::Type type) noexcept { + switch(type) { + case Material::Type::CONDUCTOR: return "CONDUCTOR"; + case Material::Type::DIELECTRIC: return "DIELECTRIC"; + case Material::Type::AIR: return "AIR"; + default: ::unreachable(); } } diff --git a/src/infra/utils/to_string.hpp b/src/infra/utils/to_string.hpp index 3fc3f088..686ad8a8 100644 --- a/src/infra/utils/to_string.hpp +++ b/src/infra/utils/to_string.hpp @@ -12,6 +12,7 @@ #include "domain/geometrics/normal.hpp" #include "domain/mesh/meshline_policy.hpp" #include "domain/meshline_policy_manager.hpp" +#include "domain/material.hpp" //****************************************************************************** std::string to_string(domain::Edge::Direction direction) noexcept; @@ -22,3 +23,4 @@ std::string to_string(domain::Segment::Axis axis) noexcept; std::string to_string(domain::Axis axis) noexcept; std::string to_string(domain::Normal normal) noexcept; std::string to_string(domain::Plane plane) noexcept; +std::string to_string(domain::Material::Type type) noexcept; diff --git a/src/ui/qt/edit/edit_model_edge.cpp b/src/ui/qt/edit/edit_model_edge.cpp index a854b5c5..bc386e9e 100644 --- a/src/ui/qt/edit/edit_model_edge.cpp +++ b/src/ui/qt/edit/edit_model_edge.cpp @@ -20,9 +20,10 @@ EditModelEdge::EditModelEdge(domain::Edge* edge, QObject* parent) , edge(edge) { auto const& state = edge->get_current_state(); - setRowCount(1); + 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."); } //****************************************************************************** @@ -30,7 +31,8 @@ void EditModelEdge::commit() { auto state = edge->get_current_state(); std::array does_succeed = { - try_to_bool(item(0, V)->checkState(), state.to_mesh) + try_to_bool(item(0, V)->checkState(), state.to_mesh), + try_to_bool(item(1, V)->checkState(), state.to_reverse) }; if(std::ranges::all_of(does_succeed, is_true)) { diff --git a/src/ui/qt/main_window.cpp b/src/ui/qt/main_window.cpp index f57157e6..e261e9c9 100644 --- a/src/ui/qt/main_window.cpp +++ b/src/ui/qt/main_window.cpp @@ -19,6 +19,7 @@ #include "utils/state_management.hpp" #include "utils/unreachable.hpp" #include "about_dialog.hpp" +#include "settings.hpp" #include "ui_main_window.h" #include "main_window.hpp" @@ -53,6 +54,10 @@ MainWindow::MainWindow(app::OpenEMSH& oemsh, QWidget* parent) } ui->m_style->addAction(action); } + + Settings::singleton() = { + .does_use_material_color = ui->a_does_use_csx_properties_color->isChecked() + }; } //****************************************************************************** @@ -371,6 +376,12 @@ void MainWindow::on_a_redo_triggered() { QGuiApplication::restoreOverrideCursor(); } +//****************************************************************************** +void MainWindow::on_a_does_use_csx_properties_color_triggered() { + Settings::singleton().does_use_material_color = ui->a_does_use_csx_properties_color->isChecked(); + ui->structure_view->viewport()->update(); +} + //****************************************************************************** void MainWindow::go_to_or_make_current_state() { auto* t = Caretaker::singleton().get_current_timepoint(); @@ -423,6 +434,12 @@ void MainWindow::run(app::Step from) { make_current_state_view(); } +//****************************************************************************** +void MainWindow::run() { + oemsh.run_all_steps(); + make_current_state_view(); +} + //****************************************************************************** void MainWindow::handle_edition_from(app::Step from, std::function const& edit) { oemsh.go_before(from); diff --git a/src/ui/qt/main_window.hpp b/src/ui/qt/main_window.hpp index adec0955..0fad6f76 100644 --- a/src/ui/qt/main_window.hpp +++ b/src/ui/qt/main_window.hpp @@ -39,7 +39,8 @@ class MainWindow : public QMainWindow { void go_to_current_state(); void make_current_state_view(); void go_to_or_make_current_state(); - void run(app::Step from = app::Step::DETECT_CONFLICT_EIP); + void run(app::Step from); + void run(); private slots: void on_a_about_triggered(); @@ -75,6 +76,7 @@ private slots: void on_a_mesh_next_triggered(); void on_a_undo_triggered(); void on_a_redo_triggered(); + void on_a_does_use_csx_properties_color_triggered(); void edit_global_params(); void handle_edition_from(app::Step from, std::function const& edit); diff --git a/src/ui/qt/main_window.ui b/src/ui/qt/main_window.ui index fb0e9320..b9f07ec2 100644 --- a/src/ui/qt/main_window.ui +++ b/src/ui/qt/main_window.ui @@ -616,7 +616,17 @@ + + + Settings + + + true + + + + @@ -774,6 +784,20 @@ + + + Use CSX Properties colors + + + In Structure View, draw selected shapes using color from CSX Properties, if available + + + true + + + true + + diff --git a/src/ui/qt/processing_view/processing_conflict_colinear_edges.cpp b/src/ui/qt/processing_view/processing_conflict_colinear_edges.cpp index bffdf67d..ddd41343 100644 --- a/src/ui/qt/processing_view/processing_conflict_colinear_edges.cpp +++ b/src/ui/qt/processing_view/processing_conflict_colinear_edges.cpp @@ -17,7 +17,7 @@ namespace ui::qt { //****************************************************************************** ProcessingConflictColinearEdges::ProcessingConflictColinearEdges(domain::ConflictColinearEdges const* conflict, QGraphicsItem* parent) -: nodegraph::Node("ConflictColinearEdges", parent) +: nodegraph::Node("ConflictColinearEdges - " + (conflict ? QString::number(conflict->id) : QString()), parent) , locate_processing_conflict_ce_params(default_locator) , conflict(conflict) { diff --git a/src/ui/qt/processing_view/processing_conflict_edge_in_polygon.cpp b/src/ui/qt/processing_view/processing_conflict_edge_in_polygon.cpp index 9fe5297e..81003ac7 100644 --- a/src/ui/qt/processing_view/processing_conflict_edge_in_polygon.cpp +++ b/src/ui/qt/processing_view/processing_conflict_edge_in_polygon.cpp @@ -18,7 +18,7 @@ namespace ui::qt { //****************************************************************************** ProcessingConflictEdgeInPolygon::ProcessingConflictEdgeInPolygon(domain::ConflictEdgeInPolygon const* conflict, QGraphicsItem* parent) -: nodegraph::Node("ConflictEdgeInPolygon", parent) +: nodegraph::Node("ConflictEdgeInPolygon - " + (conflict ? QString::number(conflict->id) : QString()), parent) , locate_processing_conflict_eip_params(default_locator) , conflict(conflict) { diff --git a/src/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.cpp b/src/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.cpp index 90af3f5b..dcc306e2 100644 --- a/src/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.cpp +++ b/src/ui/qt/processing_view/processing_conflict_too_close_meshline_policies.cpp @@ -18,7 +18,7 @@ namespace ui::qt { //****************************************************************************** ProcessingConflictTooCloseMeshlinePolicies::ProcessingConflictTooCloseMeshlinePolicies(domain::ConflictTooCloseMeshlinePolicies const* conflict, QGraphicsItem* parent) -: nodegraph::Node("ConflictTooCloseMeshlinePolicies", parent) +: nodegraph::Node("ConflictTooCloseMeshlinePolicies - " + (conflict ? QString::number(conflict->id) : QString()), parent) , locate_processing_conflict_tcmlp_params(default_locator) , conflict(conflict) { diff --git a/src/ui/qt/processing_view/processing_edge.cpp b/src/ui/qt/processing_view/processing_edge.cpp index 1d974695..7150cd56 100644 --- a/src/ui/qt/processing_view/processing_edge.cpp +++ b/src/ui/qt/processing_view/processing_edge.cpp @@ -20,7 +20,7 @@ namespace ui::qt { //****************************************************************************** ProcessingEdge::ProcessingEdge(domain::Edge const* edge, QGraphicsItem* parent) -: nodegraph::Node("Edge", parent) +: nodegraph::Node("Edge - " + (edge ? QString::number(edge->id) : QString()), parent) , locate_processing_edge_params(default_locator) , edge(edge) { @@ -53,9 +53,11 @@ ProcessingEdge::ProcessingEdge(domain::Edge const* edge, QGraphicsItem* parent) QString normal("Normal: "); QString to_mesh("To mesh: "); + QString to_reverse("To reverse: "); if(edge) { normal += QString::fromStdString(to_string(edge->normal)); to_mesh += (edge->get_current_state().to_mesh ? "true" : "false"); + to_reverse += (edge->get_current_state().to_reverse ? "true" : "false"); } auto* text_normal = new nodegraph::Text(normal, this); @@ -65,6 +67,13 @@ ProcessingEdge::ProcessingEdge(domain::Edge const* edge, QGraphicsItem* parent) return locate_processing_edge_params().main; }; + auto* text_to_reverse = new nodegraph::Text(to_reverse, this); + text_to_reverse->setFlag(QGraphicsItem::ItemIsSelectable); + text_to_reverse->setAcceptedMouseButtons(Qt::NoButton); + text_to_reverse->locate_text_params = [this]() -> auto& { + return locate_processing_edge_params().main; + }; + auto* text_to_mesh = new nodegraph::Text(to_mesh, this); text_to_mesh->setFlag(QGraphicsItem::ItemIsSelectable); text_to_mesh->setAcceptedMouseButtons(Qt::NoButton); @@ -96,6 +105,7 @@ ProcessingEdge::ProcessingEdge(domain::Edge const* edge, QGraphicsItem* parent) v_box1->addStretch(); v_box2->addItem(text_normal); v_box2->addItem(text_to_mesh); + v_box2->addItem(text_to_reverse); v_box3->addStretch(); v_box3->addItem(output_port); v_box3->addStretch(); diff --git a/src/ui/qt/processing_view/processing_interval.cpp b/src/ui/qt/processing_view/processing_interval.cpp index 8dbafa2e..072f089d 100644 --- a/src/ui/qt/processing_view/processing_interval.cpp +++ b/src/ui/qt/processing_view/processing_interval.cpp @@ -19,7 +19,7 @@ namespace ui::qt { //****************************************************************************** ProcessingInterval::ProcessingInterval(domain::Interval const* interval, QGraphicsItem* parent) -: nodegraph::Node("Interval", parent) +: nodegraph::Node("Interval - " + (interval ? QString::number(interval->id) : QString()), parent) , locate_processing_interval_params(default_locator) , interval(interval) { diff --git a/src/ui/qt/processing_view/processing_meshline.cpp b/src/ui/qt/processing_view/processing_meshline.cpp index 8370ebee..e58aae4b 100644 --- a/src/ui/qt/processing_view/processing_meshline.cpp +++ b/src/ui/qt/processing_view/processing_meshline.cpp @@ -20,7 +20,7 @@ namespace ui::qt { //****************************************************************************** ProcessingMeshline::ProcessingMeshline(domain::Meshline const* meshline, QGraphicsItem* parent) -: nodegraph::Node("Meshline", parent) +: nodegraph::Node("Meshline - " + (meshline ? QString::number(meshline->id) : QString()), parent) , locate_processing_meshline_params(default_locator) , meshline(meshline) { diff --git a/src/ui/qt/processing_view/processing_meshline_policy.cpp b/src/ui/qt/processing_view/processing_meshline_policy.cpp index eb5b1f34..ee27412c 100644 --- a/src/ui/qt/processing_view/processing_meshline_policy.cpp +++ b/src/ui/qt/processing_view/processing_meshline_policy.cpp @@ -24,7 +24,7 @@ namespace ui::qt { //****************************************************************************** ProcessingMeshlinePolicy::ProcessingMeshlinePolicy(domain::MeshlinePolicy const* meshline_policy, QGraphicsItem* parent) -: nodegraph::Node("MeshlinePolicy", parent) +: nodegraph::Node("MeshlinePolicy - " + (meshline_policy ? QString::number(meshline_policy->id) : QString()), parent) , locate_processing_meshline_policy_params(default_locator) , meshline_policy(meshline_policy) { diff --git a/src/ui/qt/processing_view/processing_polygon.cpp b/src/ui/qt/processing_view/processing_polygon.cpp index b5644d79..1fb09566 100644 --- a/src/ui/qt/processing_view/processing_polygon.cpp +++ b/src/ui/qt/processing_view/processing_polygon.cpp @@ -9,6 +9,7 @@ #include "domain/geometrics/polygon.hpp" #include "ui/qt/data_keys.hpp" #include "ui/qt/utils/nodegraph/rect.hpp" +#include "infra/utils/to_string.hpp" #include "processing_edge.hpp" #include "processing_polygon.hpp" @@ -17,7 +18,7 @@ namespace ui::qt { //****************************************************************************** ProcessingPolygon::ProcessingPolygon(domain::Polygon const* polygon, QGraphicsItem* parent) -: nodegraph::Container("Polygon " + (polygon ? QString::fromStdString(polygon->name) : QString()), QSizeF(50, 10), parent) +: nodegraph::Container("Polygon - " + (polygon ? QString::number(polygon->id) + " - " + QString::fromStdString(polygon->name) : QString()), QSizeF(50, 10), parent) , locate_processing_polygon_params(default_locator) , polygon(polygon) { @@ -40,7 +41,34 @@ ProcessingPolygon::ProcessingPolygon(domain::Polygon const* polygon, QGraphicsIt return locate_processing_polygon_params().port; }; + QString type("Type: "); + QString priority("Priority: "); + if(polygon) { + if(polygon->material) { + type += QString::fromStdString(to_string(polygon->material->type)); + } + priority += QString::number(polygon->priority); + } + + auto* text_type = new nodegraph::Text(type, this); + text_type->setFlag(QGraphicsItem::ItemIsSelectable); + text_type->setAcceptedMouseButtons(Qt::NoButton); + text_type->locate_text_params = [this]() -> auto& { + return locate_processing_polygon_params().main; + }; + + auto* text_priority = new nodegraph::Text(priority, this); + text_priority->setFlag(QGraphicsItem::ItemIsSelectable); + text_priority->setAcceptedMouseButtons(Qt::NoButton); + text_priority->locate_text_params = [this]() -> auto& { + return locate_processing_polygon_params().main; + }; + auto* h_box = new QGraphicsLinearLayout(Qt::Horizontal, layout()); + auto* v_box = new QGraphicsLinearLayout(Qt::Vertical, h_box); + layout()->insertItem(1, v_box); + v_box->addItem(text_type); + v_box->addItem(text_priority); layout()->addItem(h_box); h_box->addStretch(); h_box->addItem(output_port); diff --git a/src/ui/qt/processing_view/processing_polygon.hpp b/src/ui/qt/processing_view/processing_polygon.hpp index 79282d90..16914148 100644 --- a/src/ui/qt/processing_view/processing_polygon.hpp +++ b/src/ui/qt/processing_view/processing_polygon.hpp @@ -34,6 +34,7 @@ class ProcessingPolygon : public nodegraph::Container { 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::Rect::Params const& nested_zone = default_locator(); }; diff --git a/src/ui/qt/processing_view/processing_style.cpp b/src/ui/qt/processing_view/processing_style.cpp index de9e5b51..5262d421 100644 --- a/src/ui/qt/processing_view/processing_style.cpp +++ b/src/ui/qt/processing_view/processing_style.cpp @@ -335,6 +335,7 @@ MAKER_DEF(ProcessingStyleSelector, polygon) { .node = get_node(), .port = get_port_normal(), .title = get_title(), + .main = get_text_normal(), .nested_zone = get_nested_zone() }; } diff --git a/src/ui/qt/settings.hpp b/src/ui/qt/settings.hpp new file mode 100644 index 00000000..cc2c9132 --- /dev/null +++ b/src/ui/qt/settings.hpp @@ -0,0 +1,24 @@ +///***************************************************************************** +/// @date Feb 2021 +/// @copyright GPL-3.0-or-later +/// @author Thomas Lepoix +///***************************************************************************** + +#pragma once + +namespace ui::qt { + +//****************************************************************************** +struct Settings { + static Settings& singleton() noexcept; + + bool does_use_material_color; +}; + +//****************************************************************************** +inline Settings& Settings::singleton() noexcept { + static Settings s; + return s; +} + +} // namespace ui::qt diff --git a/src/ui/qt/structure_view/structure_polygon.cpp b/src/ui/qt/structure_view/structure_polygon.cpp index 3216edbe..4cda1619 100644 --- a/src/ui/qt/structure_view/structure_polygon.cpp +++ b/src/ui/qt/structure_view/structure_polygon.cpp @@ -8,10 +8,13 @@ #include #include +#include + #include "domain/geometrics/point.hpp" #include "domain/geometrics/polygon.hpp" #include "utils/default_locator.hpp" #include "ui/qt/data_keys.hpp" +#include "ui/qt/settings.hpp" #include "structure_polygon.hpp" @@ -40,6 +43,10 @@ StructurePolygon::StructurePolygon(domain::Polygon const* polygon, QGraphicsItem setData(DataKeys::ID, (qulonglong) polygon->id); setData(DataKeys::ENTITY, DataKeys::set_entity(polygon)); setData(DataKeys::NAME, QString::fromStdString(polygon->name)); + if(polygon->material + && polygon->material->fill_color.has_value() + && polygon->material->edge_color.has_value()) + has_color = true; } //****************************************************************************** @@ -47,22 +54,61 @@ int StructurePolygon::type() const { return Type; } +//****************************************************************************** +void StructurePolygon::hoverEnterEvent(QGraphicsSceneHoverEvent* event) { + if(!isSelected()) + setZValue(std::numeric_limits::max()); + QGraphicsItem::hoverEnterEvent(event); +} + +//****************************************************************************** +void StructurePolygon::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { + if(!isSelected()) + setZValue(0); + QGraphicsItem::hoverLeaveEvent(event); +} + +//****************************************************************************** +QVariant StructurePolygon::itemChange(GraphicsItemChange change, QVariant const& value) { + if(change == ItemSelectedChange) { + if(value.toBool()) + setZValue(std::numeric_limits::max()); + else + setZValue(0); + } + return QGraphicsItem::itemChange(change, value); +} + //****************************************************************************** void StructurePolygon::paint(QPainter* painter, QStyleOptionGraphicsItem const* option, QWidget* /*widget*/) { Params const& params = locate_structure_polygon_params(); if(option->state & QStyle::State_Selected) { - if(option->state & QStyle::State_MouseOver) { - painter->setBrush(params.fill_selected_hovered); - painter->setPen(params.contour_selected_hovered); + if(Settings::singleton().does_use_material_color && has_color) { + auto& f = polygon->material->fill_color.value(); + auto& e = polygon->material->edge_color.value(); + painter->setBrush(QColor(f.r, f.g, f.b, f.a)); + painter->setPen(QColor(e.r, e.g, e.b, e.a)); } else { - painter->setBrush(params.fill_selected); - painter->setPen(params.contour_selected); + if(option->state & QStyle::State_MouseOver) { + painter->setBrush(params.fill_selected_hovered); + painter->setPen(params.contour_selected_hovered); + } else { + painter->setBrush(params.fill_selected); + painter->setPen(params.contour_selected); + } } } else { if(option->state & QStyle::State_MouseOver) { - painter->setBrush(params.fill_regular_hovered); - painter->setPen(params.contour_regular_hovered); + if(Settings::singleton().does_use_material_color && has_color) { + auto& f = polygon->material->fill_color.value(); + auto& e = polygon->material->edge_color.value(); + painter->setBrush(QColor(f.r, f.g, f.b, f.a)); + painter->setPen(QColor(e.r, e.g, e.b, e.a)); + } else { + painter->setBrush(params.fill_regular_hovered); + painter->setPen(params.contour_regular_hovered); + } } else { painter->setBrush(params.fill_regular); painter->setPen(params.contour_regular); diff --git a/src/ui/qt/structure_view/structure_polygon.hpp b/src/ui/qt/structure_view/structure_polygon.hpp index d7de8a5b..0e692ce2 100644 --- a/src/ui/qt/structure_view/structure_polygon.hpp +++ b/src/ui/qt/structure_view/structure_polygon.hpp @@ -41,10 +41,16 @@ class StructurePolygon : public QGraphicsPolygonItem { explicit StructurePolygon(domain::Polygon const* polygon, QGraphicsItem* parent = nullptr); int type() const override; + +protected: void paint(QPainter* painter, QStyleOptionGraphicsItem const* option, QWidget* widget = nullptr) override; + void hoverEnterEvent(QGraphicsSceneHoverEvent* event) override; + void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override; + QVariant itemChange(GraphicsItemChange change, QVariant const& value) override; private: domain::Polygon const* const polygon; + bool has_color = false; }; } // namespace ui::qt diff --git a/src/ui/qt/structure_view/structure_scene.cpp b/src/ui/qt/structure_view/structure_scene.cpp index d3522541..e6a58dd5 100644 --- a/src/ui/qt/structure_view/structure_scene.cpp +++ b/src/ui/qt/structure_view/structure_scene.cpp @@ -116,30 +116,38 @@ StructureEdge* StructureScene::add(domain::Edge const* edge) { StructurePolygon* StructureScene::add(domain::Polygon const* polygon) { auto* item = new StructurePolygon(polygon, polygons); index[polygon] = item; - switch(polygon->type) { - case domain::Polygon::Type::SHAPE: - item->locate_structure_polygon_params = [this]() -> auto& { - return style_selector.get_polygon_shape(); - }; - break; - case domain::Polygon::Type::PORT: - item->locate_structure_polygon_params = [this]() -> auto& { - return style_selector.get_polygon_port(); - }; - break; - case domain::Polygon::Type::GROUND: - item->locate_structure_polygon_params = [this]() -> auto& { - return style_selector.get_polygon_ground(); - }; - break; - case domain::Polygon::Type::SUBSTRATE: - item->locate_structure_polygon_params = [this]() -> auto& { - return style_selector.get_polygon_substrate(); - }; - break; - default: - unreachable(); - } +// switch(polygon->material->type) { +// case domain::Material::Type::CONDUCTOR: +// item->locate_structure_polygon_params = [this]() -> auto& { +// return style_selector.get_polygon_shape(); +// }; +// break; +// case domain::Material::Type::PORT: +// item->locate_structure_polygon_params = [this]() -> auto& { +// return style_selector.get_polygon_port(); +// }; +// break; +// case domain::Material::Type::GROUND: +// item->locate_structure_polygon_params = [this]() -> auto& { +// return style_selector.get_polygon_ground(); +// }; +// break; +// case domain::Material::Type::DIELECTRIC: +// item->locate_structure_polygon_params = [this]() -> auto& { +// return style_selector.get_polygon_substrate(); +// }; +// break; +// case domain::Material::Type::AIR: +// item->locate_structure_polygon_params = [this]() -> auto& { +// return style_selector.get_polygon_substrate(); +// }; +// break; +// default: +// unreachable(); +// } + item->locate_structure_polygon_params = [this]() -> auto& { + return style_selector.get_polygon_shape(); + }; return item; } diff --git a/src/ui/qt/style.cpp b/src/ui/qt/style.cpp index 04991063..5b3f1b74 100644 --- a/src/ui/qt/style.cpp +++ b/src/ui/qt/style.cpp @@ -116,7 +116,8 @@ std::vector