46#include <wx/filename.h>
104 std::ifstream file( aFileName.fn_str() );
106 if( !file.is_open() )
111 if( std::getline( file, line ) )
113 if( line.find(
"!PADS-" ) != std::string::npos )
122 const std::map<std::string, UTF8>* aProperties,
PROJECT* aProject )
126 std::unique_ptr<BOARD> board( aAppendToMe ? aAppendToMe :
new BOARD() );
138 parser.
Parse( aFileName );
140 catch(
const std::exception& e )
142 THROW_IO_ERROR( wxString::Format(
"Error parsing PADS file: %s", e.what() ) );
187 return board.release();
193 const auto& nets =
m_parser->GetNets();
195 for(
const auto& pads_net : nets )
198 for(
const auto& pads_net : nets )
200 for(
const auto&
pin : pads_net.pins )
202 std::string key =
pin.ref_des +
"." +
pin.pin_name;
207 const auto& route_nets =
m_parser->GetRoutes();
209 for(
const auto& route : route_nets )
211 for(
const auto&
pin : route.pins )
213 std::string key =
pin.ref_des +
"." +
pin.pin_name;
220 for(
const auto& route : route_nets )
223 for(
const auto& pour_def :
m_parser->GetPours() )
226 for(
const auto& copper :
m_parser->GetCopperShapes() )
232 const auto& reuse_blocks =
m_parser->GetReuseBlocks();
234 for(
const auto& [blockName, block] : reuse_blocks )
236 for(
const std::string& partName : block.part_names )
246 const auto& decals =
m_parser->GetPartDecals();
247 const auto& part_types =
m_parser->GetPartTypes();
248 const auto& partInstanceAttrs =
m_parser->GetPartInstanceAttrs();
249 const auto& parts =
m_parser->GetParts();
251 for(
const auto& pads_part : parts )
260 path.push_back( symbolUuid );
264 std::string decal_name = pads_part.decal;
270 if( !pads_part.explicit_decal )
272 auto part_type_it = part_types.find( decal_name );
274 if( part_type_it != part_types.end() )
275 decal_name = part_type_it->second.decal_name;
280 std::stringstream ss( decal_name );
282 std::vector<std::string> decal_list;
284 while( std::getline( ss, segment,
':' ) )
286 decal_list.push_back( segment );
289 std::string actual_decal_name;
290 bool found_valid_decal =
false;
292 if( pads_part.alt_decal_index >= 0
293 &&
static_cast<size_t>( pads_part.alt_decal_index ) < decal_list.size() )
295 const std::string& alt_decal = decal_list[pads_part.alt_decal_index];
297 if( decals.find( alt_decal ) != decals.end() )
299 actual_decal_name = alt_decal;
300 found_valid_decal =
true;
304 if( !found_valid_decal )
306 for(
const std::string& decal : decal_list )
308 if( decals.find( decal ) != decals.end() )
310 actual_decal_name = decal;
311 found_valid_decal =
true;
317 if( found_valid_decal )
319 decal_name = actual_decal_name;
326 footprint->
SetValue( pads_part.decal );
328 if( !pads_part.alternate_decals.empty() )
332 for(
size_t i = 0; i < pads_part.alternate_decals.size(); ++i )
335 alternates += wxT(
", " );
337 alternates += wxString::FromUTF8( pads_part.alternate_decals[i] );
344 footprint->
Add( field );
347 auto partCoordScaler = [&](
double val,
bool is_x ) {
360 long long origin_nm =
static_cast<long long>( std::round( origin *
m_scaleFactor ) );
361 long long val_nm =
static_cast<long long>( std::round( val * part_factor ) );
363 long long res_nm = val_nm - origin_nm;
368 return static_cast<int>( std::clamp<long long>( res_nm, INT_MIN, INT_MAX ) );
372 partCoordScaler( pads_part.location.y,
false ) ) );
386 auto ptIt = part_types.find( pads_part.decal );
388 if( ptIt != part_types.end() )
389 partType = &ptIt->second;
391 const std::map<std::string, std::string>* instanceAttrs =
nullptr;
392 auto iaIt = partInstanceAttrs.find( pads_part.name );
394 if( iaIt != partInstanceAttrs.end() )
395 instanceAttrs = &iaIt->second;
397 auto applyAttributes = [&](
const std::vector<PADS_IO::ATTRIBUTE>& attrs,
398 std::function<int(
double)> scaler )
400 for(
const auto& attr : attrs )
403 bool ownsField =
false;
405 if( attr.name ==
"Ref.Des." )
409 else if( attr.name ==
"Part Type" || attr.name ==
"VALUE" )
411 field = &footprint->
Value();
415 std::string attrValue;
419 auto valIt = instanceAttrs->find( attr.name );
421 if( valIt != instanceAttrs->end() )
422 attrValue = valIt->second;
425 if( attrValue.empty() && partType )
427 auto valIt = partType->
attributes.find( attr.name );
430 attrValue = valIt->second;
433 if( !attrValue.empty() )
436 wxString::FromUTF8( attr.name ) );
437 field->
SetText( wxString::FromUTF8( attrValue ) );
456 int scaledSize = scaler( attr.height );
468 VECTOR2I offset( scaler( attr.x ), -scaler( attr.y ) );
484 if( attr.hjust ==
"LEFT" )
486 else if( attr.hjust ==
"RIGHT" )
491 if( attr.vjust ==
"UP" )
493 else if( attr.vjust ==
"DOWN" )
499 footprint->
Add( field );
503 auto decal_it = decals.find( decal_name );
505 if( decal_it != decals.end() )
507 auto decalScaler = [&](
double val ) {
511 const std::string& units = decal_it->second.units;
513 if( units ==
"M" || units ==
"D" || units ==
"MILS" || units ==
"MIL" )
515 else if( units ==
"MM" || units ==
"METRIC" )
517 else if( units ==
"I" || units ==
"INCHES" || units ==
"INCH" )
523 applyAttributes( decal_it->second.attributes, decalScaler );
530 wxString::Format(
_(
"Footprint '%s' not found in decal list, part skipped" ),
536 auto partScaler = [&](
double val ) {
542 if( pads_part.units ==
"M" )
return KiROUND( val );
547 applyAttributes( pads_part.attributes, partScaler );
563 blockField->
SetText( wxString::FromUTF8( blockIt->second ) );
564 footprint->
Add( blockField );
567 if( decal_it == decals.end() )
576 auto decalScaler = [&](
double val ) {
581 || decal.
units ==
"MIL" )
583 else if( decal.
units ==
"MM" || decal.
units ==
"METRIC" )
585 else if( decal.
units ==
"I" || decal.
units ==
"INCHES" || decal.
units ==
"INCH" )
594 const std::string& shape = layer_def.
shape;
599 if( shape ==
"R" || shape ==
"C" || shape ==
"A" || shape ==
"RT" )
604 else if( shape ==
"S" || shape ==
"ST" )
609 else if( shape ==
"O" || shape ==
"OT" )
612 pad->SetSize( kicad_layer, size );
614 else if( shape ==
"RF" )
617 pad->SetSize( kicad_layer, size );
624 pad->SetOffset( kicad_layer, pad_offset );
627 else if( shape ==
"OF" )
630 pad->SetSize( kicad_layer, size );
637 pad->SetOffset( kicad_layer, pad_offset );
640 else if( shape ==
"RC" || shape ==
"OC" )
643 pad->SetSize( kicad_layer, size );
647 double min_dim = std::min( size.
x, size.
y );
649 double ratio = ( min_dim > 0 ) ? (
radius / min_dim ) : 0.25;
650 ratio = std::min( ratio, 0.5 );
651 pad->SetRoundRectRadiusRatio( kicad_layer, ratio );
655 pad->SetRoundRectRadiusRatio( kicad_layer, 0.25 );
663 pad->SetOffset( kicad_layer, pad_offset );
677 for(
size_t term_idx = 0; term_idx < decal.
terminals.size(); ++term_idx )
679 const auto& term = decal.
terminals[term_idx];
683 pad->SetNumber( term.name );
685 VECTOR2I pad_pos( decalScaler( term.x ), -decalScaler( term.y ) );
691 int pin_num =
static_cast<int>( term_idx + 1 );
693 auto stack_it = decal.
pad_stacks.find( pin_num );
698 if( stack_it != decal.
pad_stacks.end() && !stack_it->second.empty() )
700 const std::vector<PADS_IO::PAD_STACK_LAYER>& stack = stack_it->second;
704 double slot_length = 0.0;
705 double slot_orientation = 0.0;
706 double pad_rotation = 0.0;
708 for(
const auto& layer_def : stack )
710 if( layer_def.
drill > 0 )
712 drill = layer_def.
drill;
713 plated = layer_def.
plated;
723 auto mapPadsLayer = [&](
int pads_layer ) ->
PCB_LAYER_ID {
724 if( pads_layer == -2 || pads_layer == 1 )
726 else if( pads_layer == -1
727 || pads_layer ==
m_parser->GetParameters().layer_count )
729 else if( pads_layer > 1
730 && pads_layer < m_parser->GetParameters().layer_count )
732 int inner_idx = pads_layer - 2;
734 if( inner_idx >= 0 && inner_idx < 30 )
741 bool has_explicit_layers =
false;
743 for(
const auto& layer_def : stack )
745 if( layer_def.
layer == -2 || layer_def.
layer == -1
746 || layer_def.
layer == 1
747 || layer_def.
layer ==
m_parser->GetParameters().layer_count )
749 has_explicit_layers =
true;
757 LSET explicitly_seen_tech;
759 for(
const auto& layer_def : stack )
761 if( layer_def.
layer > 0 )
768 explicitly_seen_tech.
set( check );
780 if( has_explicit_layers )
782 std::string front_shape;
783 std::string back_shape;
784 double front_sizeA = 0;
785 double back_sizeA = 0;
786 double front_sizeB = 0;
787 double back_sizeB = 0;
789 for(
const auto& layer_def : stack )
791 if( layer_def.
sizeA <= 0 )
794 if( layer_def.
shape ==
"RT" || layer_def.
shape ==
"ST"
795 || layer_def.
shape ==
"RA" || layer_def.
shape ==
"SA" )
802 if( mapped ==
F_Cu && front_shape.empty() )
804 front_shape = layer_def.
shape;
805 front_sizeA = layer_def.
sizeA;
806 front_sizeB = layer_def.
sizeB;
808 else if( mapped ==
B_Cu && back_shape.empty() )
810 back_shape = layer_def.
shape;
811 back_sizeA = layer_def.
sizeA;
812 back_sizeB = layer_def.
sizeB;
816 if( !front_shape.empty() && !back_shape.empty()
817 && ( front_shape != back_shape
818 || front_sizeA != back_sizeA
819 || front_sizeB != back_sizeB ) )
825 for(
const auto& layer_def : stack )
827 if( layer_def.
layer == 0 )
829 if( !has_explicit_layers )
833 convertPadShape( layer_def,
pad,
F_Cu, part_orient );
848 if( layer_def.
sizeA <= 0 )
857 if( layer_def.
shape ==
"RT" || layer_def.
shape ==
"ST" )
863 pad->SetLocalThermalSpokeWidthOverride(
869 pad->SetThermalSpokeAngleDegrees(
876 if( layer_def.
shape ==
"RA" || layer_def.
shape ==
"SA" )
895 layer_set.
set( tech_layer );
900 layer_set.
set( kicad_layer );
901 convertPadShape( layer_def,
pad, kicad_layer, part_orient );
905 if( layer_set.none() )
908 convertPadShape( stack[0],
pad,
F_Cu, part_orient );
917 if( layer_set.test(
F_Cu ) && !layer_set.test(
F_Mask )
918 && !explicitly_seen_tech.test(
F_Mask ) )
923 if( layer_set.test(
F_Cu ) && !layer_set.test(
F_Paste )
924 && !explicitly_seen_tech.test(
F_Paste ) )
929 if( layer_set.test(
B_Cu ) && !layer_set.test(
B_Mask )
930 && !explicitly_seen_tech.test(
B_Mask ) )
935 if( layer_set.test(
B_Cu ) && !layer_set.test(
B_Paste )
936 && !explicitly_seen_tech.test(
B_Paste ) )
942 if( slot_length > 0 && slot_length != drill )
946 int drillMinor = decalScaler( drill );
947 int drillMajor = decalScaler( slot_length );
952 double relAngle = slot_orientation - pad_rotation;
954 relAngle = fmod( relAngle, 360.0 );
959 bool vertical = ( relAngle > 45.0 && relAngle < 135.0 )
960 || ( relAngle > 225.0 && relAngle < 315.0 );
963 pad->SetDrillSize(
VECTOR2I( drillMinor, drillMajor ) );
965 pad->SetDrillSize(
VECTOR2I( drillMajor, drillMinor ) );
970 decalScaler( drill ) ) );
986 LSET mask_paste_bits =
991 pad->SetLayerSet( layer_set );
1002 std::string pinKey = pads_part.name +
"." + term.name;
1015 for(
const auto& item : decal.
items )
1017 if( item.points.empty() )
1024 if( item.layer == 0 )
1034 if( mapped_layer ==
B_Cu )
1041 shape_layer = mapped_layer;
1050 _(
"Skipping decal item on unmapped layer %d" ), item.layer ),
1056 bool is_circle = ( item.type ==
"CIRCLE" );
1057 bool is_closed = ( item.type ==
"CLOSED" || is_circle );
1061 if( is_circle && item.points.size() >= 2 )
1066 double x1 = item.points[0].x;
1067 double y1 = item.points[0].y;
1068 double x2 = item.points[1].x;
1069 double y2 = item.points[1].y;
1071 double cx = ( x1 + x2 ) / 2.0;
1072 double cy = ( y1 + y2 ) / 2.0;
1074 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 )
1075 + ( y2 - y1 ) * ( y2 - y1 ) )
1087 shape->
SetEnd( fp_pos + pt_on_circle );
1091 footprint->
Add( shape );
1096 if( item.points.size() < 2 )
1099 for(
size_t i = 0; i < item.points.size() - 1; ++i )
1113 VECTOR2I start( decalScaler( p1.
x ), -decalScaler( p1.
y ) );
1118 std::swap( start,
end );
1132 VECTOR2I start( decalScaler( p1.
x ), -decalScaler( p1.
y ) );
1143 footprint->
Add( shape );
1146 if( is_closed && item.points.size() > 2 )
1160 -decalScaler( pFirst.
arc.
cy ) );
1161 VECTOR2I start( decalScaler( pLast.
x ), -decalScaler( pLast.
y ) );
1162 VECTOR2I end( decalScaler( pFirst.
x ), -decalScaler( pFirst.
y ) );
1165 std::swap( start,
end );
1179 VECTOR2I start( decalScaler( pLast.
x ), -decalScaler( pLast.
y ) );
1180 VECTOR2I end( decalScaler( pFirst.
x ), -decalScaler( pFirst.
y ) );
1190 footprint->
Add( shape );
1195 if( pads_part.bottom_layer )
1205 const auto& reuse_blocks =
m_parser->GetReuseBlocks();
1207 if( reuse_blocks.empty() )
1210 std::map<std::string, PCB_GROUP*> blockGroups;
1212 for(
const auto& [blockName, block] : reuse_blocks )
1214 if( !block.instances.empty() || !block.part_names.empty() )
1217 group->SetName( wxString::FromUTF8( blockName ) );
1219 blockGroups[blockName] =
group;
1225 for(
PCB_FIELD* field : fp->GetFields() )
1227 if( field->GetName() == wxT(
"PADS_Reuse_Block" ) )
1229 std::string blockName = field->GetText().ToStdString();
1230 auto groupIt = blockGroups.find( blockName );
1232 if( groupIt != blockGroups.end() )
1234 groupIt->second->AddItem( fp );
1246 const auto& test_points =
m_parser->GetTestPoints();
1248 for(
const auto&
tp : test_points )
1254 footprint->
SetValue( wxString::FromUTF8(
tp.symbol_name ) );
1267 pad->SetNumber( wxT(
"1" ) );
1268 pad->SetPosition( pos );
1275 if( !
tp.net_name.empty() )
1290 tpField->
SetText( wxString::FromUTF8(
tp.type ) );
1291 footprint->
Add( tpField );
1300 const auto& texts =
m_parser->GetTexts();
1302 for(
const auto& pads_text : texts )
1311 _(
"Text on unmapped layer %d assigned to Comments layer" ),
1318 text->SetText( pads_text.content );
1322 int scaledSize =
scaleSize( pads_text.height );
1327 text->SetTextSize(
VECTOR2I( charWidth, charHeight ) );
1329 if( pads_text.width > 0 )
1333 text->SetTextAngle( textAngle );
1341 text->SetPosition( pos + textShift );
1343 if( pads_text.hjust ==
"LEFT" )
1345 else if( pads_text.hjust ==
"RIGHT" )
1350 if( pads_text.vjust ==
"UP" )
1352 else if( pads_text.vjust ==
"DOWN" )
1357 text->SetKeepUpright(
false );
1358 text->SetLayer( textLayer );
1366 const auto& routes =
m_parser->GetRoutes();
1367 std::set<std::pair<int, int>> placedThroughVias;
1369 for(
const auto& route : routes )
1376 for(
const auto& track_def : route.tracks )
1378 if( track_def.points.size() < 2 )
1388 _(
"Skipping track on non-copper layer %d" ), track_def.layer ),
1396 for(
size_t i = 0; i < track_def.points.size() - 1; ++i )
1407 if( ( start -
end ).EuclideanNorm() < 1000 )
1433 for(
const auto& via_def : route.vias )
1439 auto it =
m_parser->GetViaDefs().find( via_def.name );
1441 if( it !=
m_parser->GetViaDefs().end() )
1443 switch( it->second.via_type )
1456 auto key = std::make_pair( pos.
x, pos.
y );
1458 if( placedThroughVias.count( key ) )
1461 placedThroughVias.insert( key );
1466 via->SetPosition( pos );
1468 if( it !=
m_parser->GetViaDefs().end() )
1484 via->SetLayerPair( startLayer, endLayer );
1485 via->SetViaType( viaType );
1516 const auto& copperShapes =
m_parser->GetCopperShapes();
1522 return cs.outline.size() == 2 && !cs.outline[1].is_arc
1523 && !cs.filled && !cs.is_cutout;
1529 auto tryFormRectangle = [&](
size_t idx,
VECTOR2I& minCorner,
VECTOR2I& maxCorner ) ->
bool
1531 if( idx + 3 >= copperShapes.size() )
1534 const auto& c0 = copperShapes[idx];
1535 const auto& c1 = copperShapes[idx + 1];
1536 const auto& c2 = copperShapes[idx + 2];
1537 const auto& c3 = copperShapes[idx + 3];
1539 if( !isRectCandidate( c0 ) || !isRectCandidate( c1 )
1540 || !isRectCandidate( c2 ) || !isRectCandidate( c3 ) )
1545 if( c1.net_name != c0.net_name || c2.net_name != c0.net_name
1546 || c3.net_name != c0.net_name )
1551 if( c1.layer != c0.layer || c2.layer != c0.layer || c3.layer != c0.layer )
1558 for(
int i = 0; i < 4; ++i )
1561 scaleCoord( segs[i]->outline[0].y,
false ) );
1563 scaleCoord( segs[i]->outline[1].y,
false ) );
1567 for(
int i = 0; i < 4; ++i )
1572 if( s.
x != e.
x && s.
y != e.
y )
1577 for(
int i = 0; i < 3; ++i )
1579 if( pts[i * 2 + 1] != pts[( i + 1 ) * 2] )
1584 if( pts[7] != pts[0] )
1588 int minX = pts[0].
x, maxX = pts[0].
x;
1589 int minY = pts[0].
y, maxY = pts[0].
y;
1591 for(
int i = 0; i < 8; ++i )
1593 minX = std::min( minX, pts[i].x );
1594 maxX = std::max( maxX, pts[i].x );
1595 minY = std::min( minY, pts[i].y );
1596 maxY = std::max( maxY, pts[i].y );
1599 minCorner =
VECTOR2I( minX, minY );
1600 maxCorner =
VECTOR2I( maxX, maxY );
1604 for(
size_t idx = 0; idx < copperShapes.size(); ++idx )
1606 const auto& copper = copperShapes[idx];
1608 if( copper.outline.size() < 2 )
1611 if( copper.is_cutout )
1621 _(
"COPPER item on unmapped layer %d defaulting to F.Cu" ),
1636 if( tryFormRectangle( idx, minCorner, maxCorner ) )
1641 rect->
SetEnd( maxCorner );
1653 for(
size_t i = 0; i < copper.outline.size() - 1; ++i )
1655 const auto& p1 = copper.outline[i];
1656 const auto& p2 = copper.outline[i + 1];
1661 if( ( start -
end ).EuclideanNorm() < 1000 )
1687 if( !copper.net_name.empty() )
1692 if( copper.outline.size() < 3 )
1710 for(
size_t i = 0; i < copper.outline.size() - 1; ++i )
1712 const auto& p1 = copper.outline[i];
1713 const auto& p2 = copper.outline[i + 1];
1718 if( ( start -
end ).EuclideanNorm() < 1000 )
1755 const auto& clusters =
m_parser->GetClusters();
1757 if( clusters.empty() )
1760 std::map<std::string, const PADS_IO::CLUSTER*> netToClusterMap;
1762 for(
const auto& cluster : clusters )
1764 for(
const std::string& netName : cluster.net_names )
1767 netToClusterMap[converted] = &cluster;
1771 std::map<int, PCB_GROUP*> clusterGroups;
1773 for(
const auto& cluster : clusters )
1776 group->SetName( wxString::FromUTF8( cluster.name ) );
1778 clusterGroups[cluster.id] =
group;
1787 std::string netName = net->
GetNetname().ToStdString();
1788 auto clusterIt = netToClusterMap.find( netName );
1790 if( clusterIt != netToClusterMap.end() )
1792 int clusterId = clusterIt->second->id;
1793 auto groupIt = clusterGroups.find( clusterId );
1795 if( groupIt != clusterGroups.end() )
1797 groupIt->second->AddItem( track );
1807 const auto& pours =
m_parser->GetPours();
1808 const auto& params =
m_parser->GetParameters();
1812 auto isValidPoly = [](
const std::vector<PADS_IO::ARC_POINT>& pts )
1814 if( pts.size() >= 3 )
1817 if( pts.size() == 1 && pts[0].is_arc
1818 &&
std::abs( pts[0].arc.delta_angle ) >= 359.0 )
1828 int maxPriority = 0;
1830 for(
const auto& pour_def : pours )
1832 if( pour_def.priority > maxPriority )
1833 maxPriority = pour_def.priority;
1837 std::map<std::string, ZONE*> pourZoneMap;
1840 std::map<std::string, std::string> hatoutToParent;
1843 for(
const auto& pour_def : pours )
1847 hatoutToParent[pour_def.name] = pour_def.owner_pour;
1857 if( pour_def.points.size() < 3 )
1867 _(
"Skipping pour on unmapped layer %d" ), pour_def.layer ),
1880 if( pour_def.is_cutout )
1888 zone->
SetZoneName( wxString::Format( wxT(
"Cutout_%s" ), pour_def.owner_pour ) );
1898 int kicadPriority = maxPriority - pour_def.priority + 1;
1908 pourZoneMap[pour_def.name] = zone;
1913 for(
const auto& pour_def : pours )
1918 if( !isValidPoly( pour_def.points ) )
1921 auto zoneIt = pourZoneMap.find( pour_def.owner_pour );
1923 if( zoneIt == pourZoneMap.end() )
1926 ZONE* zone = zoneIt->second;
1951 for(
const auto& void_def : pours )
1956 if( !isValidPoly( void_def.points ) )
1961 auto parentIt = hatoutToParent.find( void_def.owner_pour );
1963 if( parentIt == hatoutToParent.end() )
1966 if( parentIt->second != pour_def.owner_pour )
1986 const auto& pts = polyline.points;
1988 if( pts.size() < 2 )
1991 for(
size_t i = 0; i < pts.size() - 1; ++i )
2021 if( polyline.closed && pts.size() > 2 )
2026 bool needsClosing = (
std::abs( pLast.
x - pFirst.
x ) > 0.001
2057 const auto& dimensions =
m_parser->GetDimensions();
2059 for(
const auto& dim : dimensions )
2061 if( dim.points.size() < 2 )
2075 if( dim.is_horizontal )
2085 if( dim.is_horizontal )
2087 double heightOffset = dim.crossbar_pos - dim.points[0].y;
2088 int height = -
scaleSize( heightOffset );
2093 double heightOffset = dim.crossbar_pos - dim.points[0].x;
2107 if( dim.text_height > 0 )
2109 int scaledSize =
scaleSize( dim.text_height );
2116 if( dim.text_width > 0 )
2120 if( !dim.text.empty() )
2128 if( dim.rotation != 0.0 )
2139 const auto& keepouts =
m_parser->GetKeepouts();
2140 int keepoutIndex = 0;
2142 for(
const auto& ko : keepouts )
2144 if( ko.outline.size() < 3 )
2150 if( ko.layers.empty() )
2154 else if( ko.layers.size() == 1 )
2163 _(
"Skipping keepout on unmapped layer %d" ), ko.layers[0] ),
2176 for(
int layer : ko.layers )
2181 layerSet.
set( mappedLayer );
2184 if( layerSet.none() )
2212 zone->
SetZoneName( wxString::Format( wxT(
"%s_%d" ), typeName, ++keepoutIndex ) );
2218 if( ko.outline.size() > 2 )
2220 const auto& first = ko.outline.front();
2221 const auto& last = ko.outline.back();
2223 if(
std::abs( first.x - last.x ) > 0.001 ||
std::abs( first.y - last.y ) > 0.001 )
2239 const auto& pts = graphic.points;
2246 if( pts.size() == 1 && pts[0].is_arc
2247 &&
std::abs( pts[0].arc.delta_angle - 360.0 ) < 0.1 )
2262 if( pts.size() < 2 )
2265 for(
size_t i = 0; i < pts.size() - 1; ++i )
2293 if( graphic.closed && pts.size() > 2 )
2298 bool needsClosing = (
std::abs( pLast.
x - pFirst.
x ) > 0.001
2329 wxFileName fn( aFileName );
2330 fn.SetExt( wxT(
"kicad_dru" ) );
2332 wxString customRules = wxT(
"(version 1)\n" );
2334 const auto& diffPairs =
m_parser->GetDiffPairs();
2336 for(
const auto& dp : diffPairs )
2338 if( dp.name.empty() || ( dp.gap <= 0 && dp.width <= 0 ) )
2341 wxString ruleName = wxString::Format( wxT(
"DiffPair_%s" ), wxString::FromUTF8( dp.name ) );
2343 if( dp.gap > 0 && !dp.positive_net.empty() && !dp.negative_net.empty() )
2348 wxString gapStr = wxString::FromUTF8(
FormatDouble2Str( gapMm ) ) + wxT(
"mm" );
2350 customRules += wxString::Format(
2351 wxT(
"\n(rule \"%s_gap\"\n" )
2352 wxT(
" (condition \"A.NetName == '%s' && B.NetName == '%s'\")\n" )
2353 wxT(
" (constraint clearance (min %s)))\n" ),
2354 ruleName, posNet, negNet, gapStr );
2358 if( customRules.length() > 15 )
2360 wxFile rulesFile( fn.GetFullPath(), wxFile::write );
2362 if( rulesFile.IsOpened() )
2363 rulesFile.Write( customRules );
2373 size_t trackCount = 0;
2374 size_t viaCount = 0;
2384 m_reporter->Report( wxString::Format(
_(
"Imported %zu footprints, %d nets, %zu tracks,"
2385 " %zu vias, %zu zones" ),
2388 trackCount, viaCount,
2395 const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector )
2397 std::map<wxString, PCB_LAYER_ID> layer_map;
2401 layer_map[layer.Name] = layer.AutoMapLayer;
2411 return static_cast<int>( std::clamp<int64_t>( nm, INT_MIN, INT_MAX ) );
2419 long long origin_nm =
static_cast<long long>( std::round( origin *
m_scaleFactor ) );
2420 long long val_nm =
static_cast<long long>( std::round( aVal *
m_scaleFactor ) );
2422 long long result = aIsX ? ( val_nm - origin_nm ) : ( origin_nm - val_nm );
2423 return static_cast<int>( std::clamp<long long>(
result, INT_MIN, INT_MAX ) );
2431 if(
info.padsLayerNum == aPadsLayer )
2448 if( aNetName.empty() )
2479 const std::vector<PADS_IO::ARC_POINT>& aPts )
2485 if( aPts.size() == 1 && aPts[0].is_arc
2486 &&
std::abs( aPts[0].arc.delta_angle ) >= 359.0 )
2492 constexpr int NUM_SEGS = 36;
2494 for(
int i = 0; i < NUM_SEGS; i++ )
2496 double angle = 2.0 *
M_PI * i / NUM_SEGS;
2506 for(
size_t i = 1; i < aPts.size(); i++ )
2508 const auto& pt = aPts[i];
2515 for(
int j = 1; j < arcPoly.
PointCount(); j++ )
2537 std::swap( start,
end );
2553 double startAngleRad = atan2( aPrev.
y - aCurr.
arc.
cy, aPrev.
x - aCurr.
arc.
cx );
2556 double midX = aCurr.
arc.
cx + aCurr.
arc.
radius * cos( midAngleRad );
2557 double midY = aCurr.
arc.
cy + aCurr.
arc.
radius * sin( midAngleRad );
2569 std::vector<PADS_IO::LAYER_INFO> padsLayerInfos =
m_parser->GetLayerInfos();
2595 for(
const auto& padsInfo : padsLayerInfos )
2598 info.padsLayerNum = padsInfo.number;
2599 info.name = padsInfo.name;
2604 info.type = convertLayerType( padsInfo.layer_type );
2606 std::string lowerName = padsInfo.name;
2607 std::transform( lowerName.begin(), lowerName.end(), lowerName.begin(),
2608 [](
unsigned char c ){ return std::tolower( c ); } );
2610 bool isBottom = lowerName.find(
"bottom" ) != std::string::npos
2611 || lowerName.find(
"bot" ) != std::string::npos;
2623 if( padsInfo.number == 1 )
2625 else if( padsInfo.number ==
m_parser->GetParameters().layer_count )
2634 info.required = padsInfo.required;
2638 std::vector<INPUT_LAYER_DESC> inputDescs =
2644 int copperLayerCount =
m_parser->GetParameters().layer_count;
2646 if( copperLayerCount < 1 )
2647 copperLayerCount = 2;
2649 m_loadBoard->SetCopperLayerCount( copperLayerCount );
2657 switch(
m_parser->GetParameters().units )
2679 const auto& designRules =
m_parser->GetDesignRules();
2702 if( defaultNetclass )
2704 defaultNetclass->SetClearance(
scaleSize( designRules.default_clearance ) );
2705 defaultNetclass->SetTrackWidth(
scaleSize( designRules.default_track_width ) );
2706 defaultNetclass->SetViaDiameter(
scaleSize( designRules.default_via_size ) );
2707 defaultNetclass->SetViaDrill(
scaleSize( designRules.default_via_drill ) );
2710 const auto& viaDefs =
m_parser->GetViaDefs();
2712 if( !viaDefs.empty() )
2716 const std::string& defaultViaName =
m_parser->GetParameters().default_signal_via;
2717 auto defaultIt = viaDefs.find( defaultViaName );
2719 if( defaultIt == viaDefs.end() )
2720 defaultIt = viaDefs.begin();
2722 int viaDia =
scaleSize( defaultIt->second.size );
2723 int viaDrill =
scaleSize( defaultIt->second.drill );
2728 if( defaultNetclass )
2730 defaultNetclass->SetViaDiameter( viaDia );
2731 defaultNetclass->SetViaDrill( viaDrill );
2734 for(
const auto& [
name, def] : viaDefs )
2738 const auto& netClasses =
m_parser->GetNetClasses();
2740 for(
const auto& nc : netClasses )
2742 if( nc.name.empty() )
2745 wxString ncName = wxString::FromUTF8( nc.name );
2746 std::shared_ptr<NETCLASS> netclass = std::make_shared<NETCLASS>( ncName );
2748 if( nc.clearance > 0 )
2749 netclass->SetClearance(
scaleSize( nc.clearance ) );
2751 if( nc.track_width > 0 )
2752 netclass->SetTrackWidth(
scaleSize( nc.track_width ) );
2754 if( nc.via_size > 0 )
2755 netclass->SetViaDiameter(
scaleSize( nc.via_size ) );
2757 if( nc.via_drill > 0 )
2758 netclass->SetViaDrill(
scaleSize( nc.via_drill ) );
2760 if( nc.diff_pair_width > 0 )
2761 netclass->SetDiffPairWidth(
scaleSize( nc.diff_pair_width ) );
2763 if( nc.diff_pair_gap > 0 )
2764 netclass->SetDiffPairGap(
scaleSize( nc.diff_pair_gap ) );
2768 for(
const std::string& netName : nc.net_names )
2775 const auto& diffPairs =
m_parser->GetDiffPairs();
2777 for(
const auto& dp : diffPairs )
2779 if( dp.name.empty() )
2782 wxString dpClassName =
2783 wxString::Format( wxT(
"DiffPair_%s" ), wxString::FromUTF8( dp.name ) );
2784 std::shared_ptr<NETCLASS> dpNetclass = std::make_shared<NETCLASS>( dpClassName );
2787 dpNetclass->SetDiffPairGap(
scaleSize( dp.gap ) );
2791 dpNetclass->SetDiffPairWidth(
scaleSize( dp.width ) );
2792 dpNetclass->SetTrackWidth(
scaleSize( dp.width ) );
2797 if( !dp.positive_net.empty() )
2803 if( !dp.negative_net.empty() )
2813 const auto& boardOutlines =
m_parser->GetBoardOutlines();
2815 if( !boardOutlines.empty() )
2817 double min_x = std::numeric_limits<double>::max();
2818 double max_x = std::numeric_limits<double>::lowest();
2819 double min_y = std::numeric_limits<double>::max();
2820 double max_y = std::numeric_limits<double>::lowest();
2822 for(
const auto& outline : boardOutlines )
2824 for(
const auto& pt : outline.points )
2826 min_x = std::min( min_x, pt.x );
2827 max_x = std::max( max_x, pt.x );
2828 min_y = std::min( min_y, pt.y );
2829 max_y = std::max( max_y, pt.y );
2833 if( min_x < max_x && min_y < max_y )
2842 std::vector<const PADS_IO::LAYER_INFO*> copperLayerInfos;
2844 for(
const auto& li : padsLayerInfos )
2847 copperLayerInfos.push_back( &li );
2850 bool hasStackupData =
false;
2852 for(
const auto* li : copperLayerInfos )
2854 if( li->layer_thickness > 0.0 || li->dielectric_constant > 0.0 )
2856 hasStackupData =
true;
2861 if( hasStackupData )
2868 std::map<PCB_LAYER_ID, const PADS_IO::LAYER_INFO*> copperInfoMap;
2870 for(
const auto* li : copperLayerInfos )
2875 copperInfoMap[kicadLayer] = li;
2885 auto it = copperInfoMap.find( item->GetBrdLayerId() );
2887 if( it != copperInfoMap.end() )
2889 prevCopperInfo = it->second;
2891 if( it->second->copper_thickness > 0.0 )
2892 item->SetThickness(
scaleSize( it->second->copper_thickness ) );
2897 if( prevCopperInfo )
2908 item->SetColor( wxT(
"White" ) );
2912 item->SetColor( wxT(
"Green" ) );
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & set(size_t pos)
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
void SetCustomTrackWidth(int aWidth)
Sets custom width for track (i.e.
int m_CopperEdgeClearance
void SetCustomViaSize(int aSize)
Set custom size for via diameter (i.e.
int m_SolderMaskExpansion
BOARD_STACKUP & GetStackupDescriptor()
void SetCustomViaDrill(int aDrill)
Sets custom size for via drill (i.e.
void SetBoardThickness(int aThickness)
std::vector< VIA_DIMENSION > m_ViasDimensionsList
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Manage one layer needed to make a physical board.
Manage layers needed to make a physical board.
void RemoveAll()
Delete all items in list and clear the list.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
int BuildBoardThicknessFromStackup() const
void BuildDefaultStackupList(const BOARD_DESIGN_SETTINGS *aSettings, int aActiveCopperLayersCount=0)
Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
Information pertinent to a Pcbnew printed circuit board.
void SetCenter(const VECTOR2I &aCenter)
void SetStart(const VECTOR2I &aStart)
void SetShape(SHAPE_T aShape)
void SetEnd(const VECTOR2I &aEnd)
void SetWidth(int aWidth)
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
virtual void SetVisible(bool aVisible)
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
void SetKeepUpright(bool aKeepUpright)
virtual void SetText(const wxString &aText)
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
virtual void RegisterCallback(LAYER_MAPPING_HANDLER aLayerMappingHandler)
Register a different handler to be called when mapping of input layers to KiCad layers occurs.
LAYER_MAPPING_HANDLER m_layer_mapping_handler
Callback to get layer mapping.
A logical library item identifier and consists of various portions much like a URI.
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Handle the data for a net.
const wxString & GetNetname() const
void SetNetclassPatternAssignment(const wxString &pattern, const wxString &netclass)
Sets a netclass pattern assignment Calling this method will reset the effective netclass calculation ...
std::shared_ptr< NETCLASS > GetDefaultNetclass()
Gets the default netclass for the project.
void SetNetclass(const wxString &netclassName, std::shared_ptr< NETCLASS > &netclass)
Sets the given netclass Calling user is responsible for resetting the effective netclass calculation ...
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
void Parse(const wxString &aFileName)
Maps PADS layer numbers and names to KiCad layer IDs.
Converts PADS file format units to KiCad internal units (nanometers).
static constexpr double MILS_TO_NM
static constexpr double INCHES_TO_NM
static constexpr double BASIC_TO_NM
static constexpr double MM_TO_NM
void Update()
Update the dimension's cached text and geometry.
void SetOverrideTextEnabled(bool aOverride)
void SetLineThickness(int aWidth)
virtual void SetEnd(const VECTOR2I &aPoint)
virtual void SetStart(const VECTOR2I &aPoint)
void SetOverrideText(const wxString &aValue)
For better understanding of the points that make a dimension:
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
A set of BOARD_ITEMs (i.e., without duplicates).
const IO_FILE_DESC GetBoardFileDesc() const override
Returns board file description for the PCB_IO.
int scaleSize(double aVal) const
std::vector< PADS_LAYER_INFO > m_layerInfos
SHAPE_ARC makeMidpointArc(const PADS_IO::ARC_POINT &aPrev, const PADS_IO::ARC_POINT &aCurr, int aWidth)
Build a SHAPE_ARC from two consecutive PADS points using the midpoint approach.
std::map< std::string, std::string > m_partToBlockMap
int scaleCoord(double aVal, bool aIsX) const
void setPcbShapeArc(PCB_SHAPE *aShape, const PADS_IO::ARC_POINT &aPrev, const PADS_IO::ARC_POINT &aCurr)
Configure a PCB_SHAPE as an arc from two consecutive PADS points using board-level scaleCoord.
std::map< std::string, std::string > m_pinToNetMap
PCB_LAYER_ID getMappedLayer(int aPadsLayer) const
void appendArcPoints(SHAPE_LINE_CHAIN &aChain, const std::vector< PADS_IO::ARC_POINT > &aPts)
Interpolate arc segments from an ARC_POINT vector into polyline vertices on a SHAPE_LINE_CHAIN.
std::map< wxString, PCB_LAYER_ID > m_layer_map
PADS layer names to KiCad layers.
void generateDrcRules(const wxString &aFileName)
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties, PROJECT *aProject) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
const IO_FILE_DESC GetLibraryDesc() const override
Get the descriptor for the library container that this IO plugin operates on.
void ensureNet(const std::string &aNetName)
PADS_LAYER_MAPPER m_layerMapper
PADS_UNIT_CONVERTER m_unitConverter
std::map< wxString, PCB_LAYER_ID > DefaultLayerMappingCallback(const std::vector< INPUT_LAYER_DESC > &aInputLayerDescriptionVector)
Return the automapped layers.
const PADS_IO::PARSER * m_parser
void loadReuseBlockGroups()
virtual bool CanReadBoard(const wxString &aFileName) const
Checks if this PCB_IO can read the specified board file.
PCB_IO(const wxString &aName)
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStroke(const STROKE_PARAMS &aStroke) override
virtual void SetPosition(const VECTOR2I &aPos) override
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
virtual void SetWidth(int aWidth)
Container for project specific data.
const SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError=DefaultAccuracyForPCB(), int *aActualError=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsPolygonSelfIntersecting(int aPolygonIndex) const
Check whether the aPolygonIndex-th polygon in the set is self intersecting.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int OutlineCount() const
Return the number of outlines in the set.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
Simple container to manage line stroke parameters.
Handle a list of polygons defining a copper zone.
void SetDoNotAllowPads(bool aEnable)
void SetMinThickness(int aMinThickness)
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
SHAPE_POLY_SET * Outline()
void SetIsRuleArea(bool aEnable)
void SetDoNotAllowTracks(bool aEnable)
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
void SetIsFilled(bool isFilled)
void SetLayerSet(const LSET &aLayerSet) override
void SetDoNotAllowVias(bool aEnable)
void SetThermalReliefGap(int aThermalReliefGap)
void SetDoNotAllowFootprints(bool aEnable)
void SetDoNotAllowZoneFills(bool aEnable)
void SetAssignedPriority(unsigned aPriority)
void SetPadConnection(ZONE_CONNECTION aPadConnection)
void SetZoneName(const wxString &aName)
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
double m_PadsPcbTextWidthScale
PADS text width scale factor for PCB imports.
double m_PadsPcbTextHeightScale
PADS text height scale factor for PCB imports.
int m_PcbImportMinObjectSizeNm
Minimum object size in nanometers for PCB imports.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
@ LEFT_RIGHT
Flip left to right (around the Y axis)
wxString ConvertInvertedNetName(const std::string &aNetName)
Convert a PADS net name to KiCad format, handling inverted signal notation.
KIID GenerateDeterministicUuid(const std::string &aIdentifier)
Generate a deterministic KIID from a PADS component identifier.
@ NONE
No thermal relief defined.
@ BURIED
Via spans only inner layers.
@ THROUGH
Via spans all copper layers.
@ BLIND
Via starts at top or bottom and ends at inner layer.
@ MICROVIA
Single-layer blind via (typically HDI)
@ ROUTE
Routing keepout (traces)
@ PLACEMENT
Component placement keepout.
@ COPPER
Copper pour keepout.
@ VOIDOUT
Void/empty region (VOIDOUT)
@ HATCHED
Hatched pour (HATOUT)
PADS_LAYER_FUNCTION
Layer types from PADS LAYER_TYPE field.
@ ASSEMBLY
Assembly drawing.
@ ROUTING
Copper routing layer.
@ PASTE_MASK
Solder paste mask.
@ MIXED
Mixed signal/plane.
@ UNASSIGNED
Unassigned layer.
@ DOCUMENTATION
Documentation layer.
@ SILK_SCREEN
Silkscreen/legend.
@ PLANE
Power/ground plane.
@ SOLDER_MASK
Solder mask.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Common utilities and types for parsing PADS file formats.
PADS_LAYER_TYPE
PADS layer types.
@ MILS
Thousandths of an inch (1 mil = 0.001 inch)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
Class to handle a set of BOARD_ITEMs.
std::string FormatDouble2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 This function is intended in...
Container that describes file type info.
wxString m_Description
Description shown in the file picker dialog.
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
A point that may be either a line endpoint or an arc segment.
ARC arc
Arc parameters (only valid when is_arc is true)
bool is_arc
True if this segment is an arc, false for line.
double y
Endpoint Y coordinate.
double x
Endpoint X coordinate.
double cx
Center X coordinate.
double delta_angle
Arc sweep angle in degrees (positive = CCW)
double cy
Center Y coordinate.
A copper shape from the LINES section (type=COPPER).
A 2D graphic line/shape from the LINES section (type=LINES).
double layer_thickness
Dielectric thickness (BASIC units)
double dielectric_constant
Relative permittivity (Er)
double drill
Drill hole diameter (0 for SMD)
std::string shape
Shape code: R, S, A, O, OF, RF, RT, ST, RA, SA, RC, OC.
bool plated
True if drill is plated (PTH vs NPTH)
double rotation
Pad rotation angle in degrees.
double slot_orientation
Slot orientation in degrees (0-179.999)
double thermal_spoke_orientation
First spoke orientation in degrees.
double slot_length
Slot length.
double thermal_spoke_width
Width of thermal spokes.
double finger_offset
Finger pad offset along orientation axis.
double sizeB
Secondary size (height for rectangles/ovals)
double corner_radius
Corner radius magnitude (always positive)
double sizeA
Primary size (diameter or width)
std::vector< DECAL_ITEM > items
std::vector< TERMINAL > terminals
std::map< int, std::vector< PAD_STACK_LAYER > > pad_stacks
std::map< std::string, std::string > attributes
Attribute name-value pairs from {...} block.
A polyline that may contain arc segments.
bool has_mask_front
Stack includes top soldermask opening (layer 25)
int start_layer
First PADS layer number in via span.
int end_layer
Last PADS layer number in via span.
bool has_mask_back
Stack includes bottom soldermask opening (layer 28)
Information about a single PADS layer.
@ USER
The field ID hasn't been set yet; field is invalid.
wxString result
Test unit parsing edge cases and error handling.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
VECTOR2< int32_t > VECTOR2I
@ THERMAL
Use thermal relief for pads.
@ FULL
pads are covered by copper