37#include <wx/filename.h>
103 return static_cast<int>(
static_cast<int64_t
>( aDipTraceCoord ) / 3 );
113 return static_cast<int>(
static_cast<int64_t
>( aDipTraceCoord ) / 3 );
119 return static_cast<int>(
static_cast<int64_t
>(
std::abs( aDipTraceCoord ) ) / 3 );
128 const uint8_t* data =
m_reader.GetData();
129 size_t fileSize =
m_reader.GetFileSize();
131 auto rdInt4 = [&](
size_t o ) ->
int
133 uint32_t raw = (
static_cast<uint32_t
>( data[o] ) << 24 ) | (
static_cast<uint32_t
>( data[o + 1] ) << 16 )
134 | (
static_cast<uint32_t
>( data[o + 2] ) << 8 ) |
static_cast<uint32_t
>( data[o + 3] );
135 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
141 static constexpr int UNITS_PER_MM = 30000;
143 for(
size_t o = 0; o + 24 <= fileSize; o++ )
146 int h = rdInt4( o + 4 );
148 if( w <= 0 || h <= 0 || ( w % UNITS_PER_MM ) != 0 || ( h % UNITS_PER_MM ) != 0 )
151 int wmm = w / UNITS_PER_MM;
152 int hmm = h / UNITS_PER_MM;
154 if( wmm < 50 || wmm > 2000 || hmm < 50 || hmm > 2000 )
157 int margins[4] = { rdInt4( o + 8 ), rdInt4( o + 12 ), rdInt4( o + 16 ), rdInt4( o + 20 ) };
158 bool sane = margins[0] > 0;
160 for(
int m : margins )
162 if( m < 0 || ( m % UNITS_PER_MM ) != 0 || m / UNITS_PER_MM > 100 )
192 wxString libName =
m_schematic->Project().GetProjectName();
194 if( libName.IsEmpty() )
197 libName = fn.GetName();
200 if( libName.IsEmpty() )
201 libName = wxT(
"noname" );
203 libName += wxT(
"-diptrace-import" );
234 size_t compSectionStart =
m_reader.GetOffset();
236 bool hasBusSection =
false;
270 catch(
const std::exception& e )
272 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: unexpected error at offset 0x%06zX: %s" ),
273 m_reader.GetOffset(), wxString::FromUTF8( e.what() ) ) );
282 uint8_t magicLen =
m_reader.ReadByte();
284 if( magicLen != 7 && magicLen != 11 )
286 THROW_IO_ERROR( wxString::Format(
_(
"Invalid DipTrace schematic magic length: %d (expected 7 or 11)." ),
290 std::vector<uint8_t> magicBuf( magicLen );
291 m_reader.ReadBytes( magicBuf.data(), magicLen );
293 if( memcmp( magicBuf.data(),
"DTSCHEM", 7 ) != 0 )
294 THROW_IO_ERROR(
_(
"Invalid DipTrace schematic file: bad magic header." ) );
304 const uint8_t* suffix = magicBuf.data() + 7;
306 if( !std::isdigit( suffix[0] ) || suffix[1] !=
'.' || !std::isdigit( suffix[2] ) || !std::isdigit( suffix[3] ) )
308 THROW_IO_ERROR(
_(
"Invalid DipTrace schematic file: bad legacy version suffix." ) );
312 m_version = ( suffix[2] -
'0' ) * 10 + ( suffix[3] -
'0' );
342 for(
int i = 0; i < 5; i++ )
356 uint8_t extraHdr[4] = {};
359 uint32_t extraChars = ( extraHdr[0] << 24 ) | ( extraHdr[1] << 16 ) | ( extraHdr[2] << 8 ) | extraHdr[3];
363 if( extraChars > 0 && extraChars < 1000 )
364 m_reader.Skip(
static_cast<size_t>( extraChars ) * 2 );
379 int numStyles =
m_reader.ReadInt3();
381 if( numStyles < 0 || numStyles > 2000 )
383 THROW_IO_ERROR( wxString::Format(
_(
"Invalid text style count: %d." ), numStyles ) );
386 for(
int i = 0; i < numStyles; i++ )
413 for(
int i = 0; i < 5; i++ )
432 for(
int i = 0; i < 5; i++ )
448 const uint8_t* data =
m_reader.GetData();
449 size_t fileSize =
m_reader.GetFileSize();
451 static const uint8_t marker[] = { 0x3B, 0x9A, 0xF1, 0x10, 0x3B, 0x9A, 0xF1, 0x10, 0x00, 0x00 };
452 static constexpr size_t markerLen =
sizeof( marker );
454 if( aSearchStart + markerLen + 3 >= fileSize )
457 for(
size_t off = aSearchStart; off < fileSize - markerLen - 3; off++ )
459 if( memcmp( data + off, marker, markerLen ) == 0 )
461 int count = ( ( data[off + 10] << 16 ) | ( data[off + 11] << 8 ) | data[off + 12] ) -
INT3_BIAS;
463 if( count >= 0 && count <= 1000 )
466 if( count > 1000 && count <= 10000 )
468 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid bus count %d." ), count ) );
479 const uint8_t* data =
m_reader.GetData();
480 size_t fileSize =
m_reader.GetFileSize();
485 size_t off = fileSize - 3;
489 if( data[off] == 0x0F && data[off + 1] == 0x42 && data[off + 2] == 0x40 )
495 size_t tailStart = off + 3;
496 size_t tailCount = ( fileSize - tailStart ) / 3;
498 return ( tailCount > 1 ) ? tailStart : fileSize;
509 std::vector<size_t> boundaries;
511 size_t off = aFirstComp;
512 size_t end = ( aBusSectionOffset > 20 ) ? aBusSectionOffset - 20 : 0;
518 boundaries.push_back( off );
533 const uint8_t* data =
m_reader.GetData();
534 size_t fileSize =
m_reader.GetFileSize();
538 if( aOffset + 19 > fileSize )
541 int z1 = ( ( data[aOffset + 6] << 16 ) | ( data[aOffset + 7] << 8 ) | data[aOffset + 8] ) -
INT3_BIAS;
542 int z2 = ( ( data[aOffset + 9] << 16 ) | ( data[aOffset + 10] << 8 ) | data[aOffset + 11] ) -
INT3_BIAS;
544 if( z1 != 0 || z2 != 0 )
547 int w = ( ( data[aOffset + 12] << 24 ) | ( data[aOffset + 13] << 16 ) | ( data[aOffset + 14] << 8 )
548 | data[aOffset + 15] )
551 if( w < 0 || w > 200000 )
554 int npts = ( ( data[aOffset + 16] << 16 ) | ( data[aOffset + 17] << 8 ) | data[aOffset + 18] ) -
INT3_BIAS;
556 return npts >= 1 && npts <= 100;
560 if( aOffset + 17 > fileSize )
563 if( data[aOffset + 6] != 0 || data[aOffset + 7] != 0 || data[aOffset + 8] != 0 || data[aOffset + 9] != 0 )
568 int w = ( ( data[aOffset + 10] << 24 ) | ( data[aOffset + 11] << 16 ) | ( data[aOffset + 12] << 8 )
569 | data[aOffset + 13] )
572 if( w < 0 || w > 200000 )
575 int npts = ( ( data[aOffset + 14] << 16 ) | ( data[aOffset + 15] << 8 ) | data[aOffset + 16] ) -
INT3_BIAS;
577 return npts >= 1 && npts <= 100;
587 const uint8_t* data =
m_reader.GetData();
588 size_t fileSize =
m_reader.GetFileSize();
590 static constexpr uint8_t
TAHOMA_FONT_PATTERN[] = { 0x00, 0x06, 0x00, 0x54, 0x00, 0x61, 0x00,
591 0x68, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61 };
593 if( aOffset + 29 > fileSize )
596 int sentinel = ( ( data[aOffset] << 16 ) | ( data[aOffset + 1] << 8 ) | data[aOffset + 2] ) -
INT3_BIAS;
597 int shapeField = ( ( data[aOffset + 3] << 16 ) | ( data[aOffset + 4] << 8 ) | data[aOffset + 5] ) -
INT3_BIAS;
599 if( sentinel != 1000000 || shapeField != 0 )
607 if( data[aOffset + 20] != 0 || data[aOffset + 21] != 0 )
610 int lineWidth = ( ( data[aOffset + 22] << 24 ) | ( data[aOffset + 23] << 16 ) | ( data[aOffset + 24] << 8 )
611 | data[aOffset + 25] )
614 if( lineWidth < 0 || lineWidth > 200000 )
617 int numPoints = ( ( data[aOffset + 26] << 16 ) | ( data[aOffset + 27] << 8 ) | data[aOffset + 28] ) -
INT3_BIAS;
619 return numPoints >= 1 && numPoints <= 100;
625 size_t compSectionStart =
m_reader.GetOffset();
636 bool desynced =
false;
640 size_t compStart =
m_reader.GetOffset();
647 catch(
const std::exception& )
653 if(
m_reader.GetOffset() <= compStart )
664 m_reader.SetOffset( compSectionStart );
674 for(
size_t ci = 0; ci < compStarts.size(); ci++ )
676 size_t compEnd = ( ci + 1 < compStarts.size() ) ? compStarts[ci + 1] : aBusSectionOffset;
680 m_reader.SetOffset( compStarts[ci] );
687 catch(
const std::exception& e )
690 wxString::Format(
_(
"DipTrace import: failed to parse component %zu at offset 0x%06zX: %s" ), ci,
691 compStarts[ci], wxString::FromUTF8( e.what() ) ) );
698 wxString::Format(
_(
"DipTrace import: found %zu components, but the file header declares %d." ),
706 static bool s_dumpComponents = std::getenv(
"KICAD_DIPTRACE_DUMP_COMPONENTS" ) !=
nullptr;
707 static bool s_dumpComponentDetail = std::getenv(
"KICAD_DIPTRACE_DUMP_COMPONENT_DETAIL" ) !=
nullptr;
719 size_t componentCeiling = aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize();
723 for(
size_t p =
comp.fileOffset + 16; p < componentCeiling; p++ )
727 componentCeiling = p;
733 auto dumpDetail = [&](
const wxString& aMsg )
737 m_reporter->Report( wxString::Format( wxT(
"DipTrace SCH detail @0x%06zX: %s" ),
comp.fileOffset, aMsg ),
752 dumpDetail( wxString::Format( wxT(
"hdr end=0x%06zX name='%s' ref='%s' value='%s' prefix='%s'" ),
761 if( s_dumpComponentDetail )
763 dumpDetail( wxString::Format( wxT(
"post-hdr end=0x%06zX postA=%d postB=%d flag1=%d "
764 "postC=%d postD=%d" ),
765 m_reader.GetOffset(), postA, postB, flag1, postC, postD ) );
772 comp.isMultiPart = ( pb1 == 1 );
775 int partFieldB =
m_reader.ReadInt3();
776 int partFieldC =
m_reader.ReadInt3();
777 int partBboxX1 =
m_reader.ReadInt4();
778 int partBboxY1 =
m_reader.ReadInt4();
779 int partBboxX2 =
m_reader.ReadInt4();
780 int partBboxY2 =
m_reader.ReadInt4();
783 wxString partTailStr;
785 if(
comp.isMultiPart )
788 partTailStr =
comp.partId;
794 size_t partTailStart =
m_reader.GetOffset();
800 if( partTailInt > 0 && partTailInt < 256 )
802 size_t strStart = partTailStart + 3;
803 size_t strEnd = strStart +
static_cast<size_t>( partTailInt );
804 const uint8_t* data =
m_reader.GetData();
805 size_t fileSize =
m_reader.GetFileSize();
807 if( strEnd + 3 <= fileSize )
809 bool asciiPayload =
true;
811 for(
size_t i = strStart; i < strEnd; i++ )
815 if( c < 0x20 || c > 0x7E )
817 asciiPayload =
false;
825 ( ( data[strEnd] << 16 ) | ( data[strEnd + 1] << 8 ) | data[strEnd + 2] ) -
INT3_BIAS;
827 if( nextInt3 >= -1 && nextInt3 < 1000 )
829 m_reader.SetOffset( partTailStart );
830 partTailStr =
m_reader.ReadString();
846 dumpDetail( wxString::Format( wxT(
"part end=0x%06zX part='%s' partNum='%s' sheet=%d "
847 "isMulti=%d partFieldB=%d partFieldC=%d "
848 "partBBox=[%d,%d,%d,%d] fieldD=%d fieldE=%d" ),
850 comp.isMultiPart ? 1 : 0, partFieldB, partFieldC, partBboxX1, partBboxY1, partBboxX2,
851 partBboxY2, fieldD, fieldE ) );
855 dumpDetail( wxString::Format( wxT(
"part-tail end=0x%06zX partTailInt=%d partTailStr='%s'" ),
856 m_reader.GetOffset(), partTailInt, partTailStr ) );
862 if( fieldE >= 1 && fieldE < 1000 )
864 comp.additionalFields.reserve( fieldE );
866 for(
int i = 0; i < fieldE; i++ )
868 wxString fieldName =
m_reader.ReadString();
869 wxString fieldValue =
m_reader.ReadString();
872 if( !fieldName.IsEmpty() )
873 comp.additionalFields.emplace_back( fieldName, fieldValue );
890 size_t tailAfterB =
m_reader.GetOffset();
891 wxString tailStrA =
m_reader.ReadString();
892 wxString extraTail = wxEmptyString;
898 bool simpleModernTail =
false;
928 if( s_dumpComponentDetail )
930 dumpDetail( wxString::Format( wxT(
"pre-pin-hdr end=0x%06zX fieldF=%d fieldG=%d "
931 "byte4=%d rotE4=%d libPath='%s' tailA=%d tailB=%d "
932 "tailStrA='%s' pinMetaA=%d pinMetaF=%d pinMetaB=%d "
935 tailA, tailB, tailStrA, pinMetaA, pinMetaF, pinMetaB, numPins ) );
940 bool usedPinSeparatorFallback =
false;
942 auto readModernExtraAndPins = [&]( wxString& aExtraTail,
int& aNumPins,
int& aPinHdr,
943 bool& aUsedPinSeparatorFallback ) ->
bool
945 size_t extraStart =
m_reader.GetOffset();
946 uint8_t extraHdr[4] = {};
949 uint32_t extraChars = ( extraHdr[0] << 24 ) | ( extraHdr[1] << 16 ) | ( extraHdr[2] << 8 ) | extraHdr[3];
951 if( extraChars >= 10000 && extraHdr[0] == 0 && extraHdr[1] == 0 )
953 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid component extra-tail length %u at "
955 extraChars, extraStart ) );
960 size_t extraBytes =
static_cast<size_t>( extraChars ) * 2;
961 bool fitsFile =
m_reader.GetOffset() + extraBytes <=
m_reader.GetFileSize();
963 if( extraChars < 10000 && fitsFile &&
m_reader.GetOffset() + extraBytes <= componentCeiling )
965 wxMBConvUTF16BE conv;
966 aExtraTail = wxString(
reinterpret_cast<const char*
>(
m_reader.GetData() +
m_reader.GetOffset() ),
970 else if( extraChars < 10000 && fitsFile )
995 size_t pinStart =
m_reader.GetOffset();
1000 if( ( aNumPins < 0 || aNumPins > 500 ) && pinStart + 6 <=
m_reader.GetFileSize() )
1002 m_reader.SetOffset( pinStart + 2 );
1007 if( sepPins >= 0 && sepPins <= 500 )
1011 aUsedPinSeparatorFallback =
true;
1015 m_reader.SetOffset( pinStart + 4 );
1027 bool usedTaillessFallback =
false;
1028 bool canonicalPinSeparatorFallback =
false;
1029 bool readCanonicalPins =
1030 readModernExtraAndPins( extraTail, numPins, pinHdrByte, canonicalPinSeparatorFallback );
1031 usedPinSeparatorFallback = canonicalPinSeparatorFallback;
1033 if( !readCanonicalPins || ( numPins < 0 || numPins > 500 ) )
1035 size_t canonicalEnd =
m_reader.GetOffset();
1036 wxString canonicalTailStrA = tailStrA;
1037 wxString canonicalExtraTail = extraTail;
1038 int canonicalNumPins = numPins;
1039 int canonicalPinHdrByte = pinHdrByte;
1044 tailStrA = wxEmptyString;
1045 extraTail = wxEmptyString;
1048 usedTaillessFallback =
true;
1050 bool fallbackPinSeparatorFallback =
false;
1051 bool readFallbackPins =
1052 readModernExtraAndPins( extraTail, numPins, pinHdrByte, fallbackPinSeparatorFallback );
1054 if( readFallbackPins && numPins >= 0 && numPins <= 500 )
1056 usedPinSeparatorFallback = fallbackPinSeparatorFallback;
1060 m_reader.SetOffset( canonicalEnd );
1061 tailStrA = canonicalTailStrA;
1062 extraTail = canonicalExtraTail;
1063 numPins = canonicalNumPins;
1064 pinHdrByte = canonicalPinHdrByte;
1065 usedTaillessFallback =
false;
1066 usedPinSeparatorFallback = canonicalPinSeparatorFallback;
1070 if( s_dumpComponentDetail )
1072 dumpDetail( wxString::Format( wxT(
"pre-pin-hdr end=0x%06zX fieldF=%d fieldG=%d "
1073 "byte4=%d rotE4=%d libPath='%s' tailA=%d tailB=%d "
1074 "tailStrA='%s' extraTail='%s' numPins=%d pinHdr=%d "
1075 "taillessFallback=%d pinSeparatorFallback=%d" ),
1076 m_reader.GetOffset(), fieldF, fieldG, byte4,
comp.rotationE4,
comp.libPath,
1077 tailA, tailB, tailStrA, extraTail, numPins, pinHdrByte,
1078 usedTaillessFallback ? 1 : 0, usedPinSeparatorFallback ? 1 : 0 ) );
1081 simpleModernTail = tailA == 0 && tailB == 0 && tailStrA.IsEmpty() && extraTail.IsEmpty()
1082 && !usedTaillessFallback && !usedPinSeparatorFallback;
1087 comp.datasheet = extraTail;
1090 dumpDetail( wxString::Format( wxT(
"pre-pin end=0x%06zX numPins=%d" ),
m_reader.GetOffset(), numPins ) );
1092 if( numPins < 0 || numPins > 500 )
1094 if( aUseCompEnd && !simpleModernTail )
1101 THROW_IO_ERROR( wxString::Format(
_(
"Invalid pin count %d at component offset "
1103 numPins,
comp.fileOffset ) );
1106 for(
int pinIdx = 0; pinIdx < numPins; pinIdx++ )
1108 auto consumeLaterPinSeparatorIfPresent = [&]() ->
bool
1113 size_t start =
m_reader.GetOffset();
1115 if( start + 2 >= componentCeiling )
1118 const uint8_t* data =
m_reader.GetData();
1120 if( data[start] != 0 || data[start + 1] != 0 )
1123 bool currentRecordValid =
false;
1130 currentRecordValid =
m_reader.GetOffset() <= componentCeiling;
1132 catch(
const std::exception& )
1134 currentRecordValid =
false;
1139 if( currentRecordValid )
1142 bool shiftedRecordValid =
false;
1149 shiftedRecordValid =
m_reader.GetOffset() <= componentCeiling;
1151 catch(
const std::exception& )
1153 shiftedRecordValid =
false;
1158 if( !shiftedRecordValid )
1165 if( consumeLaterPinSeparatorIfPresent() )
1166 simpleModernTail =
false;
1172 catch(
const std::exception& e )
1174 if( aUseCompEnd && !simpleModernTail )
1177 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: failed to parse pin %d in component at 0x%06zX "
1178 "(offset 0x%06zX): %s" ),
1180 wxString::FromUTF8( e.what() ) ) );
1188 auto readShapePointCountIfHeaderPrefix = [&](
size_t aOffset,
int& aPointCount ) ->
bool
1190 const uint8_t* data =
m_reader.GetData();
1191 size_t fileSize =
m_reader.GetFileSize();
1192 size_t limit = std::min( fileSize, aCompEnd );
1194 if( aOffset + 17 > limit )
1197 if( data[aOffset + 6] != 0 || data[aOffset + 7] != 0 || data[aOffset + 8] != 0 || data[aOffset + 9] != 0 )
1202 int width = ( ( data[aOffset + 10] << 24 ) | ( data[aOffset + 11] << 16 ) | ( data[aOffset + 12] << 8 )
1203 | data[aOffset + 13] )
1206 if( width < 0 || width > 200000 )
1209 aPointCount = ( ( data[aOffset + 14] << 16 ) | ( data[aOffset + 15] << 8 ) | data[aOffset + 16] ) -
INT3_BIAS;
1221 while(
m_reader.GetOffset() + 6 < componentCeiling )
1223 size_t markOff =
m_reader.GetOffset();
1224 const uint8_t* mdata =
m_reader.GetData();
1226 if( mdata[markOff] != 0 || mdata[markOff + 1] != 0 || mdata[markOff + 2] != 0 )
1229 int markType = ( ( mdata[markOff + 3] << 16 ) | ( mdata[markOff + 4] << 8 )
1230 | mdata[markOff + 5] )
1233 if( markType < 1 || markType > 3 )
1264 if(
m_reader.GetOffset() > componentCeiling )
1270 if( mark.
type == 2 || mark.
type == 3 )
1271 comp.texts.push_back( mark );
1273 catch(
const std::exception& )
1280 while(
m_reader.GetOffset() < aCompEnd &&
m_reader.GetOffset() < componentCeiling )
1282 size_t shapeOffset =
m_reader.GetOffset();
1283 int shapePointCount = 0;
1292 catch(
const std::exception& )
1300 if(
m_version >=
V31_CUTOVER && readShapePointCountIfHeaderPrefix( shapeOffset, shapePointCount )
1301 && ( shapePointCount < 1 || shapePointCount > 100 ) )
1303 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid component shape point count %d at "
1304 "offset 0x%06zX." ),
1305 shapePointCount, shapeOffset ) );
1317 catch(
const std::exception& )
1340 const uint8_t* data =
m_reader.GetData();
1341 size_t lim = std::min( componentCeiling > 0 ? componentCeiling :
m_reader.GetFileSize(),
1343 size_t lo = (
save > 24 ) ?
save - 24 : 0;
1345 for(
size_t probe = lo; probe + 6 < lim && probe <=
save + 4; probe++ )
1347 if( data[probe] != 0 || data[probe + 1] != 0 || data[probe + 2] != 0 )
1358 if(
vt.type != 2 &&
vt.type != 3 )
1363 if(
vt.fontName.IsEmpty() ||
vt.fontName.size() > 64 )
1368 if(
vt.text.IsEmpty() ||
vt.text.size() > 256 )
1376 bool haveType =
false;
1379 haveType = haveType || ( t.
type ==
vt.type );
1383 comp.texts.push_back(
vt );
1387 catch(
const std::exception& )
1400 size_t afterFirstPattern =
m_reader.GetOffset();
1403 if(
m_reader.GetOffset() == afterFirstPattern )
1404 m_reader.SetOffset( afterFirstPattern );
1407 catch(
const std::exception& e )
1409 if( s_dumpComponentDetail )
1411 dumpDetail( wxString::Format( wxT(
"pattern parse failed at 0x%06zX: %s" ),
m_reader.GetOffset(),
1412 wxString::FromUTF8( e.what() ) ) );
1416 size_t parsedEnd =
m_reader.GetOffset();
1418 if( s_dumpComponentDetail )
1420 dumpDetail( wxString::Format( wxT(
"post-pattern end=0x%06zX pins=%zu shapes=%zu "
1422 parsedEnd,
comp.pins.size(),
comp.shapes.size(),
comp.patternName ) );
1424 if( aUseCompEnd && parsedEnd < aCompEnd )
1426 dumpDetail( wxString::Format( wxT(
"tail skipped=%zu bytes to compEnd=0x%06zX" ), aCompEnd - parsedEnd,
1435 else if(
m_reader.GetOffset() != componentCeiling
1441 m_reader.SetOffset( componentCeiling );
1448 m_reporter->Report( wxString::Format( wxT(
"DipTrace SCH comp @0x%06zX ref='%s' name='%s' "
1449 "sheet=%d pins=%zu shapes=%zu pattern='%s'" ),
1451 comp.pins.size(),
comp.shapes.size(),
comp.patternName ),
1460 pin.index = aPinIndex;
1462 if( aPinIndex == 0 )
1464 pin.hasHeader =
true;
1517 size_t midTailStart =
m_reader.GetOffset();
1518 const uint8_t* data =
m_reader.GetData();
1520 if( midTailStart + 5 <=
m_reader.GetFileSize() && data[midTailStart] == 0 && data[midTailStart + 1] == 0 )
1555 size_t headerStart =
m_reader.GetOffset();
1557 if( headerStart >= 6 )
1559 const uint8_t* data =
m_reader.GetData();
1560 shape.
kindCode = ( ( data[headerStart - 6] << 16 ) | ( data[headerStart - 5] << 8 ) | data[headerStart - 4] )
1562 shape.
kindFlag = ( ( data[headerStart - 3] << 16 ) | ( data[headerStart - 2] << 8 ) | data[headerStart - 1] )
1580 int numPoints =
m_reader.ReadInt3();
1582 if( numPoints < 1 || numPoints > 100 )
1585 for(
int i = 0; i < numPoints; i++ )
1603 aComp.
shapes.push_back( shape );
1621 int numPoints =
m_reader.ReadInt3();
1623 if( numPoints < 1 || numPoints > 100 )
1626 for(
int i = 0; i < numPoints; i++ )
1641 aComp.
shapes.push_back( shape );
1647 size_t startOffset =
m_reader.GetOffset();
1648 const uint8_t* data =
m_reader.GetData();
1649 size_t limit = std::min( aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize(),
m_reader.GetFileSize() );
1651 if( startOffset + 6 > limit || data[startOffset] != 0 || data[startOffset + 1] != 0 || data[startOffset + 2] != 0 )
1657 ( ( data[startOffset + 3] << 16 ) | ( data[startOffset + 4] << 8 ) | data[startOffset + 5] ) -
INT3_BIAS;
1659 if( fieldType < 0 || fieldType > 100 )
1671 if(
text.fontName.IsEmpty() ||
text.fontName.size() > 128 ||
text.text.size() > 512 )
1672 throw std::runtime_error(
"invalid component text field string" );
1690 throw std::runtime_error(
"component text field overruns component" );
1692 catch(
const std::exception& )
1705 size_t startOffset =
m_reader.GetOffset();
1751 if( fieldA < 0 || fieldA > 500 )
1773 for(
int i = 0; i < fieldA; i++ )
1792 if( fieldB < 0 || fieldB > 1000 )
1802 for(
int i = 0; i < fieldB; i++ )
1804 if( i == fieldB - 1 )
1825 size_t patternCeiling = std::min( aCompEnd > 0 ? aCompEnd :
m_reader.GetFileSize(),
m_reader.GetFileSize() );
1827 for(
size_t p = startOffset + 16; p < patternCeiling; p++ )
1840 auto landingForCeiling = [&]() ->
size_t
1845 return patternCeiling;
1853 const uint8_t* data =
m_reader.GetData();
1854 size_t limit = patternCeiling;
1856 if( startOffset + 63 <= limit && data[startOffset] == 0 && data[startOffset + 1] == 0 )
1858 size_t tailEnd = startOffset + 63;
1867 for(
size_t pos = startOffset; pos + 2 <= limit; pos++ )
1869 int charCount = ( data[pos] << 8 ) | data[pos + 1];
1871 if( charCount < 0 || charCount > 512 )
1874 size_t strEnd = pos + 2 +
static_cast<size_t>( charCount ) * 2;
1876 if( strEnd > limit )
1881 for(
size_t i = pos + 2; i < strEnd; i += 2 )
1883 if( data[i] != 0x00 || data[i + 1] < 0x20 || data[i + 1] > 0x7E )
1893 wxMBConvUTF16BE conv;
1894 wxString modelName(
reinterpret_cast<const char*
>( data + pos + 2 ), conv,
1895 static_cast<size_t>( charCount ) * 2 );
1896 wxString lowerModel = modelName.Lower();
1898 if( !modelName.IsEmpty() && !lowerModel.EndsWith( wxT(
".step" ) )
1899 && !lowerModel.EndsWith( wxT(
".wrl" ) ) )
1904 for(
size_t tailSize : {
static_cast<size_t>( 61 ),
static_cast<size_t>( 28 ) } )
1906 size_t tailEnd = strEnd + tailSize;
1908 if( tailEnd <= limit
1922 m_reader.SetOffset( landingForCeiling() );
1926 auto readCount = [&](
const char* aName,
int aMax ) ->
int
1930 if( count < 0 || count > aMax )
1932 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid embedded pattern %s count %d at "
1933 "offset 0x%06zX." ),
1934 wxString::FromUTF8( aName ), count, startOffset ) );
1940 auto isValidUtf16StringAt = [&](
size_t aOffset ) ->
bool
1942 const uint8_t* data =
m_reader.GetData();
1943 size_t size = std::min( patternCeiling,
m_reader.GetFileSize() );
1945 if( aOffset + 2 > size )
1948 int charCount = ( data[aOffset] << 8 ) | data[aOffset + 1];
1950 if( charCount < 0 || charCount > 512 )
1953 size_t stringEnd = aOffset + 2 +
static_cast<size_t>( charCount ) * 2;
1955 if( stringEnd > size )
1958 for(
size_t i = aOffset + 2; i < stringEnd; i += 2 )
1960 if( data[i] != 0x00 || data[i + 1] < 0x20 || data[i + 1] > 0x7E )
1987 if( !isValidUtf16StringAt(
m_reader.GetOffset() ) )
2006 int aliasCount = readCount(
"alias", 100 );
2008 for(
int i = 0; i < aliasCount; i++ )
2016 if( aliasCount > 0 )
2019 int padCount = readCount(
"pad", 500 );
2031 auto readModernPadRecord = [&]()
2046 auto canReadModernPadRecordAt = [&](
size_t aOffset ) ->
bool
2054 readModernPadRecord();
2055 ok =
m_reader.GetOffset() <= patternCeiling;
2057 catch(
const std::exception& )
2066 for(
int i = 0; i < padCount; i++ )
2068 if(
m_reader.GetOffset() >= patternCeiling || !canReadModernPadRecordAt(
m_reader.GetOffset() ) )
2073 readModernPadRecord();
2075 if( i + 1 < padCount )
2077 size_t tailStart =
m_reader.GetOffset();
2079 if( tailStart + 22 <= patternCeiling && canReadModernPadRecordAt( tailStart + 22 ) )
2086 catch(
const std::exception& )
2093 auto readInt3At = [&](
size_t aOffset ) ->
int
2095 const uint8_t* data =
m_reader.GetData();
2097 return ( ( data[aOffset] << 16 ) | ( data[aOffset + 1] << 8 ) | data[aOffset + 2] ) -
INT3_BIAS;
2100 auto validUtf16StringAt = [&](
size_t aOffset,
size_t aLimit,
size_t& aEnd ) ->
bool
2102 const uint8_t* data =
m_reader.GetData();
2104 if( aOffset + 2 > aLimit )
2107 int charCount = ( data[aOffset] << 8 ) | data[aOffset + 1];
2109 if( charCount < 0 || charCount > 512 )
2112 size_t strEnd = aOffset + 2 +
static_cast<size_t>( charCount ) * 2;
2114 if( strEnd > aLimit )
2117 for(
size_t i = aOffset + 2; i < strEnd; i += 2 )
2119 if( data[i] != 0x00 )
2122 if( charCount > 0 && ( data[i + 1] < 0x20 || data[i + 1] > 0x7E ) )
2130 size_t modelSectionStart = std::string::npos;
2131 size_t modelStringStart = std::string::npos;
2132 size_t patternEnd = std::string::npos;
2133 size_t limit = std::min( patternCeiling,
m_reader.GetFileSize() );
2135 for(
size_t pos =
m_reader.GetOffset(); pos + 3 <= limit; pos++ )
2137 int modelPlacementCount = readInt3At( pos );
2139 if( modelPlacementCount < 0 || modelPlacementCount > 1000 )
2142 size_t afterPlacements = pos + 3 +
static_cast<size_t>( modelPlacementCount ) * 18;
2144 if( afterPlacements + 3 > limit || readInt3At( afterPlacements ) != 0 )
2147 size_t strStart = afterPlacements + 3;
2150 if( !validUtf16StringAt( strStart, limit, strEnd ) )
2153 for(
size_t tailSize : {
static_cast<size_t>( 61 ),
static_cast<size_t>( 28 ) } )
2155 size_t tailEnd = strEnd + tailSize;
2157 if( tailEnd > limit )
2162 modelSectionStart = pos;
2163 modelStringStart = strStart;
2164 patternEnd = tailEnd;
2169 if( modelSectionStart != std::string::npos )
2173 if( modelSectionStart == std::string::npos )
2177 m_reader.SetOffset( landingForCeiling() );
2181 m_reader.SetOffset( modelStringStart );
2195 int busCount =
m_reader.ReadInt3();
2197 if( busCount < 0 || busCount > 1000 )
2199 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid bus count %d." ), busCount ) );
2202 for(
int i = 0; i < busCount; i++ )
2219 int terminator =
m_reader.ReadInt3();
2221 if( terminator != -1 )
2223 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: bus entry %d has "
2224 "unexpected terminator %d." ),
2237 catch(
const std::exception& e )
2239 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: failed to parse bus entry "
2241 i, wxString::FromUTF8( e.what() ) ) );
2249 const uint8_t* data =
m_reader.GetData();
2250 size_t fileSize =
m_reader.GetFileSize();
2252 size_t searchStart =
m_reader.GetOffset();
2254 if( searchStart >= searchEnd )
2257 for(
size_t off = searchStart; off < searchEnd - 5; off++ )
2259 if( data[off] != 0x0F || data[off + 1] != 0x42 || data[off + 2] != 0x3F )
2262 size_t strOff = off + 3;
2266 if( strOff + 3 > searchEnd )
2269 int n = ( ( data[strOff] << 16 ) | ( data[strOff + 1] << 8 ) | data[strOff + 2] ) -
INT3_BIAS;
2271 if( n < 1 || n > 200 || strOff + 3 + (
size_t) n > fileSize )
2276 for(
int i = 0; i < n; i++ )
2278 uint8_t c = data[strOff + 3 + i];
2280 if( c < 0x20 || c > 0x7E )
2290 wxString
name = wxString::From8BitData(
reinterpret_cast<const char*
>( data + strOff + 3 ), n );
2291 size_t afterStr = strOff + 3 + n;
2296 if( afterStr + 11 <= fileSize )
2298 entry.
coordX = ( ( data[afterStr] << 24 ) | ( data[afterStr + 1] << 16 ) | ( data[afterStr + 2] << 8 )
2299 | data[afterStr + 3] )
2301 entry.
coordY = ( ( data[afterStr + 4] << 24 ) | ( data[afterStr + 5] << 16 )
2302 | ( data[afterStr + 6] << 8 ) | data[afterStr + 7] )
2304 entry.
field1 = ( ( data[afterStr + 8] << 16 ) | ( data[afterStr + 9] << 8 ) | data[afterStr + 10] )
2308 m_nets.push_back( entry );
2312 if( strOff + 2 > searchEnd )
2315 int n = ( data[strOff] << 8 ) | data[strOff + 1];
2317 if( n < 1 || n > 200 || strOff + 2 + (
size_t) ( n * 2 ) > fileSize )
2322 for(
int i = 0; i < n; i++ )
2324 uint8_t hi = data[strOff + 2 +
static_cast<size_t>( i ) * 2];
2325 uint8_t lo = data[strOff + 2 +
static_cast<size_t>( i ) * 2 + 1];
2327 if( hi != 0 || lo < 0x20 || lo > 0x7E )
2337 wxMBConvUTF16BE conv;
2338 wxString
name(
reinterpret_cast<const char*
>( data + strOff + 2 ), conv,
static_cast<size_t>( n ) * 2 );
2339 size_t afterStr = strOff + 2 +
static_cast<size_t>( n ) * 2;
2344 if( afterStr + 11 <= fileSize )
2346 entry.coordX = ( ( data[afterStr] << 24 ) | ( data[afterStr + 1] << 16 ) | ( data[afterStr + 2] << 8 )
2347 | data[afterStr + 3] )
2349 entry.coordY = ( ( data[afterStr + 4] << 24 ) | ( data[afterStr + 5] << 16 )
2350 | ( data[afterStr + 6] << 8 ) | data[afterStr + 7] )
2352 entry.field1 = ( ( data[afterStr + 8] << 16 ) | ( data[afterStr + 9] << 8 ) | data[afterStr + 10] )
2356 m_nets.push_back( entry );
2371 if( aOffsetX == 0 && aOffsetY == 0 )
2378 int64_t halfW = aHalfWidth > 0 ? aHalfWidth : 1;
2379 int64_t halfH = aHalfHeight > 0 ? aHalfHeight : 1;
2381 if(
std::abs(
static_cast<int64_t
>( aOffsetX ) ) * halfH >=
std::abs(
static_cast<int64_t
>( aOffsetY ) ) * halfW )
2383 return ( aOffsetX >= 0 ) ? 2 : 0;
2386 return ( aOffsetY >= 0 ) ? 1 : 3;
2392 if( aSheetIndex < 0 )
2398 while( (
int)
m_sheets.size() <= aSheetIndex )
2402 return m_sheets[aSheetIndex]->GetScreen();
2409 sheetName = wxString::Format( wxT(
"Sheet%d" ), aSheetIndex + 1 );
2411 int col = ( aSheetIndex - 1 ) % 4;
2412 int row = ( aSheetIndex - 1 ) / 4;
2413 VECTOR2I pos( 2540000 + col * 50800000, 2540000 + row * 50800000 );
2414 VECTOR2I size( 40640000, 30480000 );
2420 fn.SetName( fn.GetName() + wxString::Format( wxT(
"_%d" ), aSheetIndex ) );
2426 newSheet->
SetName( sheetName );
2439 for(
size_t i = 0; i <
m_sheets.size(); ++i )
2449 wxString pageNumber = wxString::Format( wxT(
"%zu" ), i + 1 );
2451 path.push_back( sheet );
2452 path.SetPageNumber( pageNumber );
2468 std::vector<SCH_SHEET*> topLevelSheets;
2469 topLevelSheets.reserve(
m_sheets.size() );
2474 topLevelSheets.push_back( sheet );
2477 if( !topLevelSheets.empty() )
2486 wxString refdes = aComp.
refdes;
2491 int dot = refdes.Find( wxT(
'.' ),
true );
2493 if( dot <= 0 || dot >=
static_cast<int>( refdes.length() ) - 1 )
2498 if( refdes.Mid( dot + 1 ).ToLong( &suffix ) && suffix >= 1 )
2499 return refdes.Left( dot );
2509 if( base.IsEmpty() )
2512 if( base.IsEmpty() )
2515 if( base.IsEmpty() )
2516 base = wxT(
"Unknown" );
2519 base += wxString::Format( wxT(
"_r%d" ), aComp.
rotationE4 );
2529 if( drawItem.GetUnit() == aUnit )
2539 return static_cast<int>( std::lround( aMm * 30000.0 ) );
2555 shape.
fontX = -20000;
2556 shape.
fontY = 10000;
2557 shape.
points.assign( aPoints.begin(), aPoints.end() );
2564 wxString libPath = aComp.
libPath.Lower();
2565 wxString compName = aComp.
compName.Lower();
2569 return aComp.
shapes.empty() && aComp.
pins.size() == 2 && libPath.Contains( wxT(
"opto_emitters_led_tht" ) )
2570 && compName.StartsWith( wxT(
"led-3mm round" ) );
2598 bool isPower = aComp.
refdes.StartsWith( wxT(
"NetPort" ) );
2602 auto pin = std::make_unique<SCH_PIN>( aLibSymbol );
2604 pin->SetName( dchPin.
name.IsEmpty() ? wxString( wxT(
"~" ) ) : dchPin.
name );
2605 pin->SetNumber( dchPin.
number.IsEmpty() ? wxString( wxT(
"1" ) ) : dchPin.
number );
2624 case 0: connection.
x -= len;
break;
2625 case 2: connection.
x += len;
break;
2626 case 1: connection.
y += len;
break;
2627 case 3: connection.
y -= len;
break;
2630 pin->SetPosition( connection );
2631 pin->SetLength( len );
2642 pin->SetUnit( aUnit );
2646 std::vector<DCH_SHAPE> fallbackShapes;
2657 if( dchShape.points.size() < 2 )
2667 bool isRectangle = dchShape.points.size() == 2 && dchShape.kindCode == 4 && dchShape.kindFlag == 0;
2672 rect->SetParent( aLibSymbol );
2677 rect->SetUnit( aUnit );
2688 bool isEllipse = dchShape.points.size() == 2 && dchShape.kindCode == 6 && dchShape.kindFlag == 0;
2698 circle->SetParent( aLibSymbol );
2702 circle->SetUnit( aUnit );
2711 bool isArc = dchShape.points.size() == 3 && dchShape.kindCode == 2 && dchShape.kindFlag == 0;
2720 arc->SetParent( aLibSymbol );
2721 arc->SetArcGeometry( start, mid,
end );
2723 arc->SetUnit( aUnit );
2729 bool isFilledPolygon = dchShape.points.size() >= 3 && dchShape.kindCode == 8 && dchShape.kindFlag == 0;
2733 poly->SetParent( aLibSymbol );
2735 for(
const VECTOR2I& pt : dchShape.points )
2739 poly->SetUnit( aUnit );
2742 if( dchShape.kindCode == 3 && dchShape.kindFlag == 0 && dchShape.points.size() == 2 )
2746 double dx =
static_cast<double>(
end.x - start.
x );
2747 double dy =
static_cast<double>(
end.y - start.
y );
2748 double len = std::sqrt( dx * dx + dy * dy );
2752 double unitX = dx / len;
2753 double unitY = dy / len;
2754 double arrowLength =
2755 std::min( len / 2.0,
static_cast<double>( std::max( width * 4,
schIUScale.MilsToIU( 35 ) ) ) );
2756 double halfWidth = arrowLength / 2.0;
2757 double baseX =
static_cast<double>(
end.x ) - unitX * arrowLength;
2758 double baseY =
static_cast<double>(
end.y ) - unitY * arrowLength;
2759 double perpX = -unitY;
2760 double perpY = unitX;
2763 arrow->SetParent( aLibSymbol );
2764 arrow->AddPoint(
VECTOR2I(
static_cast<int>( std::lround( baseX + perpX * halfWidth ) ),
2765 static_cast<int>( std::lround( baseY + perpY * halfWidth ) ) ) );
2766 arrow->AddPoint(
end );
2767 arrow->AddPoint(
VECTOR2I(
static_cast<int>( std::lround( baseX - perpX * halfWidth ) ),
2768 static_cast<int>( std::lround( baseY - perpY * halfWidth ) ) ) );
2770 arrow->SetUnit( aUnit );
2795 auto libSymbol = std::make_unique<LIB_SYMBOL>( symName );
2796 libSymbol->SetUnitCount( aUnit,
false );
2799 libSymbol->GetFootprintField().SetText( aComp.
patternName );
2801 bool isPower = aComp.
refdes.StartsWith( wxT(
"NetPort" ) );
2804 libSymbol->SetGlobalPower();
2809 if( !aComp.
pins.empty() )
2810 libSymbol->SetShowPinNames( aComp.
pins.front().netFlagB != 0 );
2825 std::map<int, std::map<int, int>> partSheetVotes;
2829 int sheetIdx = wire.sheetIndex;
2834 for(
const VECTOR2I& pt : wire.points )
2842 if( wire.points.size() >= 2 )
2844 if( wire.object1 >= 0 )
2848 partSheetVotes[wire.object1][sheetIdx]++;
2851 if( wire.object2 >= 0 )
2855 partSheetVotes[wire.object2][sheetIdx]++;
2863 for(
const auto& [partId, sheets] : partSheetVotes )
2868 for(
const auto& [sheet, count] : sheets )
2870 if( count > bestCount )
2884 const uint8_t* data =
m_reader.GetData();
2885 size_t fileSize =
m_reader.GetFileSize();
2887 if( aOffset + 16 > fileSize )
2894 for(
int i = 0; i < 4; i++ )
2896 size_t p = aOffset +
static_cast<size_t>( i ) * 4;
2897 uint32_t raw = (
static_cast<uint32_t
>( data[p] ) << 24 ) | (
static_cast<uint32_t
>( data[p + 1] ) << 16 )
2898 | (
static_cast<uint32_t
>( data[p + 2] ) << 8 ) | data[p + 3];
2899 bbox[i] =
static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
2901 if(
std::abs( bbox[i] ) > 50000000 )
2907 size_t p = aOffset + 16;
2909 for(
int si = 0; si < 5; si++ )
2912 size_t dataStart = 0;
2917 if( p + 3 > fileSize )
2920 charCount = ( ( data[p] << 16 ) | ( data[p + 1] << 8 ) | data[p + 2] ) -
INT3_BIAS;
2925 if( p + 2 > fileSize )
2928 charCount = ( data[p] << 8 ) | data[p + 1];
2932 if( charCount == 0 )
2938 if( charCount < 0 || charCount > 64 )
2941 size_t byteCount = ascii ?
static_cast<size_t>( charCount ) :
static_cast<size_t>( charCount ) * 2;
2943 if( dataStart + byteCount > fileSize )
2946 for(
int k = 0; k < charCount; k++ )
2948 unsigned ch = ascii ? data[dataStart + k]
2949 : ( ( data[dataStart +
static_cast<size_t>( k ) * 2] << 8 )
2950 | data[dataStart +
static_cast<size_t>( k ) * 2 + 1] );
2956 p = dataStart + byteCount;
2990 if( aTally.empty() )
2995 for(
const auto& [ps, count] : aTally )
2996 bestCount = std::max( bestCount, count );
3000 for(
const auto& [ps, count] : aTally )
3010 for(
const auto& [ps, count] : aTally )
3012 if( count == bestCount )
3027 std::map<std::pair<int, int>,
int> tally;
3029 for(
const VECTOR2I& p : aConnectionPoints )
3036 std::set<std::pair<int, int>> seenHere;
3038 for(
const std::pair<int, int>& ps : it->second )
3039 if( seenHere.insert( ps ).second )
3055 std::map<int, int> votes;
3057 for(
const VECTOR2I& p : aPositions )
3064 for(
int sheet : it->second )
3071 int bestSheet = aFallback;
3074 for(
const auto& [sheet, count] : votes )
3076 if( count > bestVotes )
3095 if( aComp.
libPath.Contains( wxT(
"auto_net_ports" ) ) )
3100 bool explicitUnit =
false;
3102 if( refdes != aComp.
refdes )
3106 if( aComp.
refdes.Mid( refdes.length() + 1 ).ToLong( &suffix ) && suffix >= 1 )
3108 unit =
static_cast<int>( suffix ) + 1;
3109 explicitUnit =
true;
3113 if( !refdes.IsEmpty() )
3124 unit = it->second + 1;
3152 if( !refdes.IsEmpty() )
3165 if( !aComp.
value.IsEmpty() )
3176 if( aComp.
refdes.StartsWith( wxT(
"NetPort" ) ) && !aComp.
compName.IsEmpty() )
3187 if( !aComp.
refdes.StartsWith( wxT(
"NetPort" ) ) )
3207 if( extra.first.IsEmpty() || symbol->
GetField( extra.first ) )
3211 userField.
SetText( extra.second );
3221 bool refPositioned =
false;
3222 bool valuePositioned =
false;
3232 else if( txt.
type == 3 )
3249 refPositioned =
true;
3250 refFieldOffset = off;
3252 else if( txt.
type == 3 )
3254 valuePositioned =
true;
3255 valueFieldOffset = off;
3264 if( refPositioned != valuePositioned )
3269 valField->SetPosition( pos +
VECTOR2I( -refFieldOffset.
x, refFieldOffset.
y ) );
3273 refField->SetPosition( pos +
VECTOR2I( -valueFieldOffset.
x, valueFieldOffset.
y ) );
3282 if( !refPositioned && !valuePositioned )
3307 refField->SetPosition( pos + refOffset );
3315 valField->SetPosition( pos + valueOffset );
3353 std::vector<VECTOR2I> connectionPoints;
3362 dir.
x = ( off.
x >= 0 ) ? 1 : -1;
3364 dir.
y = ( off.
y >= 0 ) ? 1 : -1;
3366 connectionPoints.emplace_back(
center.x + off.
x + dir.
x * len,
center.y + off.
y + dir.
y * len );
3375 if( votedSheet < 0 )
3381 int partId = offsetIt->second;
3386 for(
int d = 0; d <= 12 && votedSheet < 0; d++ )
3388 for(
int candidate : { partId - d, partId + d } )
3394 votedSheet = sheetIt->second;
3404 screen->
Append( symbol );
3420 if( !
comp.libPath.Contains( wxT(
"auto_net_ports" ) ) ||
comp.compName.IsEmpty() )
3432 std::vector<VECTOR2I> connectionPoints;
3434 bool havePin =
false;
3443 dir.
x = ( off.
x >= 0 ) ? 1 : -1;
3445 dir.
y = ( off.
y >= 0 ) ? 1 : -1;
3447 connectionPoints.emplace_back( pos.
x + off.
x + dir.
x * len, pos.
y + off.
y + dir.
y * len );
3470 votedSheet = sheetIt->second;
3475 int partId = offsetIt->second;
3477 for(
int d = 1; d <= 12 && votedSheet < 0; d++ )
3479 for(
int candidate : { partId - d, partId + d } )
3485 votedSheet = sheetIt->second;
3496 if( votedSheet < 0 )
3503 VECTOR2I labelPos = ( havePin && !connectionPoints.empty() ) ? connectionPoints.front() : pos;
3509 if( firstPinDir.
x > 0 )
3511 else if( firstPinDir.
x < 0 )
3513 else if( firstPinDir.
y > 0 )
3515 else if( firstPinDir.
y < 0 )
3530 int64_t bestDist = std::numeric_limits<int64_t>::max();
3534 int64_t dx =
static_cast<int64_t
>( pt.first ) - aPos.
x;
3535 int64_t dy =
static_cast<int64_t
>( pt.second ) - aPos.
y;
3536 int64_t dist = dx * dx + dy * dy;
3538 if( dist < bestDist )
3541 bestSheet = *sheets.begin();
3554 if( aPos + 2 > aSectionEnd )
3557 int cnt = ( aData[aPos] << 8 ) | aData[aPos + 1];
3559 if( cnt < 1 || cnt > 64 )
3562 size_t end = aPos + 2 +
static_cast<size_t>( cnt ) * 2;
3564 if(
end + 8 + 3 + 1 + 3 > aSectionEnd )
3567 for(
int i = 0; i < cnt; i++ )
3569 unsigned hi = aData[aPos + 2 +
static_cast<size_t>( i ) * 2];
3570 unsigned lo = aData[aPos + 2 +
static_cast<size_t>( i ) * 2 + 1];
3571 unsigned ch = ( hi << 8 ) | lo;
3573 bool ok = ( ch >= 0x20 && ch < 0x7F )
3574 || ( ch >= 0x00A0 && ch <= 0x024F )
3575 || ( ch >= 0x0400 && ch <= 0x04FF );
3581 auto rdInt4 = [&](
size_t o ) ->
int
3583 uint32_t raw = (
static_cast<uint32_t
>( aData[o] ) << 24 ) | (
static_cast<uint32_t
>( aData[o + 1] ) << 16 )
3584 | (
static_cast<uint32_t
>( aData[o + 2] ) << 8 ) |
static_cast<uint32_t
>( aData[o + 3] );
3585 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
3588 int lx = rdInt4(
end );
3589 int ly = rdInt4(
end + 4 );
3591 auto rdInt3 = [&](
size_t o ) ->
int
3593 return ( ( aData[o] << 16 ) | ( aData[o + 1] << 8 ) | aData[o + 2] ) -
INT3_BIAS;
3596 int pad = rdInt3(
end + 8 );
3602 return lx > -2000000 && lx < 2000000 && ly > -2000000 && ly < 2000000 && (
pad == 0 ||
pad == 1 )
3615 const uint8_t* data =
m_reader.GetData();
3616 size_t fileSize =
m_reader.GetFileSize();
3620 if( sectionStart == 0 || sectionStart >= sectionEnd )
3623 auto rdInt3 = [&](
size_t o ) ->
int
3625 return ( ( data[o] << 16 ) | ( data[o + 1] << 8 ) | data[o + 2] ) -
INT3_BIAS;
3628 auto rdInt4 = [&](
size_t o ) ->
int
3630 uint32_t raw = (
static_cast<uint32_t
>( data[o] ) << 24 ) | (
static_cast<uint32_t
>( data[o + 1] ) << 16 )
3631 | (
static_cast<uint32_t
>( data[o + 2] ) << 8 ) |
static_cast<uint32_t
>( data[o + 3] );
3632 return static_cast<int>(
static_cast<int64_t
>( raw ) -
INT4_BIAS );
3635 static constexpr uint8_t WIRE_NET_MARKER[] = { 0x0F, 0x42, 0x3F };
3636 static constexpr size_t WIRE_NET_MARKER_LEN =
sizeof( WIRE_NET_MARKER );
3638 auto isExpectedWireNetMarker = [&](
size_t aMarkerOffset,
int aExpectedIndex ) ->
bool
3640 if( aMarkerOffset < 13 || aMarkerOffset + WIRE_NET_MARKER_LEN > sectionEnd )
3643 if( memcmp( data + aMarkerOffset, WIRE_NET_MARKER, WIRE_NET_MARKER_LEN ) != 0 )
3646 if( data[aMarkerOffset - 13] != 0x01 )
3649 int fieldA = rdInt3( aMarkerOffset - 9 );
3650 int fieldB = rdInt3( aMarkerOffset - 6 );
3651 int netIndex = rdInt3( aMarkerOffset - 3 );
3653 if( netIndex != aExpectedIndex )
3660 return fieldA >= -1 && fieldA <= 100000 && fieldB >= -1 && fieldB <= 100000;
3663 auto decodeWireNetName = [&](
size_t aNameOffset, wxString& aName,
size_t& aAfterName, wxString& aError ) ->
bool
3665 if( aNameOffset + 2 > sectionEnd )
3667 aError = wxT(
"missing UTF-16 length" );
3671 int nameLen = ( data[aNameOffset] << 8 ) | data[aNameOffset + 1];
3673 if( nameLen < 1 || nameLen > 64 )
3675 aError = wxString::Format( wxT(
"invalid UTF-16 length %d" ), nameLen );
3679 aAfterName = aNameOffset + 2 +
static_cast<size_t>( nameLen ) * 2;
3681 if( aAfterName + 8 + 3 + 1 + 3 > sectionEnd )
3683 aError = wxT(
"name overruns wire-net record" );
3687 for(
int i = 0; i < nameLen; i++ )
3689 unsigned hi = data[aNameOffset + 2 +
static_cast<size_t>( i ) * 2];
3690 unsigned lo = data[aNameOffset + 2 +
static_cast<size_t>( i ) * 2 + 1];
3691 unsigned ch = ( hi << 8 ) | lo;
3694 ( ch >= 0x20 && ch < 0x7F ) || ( ch >= 0x00A0 && ch <= 0x024F ) || ( ch >= 0x0400 && ch <= 0x04FF );
3698 aError = wxString::Format( wxT(
"invalid UTF-16 character 0x%04X" ), ch );
3703 wxMBConvUTF16BE conv;
3704 aName = wxString(
reinterpret_cast<const char*
>( data + aNameOffset + 2 ), conv,
3705 static_cast<size_t>( nameLen ) * 2 );
3710 auto findNextWireNetName = [&](
size_t aSearchStart,
size_t aSearchEnd,
int aExpectedIndex ) ->
size_t
3712 if( aSearchStart >= aSearchEnd )
3715 for(
size_t marker = aSearchStart; marker + WIRE_NET_MARKER_LEN <= aSearchEnd; marker++ )
3717 if( memcmp( data + marker, WIRE_NET_MARKER, WIRE_NET_MARKER_LEN ) != 0 )
3720 if( !isExpectedWireNetMarker( marker, aExpectedIndex ) )
3723 size_t nameOffset = marker + WIRE_NET_MARKER_LEN;
3724 wxString candidateName;
3726 size_t afterName = 0;
3728 if( !decodeWireNetName( nameOffset, candidateName, afterName, nameError ) )
3730 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire-net name for net index %d at "
3731 "offset 0x%06zX: %s." ),
3732 aExpectedIndex, nameOffset, nameError ) );
3743 int expectedWireNetIndex = 0;
3744 size_t pos = findNextWireNetName( sectionStart, sectionEnd, expectedWireNetIndex );
3750 size_t lastRecordEnd = 0;
3752 while( pos != 0 && pos < sectionEnd && safetyNets++ < 100000 )
3759 size_t afterName = 0;
3761 if( !decodeWireNetName( o, netName, afterName, nameError ) )
3763 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire-net name for net index %d at "
3764 "offset 0x%06zX: %s." ),
3765 expectedWireNetIndex, o, nameError ) );
3771 if( o + 3 > sectionEnd )
3774 int pinCount = rdInt3( o );
3775 size_t pinCountOffset = o;
3778 if( pinCount < 0 || pinCount > 4000 || o +
static_cast<size_t>( pinCount ) * 6 + 3 > sectionEnd )
3780 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire-net pin count %d for net '%s' at "
3781 "offset 0x%06zX." ),
3782 pinCount, netName, pinCountOffset ) );
3785 o +=
static_cast<size_t>( pinCount ) * 6;
3787 int wireCount = rdInt3( o );
3788 size_t wireCountOffset = o;
3791 if( wireCount < 0 || wireCount > 100000 )
3793 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire count %d for net '%s' at offset "
3795 wireCount, netName, wireCountOffset ) );
3798 bool brokeEarly =
false;
3800 for(
int w = 0; w < wireCount; w++ )
3802 if( o + 36 + 1 + 3 > sectionEnd )
3809 wire.
object1 = rdInt3( o + 0 );
3810 wire.
object2 = rdInt3( o + 3 );
3813 wire.
bus1 = rdInt3( o + 12 );
3814 wire.
bus2 = rdInt3( o + 15 );
3820 int pointCount = rdInt3( o );
3821 size_t pointCountOffset = o;
3824 if( pointCount < 0 || pointCount > 4000 || o +
static_cast<size_t>( pointCount ) * 11 + 8 > sectionEnd )
3826 THROW_IO_ERROR( wxString::Format(
_(
"DipTrace import: invalid wire point count %d for net '%s' at "
3827 "offset 0x%06zX." ),
3828 pointCount, netName, pointCountOffset ) );
3831 wire.
points.reserve( pointCount );
3833 for(
int p = 0; p < pointCount; p++ )
3835 int dtX = rdInt4( o );
3836 int dtY = rdInt4( o + 4 );
3848 if( wire.
points.size() >= 2 )
3854 m_wires.push_back( std::move( wire ) );
3862 expectedWireNetIndex++;
3865 pos = findNextWireNetName( o, std::min( sectionEnd, o + 400 ), expectedWireNetIndex );
3882 if( searchStart == 0 || searchStart >= sectionEnd )
3885 size_t originalOffset =
m_reader.GetOffset();
3887 auto readSheetShapeRecord = [&]() -> std::optional<DCH_SHEET_SHAPE>
3889 uint8_t flagA =
m_reader.ReadByte();
3890 uint8_t flagB =
m_reader.ReadByte();
3892 int kindCode =
m_reader.ReadInt3();
3893 int drawOrder =
m_reader.ReadInt3();
3897 uint8_t color[3] = {};
3903 int sheetIndex =
m_reader.ReadInt3();
3905 int lineWidth =
m_reader.ReadInt4();
3909 int pointCount =
m_reader.ReadInt3();
3911 if( flagA != 1 || flagB != 0 || fieldA != 0 || fieldB != 0 || fieldC != -1 || fieldD != 0 )
3912 return std::nullopt;
3914 if( kindCode != 1 && kindCode != 4 )
3915 return std::nullopt;
3917 if( drawOrder < 0 || drawOrder > 1000 || sheetIndex < 0 || sheetIndex >=
m_numSheets )
3918 return std::nullopt;
3920 if( lineWidth < 0 || lineWidth > 200000 || pointCount < 1 || pointCount > 100 )
3921 return std::nullopt;
3927 shape.
color[0] = color[0];
3928 shape.
color[1] = color[1];
3929 shape.
color[2] = color[2];
3930 shape.
points.reserve( pointCount );
3932 for(
int i = 0; i < pointCount; i++ )
3936 shape.
points.emplace_back( x, y );
3941 uint8_t tailFlagA =
m_reader.ReadByte();
3942 uint8_t tailFlagB =
m_reader.ReadByte();
3946 if( tailA != -1 || tailB != -1 || tailFlagA != 0 || tailFlagB != 1 || extentX != -20000 || extentY != 10000 )
3947 return std::nullopt;
3952 for(
size_t offset = searchStart; offset + 3 < sectionEnd; offset++ )
3959 if( count < 1 || count > 1000 )
3962 std::vector<DCH_SHEET_SHAPE> shapes;
3963 shapes.reserve( count );
3967 for(
int i = 0; i < count; i++ )
3969 std::optional<DCH_SHEET_SHAPE> shape = readSheetShapeRecord();
3977 shapes.push_back( *shape );
3980 if( valid && !shapes.empty() &&
m_reader.GetOffset() <= sectionEnd )
3986 catch(
const std::exception& )
3991 m_reader.SetOffset( originalOffset );
4005 if( dchShape.points.size() < 2 )
4016 if( dchShape.kindCode == 4 && dchShape.points.size() == 2 )
4028 if( dchShape.kindCode == 1 )
4032 for(
const VECTOR2I& pt : dchShape.points )
4048 int sheetIdx = wire.sheetIndex;
4058 for(
size_t i = 1; i < wire.points.size(); i++ )
4078 std::set<SCH_SCREEN*> screens;
4085 if( sheet && sheet->GetScreen() )
4086 screens.insert( sheet->GetScreen() );
4089 std::map<SCH_SCREEN*, std::set<std::pair<int, int>>> junctions;
4095 std::deque<EDA_ITEM*> items;
4097 for(
SCH_ITEM* item : screen->Items() )
4098 items.push_back( item );
4100 for(
const VECTOR2I& pt : screen->GetNeededJunctions( items ) )
4101 junctions[screen].insert( { pt.x, pt.y } );
4108 std::map<SCH_SCREEN*, std::set<std::pair<int, int>>> interior;
4112 int sheetIdx = ( aWire.sheetIndex >= 0 && aWire.sheetIndex <
m_numSheets ) ? aWire.sheetIndex : 0;
4123 for(
size_t i = 1; i + 1 < wire.points.size(); i++ )
4126 interior[screen].insert( { p.
x, p.
y } );
4134 if( !screen || wire.points.empty() )
4137 const std::set<std::pair<int, int>>& sheetInterior = interior[screen];
4139 if( wire.bus1 != -1 )
4143 if( sheetInterior.count( { p.x, p.y } ) )
4144 junctions[screen].insert( { p.
x, p.
y } );
4147 if( wire.bus2 != -1 )
4151 if( sheetInterior.count( { p.x, p.y } ) )
4152 junctions[screen].insert( { p.
x, p.
y } );
4156 for(
const auto& [screen, pts] : junctions )
4158 for(
const std::pair<int, int>& pt : pts )
4176 symbol->SetLibSymbol(
new LIB_SYMBOL( *libIt->second ) );
4209 std::set<SCH_SCREEN*> screens;
4216 if( sheet && sheet->GetScreen() )
4217 screens.insert( sheet->GetScreen() );
4221 screen->SetPageSettings( pageInfo );
4238 catch(
const std::exception& e )
4242 m_reporter->Report( wxString::Format(
_(
"DipTrace import: failed to create symbol "
4243 "for %s (%s): %s" ),
4244 comp.refdes,
comp.compName, wxString::FromUTF8( e.what() ) ),
4262 m_reporter->Report( wxString::Format(
_(
"DipTrace import: loaded %zu components, %zu buses, "
4263 "%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
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 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.