28#include <unordered_set>
33 bool aBreakCrossings )
42 info.hasBusEntry =
false;
43 info.hasExplicitJunctionDot =
false;
44 info.isJunction =
false;
45 info.hasBusEntryToMultipleWires =
false;
46 info.hasBusEntryToMultipleBuses =
false;
47 info.hasBusAtPoint =
false;
49 bool breakLines[2] = {
false };
50 std::unordered_set<int> exitAngles[2];
51 std::vector<const SCH_LINE*> midPointLines[2];
54 int busEntryBusAngles = 0;
57 int busEndpointSegments = 0;
60 std::list<std::unique_ptr<SCH_LINE>> mergedLines;
69 switch( item->Type() )
76 mergedLines.emplace_back(
new SCH_LINE( *line ) );
82 if( item->HitTest( aPosition, -1 ) )
83 info.hasExplicitJunctionDot =
true;
89 info.hasBusEntry =
true;
106 if( mergedLines.size() + filtered.
size() < 2 )
113 std::unordered_set<int> preMergeWireExits;
114 std::unordered_set<int> preMergeBusExits;
116 for(
const auto& line : mergedLines )
118 if( line->GetStartPoint() == line->GetEndPoint() )
121 if( !line->IsConnected( aPosition ) )
125 preMergeWireExits.insert( line->GetAngleFrom( aPosition ) );
127 preMergeBusExits.insert( line->GetAngleFrom( aPosition ) );
130 const bool keepStubJunction = preMergeWireExits.size() >= 3 || preMergeBusExits.size() >= 3;
137 if(
info.hasExplicitJunctionDot || aBreakCrossings || keepStubJunction )
142 for(
auto it_i = mergedLines.begin(); it_i != mergedLines.end() && !merged; ++it_i )
144 for(
auto it_j = std::next( it_i ); it_j != mergedLines.end(); ++it_j )
146 if(
auto* line = ( *it_i )->MergeOverlap(
nullptr, it_j->get(),
false ) )
149 mergedLines.erase( it_j );
157 for(
const auto& line : mergedLines )
158 filtered.
insert( line.get() );
162 int uniqueAngle = 10000;
164 for(
const SCH_ITEM* item : filtered )
169 switch( item->Type() )
172 if( item->HitTest( aPosition, -1 ) )
173 info.hasExplicitJunctionDot =
true;
193 breakLines[layer] =
true;
194 exitAngles[layer].insert( line->
GetAngleFrom( aPosition ) );
197 busEndpointSegments++;
199 else if( line->
HitTest( aPosition, -1 ) )
201 if( aBreakCrossings )
202 breakLines[layer] =
true;
205 midPointLines[layer].push_back( line );
208 if( layer == BUSES && line->
HitTest( aPosition, -1 ) )
209 info.hasBusAtPoint =
true;
214 if( item->IsConnected( aPosition ) )
216 breakLines[BUSES] =
true;
217 exitAngles[BUSES].insert( uniqueAngle++ );
219 breakLines[WIRES] =
true;
220 exitAngles[WIRES].insert( uniqueAngle++ );
221 info.hasBusEntry =
true;
228 if( item->IsConnected( aPosition ) )
230 breakLines[WIRES] =
true;
231 exitAngles[WIRES].insert( uniqueAngle++ );
237 if( item->IsConnected( aPosition ) )
240 breakLines[BUSES] =
true;
242 breakLines[WIRES] =
true;
249 if( item->IsConnected( aPosition ) )
250 breakLines[WIRES] =
true;
259 for(
int layer : { WIRES, BUSES } )
261 if( breakLines[layer] )
263 for(
const SCH_LINE* line : midPointLines[layer] )
265 exitAngles[layer].insert( line->GetAngleFrom( aPosition ) );
266 exitAngles[layer].insert( line->GetReverseAngleFrom( aPosition ) );
271 if(
info.hasBusEntry )
276 info.hasBusEntryToMultipleWires = exitAngles[WIRES].size() > 2 && exitAngles[BUSES].size() == 1;
280 const int realBusAngles =
static_cast<int>( exitAngles[BUSES].size() ) - busEntryBusAngles;
281 info.hasBusEntryToMultipleBuses = realBusAngles >= 3 && busEndpointSegments >= 1;
285 info.isJunction = exitAngles[WIRES].size() >= 3 || exitAngles[BUSES].size() >= 3;
292 const std::vector<SCH_ITEM*>& aItems )
295 std::unordered_set<const SCH_ITEM*> previewSet( aItems.begin(), aItems.end() );
300 if( !item->IsConnectable() )
303 if( previewSet.count( item ) )
312 if( !item || !item->IsConnectable() )
319 std::vector<VECTOR2I> pts;
323 if( !item || !item->IsConnectable() )
326 std::vector<VECTOR2I> new_pts = item->GetConnectionPoints();
327 pts.insert( pts.end(), new_pts.begin(), new_pts.end() );
333 for(
const VECTOR2I& pt : connections )
341 std::sort( pts.begin(), pts.end(),
344 return a.x < b.x || ( a.x == b.x && a.y < b.y );
347 pts.erase( std::unique( pts.begin(), pts.end() ), pts.end() );
349 std::vector<SCH_JUNCTION*> jcts;
355 if(
info.AllowsExplicitJunction() )
359 if(
info.hasBusAtPoint )
362 jcts.push_back( junction );
Implement an R-tree for fast spatial and type indexing of schematic items.
size_t size() const
Return the number of items in the tree.
EE_TYPE Overlapping(const BOX2I &aRect) const
void insert(SCH_ITEM *aItem)
Insert an item into the tree.
static bool IsBusLabel(const wxString &aLabel)
Test if aLabel has a bus notation.
Base class for any item which can be embedded within the SCHEMATIC container class,...
void SetLayer(SCH_LAYER_ID aLayer)
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
bool IsConnected(const VECTOR2I &aPoint) const
Test the item to see if it is connected to aPoint.
Segment description base class to describe items which have 2 end points (track, wire,...
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
int GetAngleFrom(const VECTOR2I &aPoint) const
VECTOR2I GetEndPoint() const
VECTOR2I GetStartPoint() const
bool IsConnectable() const override
EE_RTREE & Items()
Get the full RTree, usually for iterating.
std::vector< VECTOR2I > GetConnections() const
Collect a unique list of all possible connection points in the schematic.
#define STRUCT_DELETED
flag indication structures to be erased
#define SKIP_STRUCT
flag indicating that the structure should be ignored
std::vector< SCH_JUNCTION * > PreviewJunctions(const class SCH_SCREEN *aScreen, const std::vector< class SCH_ITEM * > &aItems)
Determine the points where explicit junctions would be required if the given temporary items were com...
POINT_INFO AnalyzePoint(const EE_RTREE &aItem, const VECTOR2I &aPosition, bool aBreakCrossings)
Check a tree of items for a confluence at a given point and work out what kind of junction it is,...
A selection of information about a point in the schematic that might be eligible for turning into a j...
bool IsPointOnSegment(const VECTOR2I &aSegStart, const VECTOR2I &aSegEnd, const VECTOR2I &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
VECTOR2< int32_t > VECTOR2I