39#include <unordered_map>
40#include <unordered_set>
45#define MAGIC_TEARDROP_ZONE_ID 30000
65 for(
int ii = 0; ii < 2 * aSlot; ++ii )
74 KIID uuid = aCopperUuid;
108 std::vector<VECTOR2I>& aPoints,
PCB_TRACK* aSourceTrack,
109 const KIID& aUuid )
const
135 outline->
Append( pt.x, pt.y );
150 std::vector<VECTOR2I>& aPoints,
174 outline->
Append( pt.x, pt.y );
184 m_board->GetDesignSettings().m_MaxError );
198 std::vector<VECTOR2I>& aPoints,
201 ZONE* new_teardrop =
createTeardrop( aTeardropVariant, aPoints, aSourceTrack, aUuid );
208 const int bmin[2] = { bbox.
GetX(), bbox.
GetY() };
212 aCommit.
Added( new_teardrop );
219 aCommit.
Added( new_teardrop_mask );
231 std::vector<VECTOR2I> points;
244 std::vector<BOARD_ITEM*>* dirtyPadsAndVias,
245 std::set<PCB_TRACK*>* dirtyTracks,
246 const std::vector<BOARD_ITEM*>* dirtyCopper )
248 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
250 struct TEARDROP_ANCHORS
252 std::vector<PAD*> pads;
253 std::vector<PCB_VIA*> vias;
254 std::vector<PCB_TRACK*> tracks;
257 std::vector<ZONE*> masks;
258 std::vector<ZONE*> copperTeardrops;
259 std::map<ZONE*, TEARDROP_ANCHORS> anchors;
263 if( !zone->IsTeardropArea() )
268 if( !zone->IsOnCopperLayer() )
270 masks.push_back( zone );
274 copperTeardrops.push_back( zone );
276 TEARDROP_ANCHORS& zoneAnchors = anchors[zone];
278 connectivity->GetConnectedPadsAndVias( zone, &zoneAnchors.pads, &zoneAnchors.vias );
279 zoneAnchors.tracks = connectivity->GetConnectedTracks( zone );
290 std::map<PCB_LAYER_ID, std::vector<DIRTY_COPPER>> dirtyCopperByLayer;
296 DIRTY_COPPER entry = { item->GetBoundingBox(),
copperNetcode( item ) };
298 for(
PCB_LAYER_ID layer : item->GetLayerSet().CuStack() )
299 dirtyCopperByLayer[layer].push_back( entry );
303 int maxClearance =
m_board->GetMaxClearanceValue();
307 auto foreignNeighbourMoved =
308 [&](
ZONE* zone ) ->
bool
312 auto it = dirtyCopperByLayer.find( layer );
314 if( it == dirtyCopperByLayer.end() )
319 BOX2I reach = zone->GetBoundingBox();
323 for(
const DIRTY_COPPER& item : it->second )
326 if( zone->GetNetCode() > 0 && item.netcode == zone->GetNetCode() )
336 std::unordered_set<BOARD_ITEM*> dirtyPadViaSet( dirtyPadsAndVias->begin(),
337 dirtyPadsAndVias->end() );
340 [&](
const TEARDROP_ANCHORS& zoneAnchors )
344 return dirtyPadViaSet.count( aItem ) > 0;
347 return std::any_of( zoneAnchors.pads.begin(), zoneAnchors.pads.end(),
349 || std::any_of( zoneAnchors.vias.begin(), zoneAnchors.vias.end(),
351 || std::any_of( zoneAnchors.tracks.begin(), zoneAnchors.tracks.end(),
354 return dirtyTracks->contains( aTrack );
360 for(
ZONE* zone : copperTeardrops )
362 if( !foreignNeighbourMoved( zone ) )
365 const TEARDROP_ANCHORS& zoneAnchors = anchors[zone];
367 for(
PAD*
pad : zoneAnchors.pads )
369 if( dirtyPadViaSet.insert(
pad ).second )
370 dirtyPadsAndVias->push_back(
pad );
375 if( dirtyPadViaSet.insert(
via ).second )
376 dirtyPadsAndVias->push_back(
via );
379 for(
PCB_TRACK* track : zoneAnchors.tracks )
380 dirtyTracks->insert( track );
383 std::map<PCB_LAYER_ID, std::vector<ZONE*>> survivingCopper;
384 std::unordered_map<KIID, bool> maskSurvives;
386 for(
ZONE* zone : copperTeardrops )
388 bool stale = isStale( anchors[zone] );
391 maskSurvives[
maskUuidFor( zone->m_Uuid )] = !stale;
396 survivingCopper[zone->GetFirstLayer()].push_back( zone );
399 for(
ZONE* mask : masks )
403 if(
auto it = maskSurvives.find( mask->m_Uuid ); it != maskSurvives.end() )
412 BOX2I maskBBox = mask->Outline()->BBox();
416 for(
ZONE* copper : survivingCopper[copperLayer] )
418 BOX2I copperBBox = copper->GetBoundingBox();
433 m_board->BulkRemoveStaleTeardrops( aCommit );
438 const std::vector<BOARD_ITEM*>* dirtyPadsAndVias,
439 const std::set<PCB_TRACK*>* dirtyTracks,
440 bool aForceFullUpdate )
442 if(
m_board->LegacyTeardrops() )
450 if( aForceFullUpdate )
454 if( zone->IsTeardropArea() )
458 m_board->BulkRemoveStaleTeardrops( aCommit );
463 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
464 std::unordered_set<BOARD_ITEM*> dirtyPadViaSet;
466 if( dirtyPadsAndVias )
467 dirtyPadViaSet.insert( dirtyPadsAndVias->begin(), dirtyPadsAndVias->end() );
474 std::vector<PAD*> connectedPads;
475 std::vector<PCB_VIA*> connectedVias;
477 connectivity->GetConnectedPadsAndVias( track, &connectedPads, &connectedVias );
479 bool forceUpdate = aForceFullUpdate || dirtyTracks->contains( track );
481 for(
PAD*
pad : connectedPads )
483 if( !forceUpdate && !dirtyPadViaSet.count(
pad ) )
487 VECTOR2I padSize =
pad->GetSize( track->GetLayer() );
488 int annularWidth = std::min( padSize.
x, padSize.
y );
502 bool startHitsPad =
pad->HitTest( track->GetStart(), 0, track->GetLayer() );
503 bool endHitsPad =
pad->HitTest( track->GetEnd(), 0, track->GetLayer() );
506 if( startHitsPad && endHitsPad )
510 if( startHitsPad != endHitsPad
512 startHitsPad ? track->GetStart() : track->GetEnd() )
513 < track->GetWidth() )
524 if( !startHitsPad && !endHitsPad && track->HitTest(
pad->GetPosition() ) )
532 track,
pad,
pad->GetPosition(),
536 track,
pad,
pad->GetPosition(),
542 track,
pad,
pad->GetPosition(),
549 if( !forceUpdate && !dirtyPadViaSet.count(
via ) )
553 int annularWidth =
via->GetWidth( track->GetLayer() );
567 bool startHitsVia =
via->HitTest( track->GetStart() );
568 bool endHitsVia =
via->HitTest( track->GetEnd() );
571 if( startHitsVia && endHitsVia )
575 if( startHitsVia != endHitsVia
577 startHitsVia ? track->GetStart() : track->GetEnd() )
578 < track->GetWidth() )
584 if( !startHitsVia && !endHitsVia && track->HitTest(
via->GetPosition() ) )
592 track,
via,
via->GetPosition(),
596 track,
via,
via->GetPosition(),
602 track,
via,
via->GetPosition(),
608 if( ( aForceFullUpdate || !dirtyTracks->empty() )
627 m_board->BulkRemoveStaleTeardrops( aCommit );
642 bool operator()(
ZONE* a,
ZONE* b)
const
656 td->CalculateOutlineArea();
663 std::map<int, std::set<unsigned>> taken;
667 if( zone->IsTeardropArea() && !created.count( zone ) )
668 taken[zone->GetFirstLayer()].insert( zone->GetAssignedPriority() );
675 if( td->GetFirstLayer() != curr_layer )
677 curr_layer = td->GetFirstLayer();
681 const std::set<unsigned>& layerTaken = taken[curr_layer];
683 while( layerTaken.count( priority_base )
684 && priority_base < std::numeric_limits<unsigned>::max() )
689 td->SetAssignedPriority( priority_base );
691 if( priority_base < std::numeric_limits<unsigned>::max() )
698 const std::set<PCB_TRACK*>* aTracks,
699 bool aForceFullUpdate,
bool aSetPriorities )
701 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
710 std::vector<PCB_TRACK*>* sublist = &grp.second;
712 if( sublist->size() <= 1 )
722 std::sort( sublist->begin(), sublist->end(), compareLess );
723 int min_width = sublist->front()->GetWidth();
724 int max_width = sublist->back()->GetWidth();
727 if( max_width == min_width )
730 for(
unsigned ii = 0; ii < sublist->size()-1; ii++ )
733 int track_len = (int) track->
GetLength();
734 bool track_needs_update = aForceFullUpdate || aTracks->contains( track );
740 min_width =
KiROUND( min_width * th );
742 for(
unsigned jj = ii+1; jj < sublist->size(); jj++ )
747 if( min_width >= candidate->
GetWidth() )
752 if( track_len <= candidate->
GetWidth() /2 )
764 pos = candidate->
GetEnd();
773 if( !track_needs_update && !aTracks->contains( candidate ) )
777 bool existingPadOrVia =
false;
778 std::vector<PAD*> connectedPads;
779 std::vector<PCB_VIA*> connectedVias;
781 connectivity->GetConnectedPadsAndVias( track, &connectedPads, &connectedVias );
783 for(
PAD*
pad : connectedPads )
785 if(
pad->HitTest( pos ) )
786 existingPadOrVia =
true;
791 if(
via->HitTest( pos ) )
792 existingPadOrVia =
true;
795 if( existingPadOrVia )
799 track, candidate, pos,
constexpr EDA_IU_SCALE pcbIUScale
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
NETINFO_ITEM * GetNet() const
Return NETINFO_ITEM object for a given item.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
Information pertinent to a Pcbnew printed circuit board.
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr coord_type GetY() const
constexpr coord_type GetX() const
constexpr const Vec GetCenter() const
constexpr bool Contains(const Vec &aPoint) const
constexpr coord_type GetRight() const
constexpr bool Intersects(const BOX2< Vec > &aRect) const
constexpr coord_type GetBottom() const
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
KICAD_T Type() const
Returns the type of object.
static KIID Combine(const KIID &aFirst, const KIID &aSecond)
Creates a deterministic KIID from two input KIIDs by XORing their underlying UUIDs.
void Increment()
Generates a deterministic replacement for a given ID.
const VECTOR2I & GetMid() const
int GetSolderMaskExpansion() const
void SetHasSolderMask(bool aVal)
virtual double GetLength() const
Get the length of the track using the hypotenuse calculation.
void SetEnd(const VECTOR2I &aEnd)
bool HasSolderMask() const
void SetStart(const VECTOR2I &aStart)
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
std::optional< int > GetLocalSolderMaskMargin() const
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
EDA_ITEM_FLAGS IsPointOnEnds(const VECTOR2I &point, int min_dist=0) const
Return STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if point if near (dist = m...
virtual void SetWidth(int aWidth)
virtual int GetWidth() const
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Represent a set of closed polygons.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
std::map< PCB_LAYER_ID, KIRTREE::DYNAMIC_RTREE< ZONE *, int, 2 > > m_createdTdRTree
The teardrops of this pass by layer, since m_copperRTree cannot take inserts once built.
ZONE * createTeardropMask(TEARDROP_VARIANT aTeardropVariant, std::vector< VECTOR2I > &aPoints, PCB_TRACK *aSourceTrack, const KIID &aUuid) const
static int GetWidth(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
static int copperNetcode(const BOARD_ITEM *aItem)
TEARDROP_MANAGER(BOARD *aBoard, TOOL_MANAGER *aToolManager)
static KIID teardropUuid(const PCB_TRACK *aTrack, const BOARD_ITEM *aCandidate, int aSlot)
Build the UUID a teardrop is created with.
static KIID maskUuidFor(const KIID &aCopperUuid)
Build the UUID of the mask sibling of aCopperUuid.
ZONE * createTeardrop(TEARDROP_VARIANT aTeardropVariant, std::vector< VECTOR2I > &aPoints, PCB_TRACK *aSourceTrack, const KIID &aUuid) const
Creates a teardrop (a ZONE item) from its polygonal shape, track netcode and layer.
void UpdateTeardrops(BOARD_COMMIT &aCommit, const std::vector< BOARD_ITEM * > *dirtyPadsAndVias, const std::set< PCB_TRACK * > *dirtyTracks, bool aForceFullUpdate=false)
Update teardrops on a list of items.
void RemoveTeardrops(BOARD_COMMIT &aCommit, std::vector< BOARD_ITEM * > *dirtyPadsAndVias, std::set< PCB_TRACK * > *dirtyTracks, const std::vector< BOARD_ITEM * > *dirtyCopper=nullptr)
Remove teardrops on dirty pads, vias or tracks, and any whose neighbouring copper moved,...
void setTeardropPriorities()
Set priority of created teardrops.
TRACK_BUFFER m_trackLookupList
void AddTeardropsOnTracks(BOARD_COMMIT &aCommit, const std::set< PCB_TRACK * > *aTracks, bool aForceFullUpdate=false, bool aSetPriorities=true)
Add teardrop on tracks of different sizes connected by their end.
TEARDROP_PARAMETERS_LIST * m_prmsList
std::vector< ZONE * > m_createdTdList
void DeleteTrackToTrackTeardrops(BOARD_COMMIT &aCommit)
bool areItemsInSameZone(BOARD_ITEM *aPadOrVia, PCB_TRACK *aTrack) const
bool tryCreateTrackTeardrop(BOARD_COMMIT &aCommit, const TEARDROP_PARAMETERS &aParams, TEARDROP_VARIANT aTeardropVariant, PCB_TRACK *aTrack, PCB_TRACK *aSourceTrack, BOARD_ITEM *aCandidate, const VECTOR2I &aPos, const KIID &aUuid)
Attempts to create a track-to-track teardrop.
bool computeFittedTeardropPolygon(const TEARDROP_PARAMETERS &aParams, std::vector< VECTOR2I > &aPoints, PCB_TRACK *aTrack, PCB_TRACK *aSourceTrack, BOARD_ITEM *aOther, const VECTOR2I &aOtherPos) const
Widen a teardrop as far as the surrounding copper allows.
friend class TEARDROP_PARAMETERS
TOOL_MANAGER * m_toolManager
void createAndAddTeardropWithMask(BOARD_COMMIT &aCommit, TEARDROP_VARIANT aTeardropVariant, std::vector< VECTOR2I > &aPoints, PCB_TRACK *aSourceTrack, const KIID &aUuid)
Creates and adds a teardrop with optional mask to the board.
int computeChordThroughShape(PCB_TRACK *aTrack, BOARD_ITEM *aOther, PCB_LAYER_ID aLayer, const VECTOR2I &aInsidePoint) const
Return the centerline chord length through aOther's copper span at aInsidePoint.
static void buildCrossingStub(PCB_TRACK &aStub, const PCB_TRACK *aTrack, const VECTOR2I &aCrossedPos)
Set aStub up as the segment from one end of aTrack to the point of aTrack nearest aCrossedPos,...
double m_BestWidthRatio
The height of a teardrop as ratio between height and size of pad/via.
int m_TdMaxWidth
max allowed height for teardrops in IU. <= 0 to disable
double m_WidthtoSizeFilterRatio
The ratio (H/D) between the via/pad size and the track width max value to create a teardrop 1....
bool m_TdOnPadsInZones
A filter to exclude pads inside zone fills.
bool m_Enabled
Flag to enable teardrops.
static void GetNetcodeAndLayerFromIndex(int aIdx, int *aLayer, int *aNetcode)
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Copy settings to a given zone.
static const ZONE_SETTINGS & GetDefaultSettings()
Handle a list of polygons defining a copper zone.
double GetOutlineArea()
This area is cached from the most recent call to CalculateOutlineArea().
void SetLocalClearance(std::optional< int > aClearance)
void SetMinThickness(int aMinThickness)
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuildBorderHatch)
Set all hatch parameters for the zone.
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
SHAPE_POLY_SET * Outline()
bool SetNetCode(int aNetCode, bool aNoAssert) override
Override that clamps the netcode to 0 when this zone is in copper-thieving fill mode.
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
int GetMinThickness() const
void SetIsFilled(bool isFilled)
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
void SetPadConnection(ZONE_CONNECTION aPadConnection)
void SetTeardropAreaType(TEARDROP_TYPE aType)
Set the type of teardrop if the zone is a teardrop area for non teardrop area, the type must be TEARD...
void SetIslandRemovalMode(ISLAND_REMOVAL_MODE aRemove)
PCB_LAYER_ID GetFirstLayer() const
This file is part of the common library.
@ ALLOW_ACUTE_CORNERS
just inflate the polygon. Acute angles create spikes
#define STRUCT_DELETED
flag indication structures to be erased
std::uint32_t EDA_ITEM_FLAGS
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
#define MAGIC_TEARDROP_ZONE_ID
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
VECTOR2< int32_t > VECTOR2I
@ FULL
pads are covered by copper