86 BOOST_REQUIRE_MESSAGE( m_board,
"Failed to load board issue24543" );
90 std::shared_ptr<DRC_ITEM> item;
92 std::vector<PCB_SHAPE> pathShapes;
96 std::vector<ViolationInfo> violations;
99 BOOST_REQUIRE_MESSAGE( bds.
m_DRCEngine,
"DRC engine not initialized" );
107 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I& aPos,
int aLayer,
108 const std::function<
void(
PCB_MARKER* )>& aPathGenerator )
121 aPathGenerator( &marker );
122 vi.pathShapes = marker.
GetPath();
125 violations.push_back( vi );
133 (
int) violations.size() ) );
139 for(
FOOTPRINT* fp : m_board->Footprints() )
141 if( fp->GetReference() != wxT(
"C4" ) )
144 for(
PAD* p : fp->Pads() )
146 if( p->GetNumber() == wxT(
"1" ) )
148 else if( p->GetNumber() == wxT(
"2" ) )
153 BOOST_REQUIRE_MESSAGE( pad1 && pad2,
"C4 pads 1 and 2 not found in board" );
159 [](
const PAD* aPad )
161 double deg = aPad->GetOrientation().Normalize().AsDegrees();
162 double mod = std::fmod( deg, 90.0 );
163 return mod < 0.01 || mod > 89.99;
166 BOOST_REQUIRE_MESSAGE( !isOrthogonal( pad1 ) || !isOrthogonal( pad2 ),
167 "Expected at least one C4 pad to be rotated off-axis" );
169 const ViolationInfo* c4Violation =
nullptr;
171 for(
const ViolationInfo& vi : violations )
173 if( vi.layer !=
F_Cu )
176 const KIID idA = vi.item->GetMainItemID();
177 const KIID idB = vi.item->GetAuxItemID();
178 const bool matchA = ( idA == pad1->
m_Uuid || idA == pad2->
m_Uuid );
179 const bool matchB = ( idB == pad1->
m_Uuid || idB == pad2->
m_Uuid );
181 if( matchA && matchB && idA != idB )
188 BOOST_REQUIRE_MESSAGE( c4Violation,
189 "No F.Cu creepage violation reported between C4 pad1 and pad2" );
191 BOOST_REQUIRE_GE( c4Violation->pathShapes.size(), 1u );
194 std::vector<VECTOR2I> endpoints;
196 for(
const PCB_SHAPE& s : c4Violation->pathShapes )
198 endpoints.push_back( s.
GetStart() );
199 endpoints.push_back( s.
GetEnd() );
206 BOOST_REQUIRE( poly1->OutlineCount() > 0 && poly2->OutlineCount() > 0 );
218 auto distToNearestHoleMM =
219 [&](
const VECTOR2I& aPt ) ->
double
221 double best = std::numeric_limits<double>::max();
223 for(
const PAD* p : m_board->GetPads() )
228 std::shared_ptr<SHAPE_SEGMENT> hole = p->GetEffectiveHoleShape();
233 int r = hole->GetWidth() / 2;
234 SEG::ecoord d = hole->GetSeg().SquaredDistance( aPt );
235 double edgeDist =
std::abs( std::sqrt( (
double) d ) - r ) / 1e6;
236 best = std::min( best, edgeDist );
245 double closestToPad1 = std::numeric_limits<double>::max();
246 double closestToPad2 = std::numeric_limits<double>::max();
249 for(
const VECTOR2I& pt : endpoints )
254 if( d1 < closestToPad1 )
260 if( d2 < closestToPad2 )
268 "Path anchor nearest pad1 at (%.4f,%.4f) mm, dist-to-copper %.4f mm, "
269 "dist-to-hole %.4f mm",
270 anchor1.
x / 1e6, anchor1.
y / 1e6, closestToPad1,
271 distToNearestHoleMM( anchor1 ) ) );
273 "Path anchor nearest pad2 at (%.4f,%.4f) mm, dist-to-copper %.4f mm, "
274 "dist-to-hole %.4f mm",
275 anchor2.
x / 1e6, anchor2.
y / 1e6, closestToPad2,
276 distToNearestHoleMM( anchor2 ) ) );
283 wxString::Format(
"Creepage path endpoint nearest C4 pad1 is %.4f mm from the pad "
284 "copper outline; it should anchor on the copper. dist-to-hole=%.4f mm",
285 closestToPad1, distToNearestHoleMM( anchor1 ) ) );
288 wxString::Format(
"Creepage path endpoint nearest C4 pad2 is %.4f mm from the pad "
289 "copper outline; it should anchor on the copper. dist-to-hole=%.4f mm",
290 closestToPad2, distToNearestHoleMM( anchor2 ) ) );
298 wxString::Format(
"Creepage path anchor for C4 pad1 is pinned to the NPTH hole edge "
299 "(%.4f mm) instead of the pad copper (%.4f mm).",
300 distToNearestHoleMM( anchor1 ), closestToPad1 ) );
303 wxString::Format(
"Creepage path anchor for C4 pad2 is pinned to the NPTH hole edge "
304 "(%.4f mm) instead of the pad copper (%.4f mm).",
305 distToNearestHoleMM( anchor2 ), closestToPad2 ) );
DRC_CREEPAGE_ROTATED_PAD_FIXTURE()=default
BOOST_FIXTURE_TEST_CASE(CreepageRotatedRectPadIssue24543, DRC_CREEPAGE_ROTATED_PAD_FIXTURE)