35#include <unordered_set>
37#include <fmt/format.h>
49 { 0x00,
"OF" }, { 0x01,
"RF" }, { 0x02,
"R" }, { 0x03,
"S" },
50 { 0x06,
"RT" }, { 0x07,
"ST" }, { 0x08,
"RA" }, { 0x09,
"SA" },
108 if( aVersion <= 0x2021 )
111 if( aVersion == 0x2022 )
179 std::vector<uint8_t> header;
192static void logParsePhase(
const char* aWhat, std::chrono::steady_clock::time_point aStart )
194 static const bool enabled = getenv(
"KICAD_PADS_PROFILE" ) !=
nullptr;
199 const double ms = std::chrono::duration<double, std::milli>( std::chrono::steady_clock::now() - aStart ).count();
201 fputs( fmt::format(
"PROF {:<32} {:>8.1f} ms\n", aWhat, ms ).c_str(), stderr );
207 std::vector<uint8_t> bytes;
212 m_sdb.Load( std::move( bytes ) );
221#define KITIME( call ) \
224 auto _t0 = std::chrono::steady_clock::now(); \
226 logParsePhase( #call, _t0 ); \
277 return p.name.empty();
285 return m_sdb.Section( aIndex );
291 return static_cast<double>( aRawValue );
297 return static_cast<double>( aRawValue );
306 return static_cast<double>( aRawAngle ) /
static_cast<double>(
ANGLE_SCALE );
314 if( !
m_sdb.Coords().Found() )
317 uint32_t headerBase =
m_sdb.Coords().HeaderBase();
319 if( !
m_cursor.InBounds( headerBase, 20 ) )
323 uint32_t maxLayer =
m_sdb.RecordAt( headerBase ).U32( 16 );
325 if( maxLayer >= 1 && maxLayer <= 64 )
326 m_parameters.layer_count =
static_cast<int>( maxLayer );
337 int aNameOff,
const std::string& aRefDes )
const
356 constexpr size_t LOGICAL_ROTATION = 44;
361 if( section->
count == 0 )
365 || ( section->
stride != 96 && section->
stride != 112 ) )
368 const size_t logicalBase = section->
physicalOffset - LOGICAL_ROTATION;
375 const size_t base = logicalBase +
static_cast<size_t>(
index ) * section->
stride;
377 std::string refdes = record.
Str( 44, 16 );
378 const size_t nextBase = logicalBase +
static_cast<size_t>(
index + 1 ) * section->
stride;
379 SDB_RECORD nextRecord =
m_sdb.RecordAt(
static_cast<uint32_t
>( nextBase ) );
383 if( section->
stride == 112 )
386 if( section->
stride == 96 )
394 if( section->
stride == 112 )
396 int32_t clusterId = record.
I32( 108 );
403 m_parts.push_back( std::move( part ) );
424 if( sec68->
count == 0 )
430 static constexpr size_t REC_SIZE = 60;
436 constexpr size_t SEC69_LEAD_IN = 12;
438 if( sec69Rec0 < SEC69_LEAD_IN || sec68->count > ( sec69Rec0 - SEC69_LEAD_IN ) / REC_SIZE )
441 size_t base = sec69Rec0 - SEC69_LEAD_IN -
static_cast<size_t>( sec68->
count ) * REC_SIZE;
443 for( uint32_t i = 0; i < sec68->
count; ++i )
446 std::string
name = rec.
Str( 4, 16 );
450 if( rec.
U32( 0 ) != i + 1 ||
name.empty() )
455 cluster.
id =
static_cast<int>( i ) + 1;
466 if( !entry || !layerSection )
469 const uint32_t expectedRecordSize =
m_version <= 0x2021 ? 52 :
m_version == 0x2022 ? 56 : 64;
472 ||
static_cast<uint64_t
>( entry->
count ) * expectedRecordSize != entry->
totalBytes )
475 if( entry->
count == 0 )
478 const uint32_t logicalRotation =
m_version == 0x2022 ? 20 :
m_version <= 0x2021 ? 24 : 28;
484 uint32_t recSize = entry->
stride;
491 std::string shapeName =
"R";
495 shapeName = shapeIt->second;
503 psl.
shape = shapeName;
504 psl.
sizeA =
static_cast<double>( padWidth );
505 psl.
drill =
static_cast<double>( drill );
511 psl.
plated = drill > 0 && padWidth - drill > OLD_NPTH_CLEARANCE;
515 psl.
plated = drill > 0 && drill < padWidth;
518 bool isFinger = ( shapeName ==
"RF" || shapeName ==
"OF" || shapeName ==
"RC" );
523 if( isFinger && finLength > 0 )
524 psl.
sizeB =
static_cast<double>( finLength );
526 psl.
sizeB =
static_cast<double>( padWidth );
531 const uint32_t poolStart = entry->
physicalOffset - logicalRotation;
532 const uint64_t poolBytes =
static_cast<uint64_t
>( entry->
physicalCount ) * recSize;
534 if( !
m_cursor.InBounds( poolStart, poolBytes ) )
539 std::vector<int32_t> maxPadDiameter( entry->
physicalCount, 0 );
541 const uint32_t layerRecordSize =
m_version <= 0x2021 ? 20 : 24;
542 const uint32_t layerTableHeaderSize =
m_version == 0x2022 ? 64 :
m_version <= 0x2021 ? 20 : 24;
543 uint64_t layerTableStart64 =
static_cast<uint64_t
>( poolStart ) + poolBytes + layerTableHeaderSize;
544 const uint64_t layerTableBytes =
static_cast<uint64_t
>( layerSection->
count ) * layerRecordSize;
546 if( layerTableBytes != layerSection->
totalBytes || layerTableStart64 >
m_data.size()
547 || layerTableBytes >
m_data.size() - layerTableStart64 )
552 const uint32_t layerTableStart =
static_cast<uint32_t
>( layerTableStart64 );
558 uint32_t base = poolStart + i * recSize;
571 if( ( nextRec.
U32( 0 ) & 8U ) != 0 )
579 layers.push_back( defaultLayer );
580 maxPadDiameter[i] =
static_cast<int32_t
>( defaultLayer.
sizeA );
592 bool successorMetadata = endCursor ||
m_version == 0x2027;
593 bool rawLayerSelector = successorMetadata;
596 && ( layerSection->
count == 0 || layerCount > layerSection->
count
598 ? layerStart > layerSection->
count
599 : layerStart >= layerSection->
count || layerCount > layerSection->
count - layerStart ) ) )
604 const uint32_t controllerPhase = endCursor ? 2 % layerSection->
count : 0;
606 for( uint32_t layerIdx = 0; layerIdx < layerCount; ++layerIdx )
610 uint32_t geometryIndex = endCursor ? ( layerStart + layerSection->
count - controllerPhase + layerIdx )
611 % layerSection->
count
612 : layerStart + layerIdx;
619 uint32_t metadataIndex = geometryIndex;
621 if( successorMetadata )
623 metadataIndex = endCursor ? ( geometryIndex + 1 ) % layerSection->
count
626 if( metadataIndex >= layerSection->
count
627 && !
m_cursor.InBounds( layerTableStart + metadataIndex * layerRecordSize, layerRecordSize ) )
629 metadataIndex = geometryIndex;
632 uint32_t geometryBase = layerTableStart + geometryIndex * layerRecordSize;
633 uint32_t metadataBase = layerTableStart + metadataIndex * layerRecordSize;
637 uint8_t selector = metadataRec.
U8( 0 );
638 uint8_t shapeCode = metadataRec.
U8( 1 );
640 maxPadDiameter[i] = std::max( maxPadDiameter[i], geometryRec.
I32( 4 ) );
646 layer.
layer = selector == 0 ? 0
647 : selector == 0xFF ? -1
648 :
static_cast<int>( selector ) + ( rawLayerSelector ? 0 : 1 );
649 layer.
shape = shapeIt->second;
650 layer.
sizeA =
static_cast<double>( geometryRec.
I32( 4 ) );
651 int32_t sizeB = geometryRec.
I32( 8 );
653 if( layer.
shape ==
"RT" || layer.
shape ==
"ST" )
660 layer.
sizeB = sizeB > 0 ?
static_cast<double>( sizeB ) : layer.
sizeA;
663 layers.push_back( std::move( layer ) );
675static void logResolvedBase(
int aSection,
const char* aWhat,
size_t aResolved, uint32_t aPhysical )
677 static const bool enabled = getenv(
"KICAD_PADS_SECBASE" ) !=
nullptr;
682 fprintf( stderr,
"SECBASE %d %s resolved=%zu physical=%u\n", aSection, aWhat, aResolved, aPhysical );
703 static constexpr int REC_SIZE = 112;
704 static constexpr int STACK_START_OFFSET = 44;
705 static constexpr int SENTINEL_OFFSET = 64;
706 static constexpr int START_OFFSET = 68;
707 static constexpr int COUNT_OFFSET = 72;
708 static constexpr int STACK_COUNT_OFFSET = 88;
715 if( sec14->
count == 0 )
720 if( start + 12 >
m_data.size() ||
m_sdb.RecordAt( start ).Str( 0, 12 ) !=
"JMPVIA_AAAAA" )
724 if(
static_cast<uint64_t
>( sec14->
count ) * REC_SIZE >
m_data.size() - start )
730 for( uint32_t k = 0; k < sec14->
count; ++k )
732 uint32_t off = start + k * REC_SIZE;
741 std::string
name = rec.
Str( 0, 41 );
744 int32_t startCursor = rec.
I32( START_OFFSET );
745 int32_t count = rec.
I32( COUNT_OFFSET );
747 if( !
name.empty() && count > 0 && count <= 1000 )
751 if( startCursor >= 0 )
754 int32_t stackCount = rec.
I32( STACK_COUNT_OFFSET );
756 if( stackCount > 0 && stackCount <= 1000 )
760 int32_t stackStart = rec.
I32( STACK_START_OFFSET );
762 if( stackStart >= 0 )
786 if( !sec14 || sec14->
stride == 0 )
789 static constexpr int STACK_START_OFFSET = 44;
790 static constexpr int SENTINEL_OFFSET = 64;
791 static constexpr int START_OFFSET = 68;
792 static constexpr int COUNT_OFFSET = 72;
795 size_t stride = sec14->
stride;
797 std::vector<std::string>
table;
798 std::map<std::string, uint32_t> counts;
799 std::map<std::string, int32_t> starts;
800 std::map<std::string, int32_t> stackCounts;
801 std::map<std::string, int32_t> stackStarts;
804 ||
static_cast<uint64_t
>( sec14->
count ) * stride >
static_cast<uint64_t
>(
m_data.size() - start ) )
811 for(
size_t k = 0; k < sec14->
count; ++k )
813 size_t off = start + k * stride;
818 table.emplace_back();
822 std::string
name = rec.
Str( 0, 40 );
825 if( off + COUNT_OFFSET + 4 <=
m_data.size() )
827 int32_t count = rec.
I32( COUNT_OFFSET );
828 int32_t
cursor = rec.
I32( START_OFFSET );
829 int32_t stackCount = rec.
I32( 88 );
831 if( !
name.empty() && count > 0 && count <= 1000 )
833 counts.emplace(
name,
static_cast<uint32_t
>( count ) );
842 if( stackCount > 0 && stackCount <= 1000 )
844 stackCounts.emplace(
name, stackCount );
852 int32_t stackStart = rec.
I32( STACK_START_OFFSET );
854 if( stackStart >= 0 )
855 stackStarts.emplace(
name, stackStart );
863 if(
table.empty() ||
table[0] !=
"JMPVIA_AAAAA" )
889 if( !sec17 || sec17->
count == 0 )
893 THROW_IO_ERROR(
"Invalid PADS parttype-controller record extent" );
897 if( recSize != 208 && recSize != 224 )
898 THROW_IO_ERROR(
"Unsupported PADS parttype-controller record stride" );
900 const bool isLegacyLayout = recSize == 208;
901 const uint32_t decalOff = isLegacyLayout ? 112 : 96;
911 const uint32_t nameOff = 44;
913 if( !
m_cursor.InBounds( start,
static_cast<size_t>( sec17->
count ) * recSize ) )
922 for( uint32_t k = 0; k < sec17->
count; ++k )
924 uint32_t off = start + k * recSize;
927 std::vector<int32_t> decalIndices;
929 for( uint32_t indexOff = decalOff; !isLegacyLayout && indexOff + 8 <= recSize; indexOff += 8 )
931 int32_t decalIndex = record.
I32( indexOff );
933 if( decalIndex < 0 || record.
I32( indexOff + 4 ) != decalIndex )
936 decalIndices.push_back( decalIndex );
939 if( isLegacyLayout && record.
I32( decalOff ) >= 0 )
940 decalIndices.push_back( record.
I32( decalOff ) );
975 if( section->
count == 0 )
978 const size_t stride =
m_version <= 0x2019 ? 20 : 36;
980 const size_t bytes =
static_cast<size_t>( section->
count ) * stride;
982 if( base >
m_data.size() || bytes >
m_data.size() - base )
985 struct DIRECT_TERMINAL
992 std::vector<DIRECT_TERMINAL> terminals;
993 terminals.reserve( section->
count );
1000 terminals.push_back( { record.
I32( 4 ), record.
I32( 8 ), {} } );
1002 terminals.push_back( { record.
I32( 0 ), record.
I32( 4 ), record.
Str( 20, 4 ) } );
1015 const size_t start =
static_cast<size_t>( startIt->second );
1016 const size_t count = countIt->second;
1018 if( start > terminals.size() || count > terminals.size() - start )
1021 decal.terminals.clear();
1022 decal.terminals.reserve( count );
1026 const DIRECT_TERMINAL& serialized = terminals[start +
index];
1030 terminal.
name = serialized.name.empty() ? std::to_string(
index + 1 ) : serialized.name;
1031 decal.terminals.push_back( std::move( terminal ) );
1037 size_t pairCount = 0;
1045 pairCount = std::max( pairCount,
static_cast<size_t>( start ) +
static_cast<size_t>( countIt->second ) );
1049 const size_t pairBase = base + bytes - (
m_version <= 0x2019 ? 16 : 0 );
1053 if( pairBase >
m_data.size() || pairCount * 8 >
m_data.size() - pairBase )
1056 std::vector<std::pair<int32_t, int32_t>> pairs;
1057 pairs.reserve( pairCount );
1063 pairs.emplace_back( record.
I32( 0 ), record.
I32( 4 ) );
1086 if( decal.terminals.empty() )
1101 int32_t aStart, int32_t aCount )
1103 if( aStart < 0 || aCount <= 0 ||
static_cast<size_t>( aStart ) +
static_cast<size_t>( aCount ) > aPairs.size() )
1106 for( int32_t p = 0; p < aCount; ++p )
1108 const std::pair<int32_t, int32_t>& pair = aPairs[
static_cast<size_t>( aStart ) + p];
1110 if( pair.first < 0 ||
static_cast<size_t>( pair.second ) >=
m_padStackPool.size()
1116 if( pair.first > 0 &&
static_cast<size_t>( pair.first ) > aDecal.
terminals.size() )
1127 return !aName.empty() && aName !=
"___Unassigned_Obstacles_";
1142 std::unordered_set<std::string> existing;
1146 const uint32_t netRecordSize =
m_version == 0x2024 ? 416 : 424;
1147 constexpr uint32_t NET_NAME = 76;
1148 constexpr uint32_t NET_NAME_LEN = 48;
1149 constexpr uint32_t NET_SELF_PTR = 144;
1150 constexpr uint32_t NET_CLASS_PTR = 148;
1157 if( nets->
count == 0 )
1168 for( uint32_t i = 0; i < nets->
count; ++i )
1170 SDB_RECORD rec =
m_sdb.RecordAt( base +
static_cast<size_t>( i ) * netRecordSize );
1171 std::string
name = rec.
Str( NET_NAME, NET_NAME_LEN );
1183 if( uint32_t owner = rec.
U32( NET_CLASS_PTR ) )
1186 if( uint32_t selfPtr = rec.
U32( NET_SELF_PTR ) )
1196 constexpr size_t RECORD_SIZE = 68;
1197 constexpr uint32_t MARKER = 0xFE000000;
1198 constexpr uint32_t FLAG = 0x0000FFFE;
1203 const size_t netRecordSize =
m_version == 0x2024 ? 416 : 424;
1205 if( !connections || !nets )
1208 if( connections->
count == 0 )
1211 if( nets->
stride != netRecordSize )
1214 constexpr size_t RING_PREFIX = 36;
1222 auto connectionU32 = [&]( uint32_t aIndex,
size_t aField )
1225 connections->
physicalOffset - RING_PREFIX +
static_cast<size_t>( aIndex ) * RECORD_SIZE + aField;
1229 size_t runBase =
static_cast<size_t>( connections->
physicalOffset ) - RING_PREFIX;
1230 size_t runCount =
static_cast<size_t>( connections->
count ) + 1;
1235 for( uint32_t recordIndex = 0; recordIndex < runCount; ++recordIndex )
1237 if( ( recordIndex > 0 && ( connectionU32( recordIndex, 20 ) & 0xFFFFFFC0U ) != MARKER )
1238 || ( recordIndex < connections->count && ( connectionU32( recordIndex, 52 ) & 0xFFFFU ) != FLAG ) )
1246 using PIN_ID = std::pair<uint32_t, uint32_t>;
1248 std::map<PIN_ID, size_t> pinIndex;
1249 std::vector<PIN_ID> pins;
1250 std::vector<size_t> parent;
1252 auto intern = [&](
const PIN_ID& aPin )
1254 auto [it, inserted] = pinIndex.emplace( aPin, parent.size() );
1258 pins.push_back( aPin );
1259 parent.push_back( parent.size() );
1265 auto findRoot = [&](
size_t aNode )
1267 while( parent[aNode] != aNode )
1269 parent[aNode] = parent[parent[aNode]];
1270 aNode = parent[aNode];
1276 auto join = [&](
const PIN_ID& aPin,
const PIN_ID& bPin )
1278 const size_t indexA = intern( aPin );
1279 const size_t indexB = intern( bPin );
1280 const size_t rootA = findRoot( indexA );
1281 const size_t rootB = findRoot( indexB );
1283 if( rootA != rootB )
1284 parent[rootA] = rootB;
1287 for( uint32_t recordIndex = 0; recordIndex + 1 < runCount; ++recordIndex )
1289 join( { connectionU32( recordIndex, 60 ), connectionU32( recordIndex + 1, 0 ) },
1290 { connectionU32( recordIndex, 64 ), connectionU32( recordIndex + 1, 4 ) } );
1293 std::map<size_t, size_t> componentNet;
1300 const size_t root = findRoot( intern( {
anchor.placementObject,
anchor.terminalOrdinal } ) );
1301 auto [it, inserted] = componentNet.emplace( root,
anchor.netIndex );
1303 if( !inserted && it->second !=
anchor.netIndex )
1307 const bool existingIsAlias =
m_nets[it->second].name.rfind(
"$$$", 0 ) == 0;
1308 const bool incomingIsAlias =
m_nets[
anchor.netIndex].name.rfind(
"$$$", 0 ) == 0;
1310 if( existingIsAlias && incomingIsAlias )
1312 else if( existingIsAlias != incomingIsAlias )
1313 it->second = incomingIsAlias ? it->second :
anchor.netIndex;
1322 auto netIt = componentNet.find( findRoot(
index ) );
1324 if( netIt == componentNet.end() )
1327 const auto [placementObject, terminalOrdinal] = pins[
index];
1333 m_nets[netIt->second].component_refs.push_back(
m_parts[partIt->second].name );
1340 using PIN_KEY = std::pair<std::string, std::string>;
1342 std::map<PIN_KEY, size_t> pinOwners;
1357 if( decalIt ==
m_decals.end() ||
anchor.terminalOrdinal > decalIt->second.terminals.size() )
1360 const std::string& terminalName = decalIt->second.terminals[
anchor.terminalOrdinal - 1].name;
1362 if( terminalName.empty() )
1365 PIN_KEY key = std::make_pair( part.
name, terminalName );
1366 auto [owner, inserted] = pinOwners.emplace( key,
anchor.netIndex );
1368 if( inserted || owner->second ==
anchor.netIndex )
1372 const bool existingIsAlias =
m_nets[owner->second].name.rfind(
"$$$", 0 ) == 0;
1373 const bool incomingIsAlias =
m_nets[
anchor.netIndex].name.rfind(
"$$$", 0 ) == 0;
1375 if( existingIsAlias && !incomingIsAlias )
1376 owner->second =
anchor.netIndex;
1377 else if( !existingIsAlias && incomingIsAlias )
1379 else if( existingIsAlias && incomingIsAlias )
1382 THROW_IO_ERROR(
"Conflicting PADS net ownership for pin '" + part.
name +
"." + terminalName +
"'" );
1391 for(
const auto& [key, netIndex] : pinOwners )
1394 pin.ref_des = key.first;
1395 pin.pin_name = key.second;
1396 m_nets[netIndex].pins.push_back( std::move(
pin ) );
1403 std::unordered_set<std::string> existing;
1404 std::unordered_map<std::string, size_t> netIndexByName;
1414 for(
size_t i = 0; i < netOffsets.size(); ++i )
1416 SDB_RECORD rec =
m_sdb.RecordAt(
static_cast<uint32_t
>( netOffsets[i] ) );
1417 std::string
name = rec.
Str( 12, 48 );
1424 if( existing.insert(
name ).second )
1429 netIndexByName.emplace(
name,
m_nets.size() - 1 );
1434 if( uint32_t owner = rec.
U32( 84 ) )
1444 constexpr uint32_t NET_RECORD_SIZE = 144;
1446 std::vector<size_t> offsets;
1449 if( !nets || nets->
stride != NET_RECORD_SIZE )
1452 const uint64_t base =
static_cast<uint64_t
>( nets->
physicalOffset ) + 20;
1454 if( base +
static_cast<uint64_t
>( nets->
count ) * NET_RECORD_SIZE >
m_data.size() )
1457 for(
size_t i = 0; i < nets->
count; ++i )
1458 offsets.push_back( base + i * NET_RECORD_SIZE );
1466 constexpr size_t RECORD_SIZE = 68;
1467 constexpr uint32_t ENDPOINT_FLAG = 0x0000FFFE;
1468 constexpr uint32_t MARKER = 0xFE000000;
1469 constexpr uint32_t NET_RECORD_SIZE = 144;
1470 constexpr uint32_t NET_FIRST = 8;
1471 constexpr uint32_t NET_NAME = 12;
1472 constexpr uint32_t NET_COUNT = 92;
1477 if( !connections || !nets )
1478 THROW_IO_ERROR(
"Missing PADS legacy net-connection controllers" );
1480 if( connections->
count == 0 )
1483 if( nets->
stride != NET_RECORD_SIZE )
1486 const uint64_t base =
static_cast<uint64_t
>( connections->
physicalOffset ) + 16;
1488 if( base +
static_cast<uint64_t
>( connections->
count ) * RECORD_SIZE >
m_data.size() )
1493 const size_t total = connections->
count;
1497 std::map<std::pair<uint32_t, uint32_t>,
size_t> pinIndex;
1498 std::vector<size_t> parent;
1500 auto intern = [&]( uint32_t aObject, uint32_t aOrdinal )
1502 auto [it, inserted] = pinIndex.emplace( std::make_pair( aObject, aOrdinal ), parent.size() );
1505 parent.push_back( parent.size() );
1510 auto findRoot = [&](
size_t aNode )
1512 while( parent[aNode] != aNode )
1514 parent[aNode] = parent[parent[aNode]];
1515 aNode = parent[aNode];
1530 std::vector<CONNECTION> stream;
1531 stream.reserve( total );
1533 for(
size_t i = 0; i < total; ++i )
1535 SDB_RECORD rec =
m_sdb.RecordAt(
static_cast<uint32_t
>( base + i * RECORD_SIZE ) );
1537 if( ( rec.
U32( 0 ) & 0xFFFFU ) != ENDPOINT_FLAG || ( rec.
U32( 36 ) & 0xFFFFFFC0U ) != MARKER )
1539 THROW_IO_ERROR(
"Invalid PADS legacy net-connection ring framing" );
1542 CONNECTION conn{ rec.
U32( 8 ), rec.
U32( 16 ), rec.
U32( 12 ), rec.
U32( 20 ), 0 };
1544 conn.pinA = intern( conn.objectA, conn.ordinalA );
1545 size_t pinB = intern( conn.objectB, conn.ordinalB );
1547 size_t rootA = findRoot( conn.pinA );
1548 size_t rootB = findRoot( pinB );
1550 if( rootA != rootB )
1551 parent[rootA] = rootB;
1553 stream.push_back( conn );
1556 std::map<size_t, size_t> componentSize;
1558 for(
size_t i = 0; i < stream.size(); ++i )
1560 size_t root = findRoot( stream[i].
pinA );
1562 ++componentSize[root];
1565 auto netRecordName = [&](
size_t aOffset, std::string& aName, uint32_t& aCount, uint32_t& aFirst,
1566 uint32_t& aAnchorObject, uint32_t& aAnchorOrdinal )
1568 if( !
m_cursor.InBounds( aOffset, NET_RECORD_SIZE ) )
1573 aName = rec.
Str( NET_NAME, 48 );
1574 aCount = rec.
U32( NET_COUNT );
1575 aFirst = rec.
U32( NET_FIRST );
1576 aAnchorObject = rec.
U32( 0 );
1577 aAnchorOrdinal = rec.
U32( 4 );
1579 return !aName.empty() && aCount > 0 && aCount <= connections->
count;
1582 std::map<std::string, size_t> netIndexByName;
1584 for(
size_t i = 0; i <
m_nets.size(); ++i )
1585 netIndexByName.emplace(
m_nets[i].name, i );
1587 std::set<size_t> assignedComponents;
1593 uint32_t edgeIndex = 0;
1594 uint32_t anchorObject = 0;
1595 uint32_t anchorOrdinal = 0;
1597 if( !netRecordName( offset,
name, count, edgeIndex, anchorObject, anchorOrdinal ) || !
isValidNetName(
name ) )
1600 if( edgeIndex >= stream.size() )
1603 auto anchor = pinIndex.find( { anchorObject, anchorOrdinal } );
1605 if(
anchor == pinIndex.end() )
1608 const size_t root = findRoot(
anchor->second );
1610 if( findRoot( stream[edgeIndex].
pinA ) != root )
1613 if( count != componentSize[root] )
1616 if( !assignedComponents.insert( root ).second )
1617 THROW_IO_ERROR(
"Conflicting PADS legacy net component owners" );
1619 auto netIt = netIndexByName.find(
name );
1621 if( netIt == netIndexByName.end() )
1624 for(
const CONNECTION& conn : stream )
1626 if( findRoot( conn.pinA ) != root )
1642 std::set<uint32_t> ownerSet;
1645 ownerSet.insert( owner );
1647 std::vector<uint32_t> owners( ownerSet.begin(), ownerSet.end() );
1648 std::map<uint32_t, size_t> ownerOrdinal;
1650 for(
size_t k = 0; k < owners.size(); ++k )
1651 ownerOrdinal[owners[k]] = k;
1658 const size_t NAME_STRIDE =
m_version <= 0x2022 ? 28 : 280;
1659 constexpr size_t NAME_OFFSET = 8;
1660 const size_t NAME_LEN =
m_version <= 0x2022 ? 8 : 48;
1664 ||
static_cast<uint64_t
>( names->
physicalOffset ) + owners.size() * NAME_STRIDE >
m_data.size() )
1672 for(
size_t k = 0; k < owners.size(); ++k )
1676 if(
name.empty() || !std::isalnum(
static_cast<unsigned char>(
name[0] ) ) )
1677 name =
"PADS_NetClass_" + std::to_string( k + 1 );
1684 auto it = ownerOrdinal.find( owner );
1686 if( it != ownerOrdinal.end() )
1695 std::sort( nc.nets.begin(), nc.nets.end() );
1696 std::sort( nc.ruleLayers.begin(), nc.ruleLayers.end() );
1697 nc.ruleLayers.erase( std::unique( nc.ruleLayers.begin(), nc.ruleLayers.end() ), nc.ruleLayers.end() );
1704 constexpr size_t RECORD_SIZE = 28;
1705 constexpr size_t RULE_KIND = 0;
1706 constexpr size_t RULE_DETAIL_HANDLE = 4;
1707 constexpr size_t SCOPE_TYPE = 8;
1708 constexpr uint32_t NET_CLASS_SCOPE = 0x42;
1709 constexpr size_t SCOPE_REFERENCE = 12;
1710 constexpr size_t LAYER = 24;
1712 std::vector<NET_CLASS_RULE_EDGE> edges;
1715 if( !relationships || relationships->
physicalBytes != relationships->
count * RECORD_SIZE )
1718 for( uint32_t i = 0; i < relationships->
count; ++i )
1720 size_t off = relationships->
physicalOffset +
static_cast<size_t>( i ) * RECORD_SIZE;
1723 if( rec.
U32( SCOPE_TYPE ) != NET_CLASS_SCOPE )
1726 uint32_t owner = rec.
U32( SCOPE_REFERENCE );
1728 if( !aOwnerSet.count( owner ) )
1731 edges.push_back( { owner, rec.
U32( RULE_KIND ), rec.
U32( RULE_DETAIL_HANDLE ),
1732 static_cast<int>( rec.
U32(
LAYER ) ), off } );
1740 const std::map<uint32_t, size_t>& aOwnerOrdinal )
1742 constexpr uint32_t CLEARANCE_RULE_KIND = 0x29;
1746 if( e.ruleKind != CLEARANCE_RULE_KIND )
1749 auto owner = aOwnerOrdinal.find( e.owner );
1751 if( owner != aOwnerOrdinal.end() )
1752 m_netClasses[owner->second].ruleLayers.push_back( e.layer );
1758 if( !relationships || !values || values->
physicalCount == 0 )
1761 constexpr size_t RELATIONSHIP_SIZE = 28;
1762 uint32_t firstClearanceHandle = UINT32_MAX;
1764 for( uint32_t i = 0; i < relationships->
count; ++i )
1768 if( rec.
U32( 0 ) == CLEARANCE_RULE_KIND )
1769 firstClearanceHandle = std::min( firstClearanceHandle, rec.
U32( 4 ) );
1772 if( firstClearanceHandle == UINT32_MAX )
1775 const uint32_t valueStride =
m_version == 0x2017 ? 180 : 188;
1779 if( edge.ruleKind != CLEARANCE_RULE_KIND || edge.layer != 0 || edge.rulePtr < firstClearanceHandle )
1782 uint32_t
delta = edge.rulePtr - firstClearanceHandle;
1784 if(
delta % valueStride != 0 )
1792 auto owner = aOwnerOrdinal.find( edge.owner );
1794 if( owner == aOwnerOrdinal.end() )
1812 constexpr size_t OBJECT_SIZE = 864;
1813 constexpr double F64_INHERIT = -1.0;
1814 constexpr int32_t I32_INHERIT = -1;
1817 constexpr size_t NET_A_HANDLE = 12;
1818 constexpr size_t NET_B_HANDLE = 16;
1819 constexpr size_t GAP_INHERIT = 40;
1820 constexpr size_t GAP_OVERRIDE = 56;
1821 constexpr size_t WIDTH_INHERIT = 592;
1822 constexpr size_t WIDTH_OVERRIDE = 600;
1837 if(
static_cast<uint64_t
>( base ) +
static_cast<uint64_t
>( records->
physicalCount ) * OBJECT_SIZE >
m_data.size() )
1840 std::set<std::pair<std::string, std::string>> seen;
1844 size_t objStart = base +
static_cast<size_t>( i ) * OBJECT_SIZE;
1856 if( !seen.insert( { nameA, nameB } ).second )
1859 double gapOverride = obj.F64( GAP_OVERRIDE );
1860 double gap = ( gapOverride != F64_INHERIT ) ? gapOverride : obj.F64( GAP_INHERIT );
1861 int32_t widthOverride = obj.I32( WIDTH_OVERRIDE );
1862 double width = ( widthOverride != I32_INHERIT ) ?
static_cast<double>( widthOverride )
1863 :
static_cast<double>( obj.I32( WIDTH_INHERIT ) );
1866 dp.
name = nameA +
"_" + nameB;
1869 dp.
gap = ( gap != F64_INHERIT ) ? gap : 0.0;
1870 dp.
width = ( width !=
static_cast<double>( I32_INHERIT ) ) ? width : 0.0;
1882 constexpr size_t GEOMETRY_BYTES = 36;
1883 const size_t recordSize = s8 ? s8->
stride : 0;
1884 const size_t ringRotation = recordSize >= GEOMETRY_BYTES ? recordSize - GEOMETRY_BYTES : 0;
1892 const bool validStringPool =
1895 if( ( recordSize != 64 && recordSize != 72 ) || s8->
physicalOffset < ringRotation || !validStringPool
1912 parseFreeText( *s8, recordBase, recordSize, ringRotation, poolBase, poolHi );
1917 size_t aRingRotation )
1919 auto fieldAttribute = [&]( uint32_t aIndex )
1921 SDB_RECORD record =
m_sdb.RecordAt( aRecordBase +
static_cast<size_t>( aIndex ) * aRecordSize );
1923 attribute.
height = record.
I32( aRingRotation );
1924 attribute.
width = record.
I32( aRingRotation + 4 );
1925 attribute.
x = record.
I32( aRingRotation + 8 );
1926 attribute.
y = record.
I32( aRingRotation + 12 );
1928 attribute.
mirrored = record.
I32( aRingRotation + 20 ) != 0;
1934 if( fieldStart < 0 )
1937 if( partIndex >=
m_parts.size() ||
static_cast<uint32_t
>( fieldStart ) >= aText.
physicalCount )
1938 THROW_IO_ERROR(
"Invalid PADS placement field-presentation link" );
1940 std::vector<ATTRIBUTE> attributes;
1941 std::set<uint32_t> visited;
1942 uint32_t fieldIndex =
static_cast<uint32_t
>( fieldStart );
1946 if( !visited.insert( fieldIndex ).second )
1952 ATTRIBUTE attribute = fieldAttribute( fieldIndex );
1953 SDB_RECORD metadata =
m_sdb.RecordAt( aRecordBase +
static_cast<size_t>( fieldIndex + 1 ) * aRecordSize );
1954 uint32_t presentation = metadata.
U32( 24 );
1955 uint8_t fieldKind =
static_cast<uint8_t
>( presentation >> 16 );
1956 attribute.
visible = ( fieldKind & 0x20 ) != 0;
1958 if( ( presentation & 0x11000000U ) == 0x11000000U )
1960 attribute.
hjust =
"CENTER";
1961 attribute.
vjust =
"CENTER";
1965 attribute.
hjust =
"LEFT";
1966 attribute.
vjust = ( presentation & 0x20000000U ) ?
"UP" :
"DOWN";
1969 if( ( fieldKind & 0x1FU ) == 0x03 )
1970 attribute.
name =
"Part Type";
1971 else if( ( fieldKind & 0x1FU ) == 0x02 )
1972 attribute.
name =
"Ref.Des.";
1974 if( !attribute.
name.empty() )
1975 attributes.push_back( std::move( attribute ) );
1977 uint32_t association = metadata.
U32( 12 );
1979 uint8_t associationKind =
static_cast<uint8_t
>( association >> 24 );
1981 if( associationKind == 0x16 )
1983 if( ( association & 0x00FFFFFFU ) != partIndex )
1989 if( associationKind != 0x08 )
1990 THROW_IO_ERROR(
"Invalid PADS placement field-list terminator" );
1992 fieldIndex = association & 0x00FFFFFFU;
1995 m_parts[partIndex].attributes = std::move( attributes );
2001 size_t aRingRotation,
size_t aPoolBase,
size_t aPoolHi )
2003 auto cStringStartAt = [
this, aPoolHi](
size_t aAbs ) ->
bool
2005 if( aAbs >= aPoolHi )
2010 while( e < aPoolHi &&
m_data[e] != 0 )
2024 SDB_RECORD meta =
m_sdb.RecordAt( aRecordBase +
static_cast<size_t>(
index + 1 ) * aRecordSize );
2026 if( meta.
U16( 4 ) != 0xFFFE || meta.
U32( 12 ) != 0 || ( aRecordSize == 72 && meta.
U32( 28 ) != 0x49000000 ) )
2029 uint32_t layerWord = meta.
U32( 24 );
2031 if( ( layerWord >> 16 ) != 0x0020 || geom.
I32( aRingRotation ) <= 0 || geom.
I32( aRingRotation + 4 ) <= 0 )
2034 size_t soff = aPoolBase + meta.
U32( 8 );
2036 if( soff < aPoolBase || soff >= aPoolHi || ( soff != aPoolBase &&
m_data[soff - 1] != 0 )
2037 || !cStringStartAt( soff ) )
2042 std::string content =
m_sdb.RecordAt( soff ).Str( 0, aPoolHi - soff );
2044 if( content.empty() )
2047 int32_t height = geom.
I32( aRingRotation );
2048 int32_t linewidth = geom.
I32( aRingRotation + 4 );
2049 int32_t x = geom.
I32( aRingRotation + 8 );
2050 int32_t y = geom.
I32( aRingRotation + 12 );
2051 int32_t angleRaw = geom.
I32( aRingRotation + 16 );
2054 text.content = content;
2057 text.height =
static_cast<double>( height );
2058 text.width =
static_cast<double>( linewidth );
2059 text.layer =
static_cast<int>( layerWord & 0xFF );
2094 return aCur.
U8At( aTypeByte ) ==
VIA_TYPE && aCur.
U8At( aTypeByte + 4 ) == 0x17
2095 && ( aCur.
U8At( aTypeByte + 5 ) & 0x02 ) != 0;
2101 constexpr uint32_t JUNCTION_TAG = 0x3C000000;
2102 constexpr uint32_t ROUTE_CHAIN_TAG = 0x18000000;
2103 constexpr uint32_t TAG_MASK = 0xFF000000;
2104 constexpr uint32_t INDEX_MASK = 0x00FFFFFF;
2111 if( !relationships || !junctions || !nets || !routeChains )
2114 std::map<uint32_t, size_t>
result;
2115 std::vector<std::pair<uint32_t, size_t>> junctionSignals;
2118 size_t signalIndex = 0;
2120 auto readU32 = [&]()
2132 if( signalIndex >= nets->
count )
2133 THROW_IO_ERROR(
"Invalid PADS route-relationship signal count" );
2135 for(
int direction = 0; direction < 2; ++direction )
2137 uint32_t numRelationships = readU32();
2139 for( uint32_t relationship = 0; relationship < numRelationships; ++relationship )
2141 uint32_t objectId = readU32();
2142 uint32_t numValues = readU32();
2147 uint32_t expectedObjectTag = direction == 0 ? JUNCTION_TAG : ROUTE_CHAIN_TAG;
2148 uint32_t objectIndex = objectId & INDEX_MASK;
2149 uint32_t objectLimit = direction == 0 ? junctions->
count : routeChains->
count;
2151 if( ( objectId & TAG_MASK ) != expectedObjectTag || objectIndex >= objectLimit )
2152 THROW_IO_ERROR(
"Invalid PADS route-relationship object identifier" );
2154 if( direction == 0 )
2156 junctionSignals.emplace_back( objectIndex, signalIndex );
2159 uint32_t expectedValueTag = direction == 0 ? ROUTE_CHAIN_TAG : JUNCTION_TAG;
2160 uint32_t valueLimit = direction == 0 ? routeChains->
count : junctions->
count;
2162 for( uint32_t valueIndex = 0; valueIndex < numValues; ++valueIndex )
2164 uint32_t value = readU32();
2166 if( ( value & TAG_MASK ) != expectedValueTag || ( value & INDEX_MASK ) >= valueLimit )
2167 THROW_IO_ERROR(
"Invalid PADS route-relationship member identifier" );
2178 for(
const auto& [junctionIndex, sourceSignalIndex] : junctionSignals )
2180 std::optional<size_t> netIndex;
2182 if( signalIndex == nets->
count )
2187 netIndex = netIt->second;
2191 netIndex = sourceSignalIndex;
2197 auto [it, inserted] =
result.emplace( junctionIndex, *netIndex );
2199 if( !inserted && it->second != *netIndex )
2200 THROW_IO_ERROR(
"Conflicting PADS route-junction relationship" );
2217 if( entry60->
count == 0 )
2226 for(
auto& [netName, route] : routes )
2228 if( route.tracks.empty() && route.vias.empty() )
2231 m_routes.push_back( std::move( route ) );
2245 if( entry60->
stride == 0 )
2248 uint32_t stride = entry60->
stride;
2250 if( stride < 31 || entry60->physicalCount != entry60->
count )
2255 std::vector<size_t> typeBytes;
2256 const size_t ringRotation = stride - 31;
2263 for( uint32_t rec = 0; rec < entry60->
physicalCount; ++rec )
2264 typeBytes.push_back( base +
static_cast<size_t>( rec ) * stride + stride - 4 );
2270 if( typeBytes.empty() )
2275 for(
size_t junction = 0; junction < typeBytes.size(); ++junction )
2277 auto netIt = junctionNets.find(
static_cast<uint32_t
>( junction ) );
2279 if( netIt == junctionNets.end() )
2282 if( netIt->second >=
m_nets.size() || typeBytes[junction] < 27 )
2285 const size_t typeByte = typeBytes[junction];
2286 uint32_t objectHandle =
m_cursor.U32At( typeByte - 19 );
2288 if( objectHandle != 0 )
2292 std::vector<VIA_LOCATION> viaLocations;
2294 for(
size_t junction = 0; junction < typeBytes.size(); ++junction )
2296 size_t typeByte = typeBytes[junction];
2297 uint8_t type =
m_cursor.U8At( typeByte );
2303 if( typeByte < 27 || !
m_cursor.InBounds( typeByte - 27, 8 ) )
2306 int32_t vx =
m_cursor.I32At( typeByte - 27 );
2307 int32_t vy =
m_cursor.I32At( typeByte - 23 );
2309 std::string netName;
2310 uint32_t netIdx =
m_cursor.U16At( typeByte + 1 );
2312 auto relationshipIt = junctionNets.find(
static_cast<uint32_t
>( junction ) );
2314 if( relationshipIt != junctionNets.end() && relationshipIt->second <
m_nets.size() )
2316 netName =
m_nets[relationshipIt->second].name;
2320 netName = it->second;
2326 via.netName = std::move( netName );
2328 via.relationshipNet = relationshipIt != junctionNets.end();
2329 viaLocations.push_back( std::move(
via ) );
2334 std::map<std::pair<int32_t, int32_t>,
VIA_LOCATION> uniqueVias;
2338 auto [it, inserted] = uniqueVias.try_emplace( std::make_pair(
via.x,
via.y ) );
2342 it->second = std::move(
via );
2351 if(
via.relationshipNet )
2354 THROW_IO_ERROR(
"Conflicting co-located PADS via relationships" );
2368 std::vector<VIA_LOCATION> deduplicated;
2369 deduplicated.reserve( uniqueVias.size() );
2371 for(
auto& [coordinate,
via] : uniqueVias )
2372 deduplicated.push_back( std::move(
via ) );
2374 return deduplicated;
2380 std::map<std::string, ROUTE> routes;
2384 ROUTE& route = routes[
via.netName];
2399 auto stackIt = decalIt->second.pad_stacks.find( 1 );
2401 if( stackIt == decalIt->second.pad_stacks.end() )
2402 stackIt = decalIt->second.pad_stacks.find( 0 );
2404 if( stackIt != decalIt->second.pad_stacks.end() && !stackIt->second.empty() )
2406 viaDef.
stack = stackIt->second;
2408 auto spanIt = decalIt->second.drill_spans.find( stackIt->first );
2410 if( spanIt != decalIt->second.drill_spans.end() && spanIt->second.first > 0
2411 && spanIt->second.second > 0 )
2416 int spanStart = std::min( spanIt->second.first, spanIt->second.second );
2417 int spanEnd = std::max( spanIt->second.first, spanIt->second.second );
2429 if( viaDef.
stack.empty() )
2433 : std::string(
"<out-of-range>" );
2435 wxString::Format(
"Invalid PADS via padstack reference %d (%s)",
via.viaIndex,
name.c_str() ) );
2438 route.
vias.push_back( std::move( viaDef ) );
2451 if( !routeObjects || !routeLayers || !routeCells )
2454 if( routeLayers->
count == 0 ||
static_cast<uint64_t
>( routeLayers->
count ) * 2 != routeLayers->
totalBytes )
2459 if(
static_cast<uint64_t
>( routeCells->
count ) * 12 != routeCells->
totalBytes )
2462 if( routeObjects->
count == 0 )
2470 if( ( routeObjects->
stride != 36 && routeObjects->
stride != 48 )
2471 ||
static_cast<uint64_t
>( routeObjects->
count ) * routeObjects->
stride != routeObjects->
totalBytes )
2480 uint32_t cellCount = 0;
2485 std::vector<int> serializedLayerOrder;
2486 bool legacyObjects = routeObjects->
stride == 36;
2487 size_t objectStride = legacyObjects ? 36 : 48;
2488 size_t widthOffset = legacyObjects ? 8 : 20;
2489 size_t cellCountOffset = legacyObjects ? 24 : 36;
2491 auto ringU32 = [&](
size_t aRingStart,
size_t aOffset )
2495 for(
size_t byte = 0;
byte < 4; ++byte )
2497 size_t physical = aRingStart + ( aOffset + byte ) % objectBytes;
2498 value |=
static_cast<uint32_t
>(
m_cursor.U8At( physical ) ) << (
byte * 8 );
2504 std::vector<bool> seenLayers( routeLayers->
physicalCount,
false );
2507 for( uint32_t layer = 0; layer < routeLayers->
physicalCount; ++layer )
2509 uint16_t serializedLayer =
m_cursor.U16At( layerTable +
static_cast<size_t>( layer ) * 2 );
2511 if( serializedLayer >= routeLayers->
physicalCount || seenLayers[serializedLayer] )
2514 seenLayers[serializedLayer] =
true;
2515 serializedLayerOrder.push_back( serializedLayer );
2518 if( layerTable == 0 )
2522 std::vector<ROUTE_OBJECT> objects;
2526 size_t base = ( 32 +
static_cast<size_t>( i ) * objectStride ) % objectBytes;
2527 ROUTE_OBJECT object;
2529 object.width =
static_cast<int32_t
>(
ringU32( ringStart, base + widthOffset ) ) * 4;
2530 object.style =
ringU32( ringStart, base + ( legacyObjects ? 20 : 32 ) );
2531 object.cellCount =
ringU32( ringStart, base + cellCountOffset );
2532 objects.push_back(
object );
2543 std::vector<ROUTE_CELL> cells;
2545 for( uint32_t i = 0; i < routeCells->
count; ++i )
2547 size_t base = cellStart +
static_cast<size_t>( i ) * 12;
2548 int32_t first =
m_cursor.I32At( base );
2549 int32_t second =
m_cursor.I32At( base + 4 );
2550 int32_t third =
m_cursor.I32At( base + 8 );
2552 cells.push_back( { first, second, third } );
2557 struct DECODED_TRACK
2560 std::string netName;
2563 std::vector<DECODED_TRACK> decodedPieces;
2569 const std::vector<int>& objectLayers = nodes.
layers;
2570 const std::vector<uint32_t>& objectHandles = nodes.
handles;
2571 const std::map<uint32_t, std::set<size_t>>& routeNodeNets = nodes.
handleNets;
2575 size_t objectIndex = 0;
2576 size_t cellStart = 0;
2579 std::vector<ROUTE_CHUNK> chunks;
2584 for(
size_t sequence = 0; sequence < objects.size(); ++sequence )
2586 size_t match = ( sequence + objects.size() - 1 ) % objects.size();
2588 if(
cursor + objects[match].cellCount > cells.size() )
2591 const ROUTE_OBJECT&
object = objects[match];
2596 if(
object.width > 0 && (
object.style & 0x1100 ) == 0 )
2597 chunks.push_back( { match,
cursor } );
2599 cursor +=
object.cellCount;
2602 if(
cursor != cells.size() )
2605 for(
const ROUTE_CHUNK& chunk : chunks )
2607 const ROUTE_OBJECT&
object = objects[chunk.objectIndex];
2610 track.
layer = objectLayers[chunk.objectIndex];
2611 track.
width =
object.width;
2618 if( routingDirection < 0 || routingDirection > 4 )
2621 bool fixedIsX = routingDirection == 1;
2623 for(
size_t j = 0; j <
object.cellCount; ++j )
2625 const ROUTE_CELL& cell = cells[chunk.cellStart + j];
2626 double x1 = fixedIsX ? cell.x1 : cell.y;
2627 double y1 = fixedIsX ? cell.y : cell.x1;
2628 double x2 = fixedIsX ? cell.x2 : cell.y;
2629 double y2 = fixedIsX ? cell.y : cell.x2;
2631 if( track.
points.empty() || track.
points.back().x != x1 || track.
points.back().y != y1 )
2633 track.
points.emplace_back( x1, y1 );
2636 if( x1 != x2 || y1 != y2 )
2637 track.
points.emplace_back( x2, y2 );
2640 if( track.
points.size() < 2 )
2643 auto handleIt = routeNodeNets.find( objectHandles[chunk.objectIndex] );
2644 std::optional<size_t> netIndex;
2646 if( handleIt == routeNodeNets.end() )
2649 const std::set<size_t>& handleNets = handleIt->second;
2651 if( handleNets.size() > 1 )
2652 THROW_IO_ERROR( wxString::Format(
"Conflicting PADS route-object handle nets "
2653 "(object %zu, handle 0x%08X, nets %zu)",
2654 chunk.objectIndex, objectHandles[chunk.objectIndex],
2655 handleNets.size() ) );
2657 if( handleNets.size() == 1 )
2658 netIndex = *handleNets.begin();
2660 if( !netIndex || *netIndex >=
m_nets.size() )
2664 THROW_IO_ERROR( fmt::format(
"Missing PADS route-object net relationship "
2665 "(object {}, handle 0x{:08X}, layer {}, cells {}, "
2666 "first {:.0f},{:.0f}, last {:.0f},{:.0f})",
2667 chunk.objectIndex, objectHandles[chunk.objectIndex], track.
layer,
2668 object.cellCount, first.
x, first.
y, last.
x, last.
y ) );
2671 decodedPieces.push_back( { std::move( track ),
m_nets[*netIndex].name } );
2674 for( DECODED_TRACK& decoded : decodedPieces )
2676 ROUTE& route = aRoutes[decoded.netName];
2678 route.
tracks.push_back( std::move( decoded.track ) );
2685 const std::vector<int>& aSerializedLayerOrder )
2688 nodes.
layers.assign( aObjectCount, 0 );
2689 nodes.
handles.assign( aObjectCount, 0 );
2691 auto padsLayerForSerializedIndex = [&](
size_t aIndex )
2693 return aIndex < aSerializedLayerOrder.size() ? aSerializedLayerOrder[aIndex] + 1
2694 :
static_cast<int>( aIndex ) + 1;
2703 if( !routeController || !allocatorDescriptors || !layerObjectCounts || !layerObjectHandles || !routeNodes
2710 std::array<uint16_t, 4> allocatorPageCounts;
2715 size_t nodePageStart =
2716 static_cast<size_t>( allocatorPageCounts[0] ) + allocatorPageCounts[1] + allocatorPageCounts[2];
2717 size_t nodePageCount = allocatorPageCounts[3];
2719 if( nodePageCount == 0 || nodePageStart + nodePageCount > allocatorDescriptors->
physicalCount )
2725 uint32_t liveCount = 0;
2726 size_t firstOrdinal = 0;
2729 std::vector<NODE_PAGE> nodePages;
2730 size_t allocatedNodes = 0;
2732 for(
size_t page = 0; page < nodePageCount; ++page )
2734 size_t descriptor = allocatorDescriptors->
physicalOffset + ( nodePageStart + page ) * 12;
2737 if( page + 1 < nodePageCount )
2738 liveCount =
m_cursor.U32At( descriptor + 20 );
2739 else if( allocatedNodes <= routeNodes->physicalCount )
2744 nodePages.push_back( {
m_cursor.U32At( descriptor ), liveCount, allocatedNodes } );
2745 allocatedNodes += liveCount;
2751 std::vector<uint32_t> routeNodeHandles;
2754 for(
const NODE_PAGE& page : nodePages )
2757 routeNodeHandles.push_back( page.base +
index * 56 );
2760 std::map<uint32_t, size_t> routeNodeOrdinals;
2762 for(
size_t ordinal = 0; ordinal < routeNodeHandles.size(); ++ordinal )
2763 routeNodeOrdinals.emplace( routeNodeHandles[ordinal], ordinal );
2765 std::vector<std::vector<size_t>> routeNodeLinks( routeNodeHandles.size() );
2767 for(
size_t ordinal = 0; ordinal < routeNodeHandles.size(); ++ordinal )
2771 for( uint32_t linkedHandle : {
m_cursor.U32At( nodeOffset ),
m_cursor.U32At( nodeOffset + 4 ) } )
2773 auto linkedIt = routeNodeOrdinals.find( linkedHandle );
2775 if( linkedIt == routeNodeOrdinals.end() )
2778 routeNodeLinks[linkedIt->second].push_back( ordinal );
2786 std::map<uint32_t, std::set<size_t>>& routeNodeNets = nodes.
handleNets;
2787 std::vector<uint32_t> visitedStamp( routeNodeHandles.size(), UINT32_MAX );
2788 std::vector<size_t> frontier;
2789 std::vector<size_t>
next;
2791 for(
size_t root = 0; root < routeNodeHandles.size(); ++root )
2793 std::set<size_t> componentNets;
2795 visitedStamp[root] =
static_cast<uint32_t
>( root );
2796 frontier.assign( 1, root );
2798 while( !frontier.empty() && componentNets.empty() )
2802 for(
size_t ordinal : frontier )
2807 componentNets.insert( netIt->second.begin(), netIt->second.end() );
2809 for(
size_t linked : routeNodeLinks[ordinal] )
2811 if( visitedStamp[linked] ==
static_cast<uint32_t
>( root ) )
2814 visitedStamp[linked] =
static_cast<uint32_t
>( root );
2815 next.push_back( linked );
2819 frontier.swap(
next );
2822 routeNodeNets.emplace( routeNodeHandles[root], std::move( componentNets ) );
2825 auto nodeOrdinal = [&]( uint32_t aHandle ) -> std::optional<size_t>
2827 auto it = routeNodeOrdinals.find( aHandle );
2829 if( it != routeNodeOrdinals.end() )
2832 return std::nullopt;
2835 std::vector<int> serializedObjectLayers;
2836 std::vector<uint32_t> serializedObjectHandles;
2837 std::map<uint32_t, int> routeHandleLayers;
2838 size_t handleOrdinal = 0;
2840 for(
size_t layer = 0; layer < layerObjectCounts->
physicalCount; ++layer )
2844 if( handleOrdinal + count > layerObjectHandles->
physicalCount )
2854 int padsLayer = padsLayerForSerializedIndex( layer );
2855 auto [layerIt, inserted] = routeHandleLayers.emplace( handle, padsLayer );
2857 if( !inserted && layerIt->second != padsLayer )
2860 auto ordinal = nodeOrdinal( handle );
2867 if( ( classTag & 0x00800000 ) != 0 )
2869 serializedObjectLayers.push_back( padsLayer );
2870 serializedObjectHandles.push_back( handle );
2875 if( handleOrdinal != layerObjectHandles->
physicalCount || serializedObjectLayers.size() != aObjectCount )
2880 for(
size_t sequence = 0; sequence < serializedObjectLayers.size(); ++sequence )
2882 size_t object = ( sequence + aObjectCount - 1 ) % aObjectCount;
2883 nodes.
layers[object] = serializedObjectLayers[sequence];
2884 nodes.
handles[object] = serializedObjectHandles[sequence];
2900 if( !sec10 || !sec11 || !sec12 )
2903 const size_t pieceStride =
m_version <= 0x2024 ? 16 : 20;
2906 THROW_IO_ERROR(
"Invalid PADS copper-shape controller framing" );
2908 constexpr size_t MAX_COPPER_SHAPE_EDGES = 80;
2914 if(
name.size() < 4 ||
name.substr( 0, 3 ) !=
"DRW" )
2919 if( ( run.itemKind & 0xFFFFU ) != 3 )
2922 uint32_t sec11Index =
static_cast<uint32_t
>( run.pieceStart );
2924 if( sec11Index >= sec11->
count )
2937 std::vector<VECTOR2I> loop;
2955 const double cx = ( p0.
x + p1.
x ) / 2.0;
2956 const double cy = ( p0.
y + p1.
y ) / 2.0;
2957 const double radius = std::hypot( p1.
x - p0.
x, p1.
y - p0.
y ) / 2.0;
2959 constexpr int CIRCLE_SEGMENTS = 32;
2962 for(
int i = 0; i < CIRCLE_SEGMENTS; ++i )
2964 double angle = ( 2.0 *
M_PI *
static_cast<double>( i ) ) /
static_cast<double>( CIRCLE_SEGMENTS );
2965 loop.emplace_back(
static_cast<int32_t
>( std::lround( cx +
radius * std::cos( angle ) ) ),
2966 static_cast<int32_t
>( std::lround( cy +
radius * std::sin( angle ) ) ) );
2974 size_t pieceRotation = sec11->
totalBytes - ( pieceStride - 8 );
2975 uint32_t levelIndex = ( sec11Index + 1 ) % sec11->
count;
2976 uint8_t level =
ringU8( *sec11, pieceRotation, pieceStride, levelIndex, 1 );
2978 static_cast<double>(
ringI32( *sec11, pieceRotation, pieceStride, sec11Index, pieceStride - 8 ) );
2979 copper.
layer = level;
2983 int32_t rawX =
static_cast<int32_t
>( originX + pt.x );
2984 int32_t rawY =
static_cast<int32_t
>( originY + pt.y );
3010 for( uint32_t rec = 0; rec < sec10->
count; ++rec )
3014 if(
name.size() < 4 ||
name.substr( 0, 3 ) !=
"DIM" )
3022 int32_t startRow = it->second.vertexStart;
3024 int32_t bp1x = 0, bp1y = 0, bp2x = 0, bp2y = 0, arwx = 0, arwy = 0, attr = 0;
3027 || !
sec12Vertex( startRow + 4, arwx, arwy, attr ) )
3039 dim.
points.push_back( pt1 );
3040 dim.
points.push_back( pt2 );
3069 size_t aField )
const
3071 if( aSection.
totalBytes == 0 || aIndex >= aSection.
count || aField >= aStride )
3072 THROW_IO_ERROR(
"Invalid PADS circular-controller record access" );
3074 size_t logical =
static_cast<size_t>( aIndex ) * aStride + aField;
3075 size_t physical = ( aRotation + logical ) % aSection.
totalBytes;
3081 size_t aField )
const
3085 for(
size_t byte = 0;
byte < 4; ++byte )
3086 value |=
static_cast<uint32_t
>(
ringU8( aSection, aRotation, aStride, aIndex, aField +
byte ) ) << (
byte * 8 );
3093 size_t aField )
const
3095 return static_cast<int32_t
>(
ringU32( aSection, aRotation, aStride, aIndex, aField ) );
3100 size_t aField,
size_t aLength )
const
3103 value.reserve( aLength );
3105 for(
size_t byte = 0;
byte < aLength; ++byte )
3107 char c =
static_cast<char>(
ringU8( aSection, aRotation, aStride, aIndex, aField +
byte ) );
3112 value.push_back( c );
3128 if( sec10->
count == 0 )
3134 if( sec10->
totalBytes !=
static_cast<uint64_t
>( sec10->
count ) * stride )
3137 for( uint32_t ownerIndex = 0; ownerIndex < sec10->
count; ++ownerIndex )
3144 uint32_t lagIndex = ( ownerIndex + 1 ) % sec10->
count;
3158 const char* aWhat )
const
3160 uint64_t arcIndex =
static_cast<uint64_t
>( aArcStart ) +
static_cast<uint32_t
>( aAttr );
3162 if( aArcStart < 0 || arcIndex >= aArcParameters.
count
3163 || aArcParameters.
totalBytes !=
static_cast<uint64_t
>( aArcParameters.
count ) * 20 )
3165 THROW_IO_ERROR( wxString::Format(
"Invalid PADS %s arc range", aWhat ) );
3178 double xmin = aArcRecord.
I32( 0 );
3179 double ymin = aArcRecord.
I32( 4 );
3180 double xmax = aArcRecord.
I32( 8 );
3181 double ymax = aArcRecord.
I32( 12 );
3182 double centerX = ( xmin + xmax ) / 2.0;
3183 double centerY = ( ymin + ymax ) / 2.0;
3184 double startAngle = std::atan2( aStart.
y - centerY, aStart.
x - centerX ) * 180.0 /
M_PI;
3185 double endAngle = std::atan2( aEnd.
y - centerY, aEnd.
x - centerX ) * 180.0 /
M_PI;
3188 arc.
cx = centerX + aOriginX;
3189 arc.cy = centerY + aOriginY;
3190 arc.radius = ( xmax - xmin ) / 2.0;
3191 arc.start_angle = startAngle;
3205 if( !owners || !pieces || !vertices || !arcParameters )
3209 const size_t pieceStride =
m_version <= 0x2024 ? 16 : 20;
3210 const size_t pieceHead = pieceStride == 16 ? 8 : 12;
3211 const size_t cornerField = pieceStride == 16 ? 12 : 16;
3213 const size_t originYField = originXField + 4;
3214 const size_t pieceRotation = pieces->
totalBytes - pieceHead;
3218 if( ( run.itemKind & 0xFFFFU ) != 1 || run.pieceCount <= 0 || run.pieceStart < 0 || run.vertexStart < 0 )
3221 if(
static_cast<uint64_t
>( run.pieceStart ) +
static_cast<uint64_t
>( run.pieceCount ) > pieces->
count )
3226 int32_t vertexCursor = run.vertexStart;
3228 for( int32_t piece = 0; piece < run.pieceCount; ++piece )
3230 uint32_t pieceIndex =
static_cast<uint32_t
>( run.pieceStart + piece );
3231 int32_t corners =
ringI32( *pieces, pieceRotation, pieceStride, pieceIndex, cornerField );
3234 ||
static_cast<uint64_t
>( vertexCursor ) +
static_cast<uint64_t
>( corners ) > vertices->
count )
3237 std::vector<ARC_VERTEX> decoded;
3238 decoded.reserve(
static_cast<size_t>( corners ) );
3240 for( int32_t corner = 0; corner < corners; ++corner )
3242 size_t offset = vertices->
physicalOffset +
static_cast<size_t>( vertexCursor + corner ) * 12;
3244 decoded.push_back( { record.
I32( 0 ), record.
I32( 4 ), record.
I32( 8 ) } );
3247 vertexCursor += corners;
3252 static_cast<double>(
ringI32( *pieces, pieceRotation, pieceStride, pieceIndex, pieceStride - 8 ) );
3253 outline.
closed = decoded.size() >= 3 && decoded.front().x == decoded.back().x
3254 && decoded.front().y == decoded.back().y;
3259 double rawX =
static_cast<double>( vertex.
x ) + originX;
3260 double rawY =
static_cast<double>( vertex.
y ) + originY;
3262 if(
index > 0 && decoded[
index - 1].attr >= 0 )
3265 arcRecordFor( *arcParameters, run.arcStart, decoded[
index - 1].attr,
"board-outline" );
3267 outline.
points.emplace_back( rawX, rawY,
3268 deriveArc( arcRecord, decoded[
index - 1], vertex, originX, originY ) );
3272 outline.
points.emplace_back( rawX, rawY );
3289 if( !owners || !pieces || !vertices || !arcParameters )
3293 const size_t pieceStride =
m_version <= 0x2024 ? 16 : 20;
3294 const size_t pieceHead = pieceStride - 8;
3295 const size_t cornerField = pieceStride - 4;
3297 const size_t originYField = originXField + 4;
3298 const size_t pieceRotation = pieces->
totalBytes - pieceHead;
3300 if( vertices->
totalBytes !=
static_cast<uint64_t
>( vertices->
count ) * 12
3301 || arcParameters->
totalBytes !=
static_cast<uint64_t
>( arcParameters->
count ) * 20 )
3308 if( ( run.itemKind & 0xFFFFU ) != 0 ||
name.compare( 0, 3,
"DRW" ) != 0 || run.pieceCount <= 0
3309 || run.pieceStart < 0 || run.vertexStart < 0 )
3314 if(
static_cast<uint64_t
>( run.pieceStart ) +
static_cast<uint64_t
>( run.pieceCount ) > pieces->
count )
3319 int32_t vertexCursor = run.vertexStart;
3321 for( int32_t piece = 0; piece < run.pieceCount; ++piece )
3323 uint32_t pieceIndex =
static_cast<uint32_t
>( run.pieceStart + piece );
3324 int32_t corners =
ringI32( *pieces, pieceRotation, pieceStride, pieceIndex, cornerField );
3327 ||
static_cast<uint64_t
>( vertexCursor ) +
static_cast<uint64_t
>( corners ) > vertices->
count )
3329 THROW_IO_ERROR( wxString::Format(
"Invalid PADS graphic vertex range (%s piece %d, start %d, "
3330 "corners %d, count %u)",
3331 name.c_str(), piece, vertexCursor, corners, vertices->
count ) );
3336 graphic.
width =
ringI32( *pieces, pieceRotation, pieceStride, pieceIndex, pieceStride - 8 );
3337 graphic.
layer =
ringU8( *pieces, pieceRotation, pieceStride, ( pieceIndex + 1 ) % pieces->
count, 1 );
3338 graphic.
points.reserve(
static_cast<size_t>( corners ) );
3340 std::vector<ARC_VERTEX> decoded;
3341 decoded.reserve(
static_cast<size_t>( corners ) );
3343 for( int32_t corner = 0; corner < corners; ++corner )
3346 +
static_cast<uint32_t
>( vertexCursor + corner ) * 12 );
3347 decoded.push_back( { record.
I32( 0 ), record.
I32( 4 ), record.
I32( 8 ) } );
3350 vertexCursor += corners;
3351 graphic.
closed = decoded.size() >= 3 && decoded.front().x == decoded.back().x
3352 && decoded.front().y == decoded.back().y;
3354 uint8_t pieceType =
ringU8( *pieces, pieceRotation, pieceStride, ( pieceIndex + 1 ) % pieces->
count, 0 );
3356 if( pieceType == 2 && decoded.size() == 2 )
3358 double centerX = ( decoded[0].x + decoded[1].x ) / 2.0 + originX;
3359 double centerY = ( decoded[0].y + decoded[1].y ) / 2.0 + originY;
3360 double radius = std::hypot( decoded[1].x - decoded[0].x, decoded[1].y - decoded[0].y ) / 2.0;
3365 arc.start_angle = 0.0;
3366 arc.delta_angle = 360.0;
3368 graphic.
points.emplace_back( centerX +
radius, centerY, arc );
3376 double rawX =
static_cast<double>( vertex.
x ) + originX;
3377 double rawY =
static_cast<double>( vertex.
y ) + originY;
3379 if(
index > 0 && decoded[
index - 1].attr >= 0 )
3382 arcRecordFor( *arcParameters, run.arcStart, decoded[
index - 1].attr,
"graphic" );
3384 graphic.
points.emplace_back( rawX, rawY,
3385 deriveArc( arcRecord, decoded[
index - 1], vertex, originX, originY ) );
3389 graphic.
points.emplace_back( rawX, rawY );
3412 aAttr = rec.
I32( 8 );
3428 if( !pieces || it->second.pieceCount < 1 || it->second.pieceStart < 0 )
3431 size_t pieceStride =
m_version <= 0x2024 ? 16 : 20;
3432 size_t pieceHead = pieceStride == 16 ? 8 : 12;
3433 size_t cornerField = pieceStride == 16 ? 12 : 16;
3434 size_t pieceRotation = pieces->
totalBytes - pieceHead;
3436 ringI32( *pieces, pieceRotation, pieceStride,
static_cast<uint32_t
>( it->second.pieceStart ), cornerField );
3438 if( corners < 4 ||
static_cast<size_t>( corners ) > aMaxVerts + 1 )
3441 int32_t startRow = it->second.vertexStart;
3447 if( !
sec12Vertex( startRow, firstX, firstY, attr ) )
3450 for( int32_t corner = 0; corner < corners - 1; ++corner )
3455 if( !
sec12Vertex( startRow + corner, x, y, attr ) )
3458 aOut.emplace_back( x, y );
3464 if( !
sec12Vertex( startRow + corners - 1, lastX, lastY, attr ) || lastX != firstX || lastY != firstY )
3483 if( !pieces || it->second.pieceCount < 1 || it->second.pieceStart < 0 )
3486 size_t pieceStride =
m_version <= 0x2024 ? 16 : 20;
3487 size_t pieceHead = pieceStride == 16 ? 8 : 12;
3488 size_t cornerField = pieceStride == 16 ? 12 : 16;
3489 size_t pieceRotation = pieces->
totalBytes - pieceHead;
3491 if(
ringI32( *pieces, pieceRotation, pieceStride,
static_cast<uint32_t
>( it->second.pieceStart ), cornerField )
3497 int32_t startRow = it->second.vertexStart;
3499 int32_t x0 = 0, y0 = 0, x1 = 0, y1 = 0, attr = 0;
3504 if( x0 == x1 && y0 == y1 )
3521 if( !sec10 || !sec12 )
3530 int32_t originX = 0;
3531 int32_t originY = 0;
3538 std::vector<Owner> owners;
3542 if( ( run.itemKind & 0xFFFFU ) != 10 )
3562 owners.push_back( std::move( owner ) );
3565 if( owners.empty() )
3568 constexpr size_t MAX_KEEP_OUT_VERTICES = 80;
3570 for(
const Owner& owner : owners )
3577 std::vector<VECTOR2I> structuralLoop;
3579 if(
fetchOwnerLoop( owner.name, MAX_KEEP_OUT_VERTICES, structuralLoop ) )
3581 for(
const VECTOR2I& vertex : structuralLoop )
3583 int32_t rawX = owner.originX +
static_cast<int32_t
>( vertex.x );
3584 int32_t rawY = owner.originY +
static_cast<int32_t
>( vertex.y );
3588 m_keepouts.push_back( std::move( keepout ) );
3594 int64_t spanX = owner.maxX - owner.minX;
3595 int64_t spanY = owner.maxY - owner.minY;
3597 if( spanX <= 0 || spanX != spanY )
3600 constexpr int ELLIPSE_SEGMENTS = 32;
3601 double cx =
static_cast<double>( owner.minX + owner.maxX ) / 2.0;
3602 double cy =
static_cast<double>( owner.minY + owner.maxY ) / 2.0;
3603 double radius =
static_cast<double>( spanX ) / 2.0;
3605 for(
int i = 0; i < ELLIPSE_SEGMENTS; ++i )
3607 double angle = ( 2.0 *
M_PI *
static_cast<double>( i ) ) /
static_cast<double>( ELLIPSE_SEGMENTS );
3608 int32_t rawX = owner.originX +
static_cast<int32_t
>( std::lround( cx +
radius * std::cos( angle ) ) );
3609 int32_t rawY = owner.originY +
static_cast<int32_t
>( std::lround( cy +
radius * std::sin( angle ) ) );
3613 m_keepouts.push_back( std::move( keepout ) );
3644 static constexpr size_t OWNER_SIZE = 88;
3645 static constexpr size_t PIECE_SIZE = 16;
3646 static constexpr size_t VERTEX_SIZE = 8;
3650 uint32_t pieceStart = 0;
3651 uint32_t vertexStart = 0;
3652 uint32_t pieceCount = 0;
3658 std::vector<POUR_OWNER> owners;
3664 if( !sec52 || !sec53 || !sec54 )
3674 const uint8_t outlineType =
m_cursor.U8At( offset + 87 );
3675 std::string
name =
m_cursor.StringAt( offset + 70, 14 );
3677 if( outlineType != 0x32 ||
name.rfind(
"POR", 0 ) != 0 )
3681 owner.pieceStart =
m_cursor.U32At( offset );
3682 owner.vertexStart =
m_cursor.U32At( offset + 4 );
3683 owner.rawX =
m_cursor.I32At( offset + 24 );
3684 owner.rawY =
m_cursor.I32At( offset + 28 );
3685 owner.pieceCount =
m_cursor.U32At( offset + 64 );
3686 owner.name = std::move(
name );
3687 owners.push_back( std::move( owner ) );
3690 for(
const POUR_OWNER& owner : owners )
3692 uint32_t vertexIndex = owner.vertexStart;
3694 for( uint32_t pieceOrdinal = 0; pieceOrdinal < owner.pieceCount; ++pieceOrdinal )
3696 const uint32_t pieceIndex = owner.pieceStart + pieceOrdinal;
3698 if( pieceIndex >= sec53->
count )
3701 const size_t pieceOff = sec53->
physicalOffset +
static_cast<size_t>( pieceIndex ) * PIECE_SIZE;
3702 uint32_t cornerCount =
m_cursor.U32At( pieceOff );
3703 int32_t width =
m_cursor.I32At( pieceOff + 8 );
3704 uint8_t pieceType =
m_cursor.U8At( pieceOff + 12 );
3705 uint8_t layer =
m_cursor.U8At( pieceOff + 13 );
3707 if( cornerCount == 0 || vertexIndex > sec54->
count || cornerCount > sec54->
count - vertexIndex )
3710 const size_t vOff = sec54->
physicalOffset +
static_cast<size_t>( vertexIndex ) * VERTEX_SIZE;
3711 vertexIndex += cornerCount;
3715 pour.
width =
static_cast<double>( width );
3716 pour.
layer =
static_cast<int>( layer );
3718 if( pieceType == 0x33 && cornerCount == 2 )
3723 int32_t x0 = owner.rawX +
m_cursor.I32At( vOff );
3724 int32_t y0 = owner.rawY +
m_cursor.I32At( vOff + 4 );
3725 int32_t x1 = owner.rawX +
m_cursor.I32At( vOff + VERTEX_SIZE );
3726 int32_t y1 = owner.rawY +
m_cursor.I32At( vOff + VERTEX_SIZE + 4 );
3728 double cx = ( x0 + x1 ) / 2.0;
3729 double cy = ( y0 + y1 ) / 2.0;
3730 double radius = std::hypot( x1 - x0, y1 - y0 ) / 2.0;
3732 static constexpr int CIRCLE_SEGMENTS = 48;
3734 for(
int s = 0; s < CIRCLE_SEGMENTS; ++s )
3736 double angle = 2.0 *
M_PI * s / CIRCLE_SEGMENTS;
3737 int32_t rawX =
static_cast<int32_t
>( std::lround( cx +
radius * std::cos( angle ) ) );
3738 int32_t rawY =
static_cast<int32_t
>( std::lround( cy +
radius * std::sin( angle ) ) );
3745 for( uint32_t vertex = 0; vertex < cornerCount; ++vertex )
3747 size_t offset = vOff +
static_cast<size_t>( vertex ) * VERTEX_SIZE;
3748 int32_t localX =
m_cursor.I32At( offset );
3749 int32_t localY =
m_cursor.I32At( offset + 4 );
3756 m_pours.push_back( std::move( pour ) );
3770 constexpr uint64_t CONTROLLER_LEAD_IN = 12;
3771 const uint64_t base =
static_cast<uint64_t
>( section->
physicalOffset ) + CONTROLLER_LEAD_IN;
3774 return base + bytes <=
m_data.size() ?
static_cast<size_t>( base ) : 0;
3789 static constexpr size_t NAME_LEN = 24;
3790 static constexpr size_t OFF_ROUT = 32;
3791 static constexpr size_t OFF_LAYTH = 52;
3792 static constexpr size_t OFF_COPTH = 56;
3793 static constexpr size_t OFF_DIEL = 60;
3795 auto layerFunction = []( int32_t aSerializedType )
3797 switch( aSerializedType )
3812 if( recordBase == 0 )
3820 size_t rec = recordBase + k * section->
stride;
3824 info.number =
static_cast<int>( k );
3825 info.name = layerRec.
Str( 0, NAME_LEN );
3827 int32_t routingDir = layerRec.
I32( OFF_ROUT );
3828 info.routing_direction = routingDir;
3830 info.layer_thickness =
static_cast<double>( layerRec.
I32( OFF_LAYTH ) );
3831 info.copper_thickness =
static_cast<double>( layerRec.
I32( OFF_COPTH ) );
3833 float dielectric = 0.0f;
3834 std::memcpy( &dielectric, &
m_data[rec + OFF_DIEL],
sizeof(
float ) );
3835 info.dielectric_constant =
static_cast<double>( dielectric );
3839 const int32_t serializedType = k > 0 ?
m_cursor.I32At( rec - 4 ) : 0;
3873 for(
size_t partIdx = 0; partIdx <
m_parts.size(); ++partIdx )
3877 if( !part.
decal.empty() )
3885 uint32_t decalIndex = hintIt->second;
3892 if( !decalName.empty() &&
m_decals.count( decalName ) )
3893 part.
decal = decalName;
3906 for(
size_t partIdx = 0; partIdx <
m_parts.size(); ++partIdx )
3910 if( !part.
decal.empty() )
3918 uint32_t partTypeIdx = hintIt->second;
3923 uint8_t alternate = 0;
3927 alternate = alternateIt->second;
3930 int32_t decalIndex = decalIndices.empty() ? -1 : decalIndices.front();
3932 if( alternate < decalIndices.size() )
3933 decalIndex = decalIndices[alternate];
3935 if( decalIndex < 0 ||
static_cast<size_t>( decalIndex ) >=
m_decalNameTable.size() )
3940 if( !decalName.empty() &&
m_decals.count( decalName ) )
3941 part.
decal = decalName;
3951 if( !typeName.empty() && typeName != part.
decal )
3952 part.
value = typeName;
Bounds-checked little-endian read cursor over a PADS binary buffer.
uint8_t U8At(size_t aOffset) const
void decodeRoutedCopper(std::map< std::string, ROUTE > &aRoutes)
std::map< uint32_t, std::string > m_netSelfPtrToName
uint8_t ringU8(const SDB_SECTION &aSection, size_t aRotation, size_t aStride, uint32_t aIndex, size_t aField) const
double toBasicCoordY(int32_t aRawValue) const
ROUTE_OBJECT_NODES resolveRouteObjectNodes(const SDB_SECTION &aRouteLayers, size_t aObjectCount, const std::vector< int > &aSerializedLayerOrder)
std::vector< NET > m_nets
std::string ringStr(const SDB_SECTION &aSection, size_t aRotation, size_t aStride, uint32_t aIndex, size_t aField, size_t aLength) const
bool isValidNetName(const std::string &aName) const
std::map< std::string, uint32_t > m_decalTerminalCount
std::map< size_t, int > m_partClusterId
std::map< size_t, uint32_t > m_partDecalIndex
std::vector< NET_CLASS_RULE_EDGE > collectNetClassRuleEdges(const std::set< uint32_t > &aOwnerSet)
std::map< std::string, ROUTE > seedRoutesFromVias(const std::vector< VIA_LOCATION > &aVias) const
size_t layerStackupBase() const
Base of section 69's layer records after its fixed controller lead-in.
void parsePlacementFields(const SDB_SECTION &aText, size_t aRecordBase, size_t aRecordSize, size_t aRingRotation)
void parseDecalNameTableOld()
void parseNetConnectionsNew()
std::vector< VIA_LOCATION > decodeViaLocations()
std::map< uint32_t, size_t > parseRouteJunctionNets() const
std::vector< PART > m_parts
std::map< uint32_t, size_t > m_sec23RecordToNet
std::vector< NET_ANCHOR > m_netAnchors
bool usesDirectDecalChain() const
std::map< size_t, uint8_t > m_partDecalAlternate
std::map< std::string, uint32_t > m_netClassOwner
void parseDecalNameTable()
std::vector< COPPER_SHAPE > m_copper_shapes
void applyPadstackPairs(PART_DECAL &aDecal, const std::vector< std::pair< int32_t, int32_t > > &aPairs, int32_t aStart, int32_t aCount)
static constexpr int32_t ANGLE_SCALE
std::vector< POUR > m_pours
static bool IsBinaryPadsFile(const wxString &aFileName)
Check if a file appears to be a PADS binary PCB file.
std::map< std::string, PART_DECAL > m_decals
std::vector< DIFF_PAIR_DEF > m_diffPairs
std::map< std::string, int32_t > m_decalTerminalStart
std::vector< POLYLINE > m_boardOutlines
void parseFreeText(const SDB_SECTION &aText, size_t aRecordBase, size_t aRecordSize, size_t aRingRotation, size_t aPoolBase, size_t aPoolHi)
bool fetchOwnerCirclePoints(const std::string &aName, VECTOR2I &aP0, VECTOR2I &aP1) const
std::vector< size_t > oldNetRecordOffsets() const
std::map< std::string, int32_t > m_decalStackStart
std::vector< KEEPOUT > m_keepouts
void parsePartTypeTable()
std::map< std::string, int32_t > m_decalStackCount
uint32_t ringU32(const SDB_SECTION &aSection, size_t aRotation, size_t aStride, uint32_t aIndex, size_t aField) const
void parseRouteVertices()
std::map< size_t, uint32_t > m_partTypeIndex
std::map< uint32_t, size_t > m_placementObjectToPart
std::vector< std::pair< int, int > > m_padStackDrillSpans
const SDB_SECTION * getSection(int aIndex) const
std::vector< DIMENSION > m_dimensions
std::vector< LAYER_INFO > m_layerInfos
void Parse(const wxString &aFileName)
int32_t ringI32(const SDB_SECTION &aSection, size_t aRotation, size_t aStride, uint32_t aIndex, size_t aField) const
double toBasicCoordX(int32_t aRawValue) const
std::vector< std::vector< int32_t > > m_partTypeDecalIndices
void applyNetClassClearances(const std::vector< NET_CLASS_RULE_EDGE > &aEdges, const std::map< uint32_t, size_t > &aOwnerOrdinal)
bool fetchOwnerLoop(const std::string &aName, size_t aMaxVerts, std::vector< VECTOR2I > &aOut) const
PART makePlacementPart(const SDB_RECORD &aRec, int aXOff, std::optional< int > aYOff, int aAngleOff, int aNameOff, const std::string &aRefDes) const
void parseNetConnectionsOld()
bool sec12Vertex(int32_t aRow, int32_t &aX, int32_t &aY, int32_t &aAttr) const
const std::vector< uint8_t > & m_data
std::vector< std::string > m_partTypeNames
std::map< uint32_t, std::string > m_sec23IndexToNet
std::vector< NET_ANCHOR > m_netConnectionEndpoints
void assignDefaultPadStacks()
std::vector< std::vector< PAD_STACK_LAYER > > m_padStackPool
std::map< uint32_t, std::set< size_t > > m_junctionHandleNets
void parsePartPlacements()
std::map< size_t, int32_t > m_partFieldStart
void computeSec12CleanRows()
std::vector< ROUTE > m_routes
void parseBoardOutlineDirect()
std::vector< TEXT > m_texts
std::vector< GRAPHIC_LINE > m_graphicLines
std::vector< PART_CLUSTER > m_clusters
std::vector< BIN_NET_CLASS_DEF > m_netClasses
std::vector< std::string > m_decalNameTable
double toBasicAngle(int32_t aRawAngle) const
std::vector< LAYER_INFO > GetLayerInfos() const
std::map< std::string, OWNER_RUN > m_ownerRuns
SDB_RECORD arcRecordFor(const SDB_SECTION &aArcParameters, int32_t aArcStart, int32_t aAttr, const char *aWhat) const
static bool IsSupportedVersion(uint16_t aVersion)
A bounds-checked reader positioned at one record inside a buffer.
uint32_t U32(size_t aOffset) const
uint8_t U8(size_t aOffset) const
uint16_t U16(size_t aOffset) const
int32_t I32(size_t aOffset) const
std::string Str(size_t aOffset, size_t aMaxLen) const
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
constexpr size_t ORIGIN_X
constexpr size_t ROTATION
bool ReadFileHeader(const wxString &aFileName, std::vector< uint8_t > &aOut, size_t aCount)
Read at most aCount leading bytes of aFileName into aOut, which is sized to what was actually read.
static bool viaRecordValid(const BINARY_CURSOR &aCur, size_t aTypeByte)
bool HasSdbMagic(const std::vector< uint8_t > &aData, uint8_t aMagic1)
Check the PADS SDB container magic, a leading 0x00 followed by a format-specific second byte.
constexpr uint16_t SDB_RECORD_SENTINEL
constexpr double SDB_BASIC_PER_MIL
static constexpr int DECAL_NAME_OFFSET
Rotation between the physical section cursor and the logical record base.
static void logParsePhase(const char *aWhat, std::chrono::steady_clock::time_point aStart)
Enabled by setting KICAD_PADS_PROFILE.
static ARC deriveArc(const SDB_RECORD &aArcRecord, const ARC_VERTEX &aStart, const ARC_VERTEX &aEnd, double aOriginX, double aOriginY)
static void logResolvedBase(int aSection, const char *aWhat, size_t aResolved, uint32_t aPhysical)
Report a structurally derived physical section base for cross-checking the Kaitai grammar.
bool ReadFileToBuffer(const wxString &aFileName, std::vector< uint8_t > &aOut)
Read an entire file into aOut.
static const std::map< uint8_t, std::string > PAD_SHAPE_NAMES
uint16_t getU16LE(const std::vector< uint8_t > &aData, size_t aOffset)
static const PADSTACK_LAYOUT & padstackLayout(uint16_t aVersion)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
A polyline point that may instead be an arc segment.
One board-outline vertex triplet: [i32 X, i32 Y, i32 attr] where attr -1 is a plain corner and attr >...
Arc as center, radius and angles.
Every routed-copper object's PADS layer and route-node handle, indexed by object ordinal,...
std::vector< int > layers
std::vector< uint32_t > handles
std::map< uint32_t, std::set< size_t > > handleNets
One placed via recovered from the section-60 junction ring.
A PADS net class recovered from the binary design-rule graph.
Standalone copper area from the LINES section (type=COPPER), not part of a pour.
std::vector< ARC_POINT > outline
bool filled
COPCLS, COPCIR.
double width
For open polylines.
double crossbar_pos
Y for horizontal, X for vertical.
std::vector< POINT > points
Measurement endpoints.
Non-electrical drawing item from the LINES section (type=LINES).
std::vector< ARC_POINT > points
std::vector< ARC_POINT > outline
One type-66 net-class rule edge: its owner pointer, rule-detail page, full rule pointer (declaration ...
std::string shape
R, S, A, O, OF, RF, RT, ST, RA, SA, RC, OC.
double thermal_outer_diameter
Thermal or void in plane.
double slot_orientation
0-179.999 degrees
double sizeB
Height for rectangles/ovals.
double corner_radius
Always positive.
double sizeA
Diameter or width.
A PADS part cluster (named group of parts).
std::map< int, std::pair< int, int > > drill_spans
std::vector< TERMINAL > terminals
std::map< int, std::vector< PAD_STACK_LAYER > > pad_stacks
std::string decal
Primary decal (first in colon-separated list)
A polyline that may contain arc segments, used for board outlines and graphics.
std::vector< ARC_POINT > points
std::string owner_pour
Parent pour, 7th header field.
std::vector< ARC_POINT > points
std::vector< TRACK > tracks
The PADS PowerPCB .pcb file is a serialized snapshot of PADS' in-memory SDB (System DataBase) object ...
std::vector< ARC_POINT > points
std::vector< PAD_STACK_LAYER > stack
wxString result
Test unit parsing edge cases and error handling.
VECTOR2< int32_t > VECTOR2I