@@ -781,16 +781,14 @@ RulesCheckResult BoardRules::check_plane_priorities(const Board &brd) const
781
781
r.level = RulesCheckErrorLevel::PASS;
782
782
783
783
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 ;
785
785
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);
789
788
}
790
789
}
791
790
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) {
794
792
struct Path {
795
793
Path (ClipperLib::Path &&p, const Plane &pl) : path(p), plane(pl)
796
794
{
@@ -813,24 +811,90 @@ RulesCheckResult BoardRules::check_plane_priorities(const Board &brd) const
813
811
for (size_t i = 0 ; i < n; i++) {
814
812
for (size_t j = 0 ; j < n; j++) {
815
813
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
+ }
828
897
}
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};
834
898
}
835
899
}
836
900
}
0 commit comments