33#include <wx/filename.h>
77static int ReadInt4At(
const uint8_t* aData,
size_t aPos )
79 uint32_t raw = (
static_cast<uint32_t
>( aData[aPos] ) << 24 )
80 | (
static_cast<uint32_t
>( aData[aPos + 1] ) << 16 )
81 | (
static_cast<uint32_t
>( aData[aPos + 2] ) << 8 )
82 |
static_cast<uint32_t
>( aData[aPos + 3] );
83 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
112 return static_cast<int>(
static_cast<int64_t
>( aDipTraceCoord ) / 3 );
122 return static_cast<int>(
static_cast<int64_t
>( aDipTraceCoord ) / 3 );
128 return static_cast<int>(
static_cast<int64_t
>(
std::abs( aDipTraceCoord ) ) / 3 );
137 const uint8_t* data =
m_reader.GetData();
138 size_t fileSize =
m_reader.GetFileSize();
140 auto rdInt4 = [&](
size_t o ) ->
int
142 uint32_t raw = (
static_cast<uint32_t
>( data[o] ) << 24 ) | (
static_cast<uint32_t
>( data[o + 1] ) << 16 )
143 | (
static_cast<uint32_t
>( data[o + 2] ) << 8 ) |
static_cast<uint32_t
>( data[o + 3] );
144 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
150 static constexpr int UNITS_PER_MM = 30000;
152 for(
size_t o = 0; o + 24 <= fileSize; o++ )
155 int h = rdInt4( o + 4 );
157 if( w <= 0 || h <= 0 || ( w % UNITS_PER_MM ) != 0 || ( h % UNITS_PER_MM ) != 0 )
160 int wmm = w / UNITS_PER_MM;
161 int hmm = h / UNITS_PER_MM;
163 if( wmm < 50 || wmm > 2000 || hmm < 50 || hmm > 2000 )
166 int margins[4] = { rdInt4( o + 8 ), rdInt4( o + 12 ), rdInt4( o + 16 ), rdInt4( o + 20 ) };
167 bool sane = margins[0] > 0;
169 for(
int m : margins )
171 if( m < 0 || ( m % UNITS_PER_MM ) != 0 || m / UNITS_PER_MM > 100 )
201 wxString libName =
m_schematic->Project().GetProjectName();
203 if( libName.IsEmpty() )
206 libName = fn.GetName();
209 if( libName.IsEmpty() )
210 libName = wxT(
"noname" );
212 libName += wxT(
"-diptrace-import" );
246 size_t compSectionStart =
m_reader.GetOffset();
248 bool hasBusSection =
false;
282 catch(
const std::exception& e )
284 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: unexpected error at offset 0x%06zX: %s" ),
285 m_reader.GetOffset(), wxString::FromUTF8( e.what() ) ) );
294 uint8_t magicLen =
m_reader.ReadByte();
296 if( magicLen != 7 && magicLen != 11 )
298 THROW_IO_ERROR( wxString::Format(
_(
"Invalid DipTrace schematic magic length: %d (expected 7 or 11)." ),
302 std::vector<uint8_t> magicBuf( magicLen );
303 m_reader.ReadBytes( magicBuf.data(), magicLen );
305 if( memcmp( magicBuf.data(),
"DTSCHEM", 7 ) != 0 )
306 THROW_IO_ERROR(
_(
"Invalid DipTrace schematic file: bad magic header." ) );
316 const uint8_t* suffix = magicBuf.data() + 7;
318 if( !std::isdigit( suffix[0] ) || suffix[1] !=
'.' || !std::isdigit( suffix[2] ) || !std::isdigit( suffix[3] ) )
320 THROW_IO_ERROR(
_(
"Invalid DipTrace schematic file: bad legacy version suffix." ) );
324 m_version = ( suffix[2] -
'0' ) * 10 + ( suffix[3] -
'0' );
354 for(
int i = 0; i < 5; i++ )
368 uint8_t extraHdr[4] = {};
371 uint32_t extraChars = (
static_cast<uint32_t
>( extraHdr[0] ) << 24 )
372 | (
static_cast<uint32_t
>( extraHdr[1] ) << 16 )
373 | (
static_cast<uint32_t
>( extraHdr[2] ) << 8 ) | extraHdr[3];
377 if( extraChars > 0 && extraChars < 1000 )
378 m_reader.Skip(
static_cast<size_t>( extraChars ) * 2 );
393 int numStyles =
m_reader.ReadInt3();
395 if( numStyles < 0 || numStyles > 2000 )
397 THROW_IO_ERROR( wxString::Format(
_(
"Invalid text style count: %d." ), numStyles ) );
400 for(
int i = 0; i < numStyles; i++ )
427 for(
int i = 0; i < 5; i++ )
446 for(
int i = 0; i < 5; i++ )
462 const uint8_t* data =
m_reader.GetData();
463 size_t fileSize =
m_reader.GetFileSize();
465 static const uint8_t marker[] = { 0x3B, 0x9A, 0xF1, 0x10, 0x3B, 0x9A, 0xF1, 0x10, 0x00, 0x00 };
466 static constexpr size_t markerLen =
sizeof( marker );
468 if( aSearchStart + markerLen + 3 >= fileSize )
471 for(
size_t off = aSearchStart; off < fileSize - markerLen - 3; off++ )
473 if( memcmp( data + off, marker, markerLen ) == 0 )
475 int count = ( ( data[off + 10] << 16 ) | ( data[off + 11] << 8 ) | data[off + 12] ) -
INT3_BIAS;
477 if( count >= 0 && count <= 1000 )
480 if( count > 1000 && count <= 10000 )
482 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid bus count %d." ), count ) );
493 const uint8_t* data =
m_reader.GetData();
494 size_t fileSize =
m_reader.GetFileSize();
499 size_t off = fileSize - 3;
503 if( data[off] == 0x0F && data[off + 1] == 0x42 && data[off + 2] == 0x40 )
509 size_t tailStart = off + 3;
510 size_t tailCount = ( fileSize - tailStart ) / 3;
512 return ( tailCount > 1 ) ? tailStart : fileSize;
523 std::vector<size_t> boundaries;
525 size_t off = aFirstComp;
526 size_t end = ( aBusSectionOffset > 20 ) ? aBusSectionOffset - 20 : 0;
532 boundaries.push_back( off );
547 const uint8_t* data =
m_reader.GetData();
548 size_t fileSize =
m_reader.GetFileSize();
552 if( aOffset + 19 > fileSize )
555 int z1 = ( ( data[aOffset + 6] << 16 ) | ( data[aOffset + 7] << 8 ) | data[aOffset + 8] ) -
INT3_BIAS;
556 int z2 = ( ( data[aOffset + 9] << 16 ) | ( data[aOffset + 10] << 8 ) | data[aOffset + 11] ) -
INT3_BIAS;
558 if( z1 != 0 || z2 != 0 )
563 if( w < 0 || w > 200000 )
566 int npts = ( ( data[aOffset + 16] << 16 ) | ( data[aOffset + 17] << 8 ) | data[aOffset + 18] ) -
INT3_BIAS;
568 return npts >= 1 && npts <= 100;
572 if( aOffset + 17 > fileSize )
575 if( data[aOffset + 6] != 0 || data[aOffset + 7] != 0 || data[aOffset + 8] != 0 || data[aOffset + 9] != 0 )
582 if( w < 0 || w > 200000 )
585 int npts = ( ( data[aOffset + 14] << 16 ) | ( data[aOffset + 15] << 8 ) | data[aOffset + 16] ) -
INT3_BIAS;
587 return npts >= 1 && npts <= 100;
597 const uint8_t* data =
m_reader.GetData();
598 size_t fileSize =
m_reader.GetFileSize();
600 static constexpr uint8_t
TAHOMA_FONT_PATTERN[] = { 0x00, 0x06, 0x00, 0x54, 0x00, 0x61, 0x00,
601 0x68, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61 };
603 if( aOffset + 29 > fileSize )
606 int sentinel = ( ( data[aOffset] << 16 ) | ( data[aOffset + 1] << 8 ) | data[aOffset + 2] ) -
INT3_BIAS;
607 int shapeField = ( ( data[aOffset + 3] << 16 ) | ( data[aOffset + 4] << 8 ) | data[aOffset + 5] ) -
INT3_BIAS;
609 if( sentinel != 1000000 || shapeField != 0 )
617 if( data[aOffset + 20] != 0 || data[aOffset + 21] != 0 )
620 int lineWidth =
ReadInt4At( data, aOffset + 22 );
622 if( lineWidth < 0 || lineWidth > 200000 )
625 int numPoints = ( ( data[aOffset + 26] << 16 ) | ( data[aOffset + 27] << 8 ) | data[aOffset + 28] ) -
INT3_BIAS;
627 return numPoints >= 1 && numPoints <= 100;
633 size_t compSectionStart =
m_reader.GetOffset();
644 bool desynced =
false;
648 size_t compStart =
m_reader.GetOffset();
655 catch(
const std::exception& )
661 if(
m_reader.GetOffset() <= compStart )
672 m_reader.SetOffset( compSectionStart );
682 for(
size_t ci = 0; ci < compStarts.size(); ci++ )
684 size_t compEnd = ( ci + 1 < compStarts.size() ) ? compStarts[ci + 1] : aBusSectionOffset;
688 m_reader.SetOffset( compStarts[ci] );
695 catch(
const std::exception& e )
698 wxString::Format(
_(
"DipTrace import: failed to parse component %zu at offset 0x%06zX: %s" ), ci,
699 compStarts[ci], wxString::FromUTF8( e.what() ) ) );
706 wxString::Format(
_(
"DipTrace import: found %zu components, but the file header declares %d." ),
714 static bool s_dumpComponents = std::getenv(
"KICAD_DIPTRACE_DUMP_COMPONENTS" ) !=
nullptr;
715 static bool s_dumpComponentDetail = std::getenv(
"KICAD_DIPTRACE_DUMP_COMPONENT_DETAIL" ) !=
nullptr;
727 size_t componentCeiling = aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize();
731 for(
size_t p =
comp.fileOffset + 16; p < componentCeiling; p++ )
735 componentCeiling = p;
741 auto dumpDetail = [&](
const wxString& aMsg )
745 m_reporter->Report( wxString::Format( wxT(
"DipTrace SCH detail @0x%06zX: %s" ),
comp.fileOffset, aMsg ),
760 dumpDetail( wxString::Format( wxT(
"hdr end=0x%06zX name='%s' ref='%s' value='%s' prefix='%s'" ),
769 if( s_dumpComponentDetail )
771 dumpDetail( wxString::Format( wxT(
"post-hdr end=0x%06zX postA=%d postB=%d flag1=%d "
772 "postC=%d postD=%d" ),
773 m_reader.GetOffset(), postA, postB, flag1, postC, postD ) );
780 comp.isMultiPart = ( pb1 == 1 );
783 int partFieldB =
m_reader.ReadInt3();
784 int partFieldC =
m_reader.ReadInt3();
785 int partBboxX1 =
m_reader.ReadInt4();
786 int partBboxY1 =
m_reader.ReadInt4();
787 int partBboxX2 =
m_reader.ReadInt4();
788 int partBboxY2 =
m_reader.ReadInt4();
791 wxString partTailStr;
793 if(
comp.isMultiPart )
796 partTailStr =
comp.partId;
802 size_t partTailStart =
m_reader.GetOffset();
808 if( partTailInt > 0 && partTailInt < 256 )
810 size_t strStart = partTailStart + 3;
811 size_t strEnd = strStart +
static_cast<size_t>( partTailInt );
812 const uint8_t* data =
m_reader.GetData();
813 size_t fileSize =
m_reader.GetFileSize();
815 if( strEnd + 3 <= fileSize )
817 bool asciiPayload =
true;
819 for(
size_t i = strStart; i < strEnd; i++ )
823 if( c < 0x20 || c > 0x7E )
825 asciiPayload =
false;
833 ( ( data[strEnd] << 16 ) | ( data[strEnd + 1] << 8 ) | data[strEnd + 2] ) -
INT3_BIAS;
835 if( nextInt3 >= -1 && nextInt3 < 1000 )
837 m_reader.SetOffset( partTailStart );
838 partTailStr =
m_reader.ReadString();
854 dumpDetail( wxString::Format( wxT(
"part end=0x%06zX part='%s' partNum='%s' sheet=%d "
855 "isMulti=%d partFieldB=%d partFieldC=%d "
856 "partBBox=[%d,%d,%d,%d] fieldD=%d fieldE=%d" ),
858 comp.isMultiPart ? 1 : 0, partFieldB, partFieldC, partBboxX1, partBboxY1, partBboxX2,
859 partBboxY2, fieldD, fieldE ) );
863 dumpDetail( wxString::Format( wxT(
"part-tail end=0x%06zX partTailInt=%d partTailStr='%s'" ),
864 m_reader.GetOffset(), partTailInt, partTailStr ) );
870 if( fieldE >= 1 && fieldE < 1000 )
872 comp.additionalFields.reserve( fieldE );
874 for(
int i = 0; i < fieldE; i++ )
876 wxString fieldName =
m_reader.ReadString();
877 wxString fieldValue =
m_reader.ReadString();
880 if( !fieldName.IsEmpty() )
881 comp.additionalFields.emplace_back( fieldName, fieldValue );
898 size_t tailAfterB =
m_reader.GetOffset();
899 wxString tailStrA =
m_reader.ReadString();
900 wxString extraTail = wxEmptyString;
906 bool simpleModernTail =
false;
936 if( s_dumpComponentDetail )
938 dumpDetail( wxString::Format( wxT(
"pre-pin-hdr end=0x%06zX fieldF=%d fieldG=%d "
939 "byte4=%d rotE4=%d libPath='%s' tailA=%d tailB=%d "
940 "tailStrA='%s' pinMetaA=%d pinMetaF=%d pinMetaB=%d "
943 tailA, tailB, tailStrA, pinMetaA, pinMetaF, pinMetaB, numPins ) );
948 bool usedPinSeparatorFallback =
false;
950 auto readModernExtraAndPins = [&]( wxString& aExtraTail,
int& aNumPins,
int& aPinHdr,
951 bool& aUsedPinSeparatorFallback ) ->
bool
953 size_t extraStart =
m_reader.GetOffset();
954 uint8_t extraHdr[4] = {};
957 uint32_t extraChars = (
static_cast<uint32_t
>( extraHdr[0] ) << 24 )
958 | (
static_cast<uint32_t
>( extraHdr[1] ) << 16 )
959 | (
static_cast<uint32_t
>( extraHdr[2] ) << 8 ) | extraHdr[3];
961 if( extraChars >= 10000 && extraHdr[0] == 0 && extraHdr[1] == 0 )
963 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid component extra-tail length %u at "
965 extraChars, extraStart ) );
970 size_t extraBytes =
static_cast<size_t>( extraChars ) * 2;
971 bool fitsFile =
m_reader.GetOffset() + extraBytes <=
m_reader.GetFileSize();
973 if( extraChars < 10000 && fitsFile &&
m_reader.GetOffset() + extraBytes <= componentCeiling )
975 wxMBConvUTF16BE conv;
976 aExtraTail = wxString(
reinterpret_cast<const char*
>(
m_reader.GetData() +
m_reader.GetOffset() ),
980 else if( extraChars < 10000 && fitsFile )
1005 size_t pinStart =
m_reader.GetOffset();
1010 if( ( aNumPins < 0 || aNumPins > 500 ) && pinStart + 6 <=
m_reader.GetFileSize() )
1012 m_reader.SetOffset( pinStart + 2 );
1017 if( sepPins >= 0 && sepPins <= 500 )
1021 aUsedPinSeparatorFallback =
true;
1025 m_reader.SetOffset( pinStart + 4 );
1037 bool usedTaillessFallback =
false;
1038 bool canonicalPinSeparatorFallback =
false;
1039 bool readCanonicalPins =
1040 readModernExtraAndPins( extraTail, numPins, pinHdrByte, canonicalPinSeparatorFallback );
1041 usedPinSeparatorFallback = canonicalPinSeparatorFallback;
1043 if( !readCanonicalPins || ( numPins < 0 || numPins > 500 ) )
1045 size_t canonicalEnd =
m_reader.GetOffset();
1046 wxString canonicalTailStrA = tailStrA;
1047 wxString canonicalExtraTail = extraTail;
1048 int canonicalNumPins = numPins;
1049 int canonicalPinHdrByte = pinHdrByte;
1054 tailStrA = wxEmptyString;
1055 extraTail = wxEmptyString;
1058 usedTaillessFallback =
true;
1060 bool fallbackPinSeparatorFallback =
false;
1061 bool readFallbackPins =
1062 readModernExtraAndPins( extraTail, numPins, pinHdrByte, fallbackPinSeparatorFallback );
1064 if( readFallbackPins && numPins >= 0 && numPins <= 500 )
1066 usedPinSeparatorFallback = fallbackPinSeparatorFallback;
1070 m_reader.SetOffset( canonicalEnd );
1071 tailStrA = canonicalTailStrA;
1072 extraTail = canonicalExtraTail;
1073 numPins = canonicalNumPins;
1074 pinHdrByte = canonicalPinHdrByte;
1075 usedTaillessFallback =
false;
1076 usedPinSeparatorFallback = canonicalPinSeparatorFallback;
1080 if( s_dumpComponentDetail )
1082 dumpDetail( wxString::Format( wxT(
"pre-pin-hdr end=0x%06zX fieldF=%d fieldG=%d "
1083 "byte4=%d rotE4=%d libPath='%s' tailA=%d tailB=%d "
1084 "tailStrA='%s' extraTail='%s' numPins=%d pinHdr=%d "
1085 "taillessFallback=%d pinSeparatorFallback=%d" ),
1086 m_reader.GetOffset(), fieldF, fieldG, byte4,
comp.rotationE4,
comp.libPath,
1087 tailA, tailB, tailStrA, extraTail, numPins, pinHdrByte,
1088 usedTaillessFallback ? 1 : 0, usedPinSeparatorFallback ? 1 : 0 ) );
1091 simpleModernTail = tailA == 0 && tailB == 0 && tailStrA.IsEmpty() && extraTail.IsEmpty()
1092 && !usedTaillessFallback && !usedPinSeparatorFallback;
1097 comp.datasheet = extraTail;
1100 dumpDetail( wxString::Format( wxT(
"pre-pin end=0x%06zX numPins=%d" ),
m_reader.GetOffset(), numPins ) );
1102 if( numPins < 0 || numPins > 500 )
1104 if( aUseCompEnd && !simpleModernTail )
1111 THROW_IO_ERROR( wxString::Format(
_(
"Invalid pin count %d at component offset "
1113 numPins,
comp.fileOffset ) );
1116 for(
int pinIdx = 0; pinIdx < numPins; pinIdx++ )
1118 auto consumeLaterPinSeparatorIfPresent = [&]() ->
bool
1123 size_t start =
m_reader.GetOffset();
1125 if( start + 2 >= componentCeiling )
1128 const uint8_t* data =
m_reader.GetData();
1130 if( data[start] != 0 || data[start + 1] != 0 )
1133 bool currentRecordValid =
false;
1140 currentRecordValid =
m_reader.GetOffset() <= componentCeiling;
1142 catch(
const std::exception& )
1144 currentRecordValid =
false;
1149 if( currentRecordValid )
1152 bool shiftedRecordValid =
false;
1159 shiftedRecordValid =
m_reader.GetOffset() <= componentCeiling;
1161 catch(
const std::exception& )
1163 shiftedRecordValid =
false;
1168 if( !shiftedRecordValid )
1175 if( consumeLaterPinSeparatorIfPresent() )
1176 simpleModernTail =
false;
1182 catch(
const std::exception& e )
1184 if( aUseCompEnd && !simpleModernTail )
1187 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: failed to parse pin %d in component at 0x%06zX "
1188 "(offset 0x%06zX): %s" ),
1190 wxString::FromUTF8( e.what() ) ) );
1198 auto readShapePointCountIfHeaderPrefix = [&](
size_t aOffset,
int& aPointCount ) ->
bool
1200 const uint8_t* data =
m_reader.GetData();
1201 size_t fileSize =
m_reader.GetFileSize();
1202 size_t limit = std::min( fileSize, aCompEnd );
1204 if( aOffset + 17 > limit )
1207 if( data[aOffset + 6] != 0 || data[aOffset + 7] != 0 || data[aOffset + 8] != 0 || data[aOffset + 9] != 0 )
1212 int width =
ReadInt4At( data, aOffset + 10 );
1214 if( width < 0 || width > 200000 )
1217 aPointCount = ( ( data[aOffset + 14] << 16 ) | ( data[aOffset + 15] << 8 ) | data[aOffset + 16] ) -
INT3_BIAS;
1229 while(
m_reader.GetOffset() + 6 < componentCeiling )
1231 size_t markOff =
m_reader.GetOffset();
1232 const uint8_t* mdata =
m_reader.GetData();
1234 if( mdata[markOff] != 0 || mdata[markOff + 1] != 0 || mdata[markOff + 2] != 0 )
1237 int markType = ( ( mdata[markOff + 3] << 16 ) | ( mdata[markOff + 4] << 8 )
1238 | mdata[markOff + 5] )
1241 if( markType < 1 || markType > 3 )
1272 if(
m_reader.GetOffset() > componentCeiling )
1278 if( mark.
type == 2 || mark.
type == 3 )
1279 comp.texts.push_back( mark );
1281 catch(
const std::exception& )
1288 while(
m_reader.GetOffset() < aCompEnd &&
m_reader.GetOffset() < componentCeiling )
1290 size_t shapeOffset =
m_reader.GetOffset();
1291 int shapePointCount = 0;
1300 catch(
const std::exception& )
1308 if(
m_version >=
V31_CUTOVER && readShapePointCountIfHeaderPrefix( shapeOffset, shapePointCount )
1309 && ( shapePointCount < 1 || shapePointCount > 100 ) )
1311 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid component shape point count %d at "
1312 "offset 0x%06zX." ),
1313 shapePointCount, shapeOffset ) );
1325 catch(
const std::exception& )
1348 const uint8_t* data =
m_reader.GetData();
1349 size_t lim = std::min( componentCeiling > 0 ? componentCeiling :
m_reader.GetFileSize(),
1351 size_t lo = (
save > 24 ) ?
save - 24 : 0;
1353 for(
size_t probe = lo; probe + 6 < lim && probe <=
save + 4; probe++ )
1355 if( data[probe] != 0 || data[probe + 1] != 0 || data[probe + 2] != 0 )
1366 if(
vt.type != 2 &&
vt.type != 3 )
1371 if(
vt.fontName.IsEmpty() ||
vt.fontName.size() > 64 )
1376 if(
vt.text.IsEmpty() ||
vt.text.size() > 256 )
1384 bool haveType =
false;
1387 haveType = haveType || ( t.
type ==
vt.type );
1391 comp.texts.push_back(
vt );
1395 catch(
const std::exception& )
1408 size_t afterFirstPattern =
m_reader.GetOffset();
1411 if(
m_reader.GetOffset() == afterFirstPattern )
1412 m_reader.SetOffset( afterFirstPattern );
1415 catch(
const std::exception& e )
1417 if( s_dumpComponentDetail )
1419 dumpDetail( wxString::Format( wxT(
"pattern parse failed at 0x%06zX: %s" ),
m_reader.GetOffset(),
1420 wxString::FromUTF8( e.what() ) ) );
1424 size_t parsedEnd =
m_reader.GetOffset();
1426 if( s_dumpComponentDetail )
1428 dumpDetail( wxString::Format( wxT(
"post-pattern end=0x%06zX pins=%zu shapes=%zu "
1430 parsedEnd,
comp.pins.size(),
comp.shapes.size(),
comp.patternName ) );
1432 if( aUseCompEnd && parsedEnd < aCompEnd )
1434 dumpDetail( wxString::Format( wxT(
"tail skipped=%zu bytes to compEnd=0x%06zX" ), aCompEnd - parsedEnd,
1443 else if(
m_reader.GetOffset() != componentCeiling
1449 m_reader.SetOffset( componentCeiling );
1456 m_reporter->Report( wxString::Format( wxT(
"DipTrace SCH comp @0x%06zX ref='%s' name='%s' "
1457 "sheet=%d pins=%zu shapes=%zu pattern='%s'" ),
1459 comp.pins.size(),
comp.shapes.size(),
comp.patternName ),
1468 pin.index = aPinIndex;
1470 if( aPinIndex == 0 )
1472 pin.hasHeader =
true;
1525 size_t midTailStart =
m_reader.GetOffset();
1526 const uint8_t* data =
m_reader.GetData();
1528 if( midTailStart + 5 <=
m_reader.GetFileSize() && data[midTailStart] == 0 && data[midTailStart + 1] == 0 )
1563 size_t headerStart =
m_reader.GetOffset();
1565 if( headerStart >= 6 )
1567 const uint8_t* data =
m_reader.GetData();
1568 shape.
kindCode = ( ( data[headerStart - 6] << 16 ) | ( data[headerStart - 5] << 8 ) | data[headerStart - 4] )
1570 shape.
kindFlag = ( ( data[headerStart - 3] << 16 ) | ( data[headerStart - 2] << 8 ) | data[headerStart - 1] )
1588 int numPoints =
m_reader.ReadInt3();
1590 if( numPoints < 1 || numPoints > 100 )
1593 for(
int i = 0; i < numPoints; i++ )
1611 aComp.
shapes.push_back( shape );
1629 int numPoints =
m_reader.ReadInt3();
1631 if( numPoints < 1 || numPoints > 100 )
1634 for(
int i = 0; i < numPoints; i++ )
1649 aComp.
shapes.push_back( shape );
1655 size_t startOffset =
m_reader.GetOffset();
1656 const uint8_t* data =
m_reader.GetData();
1657 size_t limit = std::min( aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize(),
m_reader.GetFileSize() );
1659 if( startOffset + 6 > limit || data[startOffset] != 0 || data[startOffset + 1] != 0 || data[startOffset + 2] != 0 )
1665 ( ( data[startOffset + 3] << 16 ) | ( data[startOffset + 4] << 8 ) | data[startOffset + 5] ) -
INT3_BIAS;
1667 if( fieldType < 0 || fieldType > 100 )
1679 if(
text.fontName.IsEmpty() ||
text.fontName.size() > 128 ||
text.text.size() > 512 )
1680 throw std::runtime_error(
"invalid component text field string" );
1698 throw std::runtime_error(
"component text field overruns component" );
1700 catch(
const std::exception& )
1713 size_t startOffset =
m_reader.GetOffset();
1759 if( fieldA < 0 || fieldA > 500 )
1781 for(
int i = 0; i < fieldA; i++ )
1800 if( fieldB < 0 || fieldB > 1000 )
1810 for(
int i = 0; i < fieldB; i++ )
1812 if( i == fieldB - 1 )
1833 size_t patternCeiling = std::min( aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize(),
m_reader.GetFileSize() );
1835 for(
size_t p = startOffset + 16; p < patternCeiling; p++ )
1848 auto landingForCeiling = [&]() ->
size_t
1853 return patternCeiling;
1861 const uint8_t* data =
m_reader.GetData();
1862 size_t limit = patternCeiling;
1864 if( startOffset + 63 <= limit && data[startOffset] == 0 && data[startOffset + 1] == 0 )
1866 size_t tailEnd = startOffset + 63;
1875 for(
size_t pos = startOffset; pos + 2 <= limit; pos++ )
1877 int charCount = ( data[pos] << 8 ) | data[pos + 1];
1879 if( charCount < 0 || charCount > 512 )
1882 size_t strEnd = pos + 2 +
static_cast<size_t>( charCount ) * 2;
1884 if( strEnd > limit )
1889 for(
size_t i = pos + 2; i < strEnd; i += 2 )
1891 if( data[i] != 0x00 || data[i + 1] < 0x20 || data[i + 1] > 0x7E )
1901 wxMBConvUTF16BE conv;
1902 wxString modelName(
reinterpret_cast<const char*
>( data + pos + 2 ), conv,
1903 static_cast<size_t>( charCount ) * 2 );
1904 wxString lowerModel = modelName.Lower();
1906 if( !modelName.IsEmpty() && !lowerModel.EndsWith( wxT(
".step" ) )
1907 && !lowerModel.EndsWith( wxT(
".wrl" ) ) )
1912 for(
size_t tailSize : {
static_cast<size_t>( 61 ),
static_cast<size_t>( 28 ) } )
1914 size_t tailEnd = strEnd + tailSize;
1916 if( tailEnd <= limit
1930 m_reader.SetOffset( landingForCeiling() );
1934 auto readCount = [&](
const char* aName,
int aMax ) ->
int
1938 if( count < 0 || count > aMax )
1940 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid embedded pattern %s count %d at "
1941 "offset 0x%06zX." ),
1942 wxString::FromUTF8( aName ), count, startOffset ) );
1948 auto isValidUtf16StringAt = [&](
size_t aOffset ) ->
bool
1950 const uint8_t* data =
m_reader.GetData();
1951 size_t size = std::min( patternCeiling,
m_reader.GetFileSize() );
1953 if( aOffset + 2 > size )
1956 int charCount = ( data[aOffset] << 8 ) | data[aOffset + 1];
1958 if( charCount < 0 || charCount > 512 )
1961 size_t stringEnd = aOffset + 2 +
static_cast<size_t>( charCount ) * 2;
1963 if( stringEnd > size )
1966 for(
size_t i = aOffset + 2; i < stringEnd; i += 2 )
1968 if( data[i] != 0x00 || data[i + 1] < 0x20 || data[i + 1] > 0x7E )
1995 if( !isValidUtf16StringAt(
m_reader.GetOffset() ) )
2014 int aliasCount = readCount(
"alias", 100 );
2016 for(
int i = 0; i < aliasCount; i++ )
2024 if( aliasCount > 0 )
2027 int padCount = readCount(
"pad", 500 );
2039 auto readModernPadRecord = [&]()
2054 auto canReadModernPadRecordAt = [&](
size_t aOffset ) ->
bool
2062 readModernPadRecord();
2063 ok =
m_reader.GetOffset() <= patternCeiling;
2065 catch(
const std::exception& )
2074 for(
int i = 0; i < padCount; i++ )
2076 if(
m_reader.GetOffset() >= patternCeiling || !canReadModernPadRecordAt(
m_reader.GetOffset() ) )
2081 readModernPadRecord();
2083 if( i + 1 < padCount )
2085 size_t tailStart =
m_reader.GetOffset();
2087 if( tailStart + 22 <= patternCeiling && canReadModernPadRecordAt( tailStart + 22 ) )
2094 catch(
const std::exception& )
2101 auto readInt3At = [&](
size_t aOffset ) ->
int
2103 const uint8_t* data =
m_reader.GetData();
2105 return ( ( data[aOffset] << 16 ) | ( data[aOffset + 1] << 8 ) | data[aOffset + 2] ) -
INT3_BIAS;
2108 auto validUtf16StringAt = [&](
size_t aOffset,
size_t aLimit,
size_t& aEnd ) ->
bool
2110 const uint8_t* data =
m_reader.GetData();
2112 if( aOffset + 2 > aLimit )
2115 int charCount = ( data[aOffset] << 8 ) | data[aOffset + 1];
2117 if( charCount < 0 || charCount > 512 )
2120 size_t strEnd = aOffset + 2 +
static_cast<size_t>( charCount ) * 2;
2122 if( strEnd > aLimit )
2125 for(
size_t i = aOffset + 2; i < strEnd; i += 2 )
2127 if( data[i] != 0x00 )
2130 if( charCount > 0 && ( data[i + 1] < 0x20 || data[i + 1] > 0x7E ) )
2138 size_t modelSectionStart = std::string::npos;
2139 size_t modelStringStart = std::string::npos;
2140 size_t patternEnd = std::string::npos;
2141 size_t limit = std::min( patternCeiling,
m_reader.GetFileSize() );
2143 for(
size_t pos =
m_reader.GetOffset(); pos + 3 <= limit; pos++ )
2145 int modelPlacementCount = readInt3At( pos );
2147 if( modelPlacementCount < 0 || modelPlacementCount > 1000 )
2150 size_t afterPlacements = pos + 3 +
static_cast<size_t>( modelPlacementCount ) * 18;
2152 if( afterPlacements + 3 > limit || readInt3At( afterPlacements ) != 0 )
2155 size_t strStart = afterPlacements + 3;
2158 if( !validUtf16StringAt( strStart, limit, strEnd ) )
2161 for(
size_t tailSize : {
static_cast<size_t>( 61 ),
static_cast<size_t>( 28 ) } )
2163 size_t tailEnd = strEnd + tailSize;
2165 if( tailEnd > limit )
2170 modelSectionStart = pos;
2171 modelStringStart = strStart;
2172 patternEnd = tailEnd;
2177 if( modelSectionStart != std::string::npos )
2181 if( modelSectionStart == std::string::npos )
2185 m_reader.SetOffset( landingForCeiling() );
2189 m_reader.SetOffset( modelStringStart );
2203 int busCount =
m_reader.ReadInt3();
2205 if( busCount < 0 || busCount > 1000 )
2207 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid bus count %d." ), busCount ) );
2210 for(
int i = 0; i < busCount; i++ )
2227 int terminator =
m_reader.ReadInt3();
2229 if( terminator != -1 )
2231 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: bus entry %d has "
2232 "unexpected terminator %d." ),
2245 catch(
const std::exception& e )
2247 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: failed to parse bus entry "
2249 i, wxString::FromUTF8( e.what() ) ) );
2257 const uint8_t* data =
m_reader.GetData();
2258 size_t fileSize =
m_reader.GetFileSize();
2260 size_t searchStart =
m_reader.GetOffset();
2262 if( searchStart >= searchEnd )
2267 for(
size_t off = searchStart; off + 5 < searchEnd; off++ )
2269 if( data[off] != 0x0F || data[off + 1] != 0x42 || data[off + 2] != 0x3F )
2272 size_t strOff = off + 3;
2276 if( strOff + 3 > searchEnd )
2279 int n = ( ( data[strOff] << 16 ) | ( data[strOff + 1] << 8 ) | data[strOff + 2] ) -
INT3_BIAS;
2281 if( n < 1 || n > 200 || strOff + 3 + (
size_t) n > fileSize )
2286 for(
int i = 0; i < n; i++ )
2288 uint8_t c = data[strOff + 3 + i];
2290 if( c < 0x20 || c > 0x7E )
2300 wxString
name = wxString::From8BitData(
reinterpret_cast<const char*
>( data + strOff + 3 ), n );
2301 size_t afterStr = strOff + 3 + n;
2306 if( afterStr + 11 <= fileSize )
2310 entry.
field1 = ( ( data[afterStr + 8] << 16 ) | ( data[afterStr + 9] << 8 ) | data[afterStr + 10] )
2314 m_nets.push_back( entry );
2318 if( strOff + 2 > searchEnd )
2321 int n = ( data[strOff] << 8 ) | data[strOff + 1];
2323 if( n < 1 || n > 200 || strOff + 2 + (
size_t) ( n * 2 ) > fileSize )
2328 for(
int i = 0; i < n; i++ )
2330 uint8_t hi = data[strOff + 2 +
static_cast<size_t>( i ) * 2];
2331 uint8_t lo = data[strOff + 2 +
static_cast<size_t>( i ) * 2 + 1];
2333 if( hi != 0 || lo < 0x20 || lo > 0x7E )
2343 wxMBConvUTF16BE conv;
2344 wxString
name(
reinterpret_cast<const char*
>( data + strOff + 2 ), conv,
static_cast<size_t>( n ) * 2 );
2345 size_t afterStr = strOff + 2 +
static_cast<size_t>( n ) * 2;
2350 if( afterStr + 11 <= fileSize )
2353 entry.coordY =
ReadInt4At( data, afterStr + 4 );
2354 entry.field1 = ( ( data[afterStr + 8] << 16 ) | ( data[afterStr + 9] << 8 ) | data[afterStr + 10] )
2358 m_nets.push_back( entry );
2373 if( aOffsetX == 0 && aOffsetY == 0 )
2380 int64_t halfW = aHalfWidth > 0 ? aHalfWidth : 1;
2381 int64_t halfH = aHalfHeight > 0 ? aHalfHeight : 1;
2383 if(
std::abs(
static_cast<int64_t
>( aOffsetX ) ) * halfH >=
std::abs(
static_cast<int64_t
>( aOffsetY ) ) * halfW )
2385 return ( aOffsetX >= 0 ) ? 2 : 0;
2388 return ( aOffsetY >= 0 ) ? 1 : 3;
2394 if( aSheetIndex < 0 )
2400 while( (
int)
m_sheets.size() <= aSheetIndex )
2404 return m_sheets[aSheetIndex]->GetScreen();
2411 sheetName = wxString::Format( wxT(
"Sheet%d" ), aSheetIndex + 1 );
2413 int col = ( aSheetIndex - 1 ) % 4;
2414 int row = ( aSheetIndex - 1 ) / 4;
2415 VECTOR2I pos( 2540000 + col * 50800000, 2540000 + row * 50800000 );
2416 VECTOR2I size( 40640000, 30480000 );
2422 fn.SetName( fn.GetName() + wxString::Format( wxT(
"_%d" ), aSheetIndex ) );
2428 newSheet->
SetName( sheetName );
2441 for(
size_t i = 0; i <
m_sheets.size(); ++i )
2451 wxString pageNumber = wxString::Format( wxT(
"%zu" ), i + 1 );
2453 path.push_back( sheet );
2454 path.SetPageNumber( pageNumber );
2470 std::vector<SCH_SHEET*> topLevelSheets;
2471 topLevelSheets.reserve(
m_sheets.size() );
2476 topLevelSheets.push_back( sheet );
2479 if( !topLevelSheets.empty() )
2488 wxString refdes = aComp.
refdes;
2493 int dot = refdes.Find( wxT(
'.' ),
true );
2495 if( dot <= 0 || dot >=
static_cast<int>( refdes.length() ) - 1 )
2500 if( refdes.Mid( dot + 1 ).ToLong( &suffix ) && suffix >= 1 )
2501 return refdes.Left( dot );
2511 if( base.IsEmpty() )
2514 if( base.IsEmpty() )
2517 if( base.IsEmpty() )
2518 base = wxT(
"Unknown" );
2521 base += wxString::Format( wxT(
"_r%d" ), aComp.
rotationE4 );
2531 if( drawItem.GetUnit() == aUnit )
2541 return static_cast<int>( std::lround( aMm * 30000.0 ) );
2557 shape.
fontX = -20000;
2558 shape.
fontY = 10000;
2559 shape.
points.assign( aPoints.begin(), aPoints.end() );
2566 wxString libPath = aComp.
libPath.Lower();
2567 wxString compName = aComp.
compName.Lower();
2571 return aComp.
shapes.empty() && aComp.
pins.size() == 2 && libPath.Contains( wxT(
"opto_emitters_led_tht" ) )
2572 && compName.StartsWith( wxT(
"led-3mm round" ) );
2600 bool isPower = aComp.
refdes.StartsWith( wxT(
"NetPort" ) );
2604 auto pin = std::make_unique<SCH_PIN>( aLibSymbol );
2606 pin->SetName( dchPin.
name.IsEmpty() ? wxString( wxT(
"~" ) ) : dchPin.
name );
2607 pin->SetNumber( dchPin.
number.IsEmpty() ? wxString( wxT(
"1" ) ) : dchPin.
number );
2626 case 0: connection.
x -= len;
break;
2627 case 2: connection.
x += len;
break;
2628 case 1: connection.
y += len;
break;
2629 case 3: connection.
y -= len;
break;
2632 pin->SetPosition( connection );
2633 pin->SetLength( len );
2644 pin->SetUnit( aUnit );
2648 std::vector<DCH_SHAPE> fallbackShapes;
2659 if( dchShape.points.size() < 2 )
2669 bool isRectangle = dchShape.points.size() == 2 && dchShape.kindCode == 4 && dchShape.kindFlag == 0;
2674 rect->SetParent( aLibSymbol );
2679 rect->SetUnit( aUnit );
2690 bool isEllipse = dchShape.points.size() == 2 && dchShape.kindCode == 6 && dchShape.kindFlag == 0;
2700 circle->SetParent( aLibSymbol );
2704 circle->SetUnit( aUnit );
2713 bool isArc = dchShape.points.size() == 3 && dchShape.kindCode == 2 && dchShape.kindFlag == 0;
2722 arc->SetParent( aLibSymbol );
2723 arc->SetArcGeometry( start, mid,
end );
2725 arc->SetUnit( aUnit );
2731 bool isFilledPolygon = dchShape.points.size() >= 3 && dchShape.kindCode == 8 && dchShape.kindFlag == 0;
2735 poly->SetParent( aLibSymbol );
2737 for(
const VECTOR2I& pt : dchShape.points )
2741 poly->SetUnit( aUnit );
2744 if( dchShape.kindCode == 3 && dchShape.kindFlag == 0 && dchShape.points.size() == 2 )
2748 double dx =
static_cast<double>(
end.x - start.
x );
2749 double dy =
static_cast<double>(
end.y - start.
y );
2750 double len = std::sqrt( dx * dx + dy * dy );
2754 double unitX = dx / len;
2755 double unitY = dy / len;
2756 double arrowLength =
2757 std::min( len / 2.0,
static_cast<double>( std::max( width * 4,
schIUScale.MilsToIU( 35 ) ) ) );
2758 double halfWidth = arrowLength / 2.0;
2759 double baseX =
static_cast<double>(
end.x ) - unitX * arrowLength;
2760 double baseY =
static_cast<double>(
end.y ) - unitY * arrowLength;
2761 double perpX = -unitY;
2762 double perpY = unitX;
2765 arrow->SetParent( aLibSymbol );
2766 arrow->AddPoint(
VECTOR2I(
static_cast<int>( std::lround( baseX + perpX * halfWidth ) ),
2767 static_cast<int>( std::lround( baseY + perpY * halfWidth ) ) ) );
2768 arrow->AddPoint(
end );
2769 arrow->AddPoint(
VECTOR2I(
static_cast<int>( std::lround( baseX - perpX * halfWidth ) ),
2770 static_cast<int>( std::lround( baseY - perpY * halfWidth ) ) ) );
2772 arrow->SetUnit( aUnit );
2797 auto libSymbol = std::make_unique<LIB_SYMBOL>( symName );
2798 libSymbol->SetUnitCount( aUnit,
false );
2801 libSymbol->GetFootprintField().SetText( aComp.
patternName );
2803 bool isPower = aComp.
refdes.StartsWith( wxT(
"NetPort" ) );
2806 libSymbol->SetGlobalPower();
2811 if( !aComp.
pins.empty() )
2812 libSymbol->SetShowPinNames( aComp.
pins.front().netFlagB != 0 );
2827 std::map<int, std::map<int, int>> partSheetVotes;
2831 int sheetIdx = wire.sheetIndex;
2836 for(
const VECTOR2I& pt : wire.points )
2844 if( wire.points.size() >= 2 )
2846 if( wire.object1 >= 0 )
2850 partSheetVotes[wire.object1][sheetIdx]++;
2853 if( wire.object2 >= 0 )
2857 partSheetVotes[wire.object2][sheetIdx]++;
2865 for(
const auto& [partId, sheets] : partSheetVotes )
2870 for(
const auto& [sheet, count] : sheets )
2872 if( count > bestCount )
2886 const uint8_t* data =
m_reader.GetData();
2887 size_t fileSize =
m_reader.GetFileSize();
2889 if( aOffset + 16 > fileSize )
2896 for(
int i = 0; i < 4; i++ )
2898 size_t p = aOffset +
static_cast<size_t>( i ) * 4;
2899 uint32_t raw = (
static_cast<uint32_t
>( data[p] ) << 24 ) | (
static_cast<uint32_t
>( data[p + 1] ) << 16 )
2900 | (
static_cast<uint32_t
>( data[p + 2] ) << 8 ) | data[p + 3];
2901 bbox[i] =
static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
2903 if(
std::abs( bbox[i] ) > 50000000 )
2909 size_t p = aOffset + 16;
2911 for(
int si = 0; si < 5; si++ )
2914 size_t dataStart = 0;
2919 if( p + 3 > fileSize )
2922 charCount = ( ( data[p] << 16 ) | ( data[p + 1] << 8 ) | data[p + 2] ) -
INT3_BIAS;
2927 if( p + 2 > fileSize )
2930 charCount = ( data[p] << 8 ) | data[p + 1];
2934 if( charCount == 0 )
2940 if( charCount < 0 || charCount > 64 )
2943 size_t byteCount = ascii ?
static_cast<size_t>( charCount ) :
static_cast<size_t>( charCount ) * 2;
2945 if( dataStart + byteCount > fileSize )
2948 for(
int k = 0; k < charCount; k++ )
2950 unsigned ch = ascii ? data[dataStart + k]
2951 : ( ( data[dataStart +
static_cast<size_t>( k ) * 2] << 8 )
2952 | data[dataStart +
static_cast<size_t>( k ) * 2 + 1] );
2956 if( ch < 0x20 && ch != 0x09 && ch != 0x0A && ch != 0x0D )
2960 p = dataStart + byteCount;
2994 if( aTally.empty() )
2999 for(
const auto& [ps, count] : aTally )
3000 bestCount = std::max( bestCount, count );
3004 for(
const auto& [ps, count] : aTally )
3014 for(
const auto& [ps, count] : aTally )
3016 if( count == bestCount )
3031 std::map<std::pair<int, int>,
int> tally;
3033 for(
const VECTOR2I& p : aConnectionPoints )
3040 std::set<std::pair<int, int>> seenHere;
3042 for(
const std::pair<int, int>& ps : it->second )
3043 if( seenHere.insert( ps ).second )
3059 std::map<int, int> votes;
3061 for(
const VECTOR2I& p : aPositions )
3068 for(
int sheet : it->second )
3075 int bestSheet = aFallback;
3078 for(
const auto& [sheet, count] : votes )
3080 if( count > bestVotes )
3099 if( aComp.
libPath.Contains( wxT(
"auto_net_ports" ) ) )
3104 bool explicitUnit =
false;
3106 if( refdes != aComp.
refdes )
3110 if( aComp.
refdes.Mid( refdes.length() + 1 ).ToLong( &suffix ) && suffix >= 1 )
3112 unit =
static_cast<int>( suffix ) + 1;
3113 explicitUnit =
true;
3117 if( !refdes.IsEmpty() )
3128 unit = it->second + 1;
3156 if( !refdes.IsEmpty() )
3169 if( !aComp.
value.IsEmpty() )
3180 if( aComp.
refdes.StartsWith( wxT(
"NetPort" ) ) && !aComp.
compName.IsEmpty() )
3191 if( !aComp.
refdes.StartsWith( wxT(
"NetPort" ) ) )
3211 if( extra.first.IsEmpty() || symbol->
GetField( extra.first ) )
3215 userField.
SetText( extra.second );
3225 bool refPositioned =
false;
3226 bool valuePositioned =
false;
3236 else if( txt.
type == 3 )
3253 refPositioned =
true;
3254 refFieldOffset = off;
3256 else if( txt.
type == 3 )
3258 valuePositioned =
true;
3259 valueFieldOffset = off;
3268 if( refPositioned != valuePositioned )
3273 valField->SetPosition( pos +
VECTOR2I( -refFieldOffset.
x, refFieldOffset.
y ) );
3277 refField->SetPosition( pos +
VECTOR2I( -valueFieldOffset.
x, valueFieldOffset.
y ) );
3286 if( !refPositioned && !valuePositioned )
3311 refField->SetPosition( pos + refOffset );
3319 valField->SetPosition( pos + valueOffset );
3357 std::vector<VECTOR2I> connectionPoints;
3366 dir.
x = ( off.
x >= 0 ) ? 1 : -1;
3368 dir.
y = ( off.
y >= 0 ) ? 1 : -1;
3370 connectionPoints.emplace_back(
center.x + off.
x + dir.
x * len,
center.y + off.
y + dir.
y * len );
3379 if( votedSheet < 0 )
3385 int partId = offsetIt->second;
3390 for(
int d = 0; d <= 12 && votedSheet < 0; d++ )
3392 for(
int candidate : { partId - d, partId + d } )
3398 votedSheet = sheetIt->second;
3408 screen->
Append( symbol );
3424 if( !
comp.libPath.Contains( wxT(
"auto_net_ports" ) ) ||
comp.compName.IsEmpty() )
3436 std::vector<VECTOR2I> connectionPoints;
3438 bool havePin =
false;
3447 dir.
x = ( off.
x >= 0 ) ? 1 : -1;
3449 dir.
y = ( off.
y >= 0 ) ? 1 : -1;
3451 connectionPoints.emplace_back( pos.
x + off.
x + dir.
x * len, pos.
y + off.
y + dir.
y * len );
3474 votedSheet = sheetIt->second;
3479 int partId = offsetIt->second;
3481 for(
int d = 1; d <= 12 && votedSheet < 0; d++ )
3483 for(
int candidate : { partId - d, partId + d } )
3489 votedSheet = sheetIt->second;
3500 if( votedSheet < 0 )
3507 VECTOR2I labelPos = ( havePin && !connectionPoints.empty() ) ? connectionPoints.front() : pos;
3513 if( firstPinDir.
x > 0 )
3515 else if( firstPinDir.
x < 0 )
3517 else if( firstPinDir.
y > 0 )
3519 else if( firstPinDir.
y < 0 )
3534 int64_t bestDist = std::numeric_limits<int64_t>::max();
3538 int64_t dx =
static_cast<int64_t
>( pt.first ) - aPos.
x;
3539 int64_t dy =
static_cast<int64_t
>( pt.second ) - aPos.
y;
3540 int64_t dist = dx * dx + dy * dy;
3542 if( dist < bestDist )
3545 bestSheet = *sheets.begin();
3558 if( aPos + 2 > aSectionEnd )
3561 int cnt = ( aData[aPos] << 8 ) | aData[aPos + 1];
3563 if( cnt < 1 || cnt > 64 )
3566 size_t end = aPos + 2 +
static_cast<size_t>( cnt ) * 2;
3568 if(
end + 8 + 3 + 1 + 3 > aSectionEnd )
3571 for(
int i = 0; i < cnt; i++ )
3573 unsigned hi = aData[aPos + 2 +
static_cast<size_t>( i ) * 2];
3574 unsigned lo = aData[aPos + 2 +
static_cast<size_t>( i ) * 2 + 1];
3575 unsigned ch = ( hi << 8 ) | lo;
3577 bool ok = ( ch >= 0x20 && ch < 0x7F )
3578 || ( ch >= 0x00A0 && ch <= 0x024F )
3579 || ( ch >= 0x0400 && ch <= 0x04FF );
3585 auto rdInt4 = [&](
size_t o ) ->
int
3587 uint32_t raw = (
static_cast<uint32_t
>( aData[o] ) << 24 ) | (
static_cast<uint32_t
>( aData[o + 1] ) << 16 )
3588 | (
static_cast<uint32_t
>( aData[o + 2] ) << 8 ) |
static_cast<uint32_t
>( aData[o + 3] );
3589 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
3592 int lx = rdInt4(
end );
3593 int ly = rdInt4(
end + 4 );
3595 auto rdInt3 = [&](
size_t o ) ->
int
3597 return ( ( aData[o] << 16 ) | ( aData[o + 1] << 8 ) | aData[o + 2] ) -
INT3_BIAS;
3600 int pad = rdInt3(
end + 8 );
3606 return lx > -2000000 && lx < 2000000 && ly > -2000000 && ly < 2000000 && (
pad == 0 ||
pad == 1 )
3619 const uint8_t* data =
m_reader.GetData();
3620 size_t fileSize =
m_reader.GetFileSize();
3624 if( sectionStart == 0 || sectionStart >= sectionEnd )
3627 auto rdInt3 = [&](
size_t o ) ->
int
3629 return ( ( data[o] << 16 ) | ( data[o + 1] << 8 ) | data[o + 2] ) -
INT3_BIAS;
3632 auto rdInt4 = [&](
size_t o ) ->
int
3634 uint32_t raw = (
static_cast<uint32_t
>( data[o] ) << 24 ) | (
static_cast<uint32_t
>( data[o + 1] ) << 16 )
3635 | (
static_cast<uint32_t
>( data[o + 2] ) << 8 ) |
static_cast<uint32_t
>( data[o + 3] );
3636 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
3639 static constexpr uint8_t WIRE_NET_MARKER[] = { 0x0F, 0x42, 0x3F };
3640 static constexpr size_t WIRE_NET_MARKER_LEN =
sizeof( WIRE_NET_MARKER );
3642 auto isExpectedWireNetMarker = [&](
size_t aMarkerOffset,
int aExpectedIndex ) ->
bool
3644 if( aMarkerOffset < 13 || aMarkerOffset + WIRE_NET_MARKER_LEN > sectionEnd )
3647 if( memcmp( data + aMarkerOffset, WIRE_NET_MARKER, WIRE_NET_MARKER_LEN ) != 0 )
3650 if( data[aMarkerOffset - 13] != 0x01 )
3653 int fieldA = rdInt3( aMarkerOffset - 9 );
3654 int fieldB = rdInt3( aMarkerOffset - 6 );
3655 int netIndex = rdInt3( aMarkerOffset - 3 );
3657 if( netIndex != aExpectedIndex )
3664 return fieldA >= -1 && fieldA <= 100000 && fieldB >= -1 && fieldB <= 100000;
3667 auto decodeWireNetName = [&](
size_t aNameOffset, wxString& aName,
size_t& aAfterName, wxString& aError ) ->
bool
3669 if( aNameOffset + 2 > sectionEnd )
3671 aError = wxT(
"missing UTF-16 length" );
3675 int nameLen = ( data[aNameOffset] << 8 ) | data[aNameOffset + 1];
3677 if( nameLen < 1 || nameLen > 64 )
3679 aError = wxString::Format( wxT(
"invalid UTF-16 length %d" ), nameLen );
3683 aAfterName = aNameOffset + 2 +
static_cast<size_t>( nameLen ) * 2;
3685 if( aAfterName + 8 + 3 + 1 + 3 > sectionEnd )
3687 aError = wxT(
"name overruns wire-net record" );
3691 for(
int i = 0; i < nameLen; i++ )
3693 unsigned hi = data[aNameOffset + 2 +
static_cast<size_t>( i ) * 2];
3694 unsigned lo = data[aNameOffset + 2 +
static_cast<size_t>( i ) * 2 + 1];
3695 unsigned ch = ( hi << 8 ) | lo;
3698 ( ch >= 0x20 && ch < 0x7F ) || ( ch >= 0x00A0 && ch <= 0x024F ) || ( ch >= 0x0400 && ch <= 0x04FF );
3702 aError = wxString::Format( wxT(
"invalid UTF-16 character 0x%04X" ), ch );
3707 wxMBConvUTF16BE conv;
3708 aName = wxString(
reinterpret_cast<const char*
>( data + aNameOffset + 2 ), conv,
3709 static_cast<size_t>( nameLen ) * 2 );
3714 auto findNextWireNetName = [&](
size_t aSearchStart,
size_t aSearchEnd,
int aExpectedIndex ) ->
size_t
3716 if( aSearchStart >= aSearchEnd )
3719 for(
size_t marker = aSearchStart; marker + WIRE_NET_MARKER_LEN <= aSearchEnd; marker++ )
3721 if( memcmp( data + marker, WIRE_NET_MARKER, WIRE_NET_MARKER_LEN ) != 0 )
3724 if( !isExpectedWireNetMarker( marker, aExpectedIndex ) )
3727 size_t nameOffset = marker + WIRE_NET_MARKER_LEN;
3728 wxString candidateName;
3730 size_t afterName = 0;
3732 if( !decodeWireNetName( nameOffset, candidateName, afterName, nameError ) )
3734 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire-net name for net index %d at "
3735 "offset 0x%06zX: %s." ),
3736 aExpectedIndex, nameOffset, nameError ) );
3747 int expectedWireNetIndex = 0;
3748 size_t pos = findNextWireNetName( sectionStart, sectionEnd, expectedWireNetIndex );
3754 size_t lastRecordEnd = 0;
3756 while( pos != 0 && pos < sectionEnd && safetyNets++ < 100000 )
3763 size_t afterName = 0;
3765 if( !decodeWireNetName( o, netName, afterName, nameError ) )
3767 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire-net name for net index %d at "
3768 "offset 0x%06zX: %s." ),
3769 expectedWireNetIndex, o, nameError ) );
3775 if( o + 3 > sectionEnd )
3778 int pinCount = rdInt3( o );
3779 size_t pinCountOffset = o;
3782 if( pinCount < 0 || pinCount > 4000 || o +
static_cast<size_t>( pinCount ) * 6 + 3 > sectionEnd )
3784 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire-net pin count %d for net '%s' at "
3785 "offset 0x%06zX." ),
3786 pinCount, netName, pinCountOffset ) );
3789 o +=
static_cast<size_t>( pinCount ) * 6;
3791 int wireCount = rdInt3( o );
3792 size_t wireCountOffset = o;
3795 if( wireCount < 0 || wireCount > 100000 )
3797 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire count %d for net '%s' at offset "
3799 wireCount, netName, wireCountOffset ) );
3802 bool brokeEarly =
false;
3804 for(
int w = 0; w < wireCount; w++ )
3806 if( o + 36 + 1 + 3 > sectionEnd )
3813 wire.
object1 = rdInt3( o + 0 );
3814 wire.
object2 = rdInt3( o + 3 );
3817 wire.
bus1 = rdInt3( o + 12 );
3818 wire.
bus2 = rdInt3( o + 15 );
3824 int pointCount = rdInt3( o );
3825 size_t pointCountOffset = o;
3828 if( pointCount < 0 || pointCount > 4000 || o +
static_cast<size_t>( pointCount ) * 11 + 8 > sectionEnd )
3830 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire point count %d for net '%s' at "
3831 "offset 0x%06zX." ),
3832 pointCount, netName, pointCountOffset ) );
3835 wire.
points.reserve( pointCount );
3837 for(
int p = 0; p < pointCount; p++ )
3839 int dtX = rdInt4( o );
3840 int dtY = rdInt4( o + 4 );
3852 if( wire.
points.size() >= 2 )
3858 m_wires.push_back( std::move( wire ) );
3866 expectedWireNetIndex++;
3869 pos = findNextWireNetName( o, std::min( sectionEnd, o + 400 ), expectedWireNetIndex );
3886 if( searchStart == 0 || searchStart >= sectionEnd )
3889 size_t originalOffset =
m_reader.GetOffset();
3891 auto readSheetShapeRecord = [&]() -> std::optional<DCH_SHEET_SHAPE>
3893 uint8_t flagA =
m_reader.ReadByte();
3894 uint8_t flagB =
m_reader.ReadByte();
3896 int kindCode =
m_reader.ReadInt3();
3897 int drawOrder =
m_reader.ReadInt3();
3901 uint8_t color[3] = {};
3907 int sheetIndex =
m_reader.ReadInt3();
3909 int lineWidth =
m_reader.ReadInt4();
3913 int pointCount =
m_reader.ReadInt3();
3915 if( flagA != 1 || flagB != 0 || fieldA != 0 || fieldB != 0 || fieldC != -1 || fieldD != 0 )
3916 return std::nullopt;
3918 if( kindCode != 1 && kindCode != 4 )
3919 return std::nullopt;
3921 if( drawOrder < 0 || drawOrder > 1000 || sheetIndex < 0 || sheetIndex >=
m_numSheets )
3922 return std::nullopt;
3924 if( lineWidth < 0 || lineWidth > 200000 || pointCount < 1 || pointCount > 100 )
3925 return std::nullopt;
3931 shape.
color[0] = color[0];
3932 shape.
color[1] = color[1];
3933 shape.
color[2] = color[2];
3934 shape.
points.reserve( pointCount );
3936 for(
int i = 0; i < pointCount; i++ )
3940 shape.
points.emplace_back( x, y );
3945 uint8_t tailFlagA =
m_reader.ReadByte();
3946 uint8_t tailFlagB =
m_reader.ReadByte();
3950 if( tailA != -1 || tailB != -1 || tailFlagA != 0 || tailFlagB != 1 || extentX != -20000 || extentY != 10000 )
3951 return std::nullopt;
3956 for(
size_t offset = searchStart; offset + 3 < sectionEnd; offset++ )
3963 if( count < 1 || count > 1000 )
3966 std::vector<DCH_SHEET_SHAPE> shapes;
3967 shapes.reserve( count );
3971 for(
int i = 0; i < count; i++ )
3973 std::optional<DCH_SHEET_SHAPE> shape = readSheetShapeRecord();
3981 shapes.push_back( *shape );
3984 if( valid && !shapes.empty() &&
m_reader.GetOffset() <= sectionEnd )
3990 catch(
const std::exception& )
3995 m_reader.SetOffset( originalOffset );
4009 if( dchShape.points.size() < 2 )
4020 if( dchShape.kindCode == 4 && dchShape.points.size() == 2 )
4032 if( dchShape.kindCode == 1 )
4036 for(
const VECTOR2I& pt : dchShape.points )
4052 int sheetIdx = wire.sheetIndex;
4062 for(
size_t i = 1; i < wire.points.size(); i++ )
4082 std::set<SCH_SCREEN*> screens;
4089 if( sheet && sheet->GetScreen() )
4090 screens.insert( sheet->GetScreen() );
4093 std::map<SCH_SCREEN*, std::set<std::pair<int, int>>> junctions;
4099 std::deque<EDA_ITEM*> items;
4101 for(
SCH_ITEM* item : screen->Items() )
4102 items.push_back( item );
4104 for(
const VECTOR2I& pt : screen->GetNeededJunctions( items ) )
4105 junctions[screen].insert( { pt.x, pt.y } );
4112 std::map<SCH_SCREEN*, std::set<std::pair<int, int>>> interior;
4116 int sheetIdx = ( aWire.sheetIndex >= 0 && aWire.sheetIndex <
m_numSheets ) ? aWire.sheetIndex : 0;
4127 for(
size_t i = 1; i + 1 < wire.points.size(); i++ )
4130 interior[screen].insert( { p.
x, p.
y } );
4138 if( !screen || wire.points.empty() )
4141 const std::set<std::pair<int, int>>& sheetInterior = interior[screen];
4143 if( wire.bus1 != -1 )
4147 if( sheetInterior.count( { p.x, p.y } ) )
4148 junctions[screen].insert( { p.
x, p.
y } );
4151 if( wire.bus2 != -1 )
4155 if( sheetInterior.count( { p.x, p.y } ) )
4156 junctions[screen].insert( { p.
x, p.
y } );
4160 for(
const auto& [screen, pts] : junctions )
4162 for(
const std::pair<int, int>& pt : pts )
4180 symbol->SetLibSymbol(
new LIB_SYMBOL( *libIt->second ) );
4213 std::set<SCH_SCREEN*> screens;
4220 if( sheet && sheet->GetScreen() )
4221 screens.insert( sheet->GetScreen() );
4225 screen->SetPageSettings( pageInfo );
4242 catch(
const std::exception& e )
4246 m_reporter->Report( wxString::Format(
_(
"DipTrace import: failed to create symbol "
4247 "for %s (%s): %s" ),
4248 comp.refdes,
comp.compName, wxString::FromUTF8( e.what() ) ),
4266 m_reporter->Report( wxString::Format(
_(
"DipTrace import: loaded %zu components, %zu buses, "
4267 "%zu net-port labels from version %d file with %d sheets." ),
constexpr EDA_IU_SCALE schIUScale
void SetPageNumber(const wxString &aPageNumber)
constexpr size_type GetWidth() const
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
void parseOneComponent(size_t aCompEnd, bool aUseCompEnd=true)
static int toKiCadCoordY(int aDipTraceCoord)
std::map< wxString, int > m_refdesUnitMap
Map from refdes to the number of units already created for multi-unit symbols.
void parsePreComponentSettings()
std::vector< DCH_SHEET_DEF > m_sheetDefs
int sheetForNearestWire(const VECTOR2I &aPos) const
Sheet whose decoded wire geometry is closest to aPos, or -1 when no wire exists.
bool isShapeStart(size_t aOffset) const
Check if the data at the given offset looks like a shape/polyline start.
void parseFontBearingShape(DCH_COMPONENT &aComp)
static int pinOrientationFromOffset(int aOffsetX, int aOffsetY, int aHalfWidth, int aHalfHeight)
Determine the pin orientation from the pin connection-point offset relative to the symbol body center...
void buildWirePointSheets()
Build the maps from wire-point position to the sheet(s) and part(s) connecting there,...
void createWires()
Emit SCH_LINE wire segments decoded from the net/wire section.
bool parseComponentTextField(DCH_COMPONENT &aComp, size_t aCompEnd)
size_t m_netPortLabelCount
Count of net-port labels emitted, for the import summary report.
wxString normalizedRefdes(const DCH_COMPONENT &aComp) const
std::vector< size_t > scanComponentBoundaries(size_t aFirstComp, size_t aBusSectionOffset) const
Pre-scan the file to find component start offsets using the bbox(4*int4) + 5-string pattern.
wxString componentSymbolName(const DCH_COMPONENT &aComp) const
Library symbol name for a component.
void parseComponents(size_t aBusSectionOffset)
void createJunctions()
Synthesize junctions where conductors coincide (DipTrace stores none explicitly).
void createSymbolInstance(const DCH_COMPONENT &aComp, SCH_SCREEN *aFallbackScreen)
Create a SCH_SYMBOL instance on the given screen from a DipTrace component.
std::vector< DCH_NET_ENTRY > m_nets
int sheetForComponentPins(const std::vector< VECTOR2I > &aConnectionPoints)
Resolve a symbol's sheet from its pin connection points.
DCH_PAGE m_page
Decoded page geometry and the resulting half-page placement offset (KiCad nm).
void syncEmbeddedLibrarySymbols()
size_t findTailStart() const
Find where the int3(0) tail padding begins by scanning backward from the end of file.
bool isComponentHeaderAt(size_t aOffset) const
True if a component record header (placement + five header strings) starts at aOffset.
static int toKiCadSize(int aDipTraceCoord)
Convert a DipTrace length or stroke width to KiCad schematic internal units.
void buildComponentPartIds()
Enumerate every component header in the file (real components and net ports alike) so each component'...
std::map< wxString, std::vector< SCH_SYMBOL * > > m_placedSymbolsByLibName
std::map< size_t, int > m_offsetToPartId
Component start offset -> DipTrace part id (its index in the in-file component order).
void parseDisplaySettings()
size_t findBusSection(size_t aSearchStart) const
Find the bus section start offset by searching for the characteristic marker pattern: int4(10000) int...
void assignSheetPageNumbers()
size_t m_busSectionOffset
void createNetPortLabels()
Create a global net label for every DipTrace net-port component (auto_net_ports library).
void Parse()
Parse the .dch file and populate the schematic with KiCad objects.
std::map< std::pair< int, int >, std::vector< std::pair< int, int > > > m_pointPartSheets
Wire-endpoint position (KiCad nm) -> (partId, sheet) pairs of the parts connecting there.
std::vector< DCH_WIRE > m_wires
wxString getLibName() const
Build a library name string for the import.
VECTOR2I applyPageOffset(const VECTOR2I &aPos) const
Apply the page-center offset to an absolute KiCad-nm placement so 0,0-centered DipTrace content lands...
size_t m_componentSectionStart
File offset of the component section start, used to enumerate components in part-id order.
bool isFontBearingShapeStart(size_t aOffset) const
std::set< wxString > m_netPortNames
Names of nets that own a placed net-port component; these are the only nets DipTrace draws a label fo...
std::vector< SCH_SHEET * > m_sheets
One per DipTrace sheet.
PROGRESS_REPORTER * m_progressReporter
void createKiCadObjects()
Create KiCad objects from the parsed intermediate data and add them to the appropriate schematic shee...
int m_lastSymbolPartId
Largest part id assigned to a symbol so far; enforces the monotonic part-id order used to disambiguat...
int resolveSheetTally(const std::map< std::pair< int, int >, int > &aTally)
Resolve a (partId, sheet) -> hit-count tally to a sheet, preferring the highest-count pair with a par...
size_t m_wireSectionEnd
End offset of the decoded wire section; the sheet-shape section follows it in modern files.
void parseShape(DCH_COMPONENT &aComp)
void populateLibSymbolUnit(LIB_SYMBOL *aLibSymbol, const DCH_COMPONENT &aComp, int aUnit)
void findPageGeometry()
Locate the page-geometry record (width/height/margins, each mm*30000) in the binary and fill m_page.
std::map< int, int > m_partIdSheet
DipTrace part id -> sheet index, resolved from the wire connectivity.
int sheetForPositions(const std::vector< VECTOR2I > &aPositions, int aFallback) const
Pick the sheet a placed item belongs to by matching its connection points against the decoded wire ge...
void parseSheetDefinitions()
std::vector< DCH_SHEET_SHAPE > m_sheetShapes
SCH_SCREEN * getOrCreateSheet(int aSheetIndex)
Get or create the KiCad sheet and screen for the given DipTrace sheet index.
void parsePin(int aPinIndex, DCH_COMPONENT &aComp)
std::vector< DCH_COMPONENT > m_components
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > m_libSymbols
Symbol library cache.
void parseEmbeddedPattern(DCH_COMPONENT &aComp, size_t aCompEnd)
LIB_SYMBOL * getOrCreateLibSymbol(const DCH_COMPONENT &aComp, int aUnit)
Create a LIB_SYMBOL from the DipTrace component data.
static int toKiCadCoordX(int aDipTraceCoord)
Convert a DipTrace coordinate to KiCad schematic internal units.
SCH_PARSER(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, PROGRESS_REPORTER *aProgressReporter=nullptr, REPORTER *aReporter=nullptr)
std::vector< DCH_BUS_ENTRY > m_buses
void finalizeFlatSheetOrder()
std::map< std::pair< int, int >, std::set< int > > m_wirePointSheets
Wire-point position (KiCad nm) -> set of sheet indices carrying a wire there.
int m_componentBoundaryScanCount
virtual void SetEnd(const VECTOR2I &aEnd)
virtual void SetVisible(bool aVisible)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
A color representation with 4 components: red, green, blue, alpha.
A logical library item identifier and consists of various portions much like a URI.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Define a library symbol object.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
void SetUnitCount(int aCount, bool aDuplicateDrawItems)
Set the units per symbol count.
const BOX2I GetBodyBoundingBox(int aUnit, int aBodyStyle, bool aIncludePins, bool aIncludePrivateItems) const
Get the symbol bounding box excluding fields.
int GetUnitCount() const override
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Describe the page size and margins of a paper page on which to eventually print or plot.
void SetWidthMM(double aWidthInMM)
void SetHeightMM(double aHeightInMM)
A progress reporter interface for use in multi-threaded environments.
A pure virtual class used to derive REPORTER objects from.
Holds all the data relating to one schematic.
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
void SetShape(LABEL_FLAG_SHAPE aShape)
Segment description base class to describe items which have 2 end points (track, wire,...
void SetEndPoint(const VECTOR2I &aPosition)
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
void SetPosition(const VECTOR2I &aPos) override
void SetStroke(const STROKE_PARAMS &aStroke) override
void AddPoint(const VECTOR2I &aPosition)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
void SetFileName(const wxString &aFilename)
void SetName(const wxString &aName)
SCH_SCREEN * GetScreen() const
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
bool IsVirtualRootSheet() const
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void SetFootprintFieldText(const wxString &aFootprint)
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Simple container to manage line stroke parameters.
static const uint8_t TAHOMA_FONT_PATTERN[]
UTF-16BE pattern for the string "Tahoma" as stored in v46+ component font blocks.
static constexpr int SCHEMATIC_UTF16_STRING_VERSION
static VECTOR2I dipTraceShapePoint(double aXmm, double aYmm)
static constexpr int V31_CUTOVER
Structural layout version threshold for the .dch schematic format.
static bool isPlausibleNetName(const uint8_t *aData, size_t aPos, size_t aSectionEnd)
static KIGFX::COLOR4D dipTraceSheetShapeColor(const DCH_SHEET_SHAPE &aShape)
static bool libSymbolHasUnit(const LIB_SYMBOL *aLibSymbol, int aUnit)
static int dipTraceMm(double aMm)
static bool needsStandardThtLedShape(const DCH_COMPONENT &aComp)
static int ReadInt4At(const uint8_t *aData, size_t aPos)
Decode a 4-byte big-endian biased integer from raw data at a given offset.
static std::vector< DCH_SHAPE > standardThtLedShapes()
static DCH_SHAPE makeDipTraceShape(int aKindCode, double aLineWidthMm, std::initializer_list< VECTOR2I > aPoints)
static constexpr EDA_ANGLE ANGLE_VERTICAL
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
@ FILLED_SHAPE
Fill with object color.
static std::map< FOOTPRINT *, int > componentShapes
Association between shape names (using shapeName index) and components.
static const std::string KiCadSchematicFileExtension
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
constexpr int INT4_BIAS
Bias value added to stored 4-byte unsigned integers.
constexpr int LEGACY_STRING_VERSION
Format version at or below which strings use the legacy ASCII encoding (int3 byte-count + raw ASCII b...
constexpr int INT3_BIAS
Bias value added to stored 3-byte unsigned integers.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
@ PIN_RIGHT
The pin extends rightwards from the connection point.
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
A bus entry as read from the bus section.
A stored component text field record that precedes the embedded footprint pattern.
A component as read from the .dch file.
wxString patternName
Embedded footprint pattern name (e.g. "LED100", "CR0805")
std::vector< DCH_COMPONENT_TEXT > texts
int rotationE4
Placement rotation in radians x 1e4 (0, 15708, 31416, 47124)
std::vector< DCH_SHAPE > shapes
std::vector< std::pair< wxString, wxString > > additionalFields
User-defined additional fields, as (name, value) pairs (e.g. "Part Number (Digi-Key)").
wxString datasheet
Datasheet URL stored in the placement tail.
std::vector< DCH_PIN > pins
A net label/wire entry from the net section.
A component pin as stored in the .dch file.
int x
DipTrace coordinate units (100/3 nm)
A graphical shape primitive (polyline) in a component.
std::vector< VECTOR2I > points
Points in DipTrace coord units.
int kindFlag
Leading kind int3; observed 0 for decoded drawing shapes.
int kindCode
Leading kind int3: 1 line, 3 arrow, 4 rect, 6 obround, 8 filled polygon, 9 outline polygon/polyline.
Sheet definition as read from the file header.
A top-level schematic sheet graphical primitive.
int kindCode
1 line, 4 rectangle.
std::vector< VECTOR2I > points
Points in DipTrace coord units.
A single schematic wire decoded from the net/wire section.
int object1
Connected item id at endpoint 1.
int sheetIndex
DipTrace sheet index.
std::vector< VECTOR2I > points
KiCad nm, ready for SCH_LINE.
int subObject1
Pin/sub index at endpoint 1.
int bus1
Bus index at endpoint 1 (-1 = none)
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
CADSTAR_ARCHIVE_PARSER::VERTEX_TYPE vt
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
VECTOR2< int32_t > VECTOR2I
Definition of file extensions used in Kicad.