64 REPORT_AUX( wxT(
"Annular width violations ignored. Skipping check." ) );
68 const int progressDelta = 500;
72 REPORT_AUX( wxT(
"No annular width constraints found. Tests not run." ) );
76 if( !
reportPhase(
_(
"Checking pad & via annular rings..." ) ) )
82 switch( item->Type() )
96 pad->Padstack().ForEachUniqueLayer(
101 switch(
pad->GetShape( aLayer ) )
104 if(
pad->GetChamferRectRatio( aLayer ) > 0.30 )
132 auto getPadAnnulusPts =
136 bool handled =
false;
140 int xDist =
KiROUND( (
pad->GetSizeX() -
pad->GetDrillSizeX() ) / 2.0 );
141 int yDist =
KiROUND( (
pad->GetSizeY() -
pad->GetDrillSizeY() ) / 2.0 );
145 *ptA =
pad->GetPosition() -
VECTOR2I( 0,
pad->GetDrillSizeY() / 2 );
150 *ptA =
pad->GetPosition() -
VECTOR2I(
pad->GetDrillSizeX() / 2, 0 );
157 switch(
pad->GetShape( aLayer ) )
160 handled =
pad->GetChamferRectRatio( aLayer ) <= 0.30;
176 std::vector<const PAD*> overlappingSameNumPads;
178 for(
const PAD* p : sameNumPads )
180 if( p->IsOnLayer( aLayer )
181 &&
pad->GetBoundingBox().Intersects( p->GetBoundingBox() ) )
183 overlappingSameNumPads.push_back( p );
191 bool overlapHasConstrainingHole =
false;
192 bool overlapCoversThisPad =
false;
194 for(
const PAD* p : overlappingSameNumPads )
196 if( p->GetBoundingBox().Contains(
pad->GetBoundingBox() ) )
197 overlapCoversThisPad =
true;
199 if( p->HasHole() &&
pad->GetBoundingBox().Intersects( p->GetEffectiveHoleShape()->BBox() ) )
201 overlapHasConstrainingHole =
true;
204 if( overlapCoversThisPad && overlapHasConstrainingHole )
208 if( handled && !overlappingSameNumPads.empty() && !overlapHasConstrainingHole && !overlapCoversThisPad
209 && constraint.Value().HasMin() && !constraint.Value().HasMax() )
221 int width = ( *ptA - *ptB ).EuclideanNorm();
223 if( width >= constraint.Value().Min() )
228 if( !handled || !overlappingSameNumPads.empty() )
232 std::shared_ptr<SHAPE_SEGMENT> slot =
pad->GetEffectiveHoleShape();
234 pad->TransformShapeToPolygon( padOutline, aLayer, 0,
pad->GetMaxError(),
ERROR_INSIDE );
236 if( sameNumPads.empty() )
238 if( !padOutline.
Collide(
pad->GetPosition() ) )
241 *ptA =
pad->GetPosition();
242 *ptB =
pad->GetPosition();
249 else if( constraint.Value().HasMin() )
255 slot->TransformToPolygon( slotPolygon, 0,
ERROR_INSIDE );
257 for(
const PAD* sameNumPad : sameNumPads )
260 sameNumPad->TransformShapeToPolygon( aggregatePadOutline, aLayer, 0,
pad->GetMaxError(),
263 sameNumPad->TransformHoleToPolygon( otherPadHoles, 0,
pad->GetMaxError(),
ERROR_INSIDE );
268 if( !aggregatePadOutline.
Collide(
pad->GetPosition() ) )
271 *ptA =
pad->GetPosition();
272 *ptB =
pad->GetPosition();
282 auto checkConstraint =
291 bool fail_min =
false;
292 bool fail_max =
false;
293 int width = ( ptA - ptB ).EuclideanNorm();
295 if( constraint.Value().HasMin() )
297 v_min = constraint.Value().Min();
298 fail_min = width < v_min;
301 if( constraint.Value().HasMax() )
303 v_max = constraint.Value().Max();
304 fail_max = width > v_max;
307 if( fail_min || fail_max )
313 drcItem->SetErrorDetail(
formatMsg(
_(
"(%s min annular width %s; actual %s)" ),
314 constraint.GetName(),
321 drcItem->SetErrorDetail(
formatMsg(
_(
"(%s max annular width %s; actual %s)" ),
322 constraint.GetName(),
327 drcItem->SetItems( item );
328 drcItem->SetViolatingRule( constraint.GetParentRule() );
333 auto checkAnnularWidth =
343 via->Padstack().ForEachUniqueLayer(
351 checkConstraint( constraint,
via, ptA, ptB, aLayer );
361 std::vector<const PAD*> sameNumPads;
364 sameNumPads = fp->GetPads(
pad->GetNumber(),
pad );
366 pad->Padstack().ForEachUniqueLayer(
374 getPadAnnulusPts(
pad, aLayer, constraint, sameNumPads, &ptA, &ptB );
375 checkConstraint( constraint,
pad, ptA, ptB, aLayer );
387 total += calcEffort( item );
391 for(
PAD*
pad : footprint->Pads() )
392 total += calcEffort(
pad );
397 ii += calcEffort( item );
402 if( !checkAnnularWidth( item ) )
408 for(
PAD*
pad : footprint->Pads() )
410 ii += calcEffort(
pad );
415 if( !checkAnnularWidth(
pad ) )