62#include <compoundfilereader.h>
69#include <wx/docview.h>
71#include <wx/mstream.h>
72#include <wx/wfstream.h>
73#include <wx/zstream.h>
75#include <magic_enum.hpp>
79#include <unordered_set>
111 name = wxString::Format( wxT(
"__ALTIUM_UNNAMED_NET_%d" ), ++aCounter );
121 return aExpr.IsSameAs( wxS(
"All" ),
false );
127 static const wxString prefix = wxT(
"InNetClass('" );
130 || !aRule.
scope1expr.EndsWith( wxT(
"')" ) ) )
135 *aNetclassName = aRule.
scope1expr.Mid( prefix.Length(),
136 aRule.
scope1expr.Length() - prefix.Length() - 2 );
138 return !aNetclassName->IsEmpty();
143 NET_SETTINGS& aNetSettings, std::vector<const ARULE6*>* aUnresolved )
145 const std::map<wxString, std::shared_ptr<NETCLASS>>& netclasses = aNetSettings.
GetNetclasses();
147 for(
const auto& [kind, rules] : aRulesByKind )
155 std::set<wxString> applied;
157 for(
const ARULE6& rule : rules )
159 wxString netclassName;
164 auto it = netclasses.find( netclassName );
166 if( it == netclasses.end() )
169 aUnresolved->push_back( &rule );
175 if( !applied.insert( netclassName ).second )
178 const std::shared_ptr<NETCLASS>& netclass = it->second;
187 netclass->SetViaDiameter( rule.width );
188 netclass->SetViaDrill( rule.holeWidth );
202 THROW_IO_ERRORF( wxT(
"Component creator tries to access component id %u of %u existing components" ),
210std::shared_ptr<EMBEDDED_FILES::EMBEDDED_FILE>
212 const std::vector<char>& aCompressedData,
bool& aIsNew )
216 auto it = files.find( aModelName );
218 aIsNew = it == files.end();
225 auto file = std::make_shared<EMBEDDED_FILES::EMBEDDED_FILE>();
226 file->name = aModelName;
229 wxMemoryInputStream compressedStream( aCompressedData.data(), aCompressedData.size() );
230 wxZlibInputStream zlibStream( compressedStream );
234 file->decompressedData.resize( aCompressedData.size() * 6 );
237 while( !zlibStream.Eof() )
239 zlibStream.Read( file->decompressedData.data() + offset,
240 file->decompressedData.size() - offset );
242 size_t bytesRead = zlibStream.LastRead();
249 if( offset >= file->decompressedData.size() )
250 file->decompressedData.resize( 2 * file->decompressedData.size() );
253 file->decompressedData.resize( offset );
257 file->decompressedData.shrink_to_fit();
259 embeddedFiles->
AddFile( file );
266 const std::vector<ALTIUM_VERTICE>& aVertices )
275 double startradiant =
DEG2RAD( vertex.startangle );
276 double endradiant =
DEG2RAD( vertex.endangle );
277 VECTOR2I arcStartOffset =
KiROUND( std::cos( startradiant ) * vertex.radius,
278 -std::sin( startradiant ) * vertex.radius );
280 VECTOR2I arcEndOffset =
KiROUND( std::cos( endradiant ) * vertex.radius,
281 -std::sin( endradiant ) * vertex.radius );
283 VECTOR2I arcStart = vertex.center + arcStartOffset;
284 VECTOR2I arcEnd = vertex.center + arcEndOffset;
289 if( arcStart.
Distance( vertex.position )
290 < arcEnd.
Distance( vertex.position ) )
317 aLine.
Append( vertex.position );
327 auto override =
m_layermap.find( aAltiumLayer );
331 return override->second;
346 switch( aAltiumLayer )
448 std::vector<PCB_LAYER_ID> layers;
449 layers.reserve( layerCount );
454 layers.emplace_back( layer );
471 const wxString& aLibrary,
const wxString& aFootprintName )
491 const unsigned PROGRESS_DELTA = 250;
518 std::vector<PCB_SHAPE*> pieces;
519 std::vector<VECTOR2I> nodes;
520 std::vector<int> degree;
525 for(
size_t i = 0; i < nodes.size(); i++ )
527 if( ( nodes[i] - aPt ).EuclideanNorm() <=
epsilon )
528 return static_cast<int>( i );
531 nodes.push_back( aPt );
532 degree.push_back( 0 );
533 return static_cast<int>( nodes.size() ) - 1;
536 std::vector<std::pair<int, int>> ends;
538 for(
BOARD_ITEM* item : footprint->GraphicalItems() )
540 if( item->GetLayer() != courtyard || item->Type() !=
PCB_SHAPE_T )
548 int a = nodeAt( shape->
GetStart() );
549 int b = nodeAt( shape->
GetEnd() );
556 if( ( nodes[a] - shape->
GetStart() ).EuclideanNorm() <= snap )
559 if( ( nodes[b] - shape->
GetEnd() ).EuclideanNorm() <= snap )
560 shape->
SetEnd( nodes[b] );
565 pieces.push_back( shape );
566 ends.emplace_back( a, b );
570 std::vector<bool> hanging( pieces.size(),
false );
571 std::vector<int> open;
573 for(
size_t i = 0; i < nodes.size(); i++ )
576 open.push_back(
static_cast<int>( i ) );
579 while( !open.empty() )
581 const int node = open.back();
584 for(
size_t i = 0; i < pieces.size(); i++ )
586 if( hanging[i] || ( ends[i].first != node && ends[i].second != node ) )
590 degree[ends[i].first]--;
591 degree[ends[i].second]--;
593 const int far_idx = ends[i].first == node ? ends[i].second : ends[i].first;
595 if( degree[far_idx] == 1 )
596 open.push_back( far_idx );
602 const bool anyClosed =
603 std::any_of( hanging.begin(), hanging.end(), [](
bool aHanging ) { return !aHanging; } );
605 if( !anyClosed && pieces.size() > 2 )
608 for(
size_t i = 0; i < pieces.size(); i++ )
619 const std::map<ALTIUM_PCB_DIR, std::string>& aFileMapping,
620 const std::map<std::string, UTF8>* aProperties )
626 const std::vector<std::tuple<bool, ALTIUM_PCB_DIR, PARSE_FUNCTION_POINTER_fp>> parserOrder = {
748 for(
const std::tuple<bool, ALTIUM_PCB_DIR, PARSE_FUNCTION_POINTER_fp>& cur : parserOrder )
753 std::tie( isRequired,
directory, fp ) = cur;
758 const auto& mappedDirectory = aFileMapping.find(
directory );
760 if( mappedDirectory == aFileMapping.end() )
763 const std::vector<std::string> mappedFile{ mappedDirectory->second,
"Header" };
764 const CFB::COMPOUND_FILE_ENTRY* file = altiumPcbFile.
FindStream( mappedFile );
766 if( file ==
nullptr )
770 uint32_t numOfRecords = reader.
Read<uint32_t>();
776 m_reporter->Report( wxString::Format(
_(
"'%s' was not parsed correctly." ),
790 m_reporter->Report( wxString::Format(
_(
"'%s' was not fully parsed." ),
802 if( boardDirectory != aFileMapping.end() )
804 std::vector<std::string> mappedFile{ boardDirectory->second,
"Data" };
806 const CFB::COMPOUND_FILE_ENTRY* file = altiumPcbFile.
FindStream( mappedFile );
810 THROW_IO_ERROR(
_(
"This file does not appear to be in a valid PCB Binary Version 6.0 format. In "
811 "Altium Designer, make sure to save as \"PCB Binary Files (*.PcbDoc)\"." ) );
816 for(
const std::tuple<bool, ALTIUM_PCB_DIR, PARSE_FUNCTION_POINTER_fp>& cur : parserOrder )
821 std::tie( isRequired,
directory, fp ) = cur;
823 const auto& mappedDirectory = aFileMapping.find(
directory );
825 if( mappedDirectory == aFileMapping.end() )
827 wxASSERT_MSG( !isRequired, wxString::Format( wxT(
"Altium Directory of kind %d was "
828 "expected, but no mapping is "
829 "present in the code" ),
834 std::vector<std::string> mappedFile{ mappedDirectory->second };
837 mappedFile.emplace_back(
"Data" );
839 const CFB::COMPOUND_FILE_ENTRY* file = altiumPcbFile.
FindStream( mappedFile );
841 if( file !=
nullptr )
843 fp( altiumPcbFile, file );
845 else if( isRequired )
849 m_reporter->Report( wxString::Format(
_(
"File not found: '%s' for directory '%s'." ),
877 if( zone->GetAssignedPriority() == 1000 )
888 zone->SetAssignedPriority( priority >= 0 ? priority : 0 );
892 for( std::pair<const ALTIUM_LAYER, ZONE*>& zone :
m_outer_plane )
893 zone.second->SetAssignedPriority( 0 );
897 BS::multi_future<void> fractureFutures;
906 if( !zone->HasFilledPolysForLayer( layer ) )
910 fractureFutures.push_back(
tp.submit_task(
911 [fill = zone->GetFilledPolysList( layer )]()
919 fractureFutures.wait();
920 fractureFutures.get();
960 if( arc->
GetCenter() == dim->GetPosition() )
969 VECTOR2I radialLine = dim->GetEnd() - dim->GetStart();
974 radialLine = radialLine.
Resize( std::max(
radius, 2 ) );
975 dim->SetEnd( dim->GetStart() + (
VECTOR2I) radialLine );
976 dim->SetLeaderLength( totalLength -
radius );
986 int desired_x = ( w - bbbox.
GetWidth() ) / 2;
987 int desired_y = ( h - bbbox.
GetHeight() ) / 2;
989 VECTOR2I movementVector( desired_x - bbbox.
GetX(), desired_y - bbbox.
GetY() );
990 m_board->Move( movementVector );
996 m_board->m_LegacyDesignSettingsLoaded =
true;
1017 int minExtent = std::min( aPad->
GetSize( aLayer ).
x, aPad->
GetSize( aLayer ).
y );
1046 std::map<PCB_LAYER_ID, PADSTACK::COPPER_LAYER_PROPS> props;
1052 for( std::shared_ptr<PCB_SHAPE>& prim : layerProps.
custom_shapes )
1053 prim = std::shared_ptr<PCB_SHAPE>(
static_cast<PCB_SHAPE*
>( prim->Clone() ) );
1055 props[layer] = std::move( layerProps );
1060 for(
auto& [layer, layerProps] : props )
1061 padstack.
CopperLayer( layer ) = std::move( layerProps );
1108 LSET layers = zone->GetLayerSet();
1115 std::vector<BOARD_ITEM*> outsideStackup;
1119 if(
IsCopperLayer( item->GetLayer() ) && !stackupCopper.test( item->GetLayer() ) )
1120 outsideStackup.push_back( item );
1125 aFootprint->
Remove( item );
1137 const wxString& aFootprintName )
1139 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>(
m_board );
1144 const std::vector<std::string> libStreamName{
"Library",
"Data" };
1145 const CFB::COMPOUND_FILE_ENTRY* libStream = altiumLibFile.
FindStream( libStreamName );
1147 if( libStream ==
nullptr )
1163 std::tuple<wxString, const CFB::COMPOUND_FILE_ENTRY*> ret =
1166 wxString fpDirName = std::get<0>( ret );
1167 const CFB::COMPOUND_FILE_ENTRY* footprintStream = std::get<1>( ret );
1169 if( fpDirName.IsEmpty() )
1170 THROW_IO_ERRORF(
_(
"Footprint directory not found: '%s'." ), aFootprintName );
1172 const std::vector<std::string> streamName{ fpDirName.ToStdString(),
"Data" };
1173 const CFB::COMPOUND_FILE_ENTRY* footprintData = altiumLibFile.
FindStream( footprintStream, {
"Data" } );
1175 if( !footprintData )
1185 footprint->SetFPID( fpID );
1187 const std::vector<std::string> parametersStreamName{ fpDirName.ToStdString(),
"Parameters" };
1188 const CFB::COMPOUND_FILE_ENTRY* parametersData = altiumLibFile.
FindStream( footprintStream, {
"Parameters" } );
1190 if( parametersData !=
nullptr )
1193 std::map<wxString, wxString> parameterProperties = parametersReader.
ReadProperties();
1195 footprint->SetLibDescription( description );
1201 m_reporter->Report( wxString::Format(
_(
"File not found: '%s'." ),
FormatPath( parametersStreamName ) ),
1205 footprint->SetLibDescription( wxT(
"" ) );
1208 const std::vector<std::string> extendedPrimitiveInformationStreamName{
1209 "ExtendedPrimitiveInformation",
"Data"
1211 const CFB::COMPOUND_FILE_ENTRY* extendedPrimitiveInformationData =
1212 altiumLibFile.
FindStream( footprintStream, extendedPrimitiveInformationStreamName );
1214 if( extendedPrimitiveInformationData !=
nullptr )
1217 footprint->SetReference( wxT(
"REF**" ) );
1218 footprint->SetValue( aFootprintName );
1219 footprint->Reference().SetVisible(
true );
1220 footprint->Value().SetVisible(
true );
1223 const int defaultTextThickness(
pcbIUScale.mmToIU( 0.15 ) );
1225 for(
PCB_FIELD* field : footprint->GetFields() )
1227 field->SetTextSize( defaultTextSize );
1228 field->SetTextThickness( defaultTextThickness );
1240 drawnCopper.
set( klayer );
1243 for(
int primitiveIndex = 0; parser.
GetRemainingBytes() >= 4; primitiveIndex++ )
1247 switch( recordtype )
1251 AARC6 arc( parser );
1252 noteLayer( arc.
layer );
1259 noteLayer(
pad.layer );
1266 noteLayer(
via.layer_start );
1267 noteLayer(
via.layer_end );
1274 noteLayer( track.
layer );
1281 noteLayer(
text.layer );
1288 noteLayer( fill.
layer );
1295 noteLayer( region.
layer );
1327 if( !aPad->GetNumber().IsEmpty() )
1333 && !aPad->GetPrimitives( layer ).empty() )
1342 auto commonCopperLayer =
1357 auto mergeRegionPadInto =
1358 [&](
PAD* aNamedPad,
PAD* aRegionPad )
1360 PCB_LAYER_ID layer = commonCopperLayer( aRegionPad, aNamedPad );
1372 for(
const std::shared_ptr<PCB_SHAPE>& src : aRegionPad->
GetPrimitives( layer ) )
1377 copy->Move( anchorShift );
1400 std::vector<PAD*> regionPads;
1401 std::vector<PAD*> namedPads;
1403 for(
PAD*
pad : footprint->Pads() )
1405 if( isRegionPad(
pad ) )
1406 regionPads.push_back(
pad );
1407 else if( !
pad->GetNumber().IsEmpty() )
1408 namedPads.push_back(
pad );
1413 std::unordered_set<PAD*> consumedNamed;
1415 for(
PAD* regionPad : regionPads )
1418 : regionPad->IsOnLayer(
B_Cu ) ?
B_Cu
1421 std::shared_ptr<SHAPE_POLY_SET> outline =
1422 regionPad->GetEffectivePolygon( regionCu,
ERROR_INSIDE );
1424 if( !outline || outline->OutlineCount() == 0 )
1429 PAD* bestNamed =
nullptr;
1430 int64_t bestDistSq = std::numeric_limits<int64_t>::max();
1432 for(
PAD* namedPad : namedPads )
1434 if( consumedNamed.count( namedPad ) )
1438 && !( namedPad->GetLayerSet() & regionPad->GetLayerSet() &
LSET::AllCuMask() ).any() )
1443 if( !outline->Contains( namedPad->GetPosition(), -1, 0 ) )
1446 VECTOR2I delta = namedPad->GetPosition() - regionPad->GetPosition();
1449 if( distSq < bestDistSq )
1451 bestDistSq = distSq;
1452 bestNamed = namedPad;
1458 mergeRegionPadInto( bestNamed, regionPad );
1459 consumedNamed.insert( bestNamed );
1460 footprint->Remove( regionPad );
1465 std::set<PAD*> extensionPads;
1468 for(
bool changes =
true; changes; )
1473 [&changes](
PAD* aPad1,
PAD* aPad2 )
1475 if( !( aPad1->GetNumber().IsEmpty() ^ aPad2->GetNumber().IsEmpty() ) )
1479 const LSET sharedCopper = aPad1->GetLayerSet() & aPad2->GetLayerSet() & LSET::AllCuMask();
1481 for( PCB_LAYER_ID layer : sharedCopper )
1483 std::shared_ptr<SHAPE> shape1 = aPad1->GetEffectiveShape( layer );
1484 std::shared_ptr<SHAPE> shape2 = aPad2->GetEffectiveShape( layer );
1486 if( shape1->Collide( shape2.get() ) )
1488 if( aPad1->GetNumber().IsEmpty() )
1489 aPad1->SetNumber( aPad2->GetNumber() );
1491 aPad2->SetNumber( aPad1->GetNumber() );
1499 HelperPlaceUnfoldedCopper();
1502 footprint->AutoPositionFields();
1507 footprint->SetAttributes( footprint->GetAttributes() | footprint->GetLikelyAttribute() );
1511 if( parser.HasParsingError() )
1514 if( parser.GetRemainingBytes() != 0 )
1528 THROW_IO_ERRORF( wxT(
"Netcode with id %d does not exist. Only %zu nets are known" ),
1539 const auto rules =
m_rules.find( aKind );
1544 for(
const ARULE6& rule : rules->second )
1555 const auto rules =
m_rules.find( aKind );
1560 for(
const ARULE6& rule : rules->second )
1572 const auto rules =
m_rules.find( aKind );
1586 const CFB::COMPOUND_FILE_ENTRY* aEntry )
1604 const CFB::COMPOUND_FILE_ENTRY* aEntry )
1617 std::move( elem ) );
1621 THROW_IO_ERROR( wxT(
"ExtendedPrimitiveInformation stream is not fully parsed" ) );
1626 const CFB::COMPOUND_FILE_ENTRY* aEntry )
1643 size_t layercount = 0;
1646 while( layerid < elem.
stackup.size() && layerid != 0 )
1648 layerid = elem.
stackup[ layerid - 1 ].nextId;
1652 size_t kicadLayercount = ( layercount % 2 == 0 ) ? layercount : layercount + 1;
1653 m_board->SetCopperLayerCount( kicadLayercount );
1662 auto it = stackup.
GetList().begin();
1671 altiumLayerId < elem.
stackup.size() && altiumLayerId != 0;
1672 altiumLayerId = elem.
stackup[altiumLayerId - 1].nextId )
1678 if( layer.
nextId == 0 && layercount != kicadLayercount )
1680 m_board->SetLayerName( ( *it )->GetBrdLayerId(), wxT(
"[unused]" ) );
1683 THROW_IO_ERROR( wxT(
"Board6 stream, unexpected item while parsing stackup" ) );
1685 ( *it )->SetThickness( 0 );
1690 THROW_IO_ERROR( wxT(
"Board6 stream, unexpected item while parsing stackup" ) );
1692 ( *it )->SetThickness( 0, 0 );
1693 ( *it )->SetThicknessLocked(
true, 0 );
1701 THROW_IO_ERROR( wxT(
"Board6 stream, unexpected item while parsing stackup" ) );
1715 if( klayer ==
B_Cu )
1718 THROW_IO_ERROR( wxT(
"Board6 stream, unexpected id while parsing last stackup layer" ) );
1728 THROW_IO_ERROR( wxT(
"Board6 stream, unexpected item while parsing stackup" ) );
1761 m_reporter->Report( wxString::Format(
_(
"Board outline has %d vertices outside the "
1762 "coordinate range; they were dropped." ),
1777 for(
const auto& [altiumLayer, kicadLayer] :
m_layermap )
1798 return ordinal < ALTIUM_PADSTACK_IDX_COUNT ? static_cast<int>( ordinal ) : -1;
1810 wxString nameLower = aName.Lower();
1811 return nameLower.Contains( wxT(
"courtyard" ) ) || nameLower.Contains( wxT(
"court yard" ) )
1812 || nameLower.Contains( wxT(
"crtyd" ) );
1819 wxString nameLower = aName.Lower();
1820 return nameLower.Contains( wxT(
"assembly" ) ) || nameLower.Contains( wxT(
"assy" ) );
1829 auto check = [&isTop](
bool aTopCond,
bool aBotCond )
1831 if( aTopCond && aBotCond )
1834 if( !aTopCond && !aBotCond )
1841 wxString lower = aName.Lower();
1843 if( check( lower.StartsWith(
"top" ), lower.StartsWith(
"bot" ) ) )
1846 if( check( lower.EndsWith(
"_t" ), lower.EndsWith(
"_b" ) ) )
1849 if( check( lower.EndsWith(
".t" ), lower.EndsWith(
".b" ) ) )
1852 if( check( lower.Contains(
"top" ), lower.Contains(
"bot" ) ) )
1865 if( aStackup.size() == 0 )
1868 std::vector<INPUT_LAYER_DESC> inputLayers;
1869 std::map<wxString, ALTIUM_LAYER> altiumLayerNameMap;
1876 bool frontCourtyardMapped =
false;
1877 bool backCourtyardMapped =
false;
1879 for(
size_t ii = 0; ii < aStackup.size(); ii++ )
1881 curLayer = aStackup[ii];
1900 auto existingMapping =
m_layermap.find( layer_num );
1928 if( isTopSide && !frontCourtyardMapped )
1931 frontCourtyardMapped =
true;
1933 else if( !isTopSide && !backCourtyardMapped )
1936 backCourtyardMapped =
true;
1938 else if( !frontCourtyardMapped )
1941 frontCourtyardMapped =
true;
1943 else if( !backCourtyardMapped )
1946 backCourtyardMapped =
true;
1969 inputLayers.push_back( iLdesc );
1970 altiumLayerNameMap.insert( { curLayer.
name, layer_num } );
1974 if( inputLayers.size() == 0 )
1980 for( std::pair<wxString, PCB_LAYER_ID> layerPair : reMappedLayers )
1988 m_reporter->Report( wxString::Format(
_(
"Layer '%s' could not be mapped and "
1989 "will be skipped." ),
1997 ALTIUM_LAYER altiumID = altiumLayerNameMap.at( layerPair.first );
1998 m_layermap.insert_or_assign( altiumID, layerPair.second );
1999 enabledLayers |=
LSET( { layerPair.second } );
2004 for(
const auto& [
name, altLayer] : altiumLayerNameMap )
2006 if( reMappedLayers.find(
name ) == reMappedLayers.end()
2013 m_board->SetEnabledLayers( enabledLayers );
2014 m_board->SetVisibleLayers( enabledLayers );
2027 if( !layer.mechenabled )
2035 switch( layer.mechkind )
2100std::vector<OUTLINE_EDGE> OutlineEdgesFromChain(
const SHAPE_LINE_CHAIN& aChain )
2103 const int minEdge =
pcbIUScale.mmToIU( 0.001 );
2105 std::vector<OUTLINE_EDGE> edges;
2111 edges.push_back( {
true, aChain.
Arc( aChain.
ArcIndex( i ) ),
SEG() } );
2125void RemoveOutlineJogs( std::vector<OUTLINE_EDGE>& aEdges,
int& aCount,
int& aLargestMove )
2127 const int maxJog =
pcbIUScale.mmToIU( 0.05 );
2131 [](
const OUTLINE_EDGE& aEdge,
bool aAtEnd ) ->
VECTOR2I
2134 return aEdge.seg.
B - aEdge.seg.
A;
2141 for(
bool changed =
true; changed && aEdges.size() > 3; )
2145 for(
size_t i = 0; i < aEdges.size(); i++ )
2147 OUTLINE_EDGE& jog = aEdges[i];
2148 OUTLINE_EDGE& prev = aEdges[( i + aEdges.size() - 1 ) % aEdges.size()];
2149 OUTLINE_EDGE&
next = aEdges[( i + 1 ) % aEdges.size()];
2151 if( jog.isArc || jog.seg.
Length() > maxJog || ( prev.isArc &&
next.isArc ) )
2154 if( ( !prev.isArc && prev.seg.
Length() <= maxJog ) || ( !
next.isArc &&
next.seg.Length() <= maxJog ) )
2158 const VECTOR2I jogDirection = jog.seg.
B - jog.seg.
A;
2160 if( jogDirection.
Dot( direction( prev,
true ) ) >= 0 && jogDirection.
Dot( direction(
next,
false ) ) >= 0 )
2172 moved = nearer( prev.arc, jog.seg.
A );
2173 aLargestMove = std::max( aLargestMove,
static_cast<int>(
moved.Distance(
next.seg.A ) ) );
2176 else if(
next.isArc )
2179 aLargestMove = std::max( aLargestMove,
static_cast<int>(
moved.Distance( prev.seg.
B ) ) );
2184 aLargestMove = std::max( aLargestMove,
static_cast<int>( prev.seg.
B.
Distance(
next.seg.A ) ) );
2185 next.seg.A = prev.seg.
B;
2190 aEdges.erase( aEdges.begin() + i );
2198void AddOutlineEdges(
BOARD& aBoard,
const std::vector<OUTLINE_EDGE>& aEdges )
2202 for(
const OUTLINE_EDGE& edge : aEdges )
2204 std::unique_ptr<PCB_SHAPE> shape;
2208 shape = std::make_unique<PCB_SHAPE>( &aBoard,
SHAPE_T::ARC );
2209 shape->SetArcGeometry( edge.arc.GetP0(), edge.arc.GetArcMid(), edge.arc.GetP1() );
2214 shape->SetStart( edge.seg.A );
2215 shape->SetEnd( edge.seg.B );
2218 shape->SetStroke( stroke );
2227double FractionAlongEdge(
const OUTLINE_EDGE& aEdge,
const VECTOR2I& aPt )
2239 if(
sweep.AsDegrees() < 0 )
2247VECTOR2I PointAlongEdge(
const OUTLINE_EDGE& aEdge,
double aFraction )
2249 if( aFraction <= 0 )
2250 return aEdge.isArc ? aEdge.arc.
GetP0() : aEdge.seg.
A;
2252 if( aFraction >= 1 )
2253 return aEdge.isArc ? aEdge.arc.
GetP1() : aEdge.seg.
B;
2265bool BoundsMaterial(
const OUTLINE_EDGE& aEdge,
double aFraction,
const SHAPE_POLY_SET& aMaterial )
2267 const double probe =
pcbIUScale.mmToIU( 0.05 );
2268 VECTOR2I pt = PointAlongEdge( aEdge, aFraction );
2285std::vector<OUTLINE_EDGE> ClipOutlineEdges(
const std::vector<OUTLINE_EDGE>& aEdges,
2286 const std::vector<const SHAPE_LINE_CHAIN*>& aCutters,
2290 const int onCutter =
pcbIUScale.mmToIU( 0.005 );
2291 std::vector<OUTLINE_EDGE> kept;
2293 for(
const OUTLINE_EDGE& edge : aEdges )
2301 if( cutter->SquaredDistance( aPt,
true ) <=
SEG::Square( onCutter ) )
2312 chain.Append( edge.arc );
2316 chain.Append( edge.seg.A );
2317 chain.Append( edge.seg.B );
2320 std::vector<double> cuts = { 0.0, 1.0 };
2324 std::vector<SHAPE_LINE_CHAIN::INTERSECTION> crossings;
2325 chain.Intersect( *cutter, crossings );
2328 cuts.push_back( std::clamp( FractionAlongEdge( edge, crossing.p ), 0.0, 1.0 ) );
2331 std::sort( cuts.begin(), cuts.end() );
2334 cuts.erase( std::unique( cuts.begin(), cuts.end(),
2335 [&](
double aLeft,
double aRight )
2337 return PointAlongEdge( edge, aLeft ) == PointAlongEdge( edge, aRight );
2344 [&](
double aFrom,
double aTo )
2346 if( aFrom <= 0.0 && aTo >= 1.0 )
2349 OUTLINE_EDGE piece = edge;
2350 VECTOR2I start = PointAlongEdge( edge, aFrom );
2354 piece.arc =
SHAPE_ARC( start, PointAlongEdge( edge, ( aFrom + aTo ) / 2 ),
end, 0 );
2356 piece.seg =
SEG( start,
end );
2362 [&](
size_t aPiece )
2364 OUTLINE_EDGE piece = subEdge( cuts[aPiece], cuts[aPiece + 1] );
2365 VECTOR2I mid = PointAlongEdge( edge, ( cuts[aPiece] + cuts[aPiece + 1] ) / 2 );
2366 bool keep = nearCutter( mid ) ? aMaterial && BoundsMaterial( piece, 0.5, *aMaterial )
2367 : aRegion.Contains( mid ) == aKeepInside;
2369 return keep ? SIDE::KEEP : SIDE::DROP;
2373 [&](
size_t aFrom,
size_t aTo )
2375 return PointAlongEdge( edge, cuts[aFrom] ).Distance( PointAlongEdge( edge, cuts[aTo] ) );
2378 std::vector<SIDE> sides;
2381 for(
size_t i = 0; i + 1 < cuts.size(); i++ )
2382 sides.push_back( span( i, i + 1 ) <= onCutter ? SIDE::UNSURE : classify( i ) );
2384 for(
size_t i = 0; i < sides.size(); )
2386 if( sides[i] != SIDE::UNSURE )
2394 while( j < sides.size() && sides[j] == SIDE::UNSURE )
2397 bool hasNeighbour = i > 0 || j < sides.size();
2400 if( hasNeighbour && span( i, j ) <= onCutter )
2402 bool nextToKept = ( i > 0 && sides[i - 1] == SIDE::KEEP )
2403 || ( j < sides.size() && sides[j] == SIDE::KEEP );
2405 for(
size_t k = i; k < j; k++ )
2406 sides[k] = nextToKept ? SIDE::KEEP :
SIDE::
DROP;
2410 for(
size_t k = i; k < j; k++ )
2411 sides[k] = classify( k );
2418 for(
size_t i = 0; i < sides.size(); )
2420 if( sides[i] != SIDE::KEEP )
2428 while( j < sides.size() && sides[j] == SIDE::KEEP )
2431 kept.push_back( subEdge( cuts[i], cuts[j] ) );
2443 std::vector<OUTLINE_EDGE> edges = OutlineEdgesFromChain( aOutline );
2446 AddOutlineEdges( *
m_board, edges );
2455 std::vector<OUTLINE_EDGE> edges = OutlineEdgesFromChain(
m_boardOutline );
2457 bool merged =
false;
2462 std::vector<SHAPE_LINE_CHAIN> separate;
2463 std::vector<const SHAPE_LINE_CHAIN*> applied = { &board };
2470 cutout.SetClosed(
true );
2472 std::vector<SHAPE_LINE_CHAIN::INTERSECTION> crossings;
2474 if( board.
PointCount() < 3 || cutout.PointCount() < 3 || board.
Intersect( cutout, crossings ) == 0 )
2476 separate.push_back( cutout );
2494 std::vector<OUTLINE_EDGE> kept = ClipOutlineEdges( edges, { &cutout }, cutArea,
false, &material );
2495 std::vector<OUTLINE_EDGE> inside =
2496 ClipOutlineEdges( OutlineEdgesFromChain( cutout ), applied, region,
true,
nullptr );
2498 kept.insert( kept.end(), inside.begin(), inside.end() );
2499 edges = std::move( kept );
2500 region = std::move( material );
2501 applied.push_back( &cutout );
2507 AddOutlineEdges( *
m_board, edges );
2522 m_reporter->Report( wxString::Format(
_(
"%d tiny jogs in the board outline were removed; the largest "
2523 "moved an outline end by %s." ),
2533 const CFB::COMPOUND_FILE_ENTRY* aEntry )
2547 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( elem.
name,
false );
2549 for(
const wxString&
name : elem.
names )
2555 if(
m_board->GetDesignSettings().m_NetSettings->HasNetclass( nc->GetName() ) )
2562 msg.Printf(
_(
"More than one Altium netclass with name '%s' found. "
2563 "Only the first one will be imported." ), elem.
name );
2569 m_board->GetDesignSettings().m_NetSettings->SetNetclass( nc->GetName(), nc );
2581 m_board->m_LegacyNetclassesLoaded =
true;
2587 std::shared_ptr<NET_SETTINGS> netSettings =
m_board->GetDesignSettings().m_NetSettings;
2589 netSettings->RecomputeEffectiveNetclasses();
2593 if( net->GetNetCode() <= 0 )
2596 if( std::shared_ptr<NETCLASS> netclass = netSettings->GetEffectiveNetClass( net->GetNetname() ) )
2597 net->SetNetClass( netclass );
2603 const CFB::COMPOUND_FILE_ENTRY* aEntry )
2615 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>(
m_board );
2626 wxString fpName = elem.
pattern;
2628 if( fpName.Contains( wxT(
"\\" ) ) || fpName.Contains( wxT(
"/" ) ) )
2630 wxFileName fpPath( fpName, wxPATH_WIN );
2631 fpName = fpPath.GetFullName();
2636 footprint->SetFPID( fpID );
2638 footprint->SetPosition( elem.
position );
2639 footprint->SetOrientationDegrees( elem.
rotation );
2645 if( reference.find_first_not_of(
"0123456789" ) == wxString::npos )
2646 reference.Prepend( wxT(
"UNK" ) );
2648 footprint->SetReference( reference );
2653 path.push_back( pathid );
2654 path.push_back(
id );
2656 footprint->SetPath(
path );
2660 footprint->SetLocked( elem.
locked );
2661 footprint->Reference().SetVisible( elem.
nameon );
2662 footprint->Value().SetVisible( elem.
commenton );
2664 footprint->SetHeight( elem.
height );
2671 THROW_IO_ERROR( wxT(
"Components6 stream is not fully parsed" ) );
2678 while( Angle < aMin )
2681 while( Angle >= aMax )
2704 m_reporter->Report( wxString::Format( wxT(
"Model %s not found for footprint %s" ),
2715 std::shared_ptr<EMBEDDED_FILES::EMBEDDED_FILE> file =
2734 orientation = -orientation;
2741 modelRotation.
x += 180;
2742 modelRotation.
z = -modelRotation.
z;
2756 aFootprint->
Models().push_back( modelSettings );
2761 const CFB::COMPOUND_FILE_ENTRY* aEntry )
2767 BS::multi_future<void> embeddedFutures;
2778 if( skipComponentBodies )
2786 THROW_IO_ERRORF( wxT(
"ComponentsBodies6 stream tries to access component id %d of %zu existing "
2802 msg.Printf( wxT(
"ComponentsBodies6 stream tries to access model id %s which does "
2803 "not exist" ), elem.
modelId );
2814 std::shared_ptr<EMBEDDED_FILES::EMBEDDED_FILE> file =
2821 embeddedFutures.push_back(
tp.submit_task(
2824 EMBEDDED_FILES::CompressAndEncode( *file );
2844 orientation = -orientation;
2867 footprint->
Models().push_back( modelSettings );
2870 embeddedFutures.wait();
2873 THROW_IO_ERROR( wxT(
"ComponentsBodies6 stream is not fully parsed" ) );
2880 THROW_IO_ERROR( wxT(
"Incorrect number of reference points for linear dimension object" ) );
2889 _(
"Dimension found on an Altium layer (%d) with no KiCad equivalent. "
2890 "It has been moved to KiCad layer Eco1_User." ), aElem.
layer ),
2903 dimension->SetLayer( klayer );
2904 dimension->SetStart( referencePoint0 );
2906 if( referencePoint0 != aElem.
xy1 )
2918 VECTOR2I referenceDiff = referencePoint1 - referencePoint0;
2920 SEG segm1( referencePoint0, referencePoint0 + directionNormalVector );
2921 SEG segm2( referencePoint1, referencePoint1 + direction );
2925 THROW_IO_ERROR( wxT(
"Invalid dimension. This should never happen." ) );
2927 dimension->SetEnd( *intersection );
2931 if( direction.
Cross( referenceDiff ) > 0 )
2934 dimension->SetHeight( height );
2938 dimension->SetEnd( referencePoint1 );
2941 dimension->SetLineThickness( aElem.
linewidth );
2947 int dist = ( dimension->GetEnd() - dimension->GetStart() ).EuclideanNorm();
2949 if( dist < 3 * dimension->GetArrowLength() )
2953 wxRegEx units( wxS(
"(mm)|(in)|(mils)|(thou)|(')|(\")" ), wxRE_ADVANCED );
2965 dimension->Text().SetBold( aElem.
textbold );
2968 dimension->SetTextThickness( dimension->GetTextThickness() *
BOLD_FACTOR );
2987 THROW_IO_ERROR( wxT(
"Not enough reference points for radial dimension object" ) );
2996 _(
"Dimension found on an Altium layer (%d) with no KiCad equivalent. "
2997 "It has been moved to KiCad layer Eco1_User." ),
3006 std::unique_ptr<PCB_DIM_RADIAL> dimension = std::make_unique<PCB_DIM_RADIAL>(
m_board );
3009 dimension->SetLayer( klayer );
3010 dimension->SetStart( referencePoint0 );
3011 dimension->SetEnd( aElem.
xy1 );
3012 dimension->SetLineThickness( aElem.
linewidth );
3013 dimension->SetKeepTextAligned(
false );
3034 m_reporter->Report( wxT(
"No text position present for leader dimension object" ),
3041 dimension->SetTextPos( aElem.
textPoint.at( 0 ) );
3047 dimension->SetBold( aElem.
textbold );
3050 dimension->SetTextThickness( dimension->GetTextThickness() *
BOLD_FACTOR );
3058 int yAdjust = dimension->GetTextBox(
nullptr ).GetCenter().y - dimension->GetTextPos().y;
3059 dimension->SetTextPos( dimension->GetTextPos() +
VECTOR2I( 0, yAdjust + aElem.
textgap ) );
3076 msg.Printf(
_(
"Dimension found on an Altium layer (%d) with no KiCad equivalent. "
3077 "It has been moved to KiCad layer Eco1_User." ), aElem.
layer );
3094 shape->SetLayer( klayer );
3096 shape->SetStart( last );
3108 if( dirVec.
x != 0 || dirVec.
y != 0 )
3117 shape1->SetLayer( klayer );
3119 shape1->SetStart( referencePoint0 );
3120 shape1->SetEnd( referencePoint0 + arrVec );
3130 shape2->SetLayer( klayer );
3132 shape2->SetStart( referencePoint0 );
3133 shape2->SetEnd( referencePoint0 + arrVec );
3145 m_reporter->Report( wxT(
"No text position present for leader dimension object" ),
3152 std::unique_ptr<PCB_TEXT>
text = std::make_unique<PCB_TEXT>(
m_board );
3156 text->SetLayer( klayer );
3175 msg.Printf(
_(
"Dimension found on an Altium layer (%d) with no KiCad equivalent. "
3176 "It has been moved to KiCad layer Eco1_User." ), aElem.
layer );
3187 shape->SetLayer( klayer );
3206 msg.Printf(
_(
"Dimension found on an Altium layer (%d) with no KiCad equivalent. "
3207 "It has been moved to KiCad layer Eco1_User." ), aElem.
layer );
3217 std::unique_ptr<PCB_DIM_CENTER> dimension = std::make_unique<PCB_DIM_CENTER>(
m_board );
3219 dimension->SetLayer( klayer );
3220 dimension->SetLineThickness( aElem.
linewidth );
3221 dimension->SetStart( aElem.
xy1 );
3222 dimension->SetEnd( aElem.
xy1 + vec );
3229 const CFB::COMPOUND_FILE_ENTRY* aEntry )
3249 m_reporter->Report( wxString::Format(
_(
"Ignored Angular dimension (not yet supported)." ) ),
3262 m_reporter->Report( wxString::Format(
_(
"Ignored Datum dimension (not yet supported)." ) ),
3270 m_reporter->Report( wxString::Format(
_(
"Ignored Baseline dimension (not yet supported)." ) ),
3280 m_reporter->Report( wxString::Format(
_(
"Ignored Linear dimension (not yet supported)." ) ),
3287 m_reporter->Report( wxString::Format(
_(
"Ignored Radial dimension (not yet supported)." ) ),
3295 msg.Printf(
_(
"Ignored dimension of kind %d (not yet supported)." ), elem.
kind );
3303 THROW_IO_ERROR( wxT(
"Dimensions6 stream is not fully parsed" ) );
3308 const CFB::COMPOUND_FILE_ENTRY* aEntry,
3309 const std::vector<std::string>& aRootDir )
3320 wxString invalidChars = wxFileName::GetForbiddenChars();
3327 std::vector<std::string> stepPath = aRootDir;
3328 stepPath.emplace_back( std::to_string( idx ) );
3330 bool validName = !elem.
name.IsEmpty() && elem.
name.IsAscii()
3331 && wxString::npos == elem.
name.find_first_of( invalidChars );
3332 wxString storageName = validName ? elem.
name : wxString::Format( wxT(
"model_%d" ), idx );
3336 const CFB::COMPOUND_FILE_ENTRY* stepEntry = aAltiumPcbFile.
FindStream( stepPath );
3338 if( stepEntry ==
nullptr )
3343 msg.Printf(
_(
"File not found: '%s'. 3D-model not imported." ),
FormatPath( stepPath ) );
3350 size_t stepSize =
static_cast<size_t>( stepEntry->size );
3351 std::vector<char> stepContent( stepSize );
3359 std::move( stepContent ) ) ) );
3363 std::map<wxString, std::vector<wxString>> nameIdMap;
3366 nameIdMap[data.m_modelname].push_back(
id );
3368 for(
auto& [
name, ids] : nameIdMap )
3370 for(
size_t i = 1; i < ids.size(); i++ )
3372 const wxString&
id = ids[i];
3379 wxString modelName = modelTuple->second.m_modelname;
3381 if( modelName.Contains(
"." ) )
3384 wxString baseName = modelName.BeforeLast(
'.', &ext );
3386 modelTuple->second.m_modelname = baseName +
'_' + std::to_string( i ) +
'.' + ext;
3390 modelTuple->second.m_modelname = modelName +
'_' + std::to_string( i );
3401 std::set<wxString>& aAmbiguous )
3403 auto collect = [&](
const std::map<wxString, wxString>& aProps )
3423 if(
name.IsEmpty() )
3426 wxString key =
name.Upper();
3427 auto it = aNames.find( key );
3429 if( it == aNames.end() )
3430 aNames.emplace( key,
name );
3431 else if( it->second !=
name )
3432 aAmbiguous.insert( key );
3438 const CFB::COMPOUND_FILE_ENTRY* header = schFile.
FindStream( {
"FileHeader" } );
3460 std::set<wxString> ambiguous;
3462 for(
int i = 0;; i++ )
3464 auto it = aProperties.find(
"sch" + std::to_string( i ) );
3466 if( it == aProperties.end() )
3479 for(
const wxString& key : ambiguous )
3496 const CFB::COMPOUND_FILE_ENTRY* aEntry )
3505 int unnamedNetCount = 0;
3510 ANET6 elem( reader );
3514 if( netName.IsEmpty() )
3520 m_reporter->Report( wxString::Format(
_(
"Altium net %zu has no name; imported as '%s'." ),
3538 const CFB::COMPOUND_FILE_ENTRY* aEntry )
3552 m_reporter->Report( wxString::Format(
_(
"Polygon on layer '%s' has %d vertices "
3553 "outside the coordinate range; they were "
3591 msg.Printf(
_(
"Polygon outline count is %d, expected 1." ), outline.
OutlineCount() );
3599 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>(
m_board);
3605 zone->SetPosition( elem.
vertices.at( 0 ).position );
3606 zone->SetLocked( elem.
locked );
3608 zone->Outline()->AddOutline( outline.
Outline( 0 ) );
3615 int planeLayers = 0;
3616 int signalLayers = 0;
3630 if( planeLayers > 0 && planeClearanceRule )
3633 if( signalLayers > 0 && zoneClearanceRule )
3641 if( polygonConnectRule !=
nullptr )
3660 zone->SetThermalReliefSpokeWidth(
3671 zone->SetAssignedPriority( 1 );
3676 || zone->GetBoundingBox().Contains( outer_plane->second->GetBoundingBox() ) )
3691 const BOX2I& bbox = zone->GetBoundingBox();
3700 zone->SetHatchOrientation(
ANGLE_45 );
3715 const CFB::COMPOUND_FILE_ENTRY* aEntry )
3734 std::sort( val.second.begin(), val.second.end(),
3737 return lhs.priority < rhs.priority;
3751 if( trackWidthRule )
3753 m_board->GetDesignSettings().m_TrackMinWidth = trackWidthRule->
minLimit;
3757 if( routingViasRule )
3759 m_board->GetDesignSettings().m_ViasMinSize = routingViasRule->
minWidth;
3768 if( holeToHoleRule )
3771 if( boardOutlineRule )
3777 if( soldermaskRule )
3783 std::shared_ptr<NET_SETTINGS> netSettings =
m_board->GetDesignSettings().m_NetSettings;
3784 std::shared_ptr<NETCLASS> defaultNetclass = netSettings->GetDefaultNetclass();
3787 defaultNetclass->SetClearance( clearanceRule->
clearanceGap );
3789 if( trackWidthRule )
3790 defaultNetclass->SetTrackWidth( trackWidthRule->
preferredWidth );
3792 if( routingViasRule )
3794 defaultNetclass->SetViaDiameter( routingViasRule->
width );
3795 defaultNetclass->SetViaDrill( routingViasRule->
holeWidth );
3798 std::vector<const ARULE6*> unresolvedNetclassRules;
3804 for(
const ARULE6* rule : unresolvedNetclassRules )
3806 wxString netclassName;
3809 m_reporter->Report( wxString::Format(
_(
"Altium rule '%s' applies to netclass '%s', which this "
3810 "board does not define. Its constraint is not imported." ),
3811 rule->name, netclassName ),
3824 const CFB::COMPOUND_FILE_ENTRY* aEntry )
3840 THROW_IO_ERROR( wxT(
"BoardRegions stream is not fully parsed" ) );
3844 const CFB::COMPOUND_FILE_ENTRY* aEntry )
3852 for(
int primitiveIndex = 0; reader.
GetRemainingBytes() >= 4; primitiveIndex++ )
3877 THROW_IO_ERROR( wxT(
"ShapeBasedRegions6 stream is not fully parsed" ) );
3882 const int aPrimitiveIndex, uint16_t aNet )
3901 for(
const std::vector<ALTIUM_VERTICE>& hole : aElem.
holes )
3910 std::unique_ptr<PCB_SHAPE> region = std::make_unique<PCB_SHAPE>(
nullptr,
SHAPE_T::POLY );
3912 region->SetPolyShape( polySet );
3913 region->SetFilled(
true );
3917 [
this, aFootprint, aElem, klayer, aPrimitiveIndex]()
3952 if( restrictions == 0 )
3955 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>(
m_board );
3957 zone->SetIsRuleArea(
true );
3961 zone->SetPosition( aElem.
outline.at( 0 ).position );
3962 zone->Outline()->AddOutline( linechain );
3982 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>(
m_board );
3984 zone->SetPosition( aElem.
outline.at( 0 ).position );
3985 zone->Outline()->AddOutline( linechain );
3993 fill.
Append( linechain );
3997 zone->SetFilledPolysList( klayer, fill );
3999 zone->SetIsFilled(
true );
4000 zone->SetNeedRefill(
false );
4013 msg.Printf(
_(
"Dashed outline found on an Altium layer (%d) with no KiCad equivalent. "
4014 "It has been moved to KiCad layer Eco1_User." ), aElem.
layer );
4035 shape->SetPolyShape( linechain );
4036 shape->SetFilled(
false );
4037 shape->SetLayer( klayer );
4055 msg.Printf(
_(
"Ignored polygon shape of kind %d (not yet supported)." ), aElem.
kind );
4064 const int aPrimitiveIndex )
4084 if( restrictions == 0 )
4087 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aFootprint );
4089 zone->SetIsRuleArea(
true );
4093 zone->SetPosition( aElem.
outline.at( 0 ).position );
4094 zone->Outline()->AddOutline( linechain );
4130 msg.Printf(
_(
"Loading library '%s':\n"
4131 "Footprint %s contains a dashed outline on Altium layer (%d) with "
4132 "no KiCad equivalent. It has been moved to KiCad layer Eco1_User." ),
4144 msg.Printf(
_(
"Footprint %s contains a dashed outline on Altium layer (%d) with "
4145 "no KiCad equivalent. It has been moved to KiCad layer Eco1_User." ),
4167 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( aFootprint,
SHAPE_T::POLY );
4169 shape->SetPolyShape( linechain );
4170 shape->SetFilled(
false );
4171 shape->SetLayer( klayer );
4187 msg.Printf(
_(
"Error loading library '%s':\n"
4188 "Footprint %s contains polygon shape of kind %d (not yet supported)." ),
4200 msg.Printf(
_(
"Footprint %s contains polygon shape of kind %d (not yet supported)." ),
4211 const int aPrimitiveIndex )
4228 for(
const std::vector<ALTIUM_VERTICE>& hole : aElem.
holes )
4236 polySet.
AddHole( hole_linechain );
4241 shape->SetPolyShape( polySet );
4242 shape->SetFilled(
true );
4243 shape->SetLayer( aLayer );
4254 if( aLayer ==
F_Cu || aLayer ==
B_Cu )
4256 for(
const auto& layerExpansionMask :
4259 const PCB_LAYER_ID maskLayer = layerExpansionMask.first;
4267 int expansion = layerExpansionMask.second;
4274 maskShape->SetPolyShape( expandedPolySet );
4275 maskShape->SetFilled(
true );
4276 maskShape->SetLayer( maskLayer );
4288 const int aPrimitiveIndex )
4305 for(
const std::vector<ALTIUM_VERTICE>& hole : aElem.
holes )
4313 polySet.
AddHole( hole_linechain );
4316 if( aLayer ==
F_Cu || aLayer ==
B_Cu )
4318 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( aFootprint );
4321 padLayers.
set( aLayer );
4333 pad->SetPosition( anchorPos );
4340 shapePolys.
Move( -anchorPos );
4344 auto it = map.find( aPrimitiveIndex );
4346 if( it != map.end() )
4352 pad->SetLocalSolderPasteMargin(
info.pastemaskexpansionmanual );
4357 pad->SetLocalSolderMaskMargin(
info.soldermaskexpansionmanual );
4367 pad->SetLayerSet( padLayers );
4373 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( aFootprint,
SHAPE_T::POLY );
4375 shape->SetPolyShape( polySet );
4376 shape->SetFilled(
true );
4377 shape->SetLayer( aLayer );
4386 const CFB::COMPOUND_FILE_ENTRY* aEntry )
4402 THROW_IO_ERRORF( wxT(
"Region stream tries to access polygon id %d of %d existing polygons." ),
4408 if( zone ==
nullptr )
4427 for(
const std::vector<ALTIUM_VERTICE>& hole : elem.
holes )
4434 hole_linechain.
Append( hole.at( 0 ).position );
4436 fill.
AddHole( hole_linechain );
4456 const CFB::COMPOUND_FILE_ENTRY* aEntry )
4463 for(
int primitiveIndex = 0; reader.
GetRemainingBytes() >= 4; primitiveIndex++ )
4466 AARC6 elem( reader );
4517 THROW_IO_ERRORF( wxT(
"Tracks stream tries to access polygon id %u of %zu existing polygons." ),
4523 if( zone ==
nullptr )
4571 for(
const auto& layerExpansionMask :
4574 int width = aElem.
width + ( layerExpansionMask.second * 2 );
4578 std::unique_ptr<PCB_SHAPE> arc = std::make_unique<PCB_SHAPE>(
m_board );
4582 arc->SetLayer( layerExpansionMask.first );
4591 const int aPrimitiveIndex,
const bool aIsBoardImport )
4595 wxFAIL_MSG( wxString::Format(
"Altium: Unexpected footprint Arc with polygon id %d",
4619 std::unique_ptr<PCB_SHAPE> arc = std::make_unique<PCB_SHAPE>(
nullptr );
4626 [
this, aFootprint, aElem, klayer, aIsBoardImport]()
4628 if( aIsBoardImport )
4629 ConvertArcs6ToBoardItemOnLayer( aElem, klayer );
4631 ConvertArcs6ToFootprintItemOnLayer( aFootprint, aElem, klayer );
4641 for(
const auto& layerExpansionMask :
4644 int width = aElem.
width + ( layerExpansionMask.second * 2 );
4648 std::unique_ptr<PCB_SHAPE> arc = std::make_unique<PCB_SHAPE>( aFootprint );
4652 arc->SetLayer( layerExpansionMask.first );
4674 std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>(
m_board, &shapeArc );
4676 arc->SetWidth( aElem.
width );
4677 arc->SetLayer( aLayer );
4680 PCB_ARC* added = arc.release();
4688 if(
std::abs( sweepDegrees ) >= 359.999 )
4692 addArc( aElem.
center + startOffset, halfSweep );
4693 addArc( aElem.
center - startOffset, halfSweep );
4700 addArc( aElem.
center + startOffset, includedAngle );
4704 std::unique_ptr<PCB_SHAPE> arc = std::make_unique<PCB_SHAPE>(
m_board);
4708 arc->SetLayer( aLayer );
4718 std::unique_ptr<PCB_SHAPE> arc = std::make_unique<PCB_SHAPE>( aFootprint );
4722 arc->SetLayer( aLayer );
4729 const CFB::COMPOUND_FILE_ENTRY* aEntry )
4739 APAD6 elem( reader );
4768 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>(
m_board );
4769 footprint->SetPosition( aElem.
position );
4784 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( aFootprint );
4786 pad->SetNumber(
"" );
4795 pad->SetLayerSet(
LSET().AllCuMask() );
4827 cuLayers &=
m_board->GetEnabledLayers();
4836 pad->SetSize( layer,
VECTOR2I( diameter, diameter ) );
4852 pad->Padstack().FrontOuterLayers().has_solder_mask =
true;
4856 pad->Padstack().FrontOuterLayers().has_solder_mask =
false;
4862 pad->Padstack().BackOuterLayers().has_solder_mask =
true;
4866 pad->Padstack().BackOuterLayers().has_solder_mask =
false;
4871 pad->SetLocked(
true );
4879 PAD* added =
pad.release();
4902 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( aFootprint );
4925 msg.Printf(
_(
"Error loading library '%s':\n"
4926 "Footprint %s pad %s is not marked as multilayer, but is a TH pad." ),
4938 msg.Printf(
_(
"Footprint %s pad %s is not marked as multilayer, but is a TH pad." ),
4958 wxFAIL_MSG( wxT(
"Round holes are handled before the switch" ) );
4967 msg.Printf(
_(
"Loading library '%s':\n"
4968 "Footprint %s pad %s has a square hole (not yet supported)." ),
4980 msg.Printf(
_(
"Footprint %s pad %s has a square hole (not yet supported)." ),
4996 bool slotRotationSupported;
5000 if( !slotRotationSupported )
5010 msg.Printf(
_(
"Loading library '%s':\n"
5011 "Footprint %s pad %s has a hole-rotation of %d degrees. "
5012 "KiCad only supports 90 degree rotations." ),
5025 msg.Printf(
_(
"Footprint %s pad %s has a hole-rotation of %d degrees. "
5026 "KiCad only supports 90 degree rotations." ),
5045 msg.Printf(
_(
"Error loading library '%s':\n"
5046 "Footprint %s pad %s uses a hole of unknown kind %d." ),
5059 msg.Printf(
_(
"Footprint %s pad %s uses a hole of unknown kind %d." ),
5076 auto setCopperGeometry =
5080 bool hasAltiumEntry = aElem.
sizeAndShape && aAltiumIdx >= 0
5085 if( aElem.
holesize != 0 && hasAltiumEntry )
5102 else if( aSize.x == aSize.y )
5126 msg.Printf(
_(
"Error loading library '%s':\n"
5127 "Footprint %s pad %s uses an unknown pad shape." ),
5139 msg.Printf(
_(
"Footprint %s pad %s uses an unknown pad shape." ),
5192 setCopperGeometry( layer, idx, shape.
inner_shape[inner],
5202 switch( aElem.
layer )
5220 pad->SetLayer( klayer );
5221 pad->SetLayerSet(
LSET( { klayer } ) );
5232 pad->SetLayerSet(
pad->GetLayerSet().reset(
F_Mask ) );
5235 pad->SetLayerSet(
pad->GetLayerSet().reset(
B_Mask ) );
5253 msg.Printf(
_(
"Non-copper pad %s found on an Altium layer (%d) with no KiCad "
5254 "equivalent. It has been moved to KiCad layer Eco1_User." ),
5262 std::unique_ptr<PCB_SHAPE>
pad = std::make_unique<PCB_SHAPE>(
m_board );
5281 msg.Printf(
_(
"Loading library '%s':\n"
5282 "Footprint %s non-copper pad %s found on an Altium layer (%d) with no "
5283 "KiCad equivalent. It has been moved to KiCad layer Eco1_User." ),
5296 msg.Printf(
_(
"Footprint %s non-copper pad %s found on an Altium layer (%d) with no "
5297 "KiCad equivalent. It has been moved to KiCad layer Eco1_User." ),
5308 std::unique_ptr<PCB_SHAPE>
pad = std::make_unique<PCB_SHAPE>( aFootprint );
5324 msg.Printf(
_(
"Non-copper pad %s is connected to a net, which is not supported." ),
5335 msg.Printf(
_(
"Non-copper pad %s has a hole, which is not supported." ), aElem.
name );
5345 msg.Printf(
_(
"Non-copper pad %s has a complex pad stack (not yet supported)." ),
5377 int offset = ( std::min( aElem.
topsize.
x, aElem.
topsize.
y ) * cornerradius ) / 200;
5382 if( cornerradius < 100 )
5384 int offsetX = aElem.
topsize.
x / 2 - offset;
5385 int offsetY = aElem.
topsize.
y / 2 - offset;
5478 aShape->
SetPolyPoints( { p11 - chamferX, p11 - chamferY, p12 + chamferY, p12 - chamferX,
5479 p22 + chamferX, p22 + chamferY, p21 - chamferY, p21 + chamferX } );
5491 msg.Printf(
_(
"Non-copper pad %s uses an unknown pad shape." ), aElem.
name );
5501 const CFB::COMPOUND_FILE_ENTRY* aEntry )
5511 AVIA6 elem( reader );
5537 std::unique_ptr<PCB_VIA>
via = std::make_unique<PCB_VIA>(
m_board );
5549 if( start_layer_outside && end_layer_outside )
5553 else if( ( !start_layer_outside ) && ( !end_layer_outside ) )
5576 msg.Printf(
_(
"Via from layer %d to %d uses a non-copper layer, which is not "
5587 via->SetLayerPair( start_klayer, end_klayer );
5614 via->SetWidth( layer, altiumLayer < 0 ? aElem.
diameter
5643 const CFB::COMPOUND_FILE_ENTRY* aEntry )
5650 for(
int primitiveIndex = 0; reader.
GetRemainingBytes() >= 4; primitiveIndex++ )
5681 msg.Printf( wxT(
"ATRACK6 stream tries to access polygon id %u "
5682 "of %u existing polygons; skipping it" ),
5683 static_cast<unsigned>( aElem.
polygon ),
5684 static_cast<unsigned>(
m_polygons.size() ) );
5693 if( zone ==
nullptr )
5741 aPrimitiveIndex, aElem.
layer ) )
5743 int width = aElem.
width + ( layerExpansionMask.second * 2 );
5748 seg->SetStart( aElem.
start );
5749 seg->SetEnd( aElem.
end );
5751 seg->SetLayer( layerExpansionMask.first );
5760 const int aPrimitiveIndex,
5761 const bool aIsBoardImport )
5765 wxFAIL_MSG( wxString::Format( wxT(
"Altium: Unexpected footprint Track with polygon id %u" ),
5789 std::unique_ptr<PCB_SHAPE> seg = std::make_unique<PCB_SHAPE>(
nullptr,
SHAPE_T::SEGMENT );
5791 seg->SetStart( aElem.
start );
5792 seg->SetEnd( aElem.
end );
5797 [
this, aFootprint, aElem, klayer, aIsBoardImport]()
5799 if( aIsBoardImport )
5800 ConvertTracks6ToBoardItemOnLayer( aElem, klayer );
5802 ConvertTracks6ToFootprintItemOnLayer( aFootprint, aElem, klayer );
5813 aPrimitiveIndex, aElem.
layer ) )
5815 int width = aElem.
width + ( layerExpansionMask.second * 2 );
5818 std::unique_ptr<PCB_SHAPE> seg = std::make_unique<PCB_SHAPE>( aFootprint,
SHAPE_T::SEGMENT );
5820 seg->SetStart( aElem.
start );
5821 seg->SetEnd( aElem.
end );
5823 seg->SetLayer( layerExpansionMask.first );
5835 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>(
m_board );
5837 track->SetStart( aElem.
start );
5838 track->SetEnd( aElem.
end );
5839 track->SetWidth( aElem.
width );
5840 track->SetLayer( aLayer );
5853 seg->SetStart( aElem.
start );
5854 seg->SetEnd( aElem.
end );
5856 seg->SetLayer( aLayer );
5866 std::unique_ptr<PCB_SHAPE> seg = std::make_unique<PCB_SHAPE>( aFootprint,
SHAPE_T::SEGMENT );
5868 seg->SetStart( aElem.
start );
5869 seg->SetEnd( aElem.
end );
5871 seg->SetLayer( aLayer );
5878 const CFB::COMPOUND_FILE_ENTRY* aEntry )
5888 THROW_IO_ERROR( wxT(
"WideStrings6 stream is not fully parsed" ) );
5892 const CFB::COMPOUND_FILE_ENTRY* aEntry )
5906 THROW_IO_ERROR( wxT(
"SmartUnions6 stream is not fully parsed" ) );
5911 const CFB::COMPOUND_FILE_ENTRY* aEntry )
5916 reader.
Read<uint32_t>();
5920 THROW_IO_ERROR( wxT(
"UnionNames stream is not fully parsed" ) );
5939 if( tuning.baseline.size() < 2
5940 || ( tuning.is_diffpair && tuning.baselinecoupled.size() < 2 ) )
5945 const std::vector<BOARD_ITEM*>& items = itemsIt->second;
5959 std::unique_ptr<PCB_TUNING_PATTERN> pattern(
static_cast<PCB_TUNING_PATTERN*
>( generator ) );
5960 pattern->SetParent(
m_board );
5961 pattern->SetLayer( layer );
5962 pattern->SetTuningMode( mode );
5965 if(
auto nameIt =
m_unionNames.find( tuning.unionindex );
5966 nameIt !=
m_unionNames.end() && !nameIt->second.IsEmpty() )
5968 pattern->SetName( nameIt->second );
5971 pattern->SetMaxAmplitude( tuning.amplitude );
5972 pattern->SetMinAmplitude( tuning.minamplitude );
5973 pattern->SetSpacing( tuning.gap );
5974 pattern->SetSingleSided( tuning.singleside );
5978 pattern->SetRounded( tuning.style != 0 );
5980 if( tuning.mitterradiusratio > 0.0 )
5982 int percent =
KiROUND( tuning.mitterradiusratio * 100.0 );
5983 pattern->SetCornerRadiusPercentage( std::clamp( percent, 0, 100 ) );
5987 bool singleNet =
true;
5991 pattern->AddItem( item );
5996 netCode = bci->GetNetCode();
5997 else if( netCode != bci->GetNetCode() )
6004 if( netCode >= 0 && singleNet )
6006 pattern->SetNetCode( netCode );
6012 SEG::ecoord bestDist = std::numeric_limits<SEG::ecoord>::max();
6024 if( dist < bestDist )
6031 pattern->SetLastNetName( bestNet );
6035 pattern->SetWidth( track->GetWidth() );
6037 pattern->SetBaseLine( baseLine );
6038 pattern->SetPosition( baseLine.
CPoint( 0 ) );
6045 pattern->SetBaseLineCoupled( baseLineCoupled );
6047 int centreToCentre = baseLine.
Distance( baseLineCoupled.
CPoint( 0 ),
false );
6049 pattern->SetDiffPairGap( std::max( centreToCentre - pattern->GetWidth(), 0 ) );
6058 m_reporter->Report( wxString::Format(
_(
"Imported %d length-tuning pattern(s)." ),
6075 footprint->RunOnChildren(
6080 if( copper.count() == 1 )
6081 drawnCopper |= copper;
6086 for(
PAD*
pad : footprint->Pads() )
6095 if( !
pad->GetPrimitives( layer ).empty() )
6096 drawnCopper.
set( layer );
6107 std::unique_ptr<PCB_SHAPE> aShape, std::function<
void()> aFallback )
6109 aShape->SetLayer( aLayer );
6112 std::move( aFallback ) } );
6117 const PAD* aExclude =
nullptr )
6119 PAD* found =
nullptr;
6123 if(
pad == aExclude ||
pad->GetNumber().IsEmpty() ||
pad->GetNetCode() != aNetCode
6124 || !
pad->IsOnLayer( aLayer ) )
6130 && aShape.
Collide(
pad->GetEffectiveShape( aLayer ).get() ) )
6153 aShape->
Move( -aPad->ShapePos( aLayer ) );
6165 aPad->TransformShapeToPolygon( padCopper, layer, 0, aMaxError,
ERROR_INSIDE );
6171 aPending.
shape.reset();
6180 toPadFrame( aPending.
shape.get(), aPad, layer );
6181 aPad->AddPrimitive( layer, aPending.
shape.release() );
6185 if( aExtensionPads.count( aPad ) )
6187 toPadFrame( aPending.
shape.get(), aPad, layer );
6198 std::unique_ptr<PAD> extension = std::make_unique<PAD>( aPending.
footprint );
6207 extension->SetPosition( anchorPos );
6208 extension->SetOrientation(
ANGLE_0 );
6209 extension->SetThermalSpokeAngle(
ANGLE_90 );
6210 extension->SetLayerSet(
LSET{ layer } );
6211 extension->SetNumber( aPad->GetNumber() );
6212 extension->SetNetCode( aPad->GetNetCode() );
6217 toPadFrame( aPending.
shape.get(), extension.get(), layer );
6220 aExtensionPads.insert( extension.get() );
6224 bool changed =
false;
6229 if( !pending.shape || !aCopper.test( pending.layer ) )
6232 std::shared_ptr<SHAPE> shape = pending.shape->GetEffectiveShape( pending.layer );
6236 fold( pending,
pad );
6259 const int maxError =
m_board->GetDesignSettings().m_MaxError;
6264 std::set<PAD*> extensionPads;
6267 auto viaDiameterOn =
6273 if( aLayer ==
F_Cu )
6276 if( aLayer ==
B_Cu )
6293 for(
bool changed =
true; changed; )
6299 auto& [footprint,
via] = *it;
6300 PAD* touched =
nullptr;
6304 SHAPE_CIRCLE land(
via.position,
static_cast<int>( viaDiameterOn(
via, layer ) / 2 ) );
6334 for(
PAD*
pad : footprint->Pads() )
6336 if( !
pad->GetNumber().IsEmpty() ||
pad->GetNetCode() <= 0 )
6344 *
pad->GetEffectiveShape( layer ),
pad );
6383 footprint->SetAttributes( footprint->GetAttributes() | footprint->GetLikelyAttribute() );
6389 const CFB::COMPOUND_FILE_ENTRY* aEntry )
6448 std::unique_ptr<PCB_TEXTBOX> pcbTextbox = std::make_unique<PCB_TEXTBOX>(
m_board );
6449 std::unique_ptr<PCB_TEXT> pcbText = std::make_unique<PCB_TEXT>(
m_board );
6453 static const std::map<wxString, wxString> variableMap = {
6454 {
"LAYER_NAME",
"LAYER" },
6455 {
"PRINT_DATE",
"CURRENT_DATE" },
6456 {
"PRINT_TIME",
"CURRENT_TIME_LOCALE" },
6457 {
"PCB_FILE_NAME_NO_PATH",
"FILENAME" },
6466 item = pcbTextbox.get();
6467 text = pcbTextbox.get();
6470 text->SetText( kicadText );
6495 std::unique_ptr<PCB_TEXTBOX> fpTextbox = std::make_unique<PCB_TEXTBOX>( aFootprint );
6496 std::unique_ptr<PCB_TEXT> fpText = std::make_unique<PCB_TEXT>( aFootprint );
6513 item = &aFootprint->
Value();
6518 item = fpText.get();
6519 text = fpText.get();
6523 static const std::map<wxString, wxString> variableMap = {
6524 {
"DESIGNATOR",
"REFERENCE" },
6525 {
"COMMENT",
"VALUE" },
6526 {
"VALUE",
"ALTIUM_VALUE" },
6527 {
"LAYER_NAME",
"LAYER" },
6528 {
"PRINT_DATE",
"CURRENT_DATE" },
6529 {
"PRINT_TIME",
"CURRENT_TIME_LOCALE" },
6530 {
"PCB_FILE_NAME_NO_PATH",
"FILENAME" },
6535 item = fpTextbox.get();
6536 text = fpTextbox.get();
6541 text->SetText( kicadText );
6554 text->SetKeepUpright(
false );
6569 std::unique_ptr<PCB_BARCODE> pcbBarcode = std::make_unique<PCB_BARCODE>(
m_board );
6571 pcbBarcode->SetLayer( aLayer );
6572 pcbBarcode->SetPosition( aElem.
position );
6576 pcbBarcode->SetText( aElem.
text );
6586 pcbBarcode->AssembleBarcode();
6595 std::unique_ptr<PCB_BARCODE> fpBarcode = std::make_unique<PCB_BARCODE>( aFootprint );
6597 fpBarcode->SetLayer( aLayer );
6598 fpBarcode->SetPosition( aElem.
position );
6602 fpBarcode->SetText( aElem.
text );
6612 fpBarcode->AssembleBarcode();
6641 kicadMargin =
VECTOR2I( charWidth * 0.933, charHeight * 0.67 );
6643 kicadMargin =
VECTOR2I( charWidth * 0.808, charHeight * 0.844 );
6646 + kicadMargin * 2 - margin * 2 );
6648 kposition = kposition - kicadMargin + margin;
6665 switch( justification )
6689 msg.Printf(
_(
"Unknown textbox justification %d, aText %s" ), justification,
6709 int rectHeight = aElem.
height;
6714 kposition.
x += aElem.
isMirrored ? -margin : margin;
6715 kposition.
y -= margin;
6735 rectWidth = -rectWidth;
6740 switch( justification )
6746 kposition.
y -= rectHeight;
6752 kposition.
y -= rectHeight / 2;
6762 kposition.
x += rectWidth / 2;
6763 kposition.
y -= rectHeight;
6769 kposition.
x += rectWidth / 2;
6770 kposition.
y -= rectHeight / 2;
6776 kposition.
x += rectWidth / 2;
6782 kposition.
x += rectWidth;
6783 kposition.
y -= rectHeight;
6789 kposition.
x += rectWidth;
6790 kposition.
y -= rectHeight / 2;
6796 kposition.
x += rectWidth;
6849 if( font->
GetName().Contains( wxS(
"Arial" ) ) )
6868 const CFB::COMPOUND_FILE_ENTRY* aEntry )
6926 const bool aIsBoardImport )
6961 std::unique_ptr<PCB_SHAPE> fill = std::make_unique<PCB_SHAPE>(
nullptr,
SHAPE_T::RECTANGLE );
6967 [
this, aFootprint, aElem, klayer, aIsBoardImport]()
6969 if( aIsBoardImport )
6970 ConvertFills6ToBoardItemOnLayer( aElem, klayer );
6972 ConvertFills6ToFootprintItemOnLayer( aFootprint, aElem, klayer );
7008 fill->SetLayer( aLayer );
7022 if( aLayer ==
F_Cu || aLayer ==
B_Cu )
7024 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( aFootprint );
7027 padLayers.
set( aLayer );
7043 std::swap( width, height );
7046 pad->SetPosition( aElem.
pos1 / 2 + aElem.
pos2 / 2 );
7059 pad->SetPosition( anchorPos );
7070 aElem.
pos1.
y / 2 + aElem.
pos2.
y / 2 - anchorPos.
y );
7072 pad->AddPrimitivePoly(
F_Cu, shapePolys, 0,
true );
7076 pad->SetLayerSet( padLayers );
7082 std::unique_ptr<PCB_SHAPE> fill = std::make_unique<PCB_SHAPE>( aFootprint,
SHAPE_T::RECTANGLE );
7084 fill->SetFilled(
true );
7085 fill->SetLayer( aLayer );
7088 fill->SetStart( aElem.
pos1 );
7089 fill->SetEnd( aElem.
pos2 );
7108 layerSet.
set( klayer );
7137 if( aKeepoutRestrictions != 0 )
7138 return aKeepoutRestrictions;
7170 const uint8_t aKeepoutRestrictions )
7174 if( restrictions == 0 )
7177 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>(
m_board );
7179 zone->SetIsRuleArea(
true );
7196 const uint8_t aKeepoutRestrictions )
7200 if( restrictions == 0 )
7203 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aFootprint );
7205 zone->SetIsRuleArea(
true );
7229 if( elems.first == elems.second )
7232 std::vector<std::pair<PCB_LAYER_ID, int>> layerExpansionPairs;
7234 for(
auto it = elems.first; it != elems.second; ++it )
7274 return layerExpansionPairs;
std::string FormatPath(const std::vector< std::string > &aVectorPath)
Helper for debug logging (vector -> string)
VECTOR2I altiumSlotDrillSize(uint32_t aHoleSize, uint32_t aSlotSize, double aSlotRotation, bool &aRotationSupported)
Convert an Altium slot's independent rotation and dimensions to KiCad's cardinal drill shape.
const ARULE6 * selectAltiumPolygonRule(const std::vector< ARULE6 > &aRulesByPriorityAsc)
Select the highest Altium-priority rule whose scope references polygons.
bool altiumViaSideIsTented(bool aTentFlag, bool aManual, bool aFromHole, uint32_t aHoleSize, int32_t aMaskExpansion, int aLandDiameter)
Decide whether one side of an Altium via should be tented when imported into KiCad.
const uint8_t ALTIUM_KEEPOUT_VIA
const uint8_t ALTIUM_KEEPOUT_COPPER
const uint8_t ALTIUM_KEEPOUT_SMD_PAD
@ BOARD_OUTLINE_CLEARANCE
const uint8_t ALTIUM_KEEPOUT_TH_PAD
const uint8_t ALTIUM_KEEPOUT_TRACK
const uint8_t ALTIUM_KEEPOUT_ALL
const uint16_t ALTIUM_NET_UNCONNECTED
const uint16_t ALTIUM_POLYGON_NONE
const uint16_t ALTIUM_POLYGON_BOARD
const int ALTIUM_COMPONENT_NONE
wxString AltiumPcbSpecialStringsToKiCadStrings(const wxString &aString, const std::map< wxString, wxString > &aOverrides, std::set< wxString > *aUnmapped)
Convert the special strings in Altium PCB text to KiCad variables.
LIB_ID AltiumToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
constexpr int ALTIUM_PADSTACK_IDX_COUNT
static LSET altiumStackupCopper(const LSET &aDrawnCopper, int aMinCopperLayers)
constexpr int ALTIUM_BOTTOM_PADSTACK_IDX
static bool IsLayerNameAssembly(const wxString &aName)
void HelperShapeLineChainFromAltiumVertices(SHAPE_LINE_CHAIN &aLine, const std::vector< ALTIUM_VERTICE > &aVertices)
double normalizeAngleDegrees(double Angle, double aMin, double aMax)
Normalize angle to be aMin < angle <= aMax angle is in degrees.
static void altiumSplitPadstackPerLayer(PAD *aPad, const LSET &aBoardCopper)
constexpr double BOLD_FACTOR
constexpr int ALTIUM_TOP_PADSTACK_IDX
static void altiumCollectSchematicNetNames(const wxString &aFileName, std::map< wxString, wxString > &aNames, std::set< wxString > &aAmbiguous)
static void altiumSetFootprintStackup(FOOTPRINT *aFootprint, const LSET &aDrawnCopper, int aMinCopperLayers)
static bool GetAltiumNetclassScopeName(const ARULE6 &aRule, wxString *aNetclassName)
wxString AltiumUnnamedNetName(const BOARD &aBoard, int &aCounter)
Invent a placeholder name for an Altium net that has none.
constexpr int ALTIUM_MID2_PADSTACK_IDX
static bool IsAltiumScopeAll(const wxString &aExpr)
static bool IsLayerNameCourtyard(const wxString &aName)
static PAD * altiumFindTouchingPad(FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer, int aNetCode, const SHAPE &aShape, const PAD *aExclude=nullptr)
static void MoveOpenCourtyardItems(BOARD &aBoard)
bool IsAltiumLayerCopper(ALTIUM_LAYER aLayer)
static void altiumMakePadLayerCustom(PAD *aPad, PCB_LAYER_ID aLayer, int aMaxError)
void ApplyAltiumNetclassRules(const std::map< ALTIUM_RULE_KIND, std::vector< ARULE6 > > &aRulesByKind, NET_SETTINGS &aNetSettings, std::vector< const ARULE6 * > *aUnresolved)
Copy the values of Altium rules scoped to a single netclass onto that netclass.
static void altiumIsolatePadLayer(PAD *aPad, PCB_LAYER_ID aLayer, const LSET &aBoardCopper)
bool IsAltiumLayerAPlane(ALTIUM_LAYER aLayer)
static bool IsLayerNameTopSide(const wxString &aName)
constexpr int ALTIUM_MID1_PADSTACK_IDX
void ApplyAltiumNetclassRules(const std::map< ALTIUM_RULE_KIND, std::vector< ARULE6 > > &aRulesByKind, NET_SETTINGS &aNetSettings, std::vector< const ARULE6 * > *aUnresolved=nullptr)
Copy the values of Altium rules scoped to a single netclass onto that netclass.
wxString AltiumUnnamedNetName(const BOARD &aBoard, int &aCounter)
Invent a placeholder name for an Altium net that has none.
@ EXTENDPRIMITIVEINFORMATION
std::function< void(const ALTIUM_PCB_COMPOUND_FILE &, const CFB::COMPOUND_FILE_ENTRY *)> PARSE_FUNCTION_POINTER_fp
KIID AltiumUniqueIdToKiid(const wxString &aUniqueId)
Derive a stable KIID from an Altium component unique id.
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
#define DEFAULT_BOARD_THICKNESS_MM
@ BS_ITEM_TYPE_DIELECTRIC
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
std::map< wxString, wxString > ReadProperties()
size_t GetRemainingBytes() const
std::map< uint32_t, wxString > ReadWideStringTable()
size_t ReadAndSetSubrecordLength()
std::map< wxString, wxString > ReadProperties(std::function< std::map< wxString, wxString >(const std::string &)> handleBinaryData=[](const std::string &) { return std::map< wxString, wxString >();})
const CFB::CompoundFileReader & GetCompoundFileReader() const
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
const std::pair< AMODEL, std::vector< char > > * GetLibModel(const wxString &aModelID) const
std::tuple< wxString, const CFB::COMPOUND_FILE_ENTRY * > FindLibFootprintDirName(const wxString &aFpUnicodeName)
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
std::shared_ptr< EMBEDDED_FILES::EMBEDDED_FILE > HelperEmbedModel(FOOTPRINT *aFootprint, const wxString &aModelName, const std::vector< char > &aCompressedData, bool &aIsNew)
Return the 3D model aModelName embedded in aFootprint, inflating and embedding aCompressedData first ...
void ParseClasses6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
std::vector< PCB_DIM_RADIAL * > m_radialDimensions
const ARULE6 * GetRuleForPolygon(ALTIUM_RULE_KIND aKind) const
void ConvertArcs6ToFootprintItemOnLayer(FOOTPRINT *aFootprint, const AARC6 &aElem, PCB_LAYER_ID aLayer)
void ConvertTracks6ToBoardItem(const ATRACK6 &aElem, const int aPrimitiveIndex)
void ConvertTracks6ToFootprintItem(FOOTPRINT *aFootprint, const ATRACK6 &aElem, const int aPrimitiveIndex, const bool aIsBoardImport)
int m_highest_pour_index
Altium stores pour order across all layers.
void HelperCreateTuningPatterns()
void ConvertTexts6ToFootprintItemOnLayer(FOOTPRINT *aFootprint, const ATEXT6 &aElem, PCB_LAYER_ID aLayer)
std::map< ALTIUM_LAYER, PCB_LAYER_ID > m_layermap
void ParseVias6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void HelperParseDimensions6Leader(const ADIMENSION6 &aElem)
wxString m_footprintName
for footprint library loading error reporting
std::vector< FOOTPRINT * > m_components
void HelperFillMechanicalLayerAssignments(const std::vector< ABOARD6_LAYER_STACKUP > &aStackup)
void ParseShapeBasedRegions6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
const ARULE6 * GetRuleDefault(ALTIUM_RULE_KIND aKind) const
void HelperParsePad6NonCopper(const APAD6 &aElem, PCB_LAYER_ID aLayer, PCB_SHAPE *aShape)
void ConvertShapeBasedRegions6ToFootprintCopper(FOOTPRINT *aFootprint, const AREGION6 &aElem, const int aPrimitiveIndex, uint16_t aNet)
Plain copper region of a footprint; inner layers wait to join the pad they touch.
void ParseRegions6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
std::vector< PCB_LAYER_ID > GetKicadLayersToIterate(ALTIUM_LAYER aAltiumLayer) const
void ConvertShapeBasedRegions6ToFootprintItem(FOOTPRINT *aFootprint, const AREGION6 &aElem, const int aPrimitiveIndex)
void HelperPcpShapeAsFootprintKeepoutRegion(FOOTPRINT *aFootprint, const PCB_SHAPE &aShape, const ALTIUM_LAYER aAltiumLayer, const uint8_t aKeepoutRestrictions)
void ConvertArcs6ToBoardItem(const AARC6 &aElem, const int aPrimitiveIndex)
SHAPE_LINE_CHAIN m_boardOutline
void ConvertShapeBasedRegions6ToFootprintItemOnLayer(FOOTPRINT *aFootprint, const AREGION6 &aElem, PCB_LAYER_ID aLayer, const int aPrimitiveIndex)
std::map< ALTIUM_LAYER, ZONE * > m_outer_plane
std::vector< int > m_altiumToKicadNetcodes
std::map< uint32_t, wxString > m_unionNames
void HelperFinishBoardOutline()
void ConvertFills6ToPcbShape(const AFILL6 &aElem, PCB_SHAPE *aShape)
unsigned m_totalCount
for progress reporting
void ParseComponents6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void HelperPcpShapeAsBoardKeepoutRegion(const PCB_SHAPE &aShape, const ALTIUM_LAYER aAltiumLayer, const uint8_t aKeepoutRestrictions)
void HelperDeferComponentCopper(FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer, uint16_t aNet, std::unique_ptr< PCB_SHAPE > aShape, std::function< void()> aFallback)
Hold copper a footprint draws until its pads exist.
std::map< wxString, ALTIUM_EMBEDDED_MODEL_DATA > m_EmbeddedModels
void ConvertFills6ToBoardItemOnLayer(const AFILL6 &aElem, PCB_LAYER_ID aLayer)
std::vector< std::pair< PCB_LAYER_ID, int > > HelperGetSolderAndPasteMaskExpansions(const ALTIUM_RECORD aType, const int aPrimitiveIndex, const ALTIUM_LAYER aAltiumLayer)
void ConvertBarcodes6ToBoardItemOnLayer(const ATEXT6 &aElem, PCB_LAYER_ID aLayer)
void ConvertComponentBody6ToFootprintItem(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, FOOTPRINT *aFootprint, const ACOMPONENTBODY6 &aElem)
void HelperSetTextAlignmentAndPos(const ATEXT6 &aElem, EDA_TEXT *aEdaText)
void ParseBoard6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void ConvertFills6ToFootprintItem(FOOTPRINT *aFootprint, const AFILL6 &aElem, const bool aIsBoardImport)
void ParseExtendedPrimitiveInformationData(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void ParseFileHeader(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
std::vector< PENDING_COMPONENT_COPPER > m_pendingComponentCopper
std::set< wxString > m_specialStrings
special strings in text that KiCad has no variable for
void HelperCreateBoardOutline(const std::vector< ALTIUM_VERTICE > &aVertices)
std::map< int, std::vector< BOARD_ITEM * > > m_unionToBoardItems
void HelperAssignNetclassesToNets()
Rebuild the composite netclasses and point every net at its effective netclass.
std::map< ALTIUM_RULE_KIND, std::vector< ARULE6 > > m_rules
void ParseRules6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
PAD * ConvertVias6ToFootprintItem(FOOTPRINT *aFootprint, const AVIA6 &aElem)
void MapSchematicNetNames(const std::map< std::string, UTF8 > &aProperties)
void HelperSetZoneKeepoutRestrictions(ZONE &aZone, const uint8_t aKeepoutRestrictions)
void HelperParseDimensions6Linear(const ADIMENSION6 &aElem)
void ParseTracks6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
std::map< uint32_t, wxString > m_unicodeStrings
void ConvertTexts6ToBoardItem(const ATEXT6 &aElem)
void HelperParseDimensions6Center(const ADIMENSION6 &aElem)
void HelperParseDimensions6Radial(const ADIMENSION6 &aElem)
void ParseUnionNamesData(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
bool HelperFoldPendingCopper(const LSET &aCopper, int aMaxError, std::set< PAD * > &aExtensionPads)
Join each deferred copper shape on aCopper to the same-net numbered pad it touches.
void ParseBoardRegionsData(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void ParseArcs6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void ConvertTexts6ToBoardItemOnLayer(const ATEXT6 &aElem, PCB_LAYER_ID aLayer)
void ConvertPads6ToFootprintItemOnCopper(FOOTPRINT *aFootprint, const APAD6 &aElem)
std::unique_ptr< FOOTPRINT > ParseFootprint(ALTIUM_PCB_COMPOUND_FILE &altiumLibFile, const wxString &aFootprintName)
REPORTER * m_reporter
optional; may be nullptr
int GetNetCode(uint16_t aId) const
void ConvertTexts6ToEdaTextSettings(const ATEXT6 &aElem, EDA_TEXT &aEdaText)
void HelperBuildPadstackLayerIndex()
wxString m_library
for footprint library loading error reporting
std::vector< SHAPE_LINE_CHAIN > m_boardCutouts
void ConvertPads6ToFootprintItemOnNonCopper(FOOTPRINT *aFootprint, const APAD6 &aElem)
std::map< wxString, wxString > m_schematicNetNames
void ConvertShapeBasedRegions6ToBoardItemOnLayer(const AREGION6 &aElem, PCB_LAYER_ID aLayer, const int aPrimitiveIndex)
void ConvertTexts6ToFootprintItem(FOOTPRINT *aFootprint, const ATEXT6 &aElem)
unsigned m_lastProgressCount
void ParseFills6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
uint8_t HelperGetKeepoutRestrictions(const uint8_t aKeepoutRestrictions, const ALTIUM_LAYER aAltiumLayer)
Resolve an Altium keepout restriction mask, substituting the restrictions implied by the layer when t...
void ConvertArcs6ToFootprintItem(FOOTPRINT *aFootprint, const AARC6 &aElem, const int aPrimitiveIndex, const bool aIsBoardImport)
void HelperParseDimensions6Datum(const ADIMENSION6 &aElem)
void ConvertPads6ToBoardItem(const APAD6 &aElem)
void ConvertFills6ToFootprintItemOnLayer(FOOTPRINT *aFootprint, const AFILL6 &aElem, PCB_LAYER_ID aLayer)
void ParseWideStrings6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void remapUnsureLayers(std::vector< ABOARD6_LAYER_STACKUP > &aStackup)
std::vector< ASMARTUNION6 > m_tuningUnions
void HelperSetFootprintMountingStyles()
std::vector< ZONE * > m_polygons
void ParsePads6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void HelperFoldComponentCopperIntoPads()
Join deferred component copper and vias to the same-net pads they touch.
void ConvertArcs6ToPcbShape(const AARC6 &aElem, PCB_SHAPE *aShape)
void ConvertTracks6ToBoardItemOnLayer(const ATRACK6 &aElem, PCB_LAYER_ID aLayer)
void ConvertFills6ToBoardItem(const AFILL6 &aElem)
void HelperSetFootprintStackups()
std::map< PCB_LAYER_ID, int > m_padstackLayerIndex
void Parse(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const std::map< ALTIUM_PCB_DIR, std::string > &aFileMapping, const std::map< std::string, UTF8 > *aProperties=nullptr)
void ConvertVias6ToBoardItem(const AVIA6 &aElem)
FOOTPRINT * HelperGetFootprint(uint16_t aComponent) const
void HelperFootprintZoneToLibFrame(ZONE &aZone, const FOOTPRINT &aFootprint)
LAYER_MAPPING_HANDLER m_layerMappingHandler
void ConvertShapeBasedRegions6ToBoardItem(const AREGION6 &aElem, const int aPrimitiveIndex)
std::vector< std::pair< FOOTPRINT *, AVIA6 > > m_pendingComponentVias
void ParsePolygons6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
PCB_LAYER_ID GetKicadLayer(ALTIUM_LAYER aAltiumLayer) const
int HelperGetPadstackLayerIndex(PCB_LAYER_ID aLayer) const
Return the slot aLayer occupies in an Altium padstack's per-layer arrays.
void ParseComponentsBodies6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void ConvertTracks6ToFootprintItemOnLayer(FOOTPRINT *aFootprint, const ATRACK6 &aElem, PCB_LAYER_ID aLayer)
void ParseSmartUnions6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
wxString SchematicCasedNetName(const wxString &aNetName) const
ALTIUM_PCB(BOARD *aBoard, PROGRESS_REPORTER *aProgressReporter, LAYER_MAPPING_HANDLER &aLayerMappingHandler, REPORTER *aReporter=nullptr, const wxString &aLibrary=wxEmptyString, const wxString &aFootprintName=wxEmptyString)
void ConvertArcs6ToBoardItemOnLayer(const AARC6 &aElem, PCB_LAYER_ID aLayer)
void ParseTexts6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
std::map< ALTIUM_RECORD, std::multimap< int, const AEXTENDED_PRIMITIVE_INFORMATION > > m_extendedPrimitiveInformationMaps
void ParseModelsData(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry, const std::vector< std::string > &aRootDir)
std::map< ALTIUM_LAYER, wxString > m_layerNames
void ConvertPads6ToBoardItemOnNonCopper(const APAD6 &aElem)
void HelperSetTextboxAlignmentAndPos(const ATEXT6 &aElem, PCB_TEXTBOX *aPcbTextbox)
void ConvertBarcodes6ToFootprintItemOnLayer(FOOTPRINT *aFootprint, const ATEXT6 &aElem, PCB_LAYER_ID aLayer)
void ParseNets6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void ConvertPads6ToFootprintItem(FOOTPRINT *aFootprint, const APAD6 &aElem)
const ARULE6 * GetRule(ALTIUM_RULE_KIND aKind, const wxString &aName) const
void ParseDimensions6Data(const ALTIUM_PCB_COMPOUND_FILE &aAltiumPcbFile, const CFB::COMPOUND_FILE_ENTRY *aEntry)
void HelperPlaceUnfoldedCopper()
Run the fallback of every deferred copper shape no pad took.
void HelperSetZoneLayers(ZONE &aZone, const ALTIUM_LAYER aAltiumLayer)
static int ReadInt(const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
BASE_SET & set(size_t pos)
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
wxString GetNetname() const
Container for design settings for a BOARD object.
void SetGridOrigin(const VECTOR2I &aOrigin)
const VECTOR2I & GetGridOrigin() const
void SetAuxOrigin(const VECTOR2I &aOrigin)
const VECTOR2I & GetAuxOrigin() const
BOARD_STACKUP & GetStackupDescriptor()
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void SetIsKnockout(bool aKnockout)
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
virtual LSET BoardLayerSet() const
Return the LSET for the board that this item resides on.
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
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 Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
const FOOTPRINTS & Footprints() const
BOARD_DESIGN_SETTINGS & GetDesignSettings()
constexpr coord_type GetY() const
constexpr size_type GetWidth() const
constexpr coord_type GetX() const
constexpr size_type GetHeight() const
constexpr bool Intersects(const BOX2< Vec > &aRect) const
bool IsCardinal90() const
virtual void SetFilled(bool aFlag)
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
void SetPolyPoints(const std::vector< VECTOR2I > &aPoints)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
virtual void SetTextPos(const VECTOR2I &aPoint)
virtual int GetTextHeight() const
KIFONT::FONT * GetFont() const
void SetMirrored(bool isMirrored)
BOX2I GetTextBox(const RENDER_SETTINGS *aSettings, int aLine=-1) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
virtual int GetTextWidth() const
void SetBoldFlag(bool aBold)
Set only the bold flag, without changing the font.
void MigrateLegacyBoldStrokeWidth()
Migrate a pre-v11 bold stroke text so its stored thickness holds the base (non-bold) width.
virtual void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
GR_TEXT_V_ALIGN_T GetVertJustify() const
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
void SetFont(KIFONT::FONT *aFont)
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
const std::map< wxString, std::shared_ptr< EMBEDDED_FILE > > & EmbeddedFileMap() const
Provide an iterable view of the file collection.
static RETURN_CODE CompressAndEncode(EMBEDDED_FILE &aFile)
Take data from the decompressedData buffer and compresses it using ZSTD into the compressedEncodedDat...
VECTOR3D m_Offset
3D model offset (mm)
VECTOR3D m_Rotation
3D model rotation (degrees)
wxString m_Filename
The 3D shape filename in 3D library.
PCB_GENERATOR * CreateFromType(const wxString &aTypeStr)
static GENERATORS_MGR & Instance()
FONT is an abstract base class for both outline and stroke fonts.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
virtual bool IsStroke() const
const wxString & GetName() const
virtual bool IsOutline() const
LAYER_RANGE_ITERATOR begin() const
A logical library item identifier and consists of various portions much like a URI.
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllBoardTechMask()
Return a mask holding board technical layers (no CU layer) on both side.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
static const LSET & UserMask()
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
static LSET UserDefinedLayersMask(int aUserDefinedLayerCount=MAX_USER_DEFINED_LAYERS)
Return a mask with the requested number of user defined layers.
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Handle the data for a net.
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
NET_SETTINGS stores various net-related settings in a project context.
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetNetclasses() const
Gets all netclasses.
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
void SetRoundRectRadiusRatio(double aRatio, PCB_LAYER_ID aLayer)
void SetChamferRatio(double aRatio, PCB_LAYER_ID aLayer)
void SetOffset(const VECTOR2I &aOffset, PCB_LAYER_ID aLayer)
void SetShape(PAD_SHAPE aShape, PCB_LAYER_ID aLayer)
COPPER_LAYER_PROPS & CopperLayer(PCB_LAYER_ID aLayer)
void SetChamferPositions(int aPositions, PCB_LAYER_ID aLayer)
@ NORMAL
Shape is the same on all layers.
@ CUSTOM
Shapes can be defined on arbitrary layers.
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
void SetSize(const VECTOR2I &aSize, PCB_LAYER_ID aLayer)
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
void SetAnchorPadShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives(PCB_LAYER_ID aLayer) const
Accessor to the basic shape list for custom-shaped pads.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
static LSET PTHMask()
layer set for a through hole pad
const wxString & GetNumber() const
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool aIgnoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
void AddPrimitive(PCB_LAYER_ID aLayer, PCB_SHAPE *aPrimitive)
Add item to the custom shape primitives list.
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
void SetLocalZoneConnection(ZONE_CONNECTION aType)
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
const PADSTACK & Padstack() const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
static LSET SMDMask()
layer set for a SMD pad on Front layer
std::optional< int > GetLocalSolderPasteMargin() const
std::optional< int > GetLocalSolderMaskMargin() const
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
void SetLayerSet(const LSET &aLayers) override
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
A radial dimension indicates either the radius or diameter of an arc or circle.
void SetCenter(const VECTOR2I &aCenter) override
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
void SetShape(SHAPE_T aShape) override
void SetPosition(const VECTOR2I &aPos) override
void SetEnd(const VECTOR2I &aEnd) override
void SetPolyShape(const SHAPE_POLY_SET &aShape) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void SetStart(const VECTOR2I &aStart) override
void SetStroke(const STROKE_PARAMS &aStroke) override
VECTOR2I GetPosition() const override
void SetBorderEnabled(bool enabled)
Disables the border, this is done by changing the stroke internally.
void SetMarginTop(int aTop)
void SetMarginLeft(int aLeft)
void SetMarginBottom(int aBottom)
void SetTextAngle(const EDA_ANGLE &aAngle) override
void SetMarginRight(int aRight)
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
A progress reporter interface for use in multi-threaded environments.
A pure virtual class used to derive REPORTER objects from.
ecoord SquaredDistance(const SEG &aSeg) const
VECTOR2I::extended_type ecoord
int Length() const
Return the length (this).
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
static SEG::ecoord Square(int a)
EDA_ANGLE GetCentralAngle() const
Get the "central angle" of the arc - this is the angle at the point of the "pie slice".
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int Intersect(const SEG &aSeg, std::vector< INTERSECTION > &aIp) const
Find all intersection points between our line chain and the segment aSeg.
const SHAPE_ARC & Arc(size_t aArc) const
int Distance(const VECTOR2I &aP, bool aOutlineOnly) const
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.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
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.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
bool IsArcStart(size_t aIndex) const
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
ITERATOR IterateWithHoles(int aOutline)
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
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 Move(const VECTOR2I &aVector) override
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
SHAPE_POLY_SET CloneDropTriangulation() const
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
An abstract shape on 2D plane.
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
virtual const BOX2I BBox(int aClearance=0) const =0
Compute a bounding box of the shape, with a margin of aClearance a collision.
Simple container to manage line stroke parameters.
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
constexpr extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Handle a list of polygons defining a copper zone.
void SetNeedRefill(bool aNeedRefill)
void SetDoNotAllowPads(bool aEnable)
SHAPE_POLY_SET * Outline()
SHAPE_POLY_SET * GetFill(PCB_LAYER_ID aLayer)
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)
bool HasFilledPolysForLayer(PCB_LAYER_ID aLayer) const
void SetLayerSet(const LSET &aLayerSet) override
void SetDoNotAllowVias(bool aEnable)
void SetDoNotAllowFootprints(bool aEnable)
void SetDoNotAllowZoneFills(bool aEnable)
static int GetDefaultHatchPitch()
@ KEEP
Exists in the target, written unchanged.
@ DROP
No equivalent, left out.
@ CHAMFER_ACUTE_CORNERS
Acute angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_45
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
bool m_ImportSkipComponentBodies
Skip importing component bodies when importing some format files, such as Altium.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
#define THROW_IO_CANCELLED()
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
#define MAX_USER_DEFINED_LAYERS
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
size_t CopperLayerToOrdinal(PCB_LAYER_ID aLayer)
Converts KiCad copper layer enum to an ordinal between the front and back layers.
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
const std::vector< uint8_t > COMPOUND_FILE_HEADER
bool fileHasBinaryHeader(const wxString &aFilePath, const std::vector< uint8_t > &aHeader, size_t aOffset)
Check if a file starts with a defined binary header.
int MinimalCopperLayerCount(const LSET &aLayers)
Return the smallest even copper layer count whose stackup contains every copper layer in aLayers.
LSET GetAllFootprintLayers(const FOOTPRINT &aFootprint)
Return the union of layers referenced by every item inside the footprint (including graphic items,...
void for_all_pairs(_InputIterator __first, _InputIterator __last, _Function __f)
Apply a function to every possible pair of elements of a sequence.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ 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.
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
BARCODE class definition.
std::function< std::map< wxString, PCB_LAYER_ID >(const std::vector< INPUT_LAYER_DESC > &)> LAYER_MAPPING_HANDLER
Pointer to a function that takes a map of source and KiCad layers and returns a re-mapped version.
std::optional< VECTOR2I > OPT_VECTOR2I
wxString NotSpecifiedPrm()
uint8_t keepoutrestrictions
double dielectriclosstangent
wxString dielectricmaterial
std::vector< ABOARD6_LAYER_STACKUP > stackup
std::vector< ALTIUM_VERTICE > board_vertices
std::vector< wxString > names
wxString sourceHierachicalPath
wxString sourcefootprintlibrary
wxString sourcedesignator
std::vector< VECTOR2I > textPoint
ALTIUM_DIMENSION_KIND kind
std::vector< VECTOR2I > referencePoint
uint8_t keepoutrestrictions
std::vector< ABOARD6_LAYER_STACKUP > stackup
std::vector< char > m_data
std::unique_ptr< PCB_SHAPE > shape
Board coordinates, released once folded.
ALTIUM_PAD_SHAPE inner_shape[29]
ALTIUM_PAD_HOLE_SHAPE holeshape
ALTIUM_PAD_SHAPE_ALT alt_shape[32]
int32_t soldermaskexpansionmanual
std::unique_ptr< APAD6_SIZE_AND_SHAPE > sizeAndShape
ALTIUM_PAD_SHAPE topshape
ALTIUM_MODE pastemaskexpansionmode
ALTIUM_MODE soldermaskexpansionmode
ALTIUM_PAD_SHAPE botshape
ALTIUM_PAD_SHAPE midshape
int32_t pastemaskexpansionmanual
int32_t pad_to_die_length
std::vector< ALTIUM_VERTICE > vertices
ALTIUM_POLYGON_HATCHSTYLE hatchstyle
uint8_t keepoutrestrictions
std::vector< ALTIUM_VERTICE > outline
std::vector< std::vector< ALTIUM_VERTICE > > holes
ALTIUM_CONNECT_STYLE polygonconnectStyle
int planeclearanceClearance
int32_t polygonconnectReliefconductorwidth
int32_t polygonconnectAirgapwidth
uint32_t text_offset_width
uint32_t textbox_rect_height
ALTIUM_TEXT_POSITION textbox_rect_justification
uint32_t textbox_rect_width
uint32_t margin_border_width
bool isJustificationValid
ALTIUM_BARCODE_TYPE barcode_type
ALTIUM_TEXT_TYPE fonttype
uint8_t keepoutrestrictions
bool soldermask_expansion_from_hole
int32_t soldermask_expansion_front
bool soldermask_expansion_manual
int32_t soldermask_expansion_back
uint32_t diameter_by_layer[32]
The features of a padstack that can vary between copper layers All parameters are optional; leaving t...
std::vector< std::shared_ptr< PCB_SHAPE > > custom_shapes
Represent an intersection between two line segments.
KIBIS top(path, &reporter)
const SHAPE_LINE_CHAIN chain
static double sweep(float aStart, float aEnd)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
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.
double DEG2RAD(double deg)
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR3< double > VECTOR3D
@ THERMAL
Use thermal relief for pads.
@ NONE
Pads are not covered.
@ FULL
pads are covered by copper