60 REPORT_AUX( wxT(
"Annular width violations ignored. Skipping check." ) );
64 const int progressDelta = 500;
68 REPORT_AUX( wxT(
"No annular width constraints found. Tests not run." ) );
72 if( !
reportPhase(
_(
"Checking pad & via annular rings..." ) ) )
78 switch( item->Type() )
92 pad->Padstack().ForEachUniqueLayer(
97 switch(
pad->GetShape( aLayer ) )
100 if(
pad->GetChamferRectRatio( aLayer ) > 0.30 )
128 auto getPadAnnulusPts =
132 bool handled =
false;
136 int xDist =
KiROUND( (
pad->GetSizeX() -
pad->GetDrillSizeX() ) / 2.0 );
137 int yDist =
KiROUND( (
pad->GetSizeY() -
pad->GetDrillSizeY() ) / 2.0 );
141 *ptA =
pad->GetPosition() -
VECTOR2I( 0,
pad->GetDrillSizeY() / 2 );
146 *ptA =
pad->GetPosition() -
VECTOR2I(
pad->GetDrillSizeX() / 2, 0 );
153 switch(
pad->GetShape( aLayer ) )
156 handled =
pad->GetChamferRectRatio( aLayer ) <= 0.30;
172 std::vector<const PAD*> overlappingSameNumPads;
174 for(
const PAD* p : sameNumPads )
176 if( p->IsOnLayer( aLayer )
177 &&
pad->GetBoundingBox().Intersects( p->GetBoundingBox() ) )
179 overlappingSameNumPads.push_back( p );
187 bool overlapHasConstrainingHole =
false;
188 bool overlapCoversThisPad =
false;
190 for(
const PAD* p : overlappingSameNumPads )
192 if( p->GetBoundingBox().Contains(
pad->GetBoundingBox() ) )
193 overlapCoversThisPad =
true;
195 if( p->HasHole() &&
pad->GetBoundingBox().Intersects( p->GetEffectiveHoleShape()->BBox() ) )
197 overlapHasConstrainingHole =
true;
200 if( overlapCoversThisPad && overlapHasConstrainingHole )
204 if( handled && !overlappingSameNumPads.empty() && !overlapHasConstrainingHole && !overlapCoversThisPad
205 && constraint.Value().HasMin() && !constraint.Value().HasMax() )
217 int width = ( *ptA - *ptB ).EuclideanNorm();
219 if( width >= constraint.Value().Min() )
224 if( !handled || !overlappingSameNumPads.empty() )
228 std::shared_ptr<SHAPE_SEGMENT> slot =
pad->GetEffectiveHoleShape();
230 pad->TransformShapeToPolygon( padOutline, aLayer, 0,
pad->GetMaxError(),
ERROR_INSIDE );
232 if( sameNumPads.empty() )
234 if( !padOutline.
Collide(
pad->GetPosition() ) )
237 *ptA =
pad->GetPosition();
238 *ptB =
pad->GetPosition();
245 else if( constraint.Value().HasMin() )
251 slot->TransformToPolygon( slotPolygon, 0,
ERROR_INSIDE );
253 for(
const PAD* sameNumPad : sameNumPads )
256 sameNumPad->TransformShapeToPolygon( aggregatePadOutline, aLayer, 0,
pad->GetMaxError(),
259 sameNumPad->TransformHoleToPolygon( otherPadHoles, 0,
pad->GetMaxError(),
ERROR_INSIDE );
264 if( !aggregatePadOutline.
Collide(
pad->GetPosition() ) )
267 *ptA =
pad->GetPosition();
268 *ptB =
pad->GetPosition();
278 auto checkConstraint =
287 bool fail_min =
false;
288 bool fail_max =
false;
289 int width = ( ptA - ptB ).EuclideanNorm();
291 if( constraint.Value().HasMin() )
293 v_min = constraint.Value().Min();
294 fail_min = width < v_min;
297 if( constraint.Value().HasMax() )
299 v_max = constraint.Value().Max();
300 fail_max = width > v_max;
303 if( fail_min || fail_max )
309 drcItem->SetErrorDetail(
formatMsg(
_(
"(%s min annular width %s; actual %s)" ),
310 constraint.GetName(),
317 drcItem->SetErrorDetail(
formatMsg(
_(
"(%s max annular width %s; actual %s)" ),
318 constraint.GetName(),
323 drcItem->SetItems( item );
324 drcItem->SetViolatingRule( constraint.GetParentRule() );
329 auto checkAnnularWidth =
339 via->Padstack().ForEachUniqueLayer(
347 checkConstraint( constraint,
via, ptA, ptB, aLayer );
357 std::vector<const PAD*> sameNumPads;
360 sameNumPads = fp->GetPads(
pad->GetNumber(),
pad );
362 pad->Padstack().ForEachUniqueLayer(
370 getPadAnnulusPts(
pad, aLayer, constraint, sameNumPads, &ptA, &ptB );
371 checkConstraint( constraint,
pad, ptA, ptB, aLayer );
383 total += calcEffort( item );
387 for(
PAD*
pad : footprint->Pads() )
388 total += calcEffort(
pad );
393 ii += calcEffort( item );
398 if( !checkAnnularWidth( item ) )
404 for(
PAD*
pad : footprint->Pads() )
406 ii += calcEffort(
pad );
411 if( !checkAnnularWidth(
pad ) )