287 const std::map<wxString, wxString>& aDeviceAttributes,
288 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap )
292 std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
295 std::map<wxString, int> partUnits;
297 std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
298 std::map<int, std::map<wxString, const V3_ROW*>> unitAttributeRows;
299 std::map<int, std::map<wxString, std::vector<const V3_ROW*>>> unitParentedRows;
306 if( row.
type == wxS(
"PART" ) )
308 int unitId = ++totalUnits;
310 partUnits[row.
id] = unitId;
314 if( !partTitle.empty() )
315 partUnits[partTitle] = unitId;
317 else if( row.
type == wxS(
"META" ) )
319 if( row.
inner.contains(
"docType" ) )
331 auto resolveRowUnit = [&](
const V3_ROW& aRow )
333 wxString partId =
V3GetString( aRow.inner,
"partId" );
335 if( !partId.empty() )
337 if(
auto unitOpt =
get_opt( partUnits, partId ) )
347 int rowUnit = resolveRowUnit( row );
349 if( row.
type == wxS(
"PART" ) )
351 currentUnit = partUnits.at( row.
id );
353 else if( row.
type == wxS(
"RECT" ) )
364 rect->SetUnit( rowUnit );
369 else if( row.
type == wxS(
"CIRCLE" ) )
380 circle->SetUnit( rowUnit );
385 else if( row.
type == wxS(
"ARC" ) )
399 shape->SetUnit( rowUnit );
404 else if( row.
type == wxS(
"BEZIER" ) )
406 std::vector<double> points = row.
inner.value(
"controls", nlohmann::json::array() );
410 for(
size_t i = 1; i < points.size(); i += 2 )
416 case 1: shape->SetStart( pt );
break;
417 case 3: shape->SetBezierC1( pt );
break;
418 case 5: shape->SetBezierC2( pt );
break;
419 case 7: shape->SetEnd( pt );
break;
423 shape->SetUnit( rowUnit );
428 else if( row.
type == wxS(
"POLY" ) )
431 row.
inner.value(
"points", nlohmann::json::array() ) );
432 std::vector<double> points = flatPts;
436 for(
size_t i = 1; i < points.size(); i += 2 )
439 shape->SetUnit( rowUnit );
444 else if( row.
type == wxS(
"TEXT" ) )
450 auto text = std::make_unique<SCH_TEXT>(
456 text->SetTextAngleDegrees( angle );
457 text->SetUnit( rowUnit );
462 else if( row.
type == wxS(
"OBJ" ) )
471 wxString mimeType, data;
473 if( imageUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
475 wxArrayString paramsArr =
476 wxSplit( imageUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
478 data = imageUrl.AfterFirst(
',' );
480 if( paramsArr.size() > 0 )
481 mimeType = paramsArr[0];
483 else if( imageUrl.BeforeFirst(
':' ) == wxS(
"blob" ) )
485 wxString objectId = imageUrl.AfterLast(
':' );
487 if(
auto blob =
get_opt( aBlobMap, objectId ) )
489 wxString blobUrl = blob->url;
491 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
493 wxArrayString paramsArr =
494 wxSplit( blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
496 data = blobUrl.AfterFirst(
',' );
498 if( paramsArr.size() > 0 )
499 mimeType = paramsArr[0];
504 if( mimeType.empty() || data.empty() )
507 wxMemoryBuffer buf = wxBase64Decode( data );
509 if( mimeType == wxS(
"image/svg+xml" ) )
531 libsymImporter.
SetScale( pixelScale );
539 for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.
GetItems() )
544 wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
546 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
547 & ~wxImage::Load_Verbose );
550 if( img.LoadFile( memis, mimeType ) )
552 int dimMul = img.GetWidth() * img.GetHeight();
553 double maxPixels = 30000;
555 if( dimMul > maxPixels )
557 double scale = sqrt( maxPixels / dimMul );
558 img.Rescale( img.GetWidth() *
scale, img.GetHeight() *
scale );
570 else if( row.
type == wxS(
"PIN" ) )
572 unitParentedRows[rowUnit][row.
id].push_back( &row );
574 else if( row.
type == wxS(
"ATTR" ) )
578 if( parentId.empty() )
595 unitAttributes[rowUnit].emplace( attr.
key, attr );
596 unitAttributeRows[rowUnit].emplace( attr.
key, &row );
600 unitParentedRows[rowUnit][parentId].push_back( &row );
616 if(
auto globalNetAttr =
get_opt( unitAttributes[1], wxS(
"Global Net Name" ) ) )
618 wxString powerName = globalNetAttr->value;
620 if( powerName.IsEmpty() )
622 if(
auto nameAttr =
get_opt( unitAttributes[1], wxS(
"Name" ) ) )
623 powerName = nameAttr->value;
627 valueText->
SetText( powerName );
628 valueText->
SetVisible( globalNetAttr->valVisible );
630 if(
auto globalNetAttrRow =
get_opt( unitAttributeRows[1], wxS(
"Global Net Name" ) ) )
632 const nlohmann::json& attrInner = ( *globalNetAttrRow )->inner;
634 wxString color =
V3GetString( attrInner,
"color", wxEmptyString );
635 wxString fontFamily =
V3GetString( attrInner,
"fontFamily", wxS(
"default" ) );
636 wxString align =
V3GetString( attrInner,
"align", wxS(
"LEFT_BOTTOM" ) );
638 if( !color.empty() && color.StartsWith( wxS(
"#" ) ) )
644 if( fontFamily != wxS(
"Arial" ) && !fontFamily.IsSameAs( wxS(
"default" ),
false ) )
654 else if( vAlign == 1 )
661 else if( hAlign == 1 )
667 if( globalNetAttr->position )
670 wxString globalNetname = globalNetAttr->value;
672 if( globalNetname.IsEmpty() )
673 globalNetname = powerName;
675 if( !globalNetname.empty() )
678 _(
"Power symbol creates a global label with name '%s'" ),
685 auto designatorAttr =
get_opt( unitAttributes[1], wxS(
"Designator" ) );
687 if( designatorAttr && !designatorAttr->value.empty() )
689 wxString symbolPrefix = designatorAttr->value;
691 if( symbolPrefix.EndsWith( wxS(
"?" ) ) )
692 symbolPrefix.RemoveLast();
698 aDeviceAttributes,
true,
699 [&](
const wxString& attrName,
const wxString& value )
715 for(
auto& [unitId, parentedRows] : unitParentedRows )
717 for(
auto& [pinId, rows] : parentedRows )
719 const V3_ROW* pinRow =
nullptr;
720 std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
722 for(
const V3_ROW* r : rows )
724 if( r->type == wxS(
"ATTR" ) )
731 pinAttributes.emplace( attr.
key, attr );
734 else if( r->type == wxS(
"PIN" ) )
750 pinInfo.
pin.
inverted = ( pinShape == wxS(
"INVERTED" )
751 || pinShape == wxS(
"INVERTED_CLOCK" ) );
753 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>( ksymbol );
755 pin->SetUnit( unitId );
770 pin->SetOrientation( orient );
778 auto pinNameAttr =
get_opt( pinAttributes, wxS(
"Pin Name" ) );
781 pinNameAttr =
get_opt( pinAttributes, wxS(
"NAME" ) );
785 pin->SetName( pinNameAttr->value );
786 pinInfo.
name = pinNameAttr->value;
788 if( !pinNameAttr->valVisible )
793 auto pinNumAttr =
get_opt( pinAttributes, wxS(
"Pin Number" ) );
796 pinNumAttr =
get_opt( pinAttributes, wxS(
"NUMBER" ) );
800 pin->SetNumber( pinNumAttr->value );
801 pinInfo.
number = pinNumAttr->value;
803 if( !pinNumAttr->valVisible )
811 else if(
auto pinTypeAttr =
get_opt( pinAttributes, wxS(
"Pin Type" ) ) )
813 if( pinTypeAttr->value == wxS(
"IN" ) )
815 if( pinTypeAttr->value == wxS(
"OUT" ) )
817 if( pinTypeAttr->value == wxS(
"BI" ) )
821 if(
get_opt( pinAttributes, wxS(
"NO_CONNECT" ) ) )
824 if(
pin->GetNumberTextSize() *
int(
pin->GetNumber().size() ) >
pin->GetLength() )
825 pin->SetNumberTextSize(
pin->GetLength() /
pin->GetNumber().size() );
827 symInfo.
pins.push_back( pinInfo );
833 symInfo.
libSymbol = std::move( ksymbolPtr );
992 std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
993 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
996 std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
999 std::map<wxString, std::vector<const EASYEDAPRO::V3_ROW*>> wireGeometry;
1000 std::map<wxString, const EASYEDAPRO::V3_ROW*> wireRows;
1003 std::map<wxString, std::vector<const EASYEDAPRO::V3_ROW*>> parentedRows;
1008 if( row.
type == wxS(
"WIRE" ) )
1010 wireRows[row.
id] = &row;
1015 wireGeometry[lineGroup].push_back( &row );
1017 else if( row.
type == wxS(
"COMPONENT" ) )
1019 parentedRows[row.
id].push_back( &row );
1024 parentedRows[parentId].push_back( &row );
1031 if( row.
type == wxS(
"RECT" ) )
1044 createdItems.push_back( std::move( rect ) );
1046 else if( row.
type == wxS(
"CIRCLE" ) )
1059 createdItems.push_back( std::move(
circle ) );
1061 else if( row.
type == wxS(
"ARC" ) )
1070 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>(
SHAPE_T::ARC );
1077 createdItems.push_back( std::move( arc ) );
1079 else if( row.
type == wxS(
"POLY" ) )
1085 row.
inner.value(
"points", nlohmann::json::array() ) );
1086 std::vector<double> pointsData = flatPts;
1088 if( pointsData.size() < 4 )
1091 std::unique_ptr<SCH_SHAPE> poly = std::make_unique<SCH_SHAPE>(
SHAPE_T::POLY );
1093 for(
size_t i = 1; i < pointsData.size(); i += 2 )
1098 createdItems.push_back( std::move( poly ) );
1100 else if( row.
type == wxS(
"TEXT" ) )
1107 std::unique_ptr<SCH_TEXT> schText = std::make_unique<SCH_TEXT>(
1113 schText->SetTextAngleDegrees( angle );
1117 createdItems.push_back( std::move( schText ) );
1119 else if( row.
type == wxS(
"OBJ" ) )
1141 wxString base64Data;
1143 if( content.BeforeFirst(
':' ) == wxS(
"data" ) )
1145 wxArrayString paramsArr =
1146 wxSplit( content.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1148 if( paramsArr.size() > 0 )
1149 mimeType = paramsArr[0];
1151 base64Data = content.AfterFirst(
',' );
1153 else if( content.BeforeFirst(
':' ) == wxS(
"blob" ) )
1155 wxString objectId = content.AfterLast(
':' );
1157 if(
auto blob =
get_opt( aBlobMap, objectId ) )
1159 wxString blobUrl = blob->url;
1161 if( blobUrl.BeforeFirst(
':' ) == wxS(
"data" ) )
1163 wxArrayString paramsArr =
1164 wxSplit( blobUrl.AfterFirst(
':' ).BeforeFirst(
',' ),
';',
'\0' );
1166 if( paramsArr.size() > 0 )
1167 mimeType = paramsArr[0];
1169 base64Data = blobUrl.AfterFirst(
',' );
1174 if( mimeType.empty() || base64Data.empty() )
1177 wxMemoryBuffer buf = wxBase64Decode( base64Data );
1179 if( mimeType == wxS(
"image/svg+xml" ) )
1195 schImporter.
SetScale( pixelScale );
1201 svgImportPlugin.
Import();
1203 for( std::unique_ptr<EDA_ITEM>& item : schImporter.
GetItems() )
1207 for(
double i = angle; i > 0; i -= 90 )
1212 schItem->
Rotate( kstart,
false );
1216 schItem->
Rotate( kstart,
false );
1221 schItem->
Rotate( kstart,
false );
1236 createdItems.emplace_back( schItem );
1241 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
1244 wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
1245 & ~wxImage::Load_Verbose );
1249 VECTOR2D kcenter = kstart + ksize / 2;
1254 bitmap->SetPosition( kcenter );
1256 for(
double i = angle; i > 0; i -= 90 )
1257 bitmap->Rotate( kstart,
false );
1260 bitmap->MirrorHorizontally( kstart.
x );
1262 createdItems.push_back( std::move( bitmap ) );
1269 for(
const auto& [wireId, wireRow] : wireRows )
1271 auto geomIt = wireGeometry.find( wireId );
1272 if( geomIt == wireGeometry.end() )
1275 const std::vector<const EASYEDAPRO::V3_ROW*>& lineRows = geomIt->second;
1277 bool firstPointSet =
false;
1295 if( !firstPointSet )
1298 firstPointSet =
true;
1301 std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>(
1305 createdItems.push_back( std::move( line ) );
1309 bool netVisible =
false;
1311 bool netPosSet =
false;
1312 wxString netAlign = wxS(
"LEFT_BOTTOM" );
1313 int netRotation = 0;
1315 if(
auto attrRows =
get_opt( parentedRows, wireId ) )
1319 if( row->
type != wxS(
"ATTR" ) )
1342 if( netVisible && !netName.IsEmpty() && firstPointSet )
1344 VECTOR2D labelPos = netPosSet ? netPos : firstPoint;
1346 std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>(
1351 if( netAlign.StartsWith( wxS(
"RIGHT" ) ) )
1353 else if( netAlign.StartsWith( wxS(
"LEFT" ) ) )
1356 int rot = netRotation % 360;
1364 for(
int i = 0; i < rot; i += 90 )
1368 label->SetSpinStyle( spinStyle );
1370 createdItems.push_back( std::move( label ) );
1375 for(
const auto& [parentId, rows] : parentedRows )
1378 std::map<wxString, std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>> attributes;
1382 if( row->
type == wxS(
"COMPONENT" ) )
1386 else if( row->
type == wxS(
"ATTR" ) )
1389 attributes.emplace( attr.
key, std::make_pair( attr, row ) );
1396 auto deviceAttrIt = attributes.find(
"Device" );
1397 auto symbolAttrIt = attributes.find(
"Symbol" );
1399 std::map<wxString, wxString> compAttrs;
1401 if( deviceAttrIt != attributes.end() && !deviceAttrIt->second.first.value.IsEmpty() )
1405 if( deviceData.
found )
1406 compAttrs = std::move( deviceData.
attributes );
1411 if( symbolAttrIt != attributes.end() && !symbolAttrIt->second.first.value.IsEmpty() )
1412 symbolId = symbolAttrIt->second.first.value;
1414 symbolId =
get_def( compAttrs, wxS(
"Symbol" ), wxEmptyString );
1416 if( symbolId.IsEmpty() )
1418 wxLogWarning( wxString::Format(
1419 _(
"EasyEDA Pro v3 component '%s': missing Symbol attribute, skipping." ),
1424 auto it = aSymbolMap.find( symbolId );
1425 if( it == aSymbolMap.end() )
1428 wxLogError(
"Symbol of '%s' with uuid '%s' not found.", compName, symbolId );
1438 if( !unitName.IsEmpty() )
1444 wxLogWarning( wxString::Format(
1445 _(
"EasyEDA Pro v3 component '%s': partId '%s' not found in symbol '%s', using unit 1." ),
1446 parentId, unitName, symbolId ) );
1453 if( deviceAttrIt != attributes.end() && !deviceAttrIt->second.first.value.IsEmpty() )
1457 if( !deviceLibName.empty() )
1458 libItemName = deviceLibName;
1463 auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
1467 schSym->SetFootprintFieldText( newLibSymbol.
GetFootprint() );
1469 auto footprintAttrIt = attributes.find( wxS(
"Footprint" ) );
1471 wxString resolvedFootprint;
1473 if( footprintAttrIt != attributes.end() && !footprintAttrIt->second.first.value.IsEmpty() )
1475 aProject, aLibName );
1478 aProject, aLibName );
1480 if( !resolvedFootprint.IsEmpty() )
1481 schSym->SetFootprintFieldText( resolvedFootprint );
1488 for(
double i = rotation; i > 0; i -= 90 )
1489 schSym->Rotate(
VECTOR2I(),
true );
1492 schSym->MirrorHorizontally( 0 );
1500 auto nameAttrIt = attributes.find( wxS(
"Name" ) );
1502 if( nameAttrIt != attributes.end() && !nameAttrIt->second.first.value.IsEmpty() )
1503 netName = nameAttrIt->second.first.value;
1505 netName =
get_def( compAttrs, wxS(
"Name" ), wxEmptyString );
1507 if( netName.IsEmpty() )
1512 std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->
CurrentSheet() );
1513 SCH_PIN*
pin = pins.empty() ? nullptr : pins.front();
1515 VECTOR2I labelPos = schSym->GetPosition();
1521 labelPos =
pin->GetPosition();
1523 switch(
pin->PinDrawOrient( schSym->GetTransform() ) )
1532 switch(
pin->GetType() )
1556 std::unique_ptr<SCH_GLOBALLABEL> label =
1557 std::make_unique<SCH_GLOBALLABEL>( labelPos, netName );
1558 label->SetSpinStyle( spinStyle );
1559 label->SetShape( labelShape );
1561 bool labelVisible = !netName.IsEmpty();
1563 if( nameAttrIt != attributes.end() && nameAttrIt->second.second )
1569 && !netName.IsEmpty();
1572 wxString fontFamily =
1575 if( !color.empty() && color.StartsWith( wxS(
"#" ) ) )
1576 label->SetTextColor(
COLOR4D( color ) );
1578 if( fontFamily != wxS(
"Arial" )
1579 && !fontFamily.IsSameAs( wxS(
"default" ),
false ) )
1587 label->SetVisible( labelVisible );
1589 createdItems.push_back( std::move( label ) );
1597 auto globalNetNameAttrIt = attributes.find(
"Global Net Name" );
1598 auto nameAttrIt = attributes.find(
"Name" );
1599 wxString globalNetNameFromProject =
1600 get_def( compAttrs,
"Global Net Name", wxEmptyString );
1601 wxString nameFromProject =
get_def( compAttrs,
"Name", wxEmptyString );
1603 const std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>* valueSource =
nullptr;
1605 if( globalNetNameAttrIt != attributes.end() )
1606 valueSource = &globalNetNameAttrIt->second;
1607 else if( nameAttrIt != attributes.end() )
1608 valueSource = &nameAttrIt->second;
1610 wxString globalNetName;
1617 if( globalNetNameAttrIt != attributes.end()
1618 && !globalNetNameAttrIt->second.first.value.IsEmpty() )
1620 globalNetName = globalNetNameAttrIt->second.first.value;
1622 else if( nameAttrIt != attributes.end()
1623 && !nameAttrIt->second.first.value.IsEmpty() )
1625 globalNetName = nameAttrIt->second.first.value;
1627 else if( !globalNetNameFromProject.IsEmpty() )
1629 globalNetName = globalNetNameFromProject;
1631 else if( !nameFromProject.IsEmpty() )
1633 globalNetName = nameFromProject;
1642 if( valueSource && valueSource->second )
1648 bool valueFromNameAttr = ( nameAttrIt != attributes.end()
1649 && valueSource == &nameAttrIt->second );
1653 if( attrRotation < 0 )
1654 attrRotation += 360;
1656 bool hasExplicitStyleOrPosition =
1663 || attrRotation != 0;
1665 attr.
value = globalNetName;
1667 if( !globalNetName.IsEmpty() )
1669 else if( valueVisibleMissing )
1672 if( valueFromNameAttr && !hasExplicitStyleOrPosition )
1676 if( !globalNetName.IsEmpty() )
1678 else if( valueVisibleMissing )
1684 compAttrs, schSym.get(), attrRow->
inner );
1686 if( !globalNetName.IsEmpty() )
1693 valueField->
SetVisible( !globalNetName.IsEmpty() );
1696 for(
SCH_PIN*
pin : schSym->GetAllLibPins() )
1697 pin->SetName( globalNetName );
1699 schSym->SetRef( &aSchematic->
CurrentSheet(), wxS(
"#PWR?" ) );
1705 auto designatorAttrIt = attributes.find(
"Designator" );
1707 bool hasReferenceValue =
false;
1709 if( designatorAttrIt != attributes.end() )
1715 schSym.get(), attrRow->
inner );
1717 if( !attr.
value.IsEmpty() )
1720 hasReferenceValue =
true;
1724 if( !hasReferenceValue )
1731 [&](
const wxString& attrKey,
const wxString& value )
1733 SCH_FIELD* field = schSym->FindFieldCaseInsensitive( attrKey );
1742 wxString description =
get_def( compAttrs, wxS(
"Description" ), wxEmptyString );
1744 if( !description.empty() )
1750 auto valueAttrIt = attributes.find(
"Value" );
1751 auto nameAttrIt = attributes.find(
"Name" );
1753 wxString fallbackValue =
get_def( compAttrs, wxS(
"Value" ), wxEmptyString );
1755 if( fallbackValue.IsEmpty() )
1756 fallbackValue =
get_def( compAttrs, wxS(
"Name" ), wxEmptyString );
1758 const std::pair<EASYEDAPRO::SCH_ATTR, const EASYEDAPRO::V3_ROW*>* valueSource =
nullptr;
1760 if( valueAttrIt != attributes.end() && valueAttrIt->second.first.valVisible )
1761 valueSource = &valueAttrIt->second;
1762 else if( nameAttrIt != attributes.end() && nameAttrIt->second.first.valVisible )
1763 valueSource = &nameAttrIt->second;
1764 else if( valueAttrIt != attributes.end() )
1765 valueSource = &valueAttrIt->second;
1766 else if( nameAttrIt != attributes.end() )
1767 valueSource = &nameAttrIt->second;
1771 if( valueAttrIt != attributes.end() && !valueAttrIt->second.first.value.IsEmpty() )
1772 valueText = valueAttrIt->second.first.value;
1773 else if( nameAttrIt != attributes.end() && !nameAttrIt->second.first.value.IsEmpty() )
1774 valueText = nameAttrIt->second.first.value;
1776 valueText = fallbackValue;
1780 if( !valueText.IsEmpty() )
1782 if( valueSource && valueSource->second )
1785 attr.
value = valueText;
1788 schSym.get(), valueSource->second->inner );
1801 for(
const auto& [key, attrPair] : attributes )
1803 if( key == wxS(
"Designator" ) || key == wxS(
"Device" ) || key == wxS(
"Symbol" )
1804 || key == wxS(
"Name" ) || key == wxS(
"Value" ) )
1817 if( key == wxS(
"Footprint" ) )
1828 if( key == wxS(
"Footprint" ) )
1835 compAttrs, schSym.get(), attrRow->
inner );
1840 schSym.get(), attrRow->
inner );
1846 createdItems.push_back( std::move( schSym ) );
1850 bool hasBBox =
false;
1852 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1859 itemBBox = item->GetBoundingBox();
1863 sheetBBox = itemBBox;
1868 sheetBBox.
Merge( itemBBox );
1876 const int margin =
schIUScale.MilsToIU( 200 );
1879 -sheetBBox.
GetTop() + margin );
1883 offset.
x =
KiROUND( offset.
x / alignGrid ) * alignGrid;
1884 offset.
y =
KiROUND( offset.
y / alignGrid ) * alignGrid;
1892 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1894 item->Move( offset );
1895 screen->
Append( item.release() );
1900 for( std::unique_ptr<SCH_ITEM>& item : createdItems )
1901 screen->
Append( item.release() );