Clean up hole shapes for safety (smart pointer) and consistency.
This commit is contained in:
parent
a2c002e1da
commit
f41af10007
|
@ -429,28 +429,26 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aCo
|
|||
|
||||
OBJECT_2D* BOARD_ADAPTER::createPadWithDrill( const PAD* aPad, int aInflateValue )
|
||||
{
|
||||
VECTOR2I drillSize = aPad->GetDrillSize();
|
||||
|
||||
if( !drillSize.x || !drillSize.y )
|
||||
if( !aPad->HasHole() )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createPadWithDrill - found an invalid pad" ) );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( drillSize.x == drillSize.y ) // usual round hole
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
|
||||
|
||||
if( slot->GetSeg().A == slot->GetSeg().B )
|
||||
{
|
||||
const int radius = ( drillSize.x / 2 ) + aInflateValue;
|
||||
|
||||
return new FILLED_CIRCLE_2D( TO_SFVEC2F( aPad->GetPosition() ), TO_3DU( radius ), *aPad );
|
||||
|
||||
return new FILLED_CIRCLE_2D( TO_SFVEC2F( slot->GetSeg().A ),
|
||||
TO_3DU( slot->GetWidth() / 2 + aInflateValue ),
|
||||
*aPad );
|
||||
}
|
||||
else // Oblong hole
|
||||
else
|
||||
{
|
||||
const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
|
||||
float width = seg->GetWidth() + aInflateValue * 2;
|
||||
|
||||
return new ROUND_SEGMENT_2D( TO_SFVEC2F( seg->GetSeg().A ), TO_SFVEC2F( seg->GetSeg().B ),
|
||||
TO_3DU( width ), *aPad );
|
||||
return new ROUND_SEGMENT_2D( TO_SFVEC2F( slot->GetSeg().A ),
|
||||
TO_SFVEC2F( slot->GetSeg().B ),
|
||||
TO_3DU( slot->GetWidth() + aInflateValue * 2 ),
|
||||
*aPad );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -687,15 +687,15 @@ void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_
|
|||
if( m_Flashed )
|
||||
{
|
||||
msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
|
||||
aList.emplace_back( MSG_PANEL_ITEM( _( "Position" ), msg, BLUE ) );
|
||||
aList.emplace_back( _( "Position" ), msg );
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Printf( wxT( "(%.4f, %.4f)" ), xStart, yStart );
|
||||
aList.emplace_back( MSG_PANEL_ITEM( _( "Start" ), msg, BLUE ) );
|
||||
aList.emplace_back( _( "Start" ), msg );
|
||||
|
||||
msg.Printf( wxT( "(%.4f, %.4f)" ), xEnd, yEnd );
|
||||
aList.emplace_back( MSG_PANEL_ITEM( _( "End" ), msg, BLUE ) );
|
||||
aList.emplace_back( _( "End" ), msg );
|
||||
}
|
||||
|
||||
// Display item rotation
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wandadoo.fr
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -38,6 +38,7 @@
|
|||
class BOARD;
|
||||
class BOARD_ITEM_CONTAINER;
|
||||
class SHAPE_POLY_SET;
|
||||
class SHAPE_SEGMENT;
|
||||
class PCB_BASE_FRAME;
|
||||
class SHAPE;
|
||||
class PCB_GROUP;
|
||||
|
@ -145,7 +146,9 @@ public:
|
|||
* will be returned. Pass UNDEFINED_LAYER to return shapes for all layers.
|
||||
*/
|
||||
virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
|
||||
FLASHING aFlash = FLASHING::DEFAULT ) const;
|
||||
FLASHING aFlash = FLASHING::DEFAULT ) const;
|
||||
|
||||
virtual std::shared_ptr<SHAPE_SEGMENT> GetEffectiveHoleShape() const;
|
||||
|
||||
BOARD_ITEM_CONTAINER* GetParent() const { return (BOARD_ITEM_CONTAINER*) m_parent; }
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
|
||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -196,7 +196,7 @@ bool BOARD_ITEM::ptr_cmp::operator() ( const BOARD_ITEM* a, const BOARD_ITEM* b
|
|||
|
||||
std::shared_ptr<SHAPE> BOARD_ITEM::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
|
||||
{
|
||||
std::shared_ptr<SHAPE> shape;
|
||||
static std::shared_ptr<SHAPE> shape;
|
||||
|
||||
UNIMPLEMENTED_FOR( GetClass() );
|
||||
|
||||
|
@ -204,6 +204,16 @@ std::shared_ptr<SHAPE> BOARD_ITEM::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASH
|
|||
}
|
||||
|
||||
|
||||
std::shared_ptr<SHAPE_SEGMENT> BOARD_ITEM::GetEffectiveHoleShape() const
|
||||
{
|
||||
static std::shared_ptr<SHAPE_SEGMENT> slot;
|
||||
|
||||
UNIMPLEMENTED_FOR( GetClass() );
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
|
||||
BOARD_ITEM_CONTAINER* BOARD_ITEM::GetParentFootprint() const
|
||||
{
|
||||
BOARD_ITEM_CONTAINER* ancestor = GetParent();
|
||||
|
|
|
@ -398,14 +398,12 @@ bool CONNECTIVITY_DATA::IsConnectedOnLayer( const BOARD_CONNECTED_ITEM *aItem, i
|
|||
if( aItem->Type() == PCB_PAD_T && zoneLayer )
|
||||
{
|
||||
const PAD* pad = static_cast<const PAD*>( aItem );
|
||||
SHAPE_SEGMENT hole( *pad->GetEffectiveHoleShape() );
|
||||
PCB_LAYER_ID layer = ToLAYER_ID( aLayer );
|
||||
ZONE* zone = static_cast<ZONE*>( zoneLayer->Parent() );
|
||||
int islandIdx = zoneLayer->SubpolyIndex();
|
||||
|
||||
if( zone->IsFilled() )
|
||||
{
|
||||
const SHAPE_POLY_SET* zoneFill = zone->GetFill( layer );
|
||||
const SHAPE_POLY_SET* zoneFill = zone->GetFill( ToLAYER_ID( aLayer ) );
|
||||
const SHAPE_LINE_CHAIN& padHull = pad->GetEffectivePolygon()->Outline( 0 );
|
||||
|
||||
for( const VECTOR2I& pt : zoneFill->COutline( islandIdx ).CPoints() )
|
||||
|
@ -424,14 +422,12 @@ bool CONNECTIVITY_DATA::IsConnectedOnLayer( const BOARD_CONNECTED_ITEM *aItem, i
|
|||
else if( aItem->Type() == PCB_VIA_T && zoneLayer )
|
||||
{
|
||||
const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
|
||||
SHAPE_CIRCLE hole( via->GetCenter(), via->GetDrillValue() / 2 );
|
||||
PCB_LAYER_ID layer = ToLAYER_ID( aLayer );
|
||||
ZONE* zone = static_cast<ZONE*>( zoneLayer->Parent() );
|
||||
int islandIdx = zoneLayer->SubpolyIndex();
|
||||
|
||||
if( zone->IsFilled() )
|
||||
{
|
||||
const SHAPE_POLY_SET* zoneFill = zone->GetFill( layer );
|
||||
const SHAPE_POLY_SET* zoneFill = zone->GetFill( ToLAYER_ID( aLayer ) );
|
||||
SHAPE_CIRCLE viaHull( via->GetCenter(), via->GetWidth() / 2 );
|
||||
|
||||
for( const VECTOR2I& pt : zoneFill->COutline( islandIdx ).CPoints() )
|
||||
|
|
|
@ -1281,14 +1281,13 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
|
|||
}
|
||||
else if( m_dummyPad->GetAttribute() == PAD_ATTRIB::PTH )
|
||||
{
|
||||
const SHAPE_SEGMENT* drillShape = m_dummyPad->GetEffectiveHoleShape();
|
||||
const SEG drillSeg = drillShape->GetSeg();
|
||||
SHAPE_POLY_SET drillOutline;
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = m_dummyPad->GetEffectiveHoleShape();
|
||||
SHAPE_POLY_SET slotOutline;
|
||||
|
||||
TransformOvalToPolygon( drillOutline, drillSeg.A, drillSeg.B,
|
||||
drillShape->GetWidth(), maxError, ERROR_LOC::ERROR_INSIDE );
|
||||
TransformOvalToPolygon( slotOutline, slot->GetSeg().A, slot->GetSeg().B,
|
||||
slot->GetWidth(), maxError, ERROR_LOC::ERROR_INSIDE );
|
||||
|
||||
padOutline.BooleanSubtract( drillOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
|
||||
padOutline.BooleanSubtract( slotOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
|
||||
|
||||
if( padOutline.IsEmpty() )
|
||||
warning_msgs.Add( _( "Warning: Pad hole will leave no copper." ) );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020 CERN
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -53,13 +53,23 @@ public:
|
|||
{
|
||||
ITEM_WITH_SHAPE( BOARD_ITEM *aParent, const SHAPE* aShape,
|
||||
std::shared_ptr<SHAPE> aParentShape = nullptr ) :
|
||||
parent ( aParent ),
|
||||
shape ( aShape ),
|
||||
parent( aParent ),
|
||||
shape( aShape ),
|
||||
shapeStorage( nullptr ),
|
||||
parentShape( aParentShape )
|
||||
{};
|
||||
|
||||
BOARD_ITEM* parent;
|
||||
const SHAPE* shape;
|
||||
ITEM_WITH_SHAPE( BOARD_ITEM *aParent, std::shared_ptr<SHAPE> aShape,
|
||||
std::shared_ptr<SHAPE> aParentShape = nullptr ) :
|
||||
parent( aParent ),
|
||||
shape( aShape.get() ),
|
||||
shapeStorage( aShape ),
|
||||
parentShape( aParentShape )
|
||||
{};
|
||||
|
||||
BOARD_ITEM* parent;
|
||||
const SHAPE* shape;
|
||||
std::shared_ptr<SHAPE> shapeStorage;
|
||||
std::shared_ptr<SHAPE> parentShape;
|
||||
};
|
||||
|
||||
|
@ -79,9 +89,9 @@ public:
|
|||
|
||||
~DRC_RTREE()
|
||||
{
|
||||
for( auto tree : m_tree )
|
||||
for( drc_rtree* tree : m_tree )
|
||||
{
|
||||
for( auto el : *tree )
|
||||
for( DRC_RTREE::ITEM_WITH_SHAPE* el : *tree )
|
||||
delete el;
|
||||
|
||||
delete tree;
|
||||
|
@ -110,24 +120,12 @@ public:
|
|||
|
||||
std::vector<const SHAPE*> subshapes;
|
||||
std::shared_ptr<SHAPE> shape = aItem->GetEffectiveShape( aRefLayer );
|
||||
subshapes.clear();
|
||||
|
||||
if( shape->HasIndexableSubshapes() )
|
||||
shape->GetIndexableSubshapes( subshapes );
|
||||
else
|
||||
subshapes.push_back( shape.get() );
|
||||
|
||||
if( aItem->Type() == PCB_PAD_T )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( aItem );
|
||||
|
||||
if( pad->HasHole() )
|
||||
{
|
||||
const SHAPE* hole = pad->GetEffectiveHoleShape();
|
||||
subshapes.push_back( const_cast<SHAPE*>( hole ) );
|
||||
}
|
||||
}
|
||||
|
||||
for( const SHAPE* subshape : subshapes )
|
||||
{
|
||||
if( dynamic_cast<const SHAPE_NULL*>( subshape ) )
|
||||
|
@ -144,6 +142,22 @@ public:
|
|||
m_tree[aTargetLayer]->Insert( mmin, mmax, itemShape );
|
||||
m_count++;
|
||||
}
|
||||
|
||||
if( aItem->Type() == PCB_PAD_T && aItem->HasHole() )
|
||||
{
|
||||
std::shared_ptr<SHAPE_SEGMENT> hole = aItem->GetEffectiveHoleShape();
|
||||
BOX2I bbox = hole->BBox();
|
||||
|
||||
bbox.Inflate( aWorstClearance );
|
||||
|
||||
const int mmin[2] = { bbox.GetX(), bbox.GetY() };
|
||||
const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
|
||||
ITEM_WITH_SHAPE* itemShape = new ITEM_WITH_SHAPE( aItem, hole, shape );
|
||||
|
||||
m_tree[aTargetLayer]->Insert( mmin, mmax, itemShape );
|
||||
m_count++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -229,24 +229,18 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track,
|
|||
}
|
||||
}
|
||||
|
||||
if( testHoles && ( other->Type() == PCB_VIA_T || other->Type() == PCB_PAD_T ) )
|
||||
if( testHoles && other->HasHole() )
|
||||
{
|
||||
std::unique_ptr<SHAPE_SEGMENT> holeShape;
|
||||
std::shared_ptr<SHAPE_SEGMENT> holeShape;
|
||||
|
||||
if( other->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( other );
|
||||
pos = via->GetPosition();
|
||||
|
||||
if( via->GetLayerSet().Contains( layer ) )
|
||||
holeShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
|
||||
if( other->GetLayerSet().Contains( layer ) )
|
||||
holeShape = other->GetEffectiveHoleShape();
|
||||
}
|
||||
else if( other->Type() == PCB_PAD_T )
|
||||
else
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( other );
|
||||
|
||||
if( pad->GetDrillSize().x )
|
||||
holeShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
|
||||
holeShape = other->GetEffectiveHoleShape();
|
||||
}
|
||||
|
||||
if( holeShape )
|
||||
|
@ -285,7 +279,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track,
|
|||
|
||||
|
||||
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem, ZONE* aZone,
|
||||
PCB_LAYER_ID aLayer )
|
||||
PCB_LAYER_ID aLayer )
|
||||
{
|
||||
if( !aZone->GetLayerSet().test( aLayer ) )
|
||||
return;
|
||||
|
@ -312,31 +306,22 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
|||
int clearance = -1;
|
||||
int actual;
|
||||
VECTOR2I pos;
|
||||
PCB_VIA* via = nullptr;
|
||||
PAD* pad = nullptr;
|
||||
bool flashed = false;
|
||||
bool hasHole = false;
|
||||
bool unflashedPad = false;
|
||||
bool platedHole = false;
|
||||
|
||||
if( aItem->Type() == PCB_VIA_T )
|
||||
if( aItem->Type() == PCB_PAD_T )
|
||||
{
|
||||
via = static_cast<PCB_VIA*>( aItem );
|
||||
}
|
||||
else if( aItem->Type() == PCB_PAD_T )
|
||||
{
|
||||
pad = static_cast<PAD*>( aItem );
|
||||
flashed = pad->FlashLayer( aLayer );
|
||||
hasHole = pad->GetDrillSize().x > 0 || pad->GetDrillSize().y > 0;
|
||||
unflashedPad = !static_cast<PAD*>( aItem )->FlashLayer( aLayer );
|
||||
|
||||
if( !flashed && !hasHole )
|
||||
if( unflashedPad && !aItem->HasHole() )
|
||||
return;
|
||||
|
||||
platedHole = hasHole && pad->GetAttribute() == PAD_ATTRIB::PTH;
|
||||
platedHole = static_cast<PAD*>( aItem )->GetAttribute() == PAD_ATTRIB::PTH;
|
||||
}
|
||||
|
||||
if( zoneTree && testClearance )
|
||||
{
|
||||
if( pad && !flashed && hasHole && !platedHole )
|
||||
if( unflashedPad && !platedHole )
|
||||
constraintType = HOLE_CLEARANCE_CONSTRAINT;
|
||||
|
||||
constraint = m_drcEngine->EvalRules( constraintType, aItem, aZone, aLayer );
|
||||
|
@ -347,10 +332,10 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
|||
{
|
||||
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
|
||||
|
||||
if( pad && !flashed && hasHole )
|
||||
if( unflashedPad )
|
||||
{
|
||||
const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
|
||||
int size = hole->GetWidth();
|
||||
std::shared_ptr<SHAPE_SEGMENT> hole = aItem->GetEffectiveHoleShape();
|
||||
int size = hole->GetWidth();
|
||||
|
||||
// Note: drill size represents finish size, which means the actual hole size is
|
||||
// 2x the plating thickness larger.
|
||||
|
@ -380,18 +365,18 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZone( BOARD_ITEM* aItem,
|
|||
}
|
||||
}
|
||||
|
||||
if( zoneTree && testHoles && ( pad || via ) )
|
||||
if( zoneTree && testHoles && aItem->HasHole() )
|
||||
{
|
||||
std::unique_ptr<SHAPE_SEGMENT> holeShape;
|
||||
std::shared_ptr<SHAPE_SEGMENT> holeShape;
|
||||
|
||||
if( via && via->GetLayerSet().Contains( aLayer ) )
|
||||
if( aItem->Type() == PCB_VIA_T )
|
||||
{
|
||||
holeShape.reset( new SHAPE_SEGMENT( via->GetPosition(), via->GetPosition(),
|
||||
via->GetDrill() ) );
|
||||
if( aItem->GetLayerSet().Contains( aLayer ) )
|
||||
holeShape = aItem->GetEffectiveHoleShape();
|
||||
}
|
||||
else if( pad && pad->GetDrillSize().x )
|
||||
else
|
||||
{
|
||||
holeShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
|
||||
holeShape = aItem->GetEffectiveHoleShape();
|
||||
}
|
||||
|
||||
if( holeShape )
|
||||
|
@ -628,9 +613,9 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
|||
testHoles = false;
|
||||
}
|
||||
|
||||
if( testHoles && otherPad && pad->FlashLayer( aLayer ) && otherPad->GetDrillSize().x )
|
||||
if( testHoles && otherPad && pad->FlashLayer( aLayer ) && otherPad->HasHole() )
|
||||
{
|
||||
if( clearance > 0 && padShape->Collide( otherPad->GetEffectiveHoleShape(),
|
||||
if( clearance > 0 && padShape->Collide( otherPad->GetEffectiveHoleShape().get(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
|
@ -651,9 +636,9 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
|||
}
|
||||
}
|
||||
|
||||
if( testHoles && otherPad && otherPad->FlashLayer( aLayer ) && pad->GetDrillSize().x )
|
||||
if( testHoles && otherPad && otherPad->FlashLayer( aLayer ) && pad->HasHole() )
|
||||
{
|
||||
if( clearance > 0 && otherShape->Collide( pad->GetEffectiveHoleShape(),
|
||||
if( clearance > 0 && otherShape->Collide( pad->GetEffectiveHoleShape().get(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
|
@ -676,10 +661,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
|
|||
|
||||
if( testHoles && otherVia && otherVia->IsOnLayer( aLayer ) )
|
||||
{
|
||||
pos = otherVia->GetPosition();
|
||||
otherShape.reset( new SHAPE_SEGMENT( pos, pos, otherVia->GetDrill() ) );
|
||||
|
||||
if( clearance > 0 && padShape->Collide( otherShape.get(),
|
||||
if( clearance > 0 && padShape->Collide( otherVia->GetEffectiveHoleShape().get(),
|
||||
std::max( 0, clearance - m_drcEpsilon ),
|
||||
&actual, &pos ) )
|
||||
{
|
||||
|
|
|
@ -259,7 +259,7 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
|
|||
}
|
||||
|
||||
auto testPadAgainstCourtyards =
|
||||
[&]( const PAD* pad, const FOOTPRINT* footprint )
|
||||
[&]( const PAD* pad, const FOOTPRINT* fp )
|
||||
{
|
||||
int errorCode = 0;
|
||||
|
||||
|
@ -273,21 +273,24 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testCourtyardClearances()
|
|||
if( m_drcEngine->IsErrorLimitExceeded( errorCode ) )
|
||||
return;
|
||||
|
||||
const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
|
||||
const SHAPE_POLY_SET& front = footprint->GetPolyCourtyard( F_CrtYd );
|
||||
const SHAPE_POLY_SET& back = footprint->GetPolyCourtyard( B_CrtYd );
|
||||
if( pad->HasHole() )
|
||||
{
|
||||
std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
|
||||
const SHAPE_POLY_SET& front = fp->GetPolyCourtyard( F_CrtYd );
|
||||
const SHAPE_POLY_SET& back = fp->GetPolyCourtyard( B_CrtYd );
|
||||
|
||||
if( front.OutlineCount() > 0 && front.Collide( hole, 0 ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( errorCode );
|
||||
drce->SetItems( pad, footprint );
|
||||
reportViolation( drce, pad->GetPosition(), F_CrtYd );
|
||||
}
|
||||
else if( back.OutlineCount() > 0 && back.Collide( hole, 0 ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( errorCode );
|
||||
drce->SetItems( pad, footprint );
|
||||
reportViolation( drce, pad->GetPosition(), B_CrtYd );
|
||||
if( front.OutlineCount() > 0 && front.Collide( hole.get(), 0 ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( errorCode );
|
||||
drce->SetItems( pad, fp );
|
||||
reportViolation( drce, pad->GetPosition(), F_CrtYd );
|
||||
}
|
||||
else if( back.OutlineCount() > 0 && back.Collide( hole.get(), 0 ) )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( errorCode );
|
||||
drce->SetItems( pad, fp );
|
||||
reportViolation( drce, pad->GetPosition(), B_CrtYd );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -86,11 +86,12 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::testAgainstEdge( BOARD_ITEM* item, SHAPE*
|
|||
DRC_CONSTRAINT_T aConstraintType,
|
||||
PCB_DRC_CODE aErrorCode )
|
||||
{
|
||||
const std::shared_ptr<SHAPE>& shape = edge->GetEffectiveShape( Edge_Cuts );
|
||||
const SHAPE* edgeShape = shape.get();
|
||||
std::shared_ptr<SHAPE> shape;
|
||||
|
||||
if( edge->Type() == PCB_PAD_T )
|
||||
edgeShape = static_cast<PAD*>( edge )->GetEffectiveHoleShape();
|
||||
shape = edge->GetEffectiveHoleShape();
|
||||
else
|
||||
shape = edge->GetEffectiveShape( Edge_Cuts );
|
||||
|
||||
auto constraint = m_drcEngine->EvalRules( aConstraintType, edge, item, UNDEFINED_LAYER );
|
||||
int minClearance = constraint.GetValue().Min();
|
||||
|
@ -99,7 +100,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::testAgainstEdge( BOARD_ITEM* item, SHAPE*
|
|||
|
||||
if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE && minClearance >= 0 )
|
||||
{
|
||||
if( itemShape->Collide( edgeShape, minClearance, &actual, &pos ) )
|
||||
if( itemShape->Collide( shape.get(), minClearance, &actual, &pos ) )
|
||||
{
|
||||
if( item->Type() == PCB_TRACE_T || item->Type() == PCB_ARC_T )
|
||||
{
|
||||
|
|
|
@ -593,40 +593,28 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstItem( BOARD_ITEM* item
|
|||
|
||||
if( testHoles )
|
||||
{
|
||||
std::unique_ptr<SHAPE_SEGMENT> itemHoleShape;
|
||||
std::unique_ptr<SHAPE_SEGMENT> otherHoleShape;
|
||||
std::shared_ptr<SHAPE_SEGMENT> itemHoleShape;
|
||||
std::shared_ptr<SHAPE_SEGMENT> otherHoleShape;
|
||||
clearance = 0;
|
||||
|
||||
if( item->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( item );
|
||||
pos = via->GetPosition();
|
||||
|
||||
if( via->GetLayerSet().Contains( layer ) )
|
||||
itemHoleShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
|
||||
if( item->GetLayerSet().Contains( layer ) )
|
||||
itemHoleShape = item->GetEffectiveHoleShape();
|
||||
}
|
||||
else if( item->Type() == PCB_PAD_T )
|
||||
else if( item->HasHole() )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( item );
|
||||
|
||||
if( pad->GetDrillSize().x )
|
||||
itemHoleShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
|
||||
itemHoleShape = item->GetEffectiveHoleShape();
|
||||
}
|
||||
|
||||
if( other->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( other );
|
||||
pos = via->GetPosition();
|
||||
|
||||
if( via->GetLayerSet().Contains( layer ) )
|
||||
otherHoleShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
|
||||
if( other->GetLayerSet().Contains( layer ) )
|
||||
otherHoleShape = other->GetEffectiveHoleShape();
|
||||
}
|
||||
else if( other->Type() == PCB_PAD_T )
|
||||
else if( other->HasHole() )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( other );
|
||||
|
||||
if( pad->GetDrillSize().x )
|
||||
otherHoleShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
|
||||
otherHoleShape = other->GetEffectiveHoleShape();
|
||||
}
|
||||
|
||||
if( itemHoleShape || otherHoleShape )
|
||||
|
@ -722,8 +710,8 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aIt
|
|||
if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
|
||||
continue;
|
||||
|
||||
const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
|
||||
int size = hole->GetWidth();
|
||||
std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
|
||||
int size = hole->GetWidth();
|
||||
|
||||
// Note: drill size represents finish size, which means the actual hole
|
||||
// size is the plating thickness larger.
|
||||
|
@ -763,24 +751,18 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aIt
|
|||
}
|
||||
}
|
||||
|
||||
if( testHoles && ( aItem->Type() == PCB_VIA_T || aItem->Type() == PCB_PAD_T ) )
|
||||
if( testHoles )
|
||||
{
|
||||
std::unique_ptr<SHAPE_SEGMENT> holeShape;
|
||||
std::shared_ptr<SHAPE_SEGMENT> holeShape;
|
||||
|
||||
if( aItem->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
|
||||
pos = via->GetPosition();
|
||||
|
||||
if( via->GetLayerSet().Contains( aLayer ) )
|
||||
holeShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
|
||||
if( aItem->GetLayerSet().Contains( aLayer ) )
|
||||
holeShape = aItem->GetEffectiveHoleShape();
|
||||
}
|
||||
else if( aItem->Type() == PCB_PAD_T )
|
||||
else if( aItem->HasHole() )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( aItem );
|
||||
|
||||
if( pad->GetDrillSize().x )
|
||||
holeShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
|
||||
holeShape = aItem->GetEffectiveHoleShape();
|
||||
}
|
||||
|
||||
if( holeShape )
|
||||
|
|
|
@ -184,7 +184,7 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
|
|||
BOARD_ITEM* testItem = aTestItemShape->parent;
|
||||
const SHAPE* testShape = aTestItemShape->shape;
|
||||
|
||||
std::unique_ptr<SHAPE> hole;
|
||||
std::shared_ptr<SHAPE> hole;
|
||||
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_SILK ) )
|
||||
return false;
|
||||
|
@ -194,28 +194,13 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
|
|||
|
||||
if( testItem->IsTented() )
|
||||
{
|
||||
switch( testItem->Type() )
|
||||
if( testItem->HasHole() )
|
||||
{
|
||||
case PCB_VIA_T:
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( testItem );
|
||||
hole.reset( via->GetEffectiveShape( UNDEFINED_LAYER,
|
||||
FLASHING::NEVER_FLASHED )->Clone() );
|
||||
hole = testItem->GetEffectiveHoleShape();
|
||||
testShape = hole.get();
|
||||
break;
|
||||
}
|
||||
case PCB_PAD_T:
|
||||
else
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( testItem );
|
||||
|
||||
if( pad->GetDrillSize().x || pad->GetDrillSize().y )
|
||||
return true;
|
||||
|
||||
hole.reset( pad->GetEffectiveHoleShape()->Clone() );
|
||||
testShape = hole.get();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2322,20 +2322,16 @@ void FOOTPRINT::CheckPads( const std::function<void( const PAD*, int,
|
|||
pad->TransformShapeWithClearanceToPolygon( padOutline, layer, 0, ARC_HIGH_DEF,
|
||||
ERROR_LOC::ERROR_INSIDE );
|
||||
|
||||
const SHAPE_SEGMENT* drillShape = pad->GetEffectiveHoleShape();
|
||||
const SEG drillSeg = drillShape->GetSeg();
|
||||
SHAPE_POLY_SET drillOutline;
|
||||
std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
|
||||
SHAPE_POLY_SET holeOutline;
|
||||
|
||||
TransformOvalToPolygon( drillOutline, drillSeg.A, drillSeg.B,
|
||||
drillShape->GetWidth(), ARC_HIGH_DEF,
|
||||
ERROR_LOC::ERROR_INSIDE );
|
||||
TransformOvalToPolygon( holeOutline, hole->GetSeg().A, hole->GetSeg().B,
|
||||
hole->GetWidth(), ARC_HIGH_DEF, ERROR_LOC::ERROR_INSIDE );
|
||||
|
||||
padOutline.BooleanSubtract( drillOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
|
||||
padOutline.BooleanSubtract( holeOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
|
||||
|
||||
if( padOutline.IsEmpty() )
|
||||
{
|
||||
(aErrorHandler)( pad, DRCE_PADSTACK, _( "(PTH pad's hole leaves no copper)" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -329,17 +329,9 @@ std::shared_ptr<SHAPE> PAD::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFl
|
|||
|| ( aLayer != UNDEFINED_LAYER && !FlashLayer( aLayer ) ) )
|
||||
{
|
||||
if( GetAttribute() == PAD_ATTRIB::PTH )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = GetBoard()->GetDesignSettings();
|
||||
|
||||
// Note: drill size represents finish size, which means the actual holes size is the
|
||||
// plating thickness larger.
|
||||
auto hole = static_cast<SHAPE_SEGMENT*>( GetEffectiveHoleShape()->Clone() );
|
||||
hole->SetWidth( hole->GetWidth() + bds.GetHolePlatingThickness() );
|
||||
return std::make_shared<SHAPE_SEGMENT>( *hole );
|
||||
}
|
||||
|
||||
return std::make_shared<SHAPE_NULL>();
|
||||
return GetEffectiveHoleShape();
|
||||
else
|
||||
return std::make_shared<SHAPE_NULL>();
|
||||
}
|
||||
|
||||
if( m_shapesDirty )
|
||||
|
@ -349,12 +341,12 @@ std::shared_ptr<SHAPE> PAD::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFl
|
|||
}
|
||||
|
||||
|
||||
const SHAPE_SEGMENT* PAD::GetEffectiveHoleShape() const
|
||||
std::shared_ptr<SHAPE_SEGMENT> PAD::GetEffectiveHoleShape() const
|
||||
{
|
||||
if( m_shapesDirty )
|
||||
BuildEffectiveShapes( UNDEFINED_LAYER );
|
||||
|
||||
return m_effectiveHoleShape.get();
|
||||
return m_effectiveHoleShape;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1537,10 +1529,10 @@ bool PAD::TransformHoleWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, in
|
|||
if( !drillsize.x || !drillsize.y )
|
||||
return false;
|
||||
|
||||
const SHAPE_SEGMENT* seg = GetEffectiveHoleShape();
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = GetEffectiveHoleShape();
|
||||
|
||||
TransformOvalToPolygon( aCornerBuffer, seg->GetSeg().A, seg->GetSeg().B,
|
||||
seg->GetWidth() + aInflateValue * 2, aError, aErrorLoc );
|
||||
TransformOvalToPolygon( aCornerBuffer, slot->GetSeg().A, slot->GetSeg().B,
|
||||
slot->GetWidth() + aInflateValue * 2, aError, aErrorLoc );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -437,9 +437,9 @@ public:
|
|||
const std::shared_ptr<SHAPE_POLY_SET>& GetEffectivePolygon() const;
|
||||
|
||||
/**
|
||||
* Return a SHAPE object representing the pad's hole.
|
||||
* Return a SHAPE_SEGMENT object representing the pad's hole.
|
||||
*/
|
||||
const SHAPE_SEGMENT* GetEffectiveHoleShape() const;
|
||||
std::shared_ptr<SHAPE_SEGMENT> GetEffectiveHoleShape() const override;
|
||||
|
||||
/**
|
||||
* Return the radius of a minimum sized circle which fully encloses this pad.
|
||||
|
|
|
@ -467,22 +467,17 @@ bool calcIsInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CO
|
|||
{
|
||||
if( aItem->Type() == PCB_PAD_T )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( aItem );
|
||||
const SHAPE_SEGMENT* holeShape = pad->GetEffectiveHoleShape();
|
||||
|
||||
return areaOutline.Collide( holeShape );
|
||||
return areaOutline.Collide( aItem->GetEffectiveHoleShape().get() );
|
||||
}
|
||||
else if( aItem->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
|
||||
const SHAPE_CIRCLE holeShape( via->GetPosition(), via->GetDrillValue() );
|
||||
LSET overlap = via->GetLayerSet() & aArea->GetLayerSet();
|
||||
LSET overlap = aItem->GetLayerSet() & aArea->GetLayerSet();
|
||||
|
||||
/// Avoid buried vias that don't overlap the zone's layers
|
||||
if( overlap.count() > 0 )
|
||||
if( overlap.any() )
|
||||
{
|
||||
if( aCtx->GetLayer() == UNDEFINED_LAYER || overlap.Contains( aCtx->GetLayer() ) )
|
||||
return areaOutline.Collide( &holeShape );
|
||||
return areaOutline.Collide( aItem->GetEffectiveHoleShape().get() );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1086,13 +1086,13 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
|
|||
m_gal->SetLineWidth( m_holePlatingThickness );
|
||||
m_gal->SetStrokeColor( color );
|
||||
|
||||
const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
|
||||
int holeSize = seg->GetWidth() + m_holePlatingThickness;
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
|
||||
int holeSize = slot->GetWidth() + m_holePlatingThickness;
|
||||
|
||||
if( seg->GetSeg().A == seg->GetSeg().B ) // Circular hole
|
||||
m_gal->DrawCircle( seg->GetSeg().A, holeSize / 2 );
|
||||
if( slot->GetSeg().A == slot->GetSeg().B ) // Circular hole
|
||||
m_gal->DrawCircle( slot->GetSeg().A, KiROUND( holeSize / 2.0 ) );
|
||||
else
|
||||
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, holeSize );
|
||||
m_gal->DrawSegment( slot->GetSeg().A, slot->GetSeg().B, holeSize );
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1122,12 +1122,12 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
|
|||
|
||||
if( aLayer == LAYER_PAD_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
|
||||
{
|
||||
const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
|
||||
|
||||
if( seg->GetSeg().A == seg->GetSeg().B ) // Circular hole
|
||||
m_gal->DrawCircle( seg->GetSeg().A, getDrillSize( aPad ).x / 2 );
|
||||
if( slot->GetSeg().A == slot->GetSeg().B ) // Circular hole
|
||||
m_gal->DrawCircle( slot->GetSeg().A, slot->GetWidth() / 2 );
|
||||
else
|
||||
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() );
|
||||
m_gal->DrawSegment( slot->GetSeg().A, slot->GetSeg().B, slot->GetWidth() );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1400,9 +1400,9 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
|
|||
{
|
||||
clearance += m_holePlatingThickness;
|
||||
|
||||
const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
|
||||
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B,
|
||||
seg->GetWidth() + 2 * clearance );
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
|
||||
m_gal->DrawSegment( slot->GetSeg().A, slot->GetSeg().B,
|
||||
slot->GetWidth() + 2 * clearance );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,6 +366,12 @@ SEARCH_RESULT PCB_TRACK::Visit( INSPECTOR inspector, void* testData, const KICAD
|
|||
}
|
||||
|
||||
|
||||
std::shared_ptr<SHAPE_SEGMENT> PCB_VIA::GetEffectiveHoleShape() const
|
||||
{
|
||||
return std::make_shared<SHAPE_SEGMENT>( SEG( m_Start, m_Start ), KiROUND( m_drill / 2.0 ) );
|
||||
}
|
||||
|
||||
|
||||
bool PCB_VIA::IsTented() const
|
||||
{
|
||||
const BOARD* board = GetBoard();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include <board_connected_item.h>
|
||||
#include <convert_to_biu.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
|
||||
|
||||
class PCB_TRACK;
|
||||
|
@ -358,6 +359,8 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAPE_SEGMENT> GetEffectiveHoleShape() const override;
|
||||
|
||||
bool IsTented() const override;
|
||||
int GetSolderMaskExpansion() const;
|
||||
|
||||
|
|
|
@ -702,23 +702,22 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
|||
{
|
||||
for( PAD* pad : footprint->Pads() )
|
||||
{
|
||||
VECTOR2I hole = pad->GetDrillSize();
|
||||
|
||||
if( hole.x == 0 || hole.y == 0 )
|
||||
continue;
|
||||
|
||||
if( hole.x == hole.y )
|
||||
if( pad->HasHole() )
|
||||
{
|
||||
hole.x = std::min( smallDrill, hole.x );
|
||||
aPlotter->Circle( pad->GetPosition(), hole.x, FILL_T::NO_FILL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: small drill marks have no significance when applied to slots
|
||||
const SHAPE_SEGMENT* seg = pad->GetEffectiveHoleShape();
|
||||
aPlotter->ThickSegment( seg->GetSeg().A,
|
||||
seg->GetSeg().B,
|
||||
seg->GetWidth(), SKETCH, nullptr );
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = pad->GetEffectiveHoleShape();
|
||||
|
||||
if( slot->GetSeg().A == slot->GetSeg().B ) // circular hole
|
||||
{
|
||||
int drill = std::min( smallDrill, slot->GetWidth() );
|
||||
aPlotter->Circle( pad->GetPosition(), drill, FILL_T::NO_FILL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: small drill marks have no significance when applied to slots
|
||||
aPlotter->ThickSegment( slot->GetSeg().A,
|
||||
slot->GetSeg().B,
|
||||
slot->GetWidth(), SKETCH, nullptr );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1297,7 +1297,7 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
|
|||
if( pad->GetProperty() == PAD_PROP::CASTELLATED )
|
||||
{
|
||||
std::unique_ptr<SHAPE> hole;
|
||||
hole.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
|
||||
hole.reset( pad->GetEffectiveHoleShape()->Clone() );
|
||||
aWorld->AddEdgeExclusion( std::move( hole ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2816,24 +2816,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<SHAPE_SEGMENT> holeShape;
|
||||
|
||||
if( aOther->Type() == PCB_VIA_T )
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( aOther );
|
||||
VECTOR2I pos = via->GetPosition();
|
||||
|
||||
holeShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
|
||||
}
|
||||
else if( aOther->Type() == PCB_PAD_T )
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( aOther );
|
||||
|
||||
if( pad->GetDrillSize().x )
|
||||
holeShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
|
||||
}
|
||||
|
||||
if( holeShape )
|
||||
if( aOther->HasHole() )
|
||||
{
|
||||
constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, aVia, aOther,
|
||||
UNDEFINED_LAYER );
|
||||
|
@ -2843,8 +2826,11 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
|
|||
{
|
||||
std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( UNDEFINED_LAYER );
|
||||
|
||||
if( viaShape->Collide( holeShape.get(), clearance - m_drcEpsilon ) )
|
||||
if( viaShape->Collide( aOther->GetEffectiveHoleShape().get(),
|
||||
clearance - m_drcEpsilon ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -187,22 +187,16 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE_ON_MOVE::testCourtyardClearances()
|
|||
auto testPadAgainstCourtyards =
|
||||
[&]( const PAD* pad, FOOTPRINT* footprint ) -> bool
|
||||
{
|
||||
// Skip pads with no hole
|
||||
if( pad->GetAttribute() != PAD_ATTRIB::PTH
|
||||
&& pad->GetAttribute() != PAD_ATTRIB::NPTH )
|
||||
return false;
|
||||
|
||||
const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
|
||||
const SHAPE_POLY_SET& front = footprint->GetPolyCourtyard( F_CrtYd );
|
||||
const SHAPE_POLY_SET& back = footprint->GetPolyCourtyard( B_CrtYd );
|
||||
|
||||
if( front.OutlineCount() > 0 && front.Collide( hole, 0 ) )
|
||||
if( pad->HasHole() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if( back.OutlineCount() > 0 && back.Collide( hole, 0 ) )
|
||||
{
|
||||
return true;
|
||||
std::shared_ptr<SHAPE_SEGMENT> hole = pad->GetEffectiveHoleShape();
|
||||
const SHAPE_POLY_SET& front = footprint->GetPolyCourtyard( F_CrtYd );
|
||||
const SHAPE_POLY_SET& back = footprint->GetPolyCourtyard( B_CrtYd );
|
||||
|
||||
if( front.OutlineCount() > 0 && front.Collide( hole.get(), 0 ) )
|
||||
return true;
|
||||
else if( back.OutlineCount() > 0 && back.Collide( hole.get(), 0 ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1208,35 +1208,28 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
|
|||
return 0;
|
||||
}
|
||||
|
||||
if( fpFrame && !fpFrame->GetModel() )
|
||||
return 0;
|
||||
|
||||
if( selection.Empty() )
|
||||
{
|
||||
if( fpFrame )
|
||||
{
|
||||
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( fpFrame->GetModel() );
|
||||
FOOTPRINT* fp = static_cast<FOOTPRINT*>( fpFrame->GetModel() );
|
||||
size_t padCount = fp->GetPadCount( DO_NOT_INCLUDE_NPTH );
|
||||
|
||||
if( !footprint )
|
||||
return 0;
|
||||
msgItems.emplace_back( _( "Library" ), fp->GetFPID().GetLibNickname().wx_str() );
|
||||
|
||||
wxString msg;
|
||||
msgItems.emplace_back( _( "Footprint Name" ), fp->GetFPID().GetLibItemName().wx_str() );
|
||||
|
||||
msg = footprint->GetFPID().GetLibNickname().wx_str();
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Library" ), msg ) );
|
||||
msgItems.emplace_back( _( "Pads" ), wxString::Format( wxT( "%zu" ), padCount ) );
|
||||
|
||||
msg = footprint->GetFPID().GetLibItemName().wx_str();
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Footprint Name" ), msg ) );
|
||||
|
||||
msg.Printf( wxT( "%zu" ), (size_t) footprint->GetPadCount( DO_NOT_INCLUDE_NPTH ) );
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Pads" ), msg ) );
|
||||
|
||||
wxString doc, keyword;
|
||||
doc.Printf( _( "Doc: %s" ), footprint->GetDescription() );
|
||||
keyword.Printf( _( "Keywords: %s" ), footprint->GetKeywords() );
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( doc, keyword ) );
|
||||
msgItems.emplace_back( wxString::Format( _( "Doc: %s" ), fp->GetDescription() ),
|
||||
wxString::Format( _( "Keywords: %s" ), fp->GetKeywords() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frame->SetMsgPanel( m_frame->GetBoard() );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if( selection.GetSize() == 1 )
|
||||
|
@ -1245,15 +1238,10 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
|
|||
|
||||
item->GetMsgPanelInfo( m_frame, msgItems );
|
||||
}
|
||||
|
||||
// Pair selection broken into multiple, optional data, starting with the selection item names
|
||||
if( pcbFrame && selection.GetSize() == 2 )
|
||||
else if( pcbFrame && selection.GetSize() == 2 )
|
||||
{
|
||||
auto clearanceString =
|
||||
[&]( const DRC_CONSTRAINT& curr_constraint )
|
||||
{
|
||||
return StringFromValue( units, curr_constraint.m_Value.Min(), true );
|
||||
};
|
||||
// Pair selection broken into multiple, optional data, starting with the selected item
|
||||
// names
|
||||
|
||||
BOARD_ITEM* a = static_cast<BOARD_ITEM*>( selection[0] );
|
||||
BOARD_ITEM* b = static_cast<BOARD_ITEM*>( selection[1] );
|
||||
|
@ -1281,14 +1269,13 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
|
|||
|
||||
int actual_clearance = a_shape->GetClearance( b_shape.get() );
|
||||
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved clearance" ),
|
||||
clearanceString( constraint ) ) );
|
||||
msgItems.emplace_back( _( "Resolved clearance" ),
|
||||
MessageTextFromValue( units, constraint.m_Value.Min() ) );
|
||||
|
||||
if( actual_clearance > -1 && actual_clearance < std::numeric_limits<int>::max() )
|
||||
{
|
||||
msgItems.emplace_back(
|
||||
MSG_PANEL_ITEM( _( "Actual clearance" ),
|
||||
StringFromValue( units, actual_clearance, true ) ) );
|
||||
msgItems.emplace_back( _( "Actual clearance" ),
|
||||
MessageTextFromValue( units, actual_clearance ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1309,9 +1296,33 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
|
|||
|
||||
if( layer >= 0 )
|
||||
{
|
||||
int actual = std::numeric_limits<int>::max();
|
||||
|
||||
if( a->HasHole() )
|
||||
{
|
||||
std::shared_ptr<SHAPE_SEGMENT> hole = a->GetEffectiveHoleShape();
|
||||
std::shared_ptr<SHAPE> other( b->GetEffectiveShape( layer ) );
|
||||
|
||||
actual = std::min( actual, hole->GetClearance( other.get() ) );
|
||||
}
|
||||
|
||||
if( b->HasHole() )
|
||||
{
|
||||
std::shared_ptr<SHAPE_SEGMENT> hole = b->GetEffectiveHoleShape();
|
||||
std::shared_ptr<SHAPE> other( a->GetEffectiveShape( layer ) );
|
||||
|
||||
actual = std::min( actual, hole->GetClearance( other.get() ) );
|
||||
}
|
||||
|
||||
constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved hole clearance" ),
|
||||
clearanceString( constraint ) ) );
|
||||
msgItems.emplace_back( _( "Resolved hole clearance" ),
|
||||
MessageTextFromValue( units, constraint.m_Value.Min() ) );
|
||||
|
||||
if( actual > -1 && actual < std::numeric_limits<int>::max() )
|
||||
{
|
||||
msgItems.emplace_back( _( "Actual hole clearance" ),
|
||||
MessageTextFromValue( units, actual ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1341,13 +1352,13 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
|
|||
|
||||
if( edgeLayer == Edge_Cuts )
|
||||
{
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved edge clearance" ),
|
||||
clearanceString( constraint ) ) );
|
||||
msgItems.emplace_back( _( "Resolved edge clearance" ),
|
||||
MessageTextFromValue( units, constraint.m_Value.Min() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved margin clearance" ),
|
||||
clearanceString( constraint ) ) );
|
||||
msgItems.emplace_back( _( "Resolved margin clearance" ),
|
||||
MessageTextFromValue( units, constraint.m_Value.Min() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1355,8 +1366,8 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
|
|||
|
||||
if( msgItems.empty() )
|
||||
{
|
||||
wxString msg = wxString::Format( wxT( "%d" ), selection.GetSize() );
|
||||
msgItems.emplace_back( MSG_PANEL_ITEM( _( "Selected Items" ), msg ) );
|
||||
msgItems.emplace_back( _( "Selected Items" ),
|
||||
wxString::Format( wxT( "%d" ), selection.GetSize() ) );
|
||||
}
|
||||
|
||||
m_frame->SetMsgPanel( msgItems );
|
||||
|
|
|
@ -522,7 +522,7 @@ void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>&
|
|||
AccumulateDescription( msg, _( "No footprints" ) );
|
||||
|
||||
if( !msg.IsEmpty() )
|
||||
aList.emplace_back( MSG_PANEL_ITEM( _( "Restrictions" ), msg ) );
|
||||
aList.emplace_back( _( "Restrictions" ), msg );
|
||||
}
|
||||
else if( IsOnCopperLayer() )
|
||||
{
|
||||
|
@ -586,23 +586,14 @@ void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>&
|
|||
source ) );
|
||||
}
|
||||
|
||||
// Useful for statistics, especially when zones are complex the number of hatches
|
||||
// and filled polygons can explain the display and DRC calculation time:
|
||||
msg.Printf( wxT( "%d" ), (int) m_borderHatchLines.size() );
|
||||
aList.emplace_back( MSG_PANEL_ITEM( _( "HatchBorder Lines" ), msg ) );
|
||||
|
||||
if( !m_FilledPolysList.empty() )
|
||||
{
|
||||
count = 0;
|
||||
|
||||
for( auto item: m_FilledPolysList )
|
||||
{
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& polyset = item.second;
|
||||
count += polyset->TotalVertices();
|
||||
}
|
||||
for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& ii: m_FilledPolysList )
|
||||
count += ii.second->TotalVertices();
|
||||
|
||||
msg.Printf( wxT( "%d" ), count );
|
||||
aList.emplace_back( MSG_PANEL_ITEM( _( "Corner Count" ), msg ) );
|
||||
aList.emplace_back( _( "Corner Count" ), wxString::Format( wxT( "%d" ), count ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue