194 std::map<KIID, int> units( aUnits.begin(), aUnits.end() );
195 std::vector<const ITEM_GEOMETRY*> vertices;
196 std::vector<std::vector<KIID>> members;
197 std::unordered_map<KIID, size_t> byId;
198 std::unordered_map<uint64_t, POINT> points;
199 std::unordered_map<KIID, uint8_t> dangling;
202 auto addPort = [&](
size_t aVertex,
const KIID& aId,
VECTOR2I aPosition, CONTACT_KIND aKind, uint8_t aBit )
204 POINT& point = points[PointKey( aPosition )];
205 point.position = aPosition;
206 point.ports.push_back( { aVertex, aId, aKind, aBit } );
207 dangling[aId] |= aBit;
213 size_t index = vertices.size();
214 std::vector<KIID> active;
218 auto unit = units.find( fact.
owner );
220 if( unit == units.end() )
221 throw std::invalid_argument(
"Missing symbol unit in connectivity geometry" );
225 if(
pin.unit != 0 && unit->second != 0 &&
pin.unit != unit->second )
228 active.push_back(
pin.id );
232 dangling[
pin.id] = 0;
237 active.push_back( fact.
id );
239 for(
size_t port = 0; port < fact.
ports.size(); ++port )
240 addPort(
index, fact.
id, fact.
ports[port].position, Kind( fact.
ports[port].kind ),
241 uint8_t( 1 << port ) );
244 dangling[fact.
id] = 0;
250 vertices.push_back( &fact );
251 SortUnique( active );
252 members.push_back( std::move( active ) );
253 byId.emplace( fact.
id,
index );
259 int min[2] = { Bound( std::min( segment.
A.
x, segment.
B.
x ), -2 ),
260 Bound( std::min( segment.
A.
y, segment.
B.
y ), -2 ) };
261 int max[2] = { Bound( std::max( segment.
A.
x, segment.
B.
x ), 2 ),
262 Bound( std::max( segment.
A.
y, segment.
B.
y ), 2 ) };
267 auto tree = lines.
Build();
269 std::vector<std::array<bool, 2>> entryWire( vertices.size() );
270 std::vector<std::array<bool, 2>> entryBus( vertices.size() );
271 std::vector<std::pair<KIID, KIID>> adjacency;
272 std::vector<std::pair<KIID, KIID>> ncContacts;
273 std::vector<std::pair<KIID, KIID>> busLinks;
275 auto entryContact = [&](
const PORT& aEntry,
const PORT& aOther )
277 if( aEntry.kind !=
ENTRY && aEntry.kind != BUS_SIDE && aEntry.kind !=
ENTRY_BUS )
280 size_t end = aEntry.bit == 2 ? 1 : 0;
282 if( aOther.kind ==
WIRE )
283 entryWire[aEntry.vertex][
end] =
true;
287 entryBus[aEntry.vertex][
end] =
true;
290 busLinks.emplace_back( aEntry.item, aOther.item );
294 for(
auto& [key, point] : points )
296 int position[2] = { point.position.x, point.position.y };
297 auto visitor = [&](
size_t aIndex )
301 if( fact.
segment->Contains( point.position ) && point.position != fact.
segment->A
302 && point.position != fact.
segment->B )
304 point.ports.push_back( { aIndex, fact.
id, Kind( fact.
ports.front().kind ), 0 } );
309 tree.Search( position, position, visitor );
310 bool hasBus = std::any_of( point.ports.begin(), point.ports.end(),
311 [](
const PORT& aPort )
313 return aPort.kind == BUS || aPort.kind == ENTRY_BUS;
316 for( PORT& port : point.ports )
318 if( port.kind ==
ENTRY && hasBus )
319 port.kind = BUS_SIDE;
320 else if( vertices[port.vertex]->type ==
SCH_JUNCTION_T && hasBus )
324 for(
size_t first = 0; first < point.ports.size(); ++first )
326 const PORT& a = point.ports[first];
328 for(
size_t second = first + 1; second < point.ports.size(); ++second )
330 const PORT& b = point.ports[second];
332 if( a.vertex == b.vertex )
335 auto pair = std::minmax( a.item, b.item );
337 if( ClosesDangling( *vertices[a.vertex], *vertices[b.vertex] ) )
338 dangling[a.item] &= ~a.bit;
340 if( ClosesDangling( *vertices[b.vertex], *vertices[a.vertex] ) )
341 dangling[b.item] &= ~b.bit;
343 if( a.kind ==
NC || b.kind ==
NC )
345 ncContacts.emplace_back( pair.first, pair.second );
349 entryContact( a, b );
350 entryContact( b, a );
352 if( PROPAGATES[a.kind][b.kind] )
354 sets.
Unite( a.vertex, b.vertex );
355 adjacency.emplace_back( pair.first, pair.second );
364 const std::vector<KIID>& merged = members[
index];
367 for(
size_t first = 0; first < merged.size(); ++first )
369 for(
size_t second = first + 1; second < merged.size(); ++second )
370 adjacency.emplace_back( merged[first], merged[second] );
375 auto found = byId.find( other );
377 if( found != byId.end() && vertices[found->second]->owner == fact.
owner )
381 for(
const KIID& first : merged )
383 for(
const KIID& second : members[found->second] )
385 auto pair = std::minmax( first, second );
386 adjacency.emplace_back( pair.first, pair.second );
394 const auto& wire = entryWire[
index];
395 const auto& bus = entryBus[
index];
398 if( ( wire[0] && bus[1] ) || ( wire[1] && bus[0] ) )
400 else if( wire[0] || bus[0] )
402 else if( wire[1] || bus[1] )
405 dangling[fact.
id] = state;
409 const auto& bus = entryBus[
index];
410 dangling[fact.
id] = ( bus[0] ? 0 : 1 ) | ( bus[1] ? 0 : 2 );
416 if(
auto found = dangling.find( directive ); found != dangling.end() )
421 std::map<size_t, size_t> roots;
422 std::unordered_map<KIID, size_t> islandOf;
429 result.islands.emplace_back();
441 islandOf.emplace( item, root->second );
442 island.
dangling[item] = dangling[item];
446 auto distribute = [&](
auto& aPairs,
auto aMember )
448 SortUnique( aPairs );
450 for(
const auto& pair : aPairs )
452 size_t first = islandOf.at( pair.first );
453 size_t second = islandOf.at( pair.second );
454 (
result.islands[first].*aMember ).push_back( pair );
456 if( first != second )
457 (
result.islands[second].*aMember ).push_back( pair );
466 SortUnique( island.
items );
wxString result
Test unit parsing edge cases and error handling.