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;
96 std::vector<VECTOR2I>& aPoints,
PCB_TRACK* aSourceTrack,
97 const KIID& aUuid )
const
123 outline->
Append( pt.x, pt.y );
138 std::vector<VECTOR2I>& aPoints,
162 outline->
Append( pt.x, pt.y );
172 m_board->GetDesignSettings().m_MaxError );
186 std::vector<VECTOR2I>& aPoints,
189 ZONE* new_teardrop =
createTeardrop( aTeardropVariant, aPoints, aSourceTrack, aUuid );
197 aCommit.
Added( new_teardrop );
204 aCommit.
Added( new_teardrop_mask );
216 std::vector<VECTOR2I> points;
229 std::vector<BOARD_ITEM*>* dirtyPadsAndVias,
230 std::set<PCB_TRACK*>* dirtyTracks,
231 const std::vector<BOARD_ITEM*>* dirtyCopper )
233 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
235 struct TEARDROP_ANCHORS
237 std::vector<PAD*> pads;
238 std::vector<PCB_VIA*> vias;
239 std::vector<PCB_TRACK*> tracks;
242 std::vector<ZONE*> masks;
243 std::vector<ZONE*> copperTeardrops;
244 std::map<ZONE*, TEARDROP_ANCHORS> anchors;
248 if( !zone->IsTeardropArea() )
253 if( !zone->IsOnCopperLayer() )
255 masks.push_back( zone );
259 copperTeardrops.push_back( zone );
261 TEARDROP_ANCHORS& zoneAnchors = anchors[zone];
263 connectivity->GetConnectedPadsAndVias( zone, &zoneAnchors.pads, &zoneAnchors.vias );
264 zoneAnchors.tracks = connectivity->GetConnectedTracks( zone );
275 std::map<PCB_LAYER_ID, std::vector<DIRTY_COPPER>> dirtyCopperByLayer;
281 DIRTY_COPPER entry = { item->GetBoundingBox(),
copperNetcode( item ) };
283 for(
PCB_LAYER_ID layer : item->GetLayerSet().CuStack() )
284 dirtyCopperByLayer[layer].push_back( entry );
288 int maxClearance =
m_board->GetMaxClearanceValue();
292 auto foreignNeighbourMoved =
293 [&](
ZONE* zone ) ->
bool
297 auto it = dirtyCopperByLayer.find( layer );
299 if( it == dirtyCopperByLayer.end() )
304 BOX2I reach = zone->GetBoundingBox();
308 for(
const DIRTY_COPPER& item : it->second )
311 if( zone->GetNetCode() > 0 && item.netcode == zone->GetNetCode() )
321 std::unordered_set<BOARD_ITEM*> dirtyPadViaSet( dirtyPadsAndVias->begin(),
322 dirtyPadsAndVias->end() );
325 [&](
const TEARDROP_ANCHORS& zoneAnchors )
329 return dirtyPadViaSet.count( aItem ) > 0;
332 return std::any_of( zoneAnchors.pads.begin(), zoneAnchors.pads.end(),
334 || std::any_of( zoneAnchors.vias.begin(), zoneAnchors.vias.end(),
336 || std::any_of( zoneAnchors.tracks.begin(), zoneAnchors.tracks.end(),
339 return dirtyTracks->contains( aTrack );
345 for(
ZONE* zone : copperTeardrops )
347 if( !foreignNeighbourMoved( zone ) )
350 const TEARDROP_ANCHORS& zoneAnchors = anchors[zone];
352 for(
PAD*
pad : zoneAnchors.pads )
354 if( dirtyPadViaSet.insert(
pad ).second )
355 dirtyPadsAndVias->push_back(
pad );
360 if( dirtyPadViaSet.insert(
via ).second )
361 dirtyPadsAndVias->push_back(
via );
364 for(
PCB_TRACK* track : zoneAnchors.tracks )
365 dirtyTracks->insert( track );
368 std::map<PCB_LAYER_ID, std::vector<ZONE*>> survivingCopper;
369 std::unordered_map<KIID, bool> maskSurvives;
371 for(
ZONE* zone : copperTeardrops )
373 bool stale = isStale( anchors[zone] );
376 maskSurvives[
maskUuidFor( zone->m_Uuid )] = !stale;
381 survivingCopper[zone->GetFirstLayer()].push_back( zone );
384 for(
ZONE* mask : masks )
388 if(
auto it = maskSurvives.find( mask->m_Uuid ); it != maskSurvives.end() )
397 BOX2I maskBBox = mask->Outline()->BBox();
401 for(
ZONE* copper : survivingCopper[copperLayer] )
403 BOX2I copperBBox = copper->GetBoundingBox();
418 m_board->BulkRemoveStaleTeardrops( aCommit );
423 const std::vector<BOARD_ITEM*>* dirtyPadsAndVias,
424 const std::set<PCB_TRACK*>* dirtyTracks,
425 bool aForceFullUpdate )
427 if(
m_board->LegacyTeardrops() )
435 if( aForceFullUpdate )
439 if( zone->IsTeardropArea() )
443 m_board->BulkRemoveStaleTeardrops( aCommit );
448 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
449 std::unordered_set<BOARD_ITEM*> dirtyPadViaSet;
451 if( dirtyPadsAndVias )
452 dirtyPadViaSet.insert( dirtyPadsAndVias->begin(), dirtyPadsAndVias->end() );
459 std::vector<PAD*> connectedPads;
460 std::vector<PCB_VIA*> connectedVias;
462 connectivity->GetConnectedPadsAndVias( track, &connectedPads, &connectedVias );
464 bool forceUpdate = aForceFullUpdate || dirtyTracks->contains( track );
466 for(
PAD*
pad : connectedPads )
468 if( !forceUpdate && !dirtyPadViaSet.count(
pad ) )
472 VECTOR2I padSize =
pad->GetSize( track->GetLayer() );
473 int annularWidth = std::min( padSize.
x, padSize.
y );
487 bool startHitsPad =
pad->HitTest( track->GetStart(), 0, track->GetLayer() );
488 bool endHitsPad =
pad->HitTest( track->GetEnd(), 0, track->GetLayer() );
491 if( startHitsPad && endHitsPad )
495 if( startHitsPad != endHitsPad
497 startHitsPad ? track->GetStart() : track->GetEnd() )
498 < track->GetWidth() )
509 if( !startHitsPad && !endHitsPad && track->HitTest(
pad->GetPosition() ) )
517 track,
pad,
pad->GetPosition(),
521 track,
pad,
pad->GetPosition(),
527 track,
pad,
pad->GetPosition(),
534 if( !forceUpdate && !dirtyPadViaSet.count(
via ) )
538 int annularWidth =
via->GetWidth( track->GetLayer() );
552 bool startHitsVia =
via->HitTest( track->GetStart() );
553 bool endHitsVia =
via->HitTest( track->GetEnd() );
556 if( startHitsVia && endHitsVia )
560 if( startHitsVia != endHitsVia
562 startHitsVia ? track->GetStart() : track->GetEnd() )
563 < track->GetWidth() )
569 if( !startHitsVia && !endHitsVia && track->HitTest(
via->GetPosition() ) )
577 track,
via,
via->GetPosition(),
581 track,
via,
via->GetPosition(),
587 track,
via,
via->GetPosition(),
593 if( ( aForceFullUpdate || !dirtyTracks->empty() )
612 m_board->BulkRemoveStaleTeardrops( aCommit );
627 bool operator()(
ZONE* a,
ZONE* b)
const
641 td->CalculateOutlineArea();
648 std::map<int, std::set<unsigned>> taken;
652 if( zone->IsTeardropArea() && !created.count( zone ) )
653 taken[zone->GetFirstLayer()].insert( zone->GetAssignedPriority() );
660 if( td->GetFirstLayer() != curr_layer )
662 curr_layer = td->GetFirstLayer();
666 const std::set<unsigned>& layerTaken = taken[curr_layer];
668 while( layerTaken.count( priority_base )
669 && priority_base < std::numeric_limits<unsigned>::max() )
674 td->SetAssignedPriority( priority_base );
676 if( priority_base < std::numeric_limits<unsigned>::max() )
683 const std::set<PCB_TRACK*>* aTracks,
684 bool aForceFullUpdate,
bool aSetPriorities )
686 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
695 std::vector<PCB_TRACK*>* sublist = &grp.second;
697 if( sublist->size() <= 1 )
707 std::sort( sublist->begin(), sublist->end(), compareLess );
708 int min_width = sublist->front()->GetWidth();
709 int max_width = sublist->back()->GetWidth();
712 if( max_width == min_width )
715 for(
unsigned ii = 0; ii < sublist->size()-1; ii++ )
718 int track_len = (int) track->
GetLength();
719 bool track_needs_update = aForceFullUpdate || aTracks->contains( track );
725 min_width =
KiROUND( min_width * th );
727 for(
unsigned jj = ii+1; jj < sublist->size(); jj++ )
732 if( min_width >= candidate->
GetWidth() )
737 if( track_len <= candidate->
GetWidth() /2 )
749 pos = candidate->
GetEnd();
758 if( !track_needs_update && !aTracks->contains( candidate ) )
762 bool existingPadOrVia =
false;
763 std::vector<PAD*> connectedPads;
764 std::vector<PCB_VIA*> connectedVias;
766 connectivity->GetConnectedPadsAndVias( track, &connectedPads, &connectedVias );
768 for(
PAD*
pad : connectedPads )
770 if(
pad->HitTest( pos ) )
771 existingPadOrVia =
true;
776 if(
via->HitTest( pos ) )
777 existingPadOrVia =
true;
780 if( existingPadOrVia )
784 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 #NET_INFO 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 const Vec GetCenter() const
constexpr bool Contains(const Vec &aPoint) const
constexpr bool Intersects(const BOX2< Vec > &aRect) const
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
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.
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
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.
static void buildCrossingStub(PCB_TRACK &aStub, const PCB_TRACK *aTrack, const VECTOR2I &aEnd)
Set aStub up as the segment from one end of aTrack to aEnd, for a track that crosses the pad or via i...
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)
DRC_RTREE m_copperRTree
Every copper item plus the teardrops built so far, to keep teardrops off other nets.
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.
void ensureCopperIndex() const
Build the copper collision index, deferred so a commit with no teardrop candidate never pays for it.
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.
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
Function ExportSetting 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)
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
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuilBorderHatch)
Set all hatch parameters for the zone.
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