Skip to content

Commit 39f937a

Browse files
plane check: check for priorities of enclosing planes
1 parent cf0f435 commit 39f937a

File tree

1 file changed

+87
-23
lines changed

1 file changed

+87
-23
lines changed

src/board/board_rules_check.cpp

Lines changed: 87 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -781,16 +781,14 @@ RulesCheckResult BoardRules::check_plane_priorities(const Board &brd) const
781781
r.level = RulesCheckErrorLevel::PASS;
782782

783783

784-
std::map<std::pair<int, int>, std::vector<const Polygon *>> polys_by_priority_and_layer;
784+
std::map<int, std::vector<const Polygon *>> polys_by_layer;
785785
for (const auto &[uu, poly] : brd.polygons) {
786-
if (auto plane = dynamic_cast<const Plane *>(poly.usage.ptr)) {
787-
const auto key = std::make_pair(plane->priority, poly.layer);
788-
polys_by_priority_and_layer[key].push_back(&poly);
786+
if (poly.usage && poly.usage->get_type() == PolygonUsage::Type::PLANE) {
787+
polys_by_layer[poly.layer].push_back(&poly);
789788
}
790789
}
791790

792-
for (const auto &[key, polys] : polys_by_priority_and_layer) {
793-
const auto [prio, layer] = key;
791+
for (const auto &[layer, polys] : polys_by_layer) {
794792
struct Path {
795793
Path(ClipperLib::Path &&p, const Plane &pl) : path(p), plane(pl)
796794
{
@@ -813,24 +811,90 @@ RulesCheckResult BoardRules::check_plane_priorities(const Board &brd) const
813811
for (size_t i = 0; i < n; i++) {
814812
for (size_t j = 0; j < n; j++) {
815813
if (i < j) {
816-
ClipperLib::Clipper clipper;
817-
clipper.AddPath(paths.at(i).path, ClipperLib::ptClip, true);
818-
clipper.AddPath(paths.at(j).path, ClipperLib::ptSubject, true);
819-
ClipperLib::Paths errors;
820-
clipper.Execute(ClipperLib::ctIntersection, errors);
821-
for (const auto &ite : errors) {
822-
r.errors.emplace_back(RulesCheckErrorLevel::FAIL);
823-
auto &e = r.errors.back();
824-
e.has_location = true;
825-
Accumulator<Coordi> acc;
826-
for (const auto &ite2 : ite) {
827-
acc.accumulate({ite2.X, ite2.Y});
814+
const auto &path_a = paths.at(i);
815+
const auto &path_b = paths.at(j);
816+
ClipperLib::Paths isect;
817+
{
818+
ClipperLib::Clipper clipper;
819+
clipper.AddPath(path_a.path, ClipperLib::ptClip, true);
820+
clipper.AddPath(path_b.path, ClipperLib::ptSubject, true);
821+
clipper.Execute(ClipperLib::ctIntersection, isect);
822+
}
823+
if (isect.size()) {
824+
// planes do overlap, check if one plane completly encloses the other
825+
bool a_encloses_b = false;
826+
bool b_encloses_a = false;
827+
for (const auto &[a, b, e] : {std::make_tuple(path_a, path_b, &a_encloses_b),
828+
std::make_tuple(path_b, path_a, &b_encloses_a)}) {
829+
ClipperLib::Paths remainder;
830+
831+
ClipperLib::Clipper clipper;
832+
clipper.AddPath(a.path, ClipperLib::ptClip, true);
833+
clipper.AddPath(b.path, ClipperLib::ptSubject, true);
834+
clipper.Execute(ClipperLib::ctDifference, remainder);
835+
if (remainder.size() == 0) { // a encloses b
836+
*e = true;
837+
}
838+
}
839+
if (a_encloses_b && b_encloses_a) {
840+
// looks like both planes are identical
841+
for (const auto &ite : isect) {
842+
r.errors.emplace_back(RulesCheckErrorLevel::WARN);
843+
auto &e = r.errors.back();
844+
e.has_location = true;
845+
Accumulator<Coordi> acc;
846+
for (const auto &ite2 : ite) {
847+
acc.accumulate({ite2.X, ite2.Y});
848+
}
849+
e.location = acc.get();
850+
e.comment = "Plane outline " + get_net_name(path_a.plane.net)
851+
+ " is identical to plane outline " + get_net_name(path_b.plane.net)
852+
+ " on layer " + brd.get_layers().at(layer).name;
853+
e.error_polygons = {ite};
854+
}
855+
}
856+
else if (a_encloses_b || b_encloses_a) {
857+
// enclosing plane needs to have lower priority (higher number) than enclosed plane
858+
if ((a_encloses_b && (path_a.plane.priority <= path_b.plane.priority))
859+
|| (b_encloses_a && (path_b.plane.priority <= path_a.plane.priority))) {
860+
const auto &enclosing_plane = (a_encloses_b ? path_a : path_b).plane;
861+
const auto &enclosed_plane = (a_encloses_b ? path_b : path_a).plane;
862+
for (const auto &ite : isect) {
863+
r.errors.emplace_back(RulesCheckErrorLevel::FAIL);
864+
auto &e = r.errors.back();
865+
e.has_location = true;
866+
Accumulator<Coordi> acc;
867+
for (const auto &ite2 : ite) {
868+
acc.accumulate({ite2.X, ite2.Y});
869+
}
870+
e.location = acc.get();
871+
e.comment = "Plane " + get_net_name(enclosing_plane.net) + " enclosing plane "
872+
+ get_net_name(enclosed_plane.net) + " on layer "
873+
+ brd.get_layers().at(layer).name
874+
+ " needs higher fill order than enclosed plane";
875+
e.error_polygons = {ite};
876+
}
877+
}
878+
}
879+
else { // no polygon encloses the other, need to have different priorities
880+
if (path_a.plane.priority == path_b.plane.priority) {
881+
for (const auto &ite : isect) {
882+
r.errors.emplace_back(RulesCheckErrorLevel::FAIL);
883+
auto &e = r.errors.back();
884+
e.has_location = true;
885+
Accumulator<Coordi> acc;
886+
for (const auto &ite2 : ite) {
887+
acc.accumulate({ite2.X, ite2.Y});
888+
}
889+
e.location = acc.get();
890+
e.comment = "Plane " + get_net_name(path_a.plane.net) + " overlapping plane "
891+
+ get_net_name(path_b.plane.net) + " of fill order "
892+
+ std::to_string(path_a.plane.priority) + " on layer "
893+
+ brd.get_layers().at(layer).name;
894+
e.error_polygons = {ite};
895+
}
896+
}
828897
}
829-
e.location = acc.get();
830-
e.comment = "Plane outline " + get_net_name(paths.at(i).plane.net) + " overlaps plane outline "
831-
+ get_net_name(paths.at(j).plane.net) + " of priority " + std::to_string(prio)
832-
+ " on layer " + brd.get_layers().at(layer).name;
833-
e.error_polygons = {ite};
834898
}
835899
}
836900
}

0 commit comments

Comments
 (0)