288 const std::map<wxString, wxString>& aDeviceAttributes,
289 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap )
293 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
296 std::map<wxString, int> partUnits;
298 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
299 std::map<int, std::map<wxString, const V3_ROW*>> unitAttributeRows;
300 std::map<int, std::map<wxString, std::vector<const V3_ROW*>>> unitParentedRows;
307 if( row.
type == wxS(
"PART" ) )
309 int unitId = ++totalUnits;
311 partUnits[row.
id] = unitId;
315 if( !partTitle.empty() )
316 partUnits[partTitle] = unitId;
318 else if( row.
type == wxS(
"META" ) )
320 if( row.
inner.contains(
"docType" ) )
332 auto resolveRowUnit = [&](
const V3_ROW& aRow )
334 wxString partId =
V3GetString( aRow.inner,
"partId" );
336 if( !partId.empty() )
338 if(
auto unitOpt =
get_opt( partUnits, partId ) )
348 int rowUnit = resolveRowUnit( row );
350 if( row.
type == wxS(
"PART" ) )
352 currentUnit = partUnits.at( row.
id );
354 else if( row.
type == wxS(
"RECT" ) )
365 rect->SetUnit( rowUnit );
370 else if( row.
type == wxS(
"CIRCLE" ) )
381 circle->SetUnit( rowUnit );
386 else if( row.
type == wxS(
"ARC" ) )
400 shape->SetUnit( rowUnit );
405 else if( row.
type == wxS(
"BEZIER" ) )
407 std::vector<double> points = row.
inner.value(
"controls", nlohmann::json::array() );
411 for(
size_t i = 1; i < points.size(); i += 2 )
417 case 1: shape->SetStart( pt );
break;
418 case 3: shape->SetBezierC1( pt );
break;
419 case 5: shape->SetBezierC2( pt );
break;
420 case 7: shape->SetEnd( pt );
break;
424 shape->SetUnit( rowUnit );
429 else if( row.
type == wxS(
"POLY" ) )
432 row.
inner.value(
"points", nlohmann::json::array() ) );
433 std::vector<double> points = flatPts;
437 for(
size_t i = 1; i < points.size(); i += 2 )
440 shape->SetUnit( rowUnit );
445 else if( row.
type == wxS(
"TEXT" ) )
451 auto text = std::make_unique<SCH_TEXT>(
457 text->SetTextAngleDegrees( angle );
458 text->SetUnit( rowUnit );
463 else if( row.
type == wxS(
"OBJ" ) )
472 wxString mimeType, data;
474 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
476 wxArrayString paramsArr =
477 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
479 data = imageUrl.AfterFirst(
',' );
481 if( paramsArr.size() > 0 )
482 mimeType = paramsArr[0];
484 else if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
486 wxString objectId = imageUrl.AfterLast(
':' );
488 if(
auto blob =
get_opt( aBlobMap, objectId ) )
490 wxString blobUrl = blob->url;
492 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
494 wxArrayString paramsArr =
495 wxSplit( blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
497 data = blobUrl.AfterFirst(
',' );
499 if( paramsArr.size() > 0 )
500 mimeType = paramsArr[0];
505 if( mimeType.empty() || data.empty() )
508 wxMemoryBuffer buf = wxBase64Decode( data );
510 if( mimeType == wxS(
"image/svg+xml" ) )
532 libsymImporter.
SetScale( pixelScale );
540 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.
GetItems() )
545 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
547 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
548 & ~wxImage::Load_Verbose );
551 if( img.LoadFile( memis, mimeType ) )
553 int dimMul = img.GetWidth() * img.GetHeight();
554 double maxPixels = 30000;
556 if( dimMul > maxPixels )
558 double scale = sqrt( maxPixels / dimMul );
559 img.Rescale( img.GetWidth() *
scale, img.GetHeight() *
scale );
571 else if( row.
type == wxS(
"PIN" ) )
573 unitParentedRows[rowUnit][row.
id].push_back( &row );
575 else if( row.
type == wxS(
"ATTR" ) )
579 if( parentId.empty() )
596 unitAttributes[rowUnit].emplace( attr.
key, attr );
597 unitAttributeRows[rowUnit].emplace( attr.
key, &row );
601 unitParentedRows[rowUnit][parentId].push_back( &row );
617 if(
auto globalNetAttr =
get_opt( unitAttributes[1], wxS(
"Global Net Name" ) ) )
619 wxString powerName = globalNetAttr->value;
621 if( powerName.IsEmpty() )
623 if(
auto nameAttr =
get_opt( unitAttributes[1], wxS(
"Name" ) ) )
624 powerName = nameAttr->value;
628 valueText->
SetText( powerName );
629 valueText->
SetVisible( globalNetAttr->valVisible );
631 if(
auto globalNetAttrRow =
get_opt( unitAttributeRows[1], wxS(
"Global Net Name" ) ) )
633 const nlohmann::json& attrInner = ( *globalNetAttrRow )->inner;
635 wxString color =
V3GetString( attrInner,
"color", wxEmptyString );
636 wxString fontFamily =
V3GetString( attrInner,
"fontFamily", wxS(
"default" ) );
637 wxString align =
V3GetString( attrInner,
"align", wxS(
"LEFT_BOTTOM" ) );
639 if( !color.empty() && color.StartsWith( wxS(
"#" ) ) )
645 if( fontFamily != wxS(
"Arial" ) && !fontFamily.IsSameAs( wxS(
"default" ),
false ) )
655 else if( vAlign == 1 )
662 else if( hAlign == 1 )
668 if( globalNetAttr->position )
671 wxString globalNetname = globalNetAttr->value;
673 if( globalNetname.IsEmpty() )
674 globalNetname = powerName;
676 if( !globalNetname.empty() )
679 _(
"Power symbol creates a global label with name '%s'" ),
686 auto designatorAttr =
get_opt( unitAttributes[1], wxS(
"Designator" ) );
688 if( designatorAttr && !designatorAttr->value.empty() )
690 wxString symbolPrefix = designatorAttr->value;
692 if( symbolPrefix.EndsWith( wxS(
"?" ) ) )
693 symbolPrefix.RemoveLast();
699 aDeviceAttributes,
true,
700 [&](
const wxString& attrName,
const wxString& value )
716 for(
auto& [unitId, parentedRows] : unitParentedRows )
718 for(
auto& [pinId, rows] : parentedRows )
720 const V3_ROW* pinRow =
nullptr;
721 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
723 for(
const V3_ROW* r : rows )
725 if( r->type == wxS(
"ATTR" ) )
732 pinAttributes.emplace( attr.
key, attr );
735 else if( r->type == wxS(
"PIN" ) )
751 pinInfo.
pin.
inverted = ( pinShape == wxS(
"INVERTED" )
752 || pinShape == wxS(
"INVERTED_CLOCK" ) );
754 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>( ksymbol );
756 pin->SetUnit( unitId );
771 pin->SetOrientation( orient );
779 auto pinNameAttr =
get_opt( pinAttributes, wxS(
"Pin Name" ) );
782 pinNameAttr =
get_opt( pinAttributes, wxS(
"NAME" ) );
786 pin->SetName( pinNameAttr->value );
787 pinInfo.
name = pinNameAttr->value;
789 if( !pinNameAttr->valVisible )
794 auto pinNumAttr =
get_opt( pinAttributes, wxS(
"Pin Number" ) );
797 pinNumAttr =
get_opt( pinAttributes, wxS(
"NUMBER" ) );
801 pin->SetNumber( pinNumAttr->value );
802 pinInfo.
number = pinNumAttr->value;
804 if( !pinNumAttr->valVisible )
812 else if(
auto pinTypeAttr =
get_opt( pinAttributes, wxS(
"Pin Type" ) ) )
814 if( pinTypeAttr->value == wxS(
"IN" ) )
816 if( pinTypeAttr->value == wxS(
"OUT" ) )
818 if( pinTypeAttr->value == wxS(
"BI" ) )
822 if(
get_opt( pinAttributes, wxS(
"NO_CONNECT" ) ) )
825 if(
pin->GetNumberTextSize() *
int(
pin->GetNumber().size() ) >
pin->GetLength() )
826 pin->SetNumberTextSize(
pin->GetLength() /
pin->GetNumber().size() );
828 symInfo.
pins.push_back( pinInfo );
834 symInfo.
libSymbol = std::move( ksymbolPtr );
993 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
994 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
997 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
1000 std::map<wxString, std::vector<const EASYEDAPRO::V3_ROW*>> wireGeometry;
1001 std::map<wxString, const EASYEDAPRO::V3_ROW*> wireRows;
1004 std::map<wxString, std::vector<const EASYEDAPRO::V3_ROW*>> parentedRows;
1009 if( row.
type == wxS(
"WIRE" ) )
1011 wireRows[row.
id] = &row;
1016 wireGeometry[lineGroup].push_back( &row );
1018 else if( row.
type == wxS(
"COMPONENT" ) )
1020 parentedRows[row.
id].push_back( &row );
1025 parentedRows[parentId].push_back( &row );
1032 if( row.
type == wxS(
"RECT" ) )
1045 createdItems.push_back( std::move( rect ) );
1047 else if( row.
type == wxS(
"CIRCLE" ) )
1060 createdItems.push_back( std::move(
circle ) );
1062 else if( row.
type == wxS(
"ARC" ) )
1071 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>(
SHAPE_T::ARC );
1078 createdItems.push_back( std::move( arc ) );
1080 else if( row.
type == wxS(
"POLY" ) )
1086 row.
inner.value(
"points", nlohmann::json::array() ) );
1087 std::vector<double> pointsData = flatPts;
1089 if( pointsData.size() < 4 )
1092 std::unique_ptr<SCH_SHAPE> poly = std::make_unique<SCH_SHAPE>(
SHAPE_T::POLY );
1094 for(
size_t i = 1; i < pointsData.size(); i += 2 )
1099 createdItems.push_back( std::move( poly ) );
1101 else if( row.
type == wxS(
"TEXT" ) )
1108 std::unique_ptr<SCH_TEXT> schText = std::make_unique<SCH_TEXT>(
1114 schText->SetTextAngleDegrees( angle );
1118 createdItems.push_back( std::move( schText ) );
1120 else if( row.
type == wxS(
"OBJ" ) )
1142 wxString base64Data;
1144 if( content.BeforeFirst(
':' ) == wxS(
"data" ) )
1146 wxArrayString paramsArr =
1147 wxSplit( content.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1149 if( paramsArr.size() > 0 )
1150 mimeType = paramsArr[0];
1152 base64Data = content.AfterFirst(
',' );
1154 else if( content.BeforeFirst(
':' ) == wxS(
"blob" ) )
1156 wxString objectId = content.AfterLast(
':' );
1158 if(
auto blob =
get_opt( aBlobMap, objectId ) )
1160 wxString blobUrl = blob->url;
1162 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
1164 wxArrayString paramsArr =
1165 wxSplit( blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1167 if( paramsArr.size() > 0 )
1168 mimeType = paramsArr[0];
1170 base64Data = blobUrl.AfterFirst(
',' );
1175 if( mimeType.empty() || base64Data.empty() )
1178 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1180 if( mimeType == wxS(
"image/svg+xml" ) )
1196 schImporter.
SetScale( pixelScale );
1202 svgImportPlugin.
Import();
1204 for( std::unique_ptr<EDA_ITEM>& item : schImporter.
GetItems() )
1208 for(
double i = angle; i > 0; i -= 90 )
1213 schItem->
Rotate( kstart,
false );
1217 schItem->
Rotate( kstart,
false );
1222 schItem->
Rotate( kstart,
false );
1237 createdItems.emplace_back( schItem );
1242 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1245 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1246 & ~wxImage::Load_Verbose );
1250 VECTOR2D kcenter = kstart + ksize / 2;
1255 bitmap->SetPosition( kcenter );
1257 for(
double i = angle; i > 0; i -= 90 )
1258 bitmap->Rotate( kstart,
false );
1261 bitmap->MirrorHorizontally( kstart.
x );
1263 createdItems.push_back( std::move( bitmap ) );
1270 for(
const auto& [wireId, wireRow] : wireRows )
1272 auto geomIt = wireGeometry.find( wireId );
1273 if( geomIt == wireGeometry.end() )
1276 const std::vector<const EASYEDAPRO::V3_ROW*>& lineRows = geomIt->second;
1278 bool firstPointSet =
false;
1296 if( !firstPointSet )
1299 firstPointSet =
true;
1302 std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>(
1306 createdItems.push_back( std::move( line ) );
1310 bool netVisible =
false;
1312 bool netPosSet =
false;
1313 wxString netAlign = wxS(
"LEFT_BOTTOM" );
1314 int netRotation = 0;
1316 if(
auto attrRows =
get_opt( parentedRows, wireId ) )
1320 if( row->
type != wxS(
"ATTR" ) )
1343 if( netVisible && !netName.IsEmpty() && firstPointSet )
1345 VECTOR2D labelPos = netPosSet ? netPos : firstPoint;
1347 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>(
1352 if( netAlign.StartsWith( wxS(
"RIGHT" ) ) )
1354 else if( netAlign.StartsWith( wxS(
"LEFT" ) ) )
1357 int rot = netRotation % 360;
1365 for(
int i = 0; i < rot; i += 90 )
1369 label->SetSpinStyle( spinStyle );
1371 createdItems.push_back( std::move( label ) );
1376 for(
const auto& [parentId, rows] : parentedRows )
1379 std::map<wxString, std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>> attributes;
1383 if( row->
type == wxS(
"COMPONENT" ) )
1387 else if( row->
type == wxS(
"ATTR" ) )
1390 attributes.emplace( attr.
key, std::make_pair( attr, row ) );
1397 auto deviceAttrIt = attributes.find(
"Device" );
1398 auto symbolAttrIt = attributes.find(
"Symbol" );
1400 std::map<wxString, wxString> compAttrs;
1402 if( deviceAttrIt != attributes.end() && !deviceAttrIt->second.first.value.IsEmpty() )
1406 if( deviceData.
found )
1407 compAttrs = std::move( deviceData.
attributes );
1412 if( symbolAttrIt != attributes.end() && !symbolAttrIt->second.first.value.IsEmpty() )
1413 symbolId = symbolAttrIt->second.first.value;
1415 symbolId =
get_def( compAttrs, wxS(
"Symbol" ), wxEmptyString );
1417 if( symbolId.IsEmpty() )
1419 wxLogTrace(
traceEasyEdaIo, wxT(
"EasyEDA Pro v3 component '%s': missing Symbol attribute, skipping." ),
1424 auto it = aSymbolMap.find( symbolId );
1425 if( it == aSymbolMap.end() )
1428 wxLogTrace(
traceEasyEdaIo,
"Symbol of '%s' with uuid '%s' not found.", compName, symbolId );
1438 if( !unitName.IsEmpty() )
1445 wxT(
"EasyEDA Pro v3 component '%s': partId '%s' not found in "
1446 "symbol '%s', using unit 1." ),
1447 parentId, unitName, symbolId );
1454 if( deviceAttrIt != attributes.end() && !deviceAttrIt->second.first.value.IsEmpty() )
1458 if( !deviceLibName.empty() )
1459 libItemName = deviceLibName;
1464 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1468 schSym->SetFootprintFieldText( newLibSymbol.
GetFootprint() );
1470 auto footprintAttrIt = attributes.find( wxS(
"Footprint" ) );
1472 wxString resolvedFootprint;
1474 if( footprintAttrIt != attributes.end() && !footprintAttrIt->second.first.value.IsEmpty() )
1476 aProject, aLibName );
1479 aProject, aLibName );
1481 if( !resolvedFootprint.IsEmpty() )
1482 schSym->SetFootprintFieldText( resolvedFootprint );
1489 for(
double i = rotation; i > 0; i -= 90 )
1490 schSym->Rotate(
VECTOR2I(),
true );
1493 schSym->MirrorHorizontally( 0 );
1501 auto nameAttrIt = attributes.find( wxS(
"Name" ) );
1503 if( nameAttrIt != attributes.end() && !nameAttrIt->second.first.value.IsEmpty() )
1504 netName = nameAttrIt->second.first.value;
1506 netName =
get_def( compAttrs, wxS(
"Name" ), wxEmptyString );
1508 if( netName.IsEmpty() )
1513 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->
CurrentSheet() );
1514 SCH_PIN*
pin = pins.empty() ? nullptr : pins.front();
1516 VECTOR2I labelPos = schSym->GetPosition();
1522 labelPos =
pin->GetPosition();
1524 switch(
pin->PinDrawOrient( schSym->GetTransform() ) )
1533 switch(
pin->GetType() )
1557 std::unique_ptr<SCH_GLOBALLABEL> label =
1558 std::make_unique<SCH_GLOBALLABEL>( labelPos, netName );
1559 label->SetSpinStyle( spinStyle );
1560 label->SetShape( labelShape );
1562 bool labelVisible = !netName.IsEmpty();
1564 if( nameAttrIt != attributes.end() && nameAttrIt->second.second )
1570 && !netName.IsEmpty();
1573 wxString fontFamily =
1576 if( !color.empty() && color.StartsWith( wxS(
"#" ) ) )
1577 label->SetTextColor(
COLOR4D( color ) );
1579 if( fontFamily != wxS(
"Arial" )
1580 && !fontFamily.IsSameAs( wxS(
"default" ),
false ) )
1588 label->SetVisible( labelVisible );
1590 createdItems.push_back( std::move( label ) );
1598 auto globalNetNameAttrIt = attributes.find(
"Global Net Name" );
1599 auto nameAttrIt = attributes.find(
"Name" );
1600 wxString globalNetNameFromProject =
1601 get_def( compAttrs,
"Global Net Name", wxEmptyString );
1602 wxString nameFromProject =
get_def( compAttrs,
"Name", wxEmptyString );
1604 const std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>* valueSource =
nullptr;
1606 if( globalNetNameAttrIt != attributes.end() )
1607 valueSource = &globalNetNameAttrIt->second;
1608 else if( nameAttrIt != attributes.end() )
1609 valueSource = &nameAttrIt->second;
1611 wxString globalNetName;
1618 if( globalNetNameAttrIt != attributes.end()
1619 && !globalNetNameAttrIt->second.first.value.IsEmpty() )
1621 globalNetName = globalNetNameAttrIt->second.first.value;
1623 else if( nameAttrIt != attributes.end()
1624 && !nameAttrIt->second.first.value.IsEmpty() )
1626 globalNetName = nameAttrIt->second.first.value;
1628 else if( !globalNetNameFromProject.IsEmpty() )
1630 globalNetName = globalNetNameFromProject;
1632 else if( !nameFromProject.IsEmpty() )
1634 globalNetName = nameFromProject;
1643 if( valueSource && valueSource->second )
1649 bool valueFromNameAttr = ( nameAttrIt != attributes.end()
1650 && valueSource == &nameAttrIt->second );
1654 if( attrRotation < 0 )
1655 attrRotation += 360;
1657 bool hasExplicitStyleOrPosition =
1664 || attrRotation != 0;
1666 attr.
value = globalNetName;
1668 if( !globalNetName.IsEmpty() )
1670 else if( valueVisibleMissing )
1673 if( valueFromNameAttr && !hasExplicitStyleOrPosition )
1677 if( !globalNetName.IsEmpty() )
1679 else if( valueVisibleMissing )
1685 compAttrs, schSym.get(), attrRow->
inner );
1687 if( !globalNetName.IsEmpty() )
1694 valueField->
SetVisible( !globalNetName.IsEmpty() );
1697 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1698 pin->SetName( globalNetName );
1700 schSym->SetRef( &aSchematic->
CurrentSheet(), wxS(
"#PWR?" ) );
1706 auto designatorAttrIt = attributes.find(
"Designator" );
1708 bool hasReferenceValue =
false;
1710 if( designatorAttrIt != attributes.end() )
1716 schSym.get(), attrRow->
inner );
1718 if( !attr.
value.IsEmpty() )
1721 hasReferenceValue =
true;
1725 if( !hasReferenceValue )
1732 [&](
const wxString& attrKey,
const wxString& value )
1734 SCH_FIELD* field = schSym->FindFieldCaseInsensitive( attrKey );
1743 wxString description =
get_def( compAttrs, wxS(
"Description" ), wxEmptyString );
1745 if( !description.empty() )
1751 auto valueAttrIt = attributes.find(
"Value" );
1752 auto nameAttrIt = attributes.find(
"Name" );
1754 wxString fallbackValue =
get_def( compAttrs, wxS(
"Value" ), wxEmptyString );
1756 if( fallbackValue.IsEmpty() )
1757 fallbackValue =
get_def( compAttrs, wxS(
"Name" ), wxEmptyString );
1759 const std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>* valueSource =
nullptr;
1761 if( valueAttrIt != attributes.end() && valueAttrIt->second.first.valVisible )
1762 valueSource = &valueAttrIt->second;
1763 else if( nameAttrIt != attributes.end() && nameAttrIt->second.first.valVisible )
1764 valueSource = &nameAttrIt->second;
1765 else if( valueAttrIt != attributes.end() )
1766 valueSource = &valueAttrIt->second;
1767 else if( nameAttrIt != attributes.end() )
1768 valueSource = &nameAttrIt->second;
1772 if( valueAttrIt != attributes.end() && !valueAttrIt->second.first.value.IsEmpty() )
1773 valueText = valueAttrIt->second.first.value;
1774 else if( nameAttrIt != attributes.end() && !nameAttrIt->second.first.value.IsEmpty() )
1775 valueText = nameAttrIt->second.first.value;
1777 valueText = fallbackValue;
1781 if( !valueText.IsEmpty() )
1783 if( valueSource && valueSource->second )
1786 attr.
value = valueText;
1789 schSym.get(), valueSource->second->inner );
1802 for(
const auto& [key, attrPair] : attributes )
1804 if( key == wxS(
"Designator" ) || key == wxS(
"Device" ) || key == wxS(
"Symbol" )
1805 || key == wxS(
"Name" ) || key == wxS(
"Value" ) )
1818 if( key == wxS(
"Footprint" ) )
1829 if( key == wxS(
"Footprint" ) )
1836 compAttrs, schSym.get(), attrRow->
inner );
1841 schSym.get(), attrRow->
inner );
1847 createdItems.push_back( std::move( schSym ) );
1851 bool hasBBox =
false;
1853 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1860 itemBBox = item->GetBoundingBox();
1864 sheetBBox = itemBBox;
1869 sheetBBox.
Merge( itemBBox );
1877 const int margin =
schIUScale.MilsToIU( 200 );
1880 -sheetBBox.
GetTop() + margin );
1884 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1885 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1893 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1895 item->Move( offset );
1896 screen->
Append( item.release() );
1901 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1902 screen->
Append( item.release() );