CADSTAR PCB Archive Importer: Load TEMPLATEs, COPPERs and NETs (including Tracks and Vias)

This commit is contained in:
Roberto Fernandez Bautista 2020-08-31 23:09:29 +01:00 committed by Seth Hillbrand
parent 05de678f4e
commit 866c069873
7 changed files with 974 additions and 156 deletions

View File

@ -47,6 +47,17 @@ void CADSTAR_ARCHIVE_PARSER::POINT::Parse( XNODE* aNode )
}
void CADSTAR_ARCHIVE_PARSER::LONGPOINT::Parse( XNODE* aNode )
{
wxASSERT( aNode->GetName() == wxT( "PT" ) );
x = GetXmlAttributeIDLong( aNode, 0 );
y = GetXmlAttributeIDLong( aNode, 1 );
}
bool CADSTAR_ARCHIVE_PARSER::VERTEX::IsVertex( XNODE* aNode )
{
wxString aNodeName = aNode->GetName();
@ -241,7 +252,7 @@ long CADSTAR_ARCHIVE_PARSER::GetXmlAttributeIDLong( XNODE* aNode, unsigned int a
void CADSTAR_ARCHIVE_PARSER::CheckNoChildNodes( XNODE* aNode )
{
if( aNode->GetChildren() )
if( aNode && aNode->GetChildren() )
{
THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() );
}
@ -250,7 +261,7 @@ void CADSTAR_ARCHIVE_PARSER::CheckNoChildNodes( XNODE* aNode )
void CADSTAR_ARCHIVE_PARSER::CheckNoNextNodes( XNODE* aNode )
{
if( aNode->GetNext() )
if( aNode && aNode->GetNext() )
{
THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetNext()->GetName(), aNode->GetParent()->GetName() );
}

View File

@ -83,6 +83,15 @@ public:
};
struct LONGPOINT
{
long x = UNDEFINED_VALUE;
long y = UNDEFINED_VALUE;
void Parse( XNODE* aNode );
};
enum class VERTEX_TYPE
{
POINT,

View File

@ -26,47 +26,53 @@
#include <cadstar_pcb_archive_loader.h>
#include <board_stackup_manager/stackup_predefined_prms.h> // KEY_COPPER, KEY_CORE, KEY_PREPREG
#include <class_drawsegment.h> // DRAWSEGMENT
#include <limits> // std::numeric_limits
#include <trigo.h>
#include <class_board.h>
#include <class_dimension.h>
#include <class_drawsegment.h> // DRAWSEGMENT
#include <class_edge_mod.h>
#include <class_module.h>
#include <class_pcb_text.h>
#include <class_track.h>
#include <class_zone.h>
#include <convert_basic_shapes_to_polygon.h>
#include <trigo.h>
#include <limits> // std::numeric_limits
void CADSTAR_PCB_ARCHIVE_LOADER::Load( ::BOARD* aBoard )
{
mBoard = aBoard;
Parse();
wxPoint designSize =
Assignments.Technology.DesignArea.first - Assignments.Technology.DesignArea.second;
LONGPOINT designLimit = Assignments.Technology.DesignLimit;
//Note: can't use getKiCadPoint() due wxPoint being int - need long long to make the check
long long designSizeXkicad = (long long) designSize.x * KiCadUnitMultiplier;
long long designSizeYkicad = (long long) designSize.y * KiCadUnitMultiplier;
long long maxDesignSizekicad = (long long) std::numeric_limits<int>::max()
+ std::abs( std::numeric_limits<int>::min() );
long long designSizeXkicad = (long long) designLimit.x * KiCadUnitMultiplier;
long long designSizeYkicad = (long long) designLimit.y * KiCadUnitMultiplier;
// Max size limited by the positive dimention of wxPoint
long long maxDesignSizekicad = (long long) std::numeric_limits<int>::max();
if( designSizeXkicad > maxDesignSizekicad || designSizeYkicad > maxDesignSizekicad )
THROW_IO_ERROR( wxString::Format(
_( "The design is too large and cannot be imported into KiCad. \n"
"Please reduce the maximum design size in CADSTAR by navigating to: \n"
"Design Tab -> Properties -> Design Options -> Maximum Design Size. \n"
"Current Design size: %d, %d micrometers. \n"
"Maximum permitted design size: %d, %d micrometers.\n" ),
designSizeXkicad / 1000, designSizeYkicad / 1000, maxDesignSizekicad / 1000,
maxDesignSizekicad / 1000 ) );
"Current Design size: %.2f, %.2f milimetres. \n"
"Maximum permitted design size: %.2f, %.2f milimetres.\n" ),
(double) designSizeXkicad / 1E6, (double) designSizeYkicad / 1E6,
(double) maxDesignSizekicad / 1E6, (double) maxDesignSizekicad / 1E6 ) );
mDesignCenter =
( Assignments.Technology.DesignArea.first + Assignments.Technology.DesignArea.second )
/ 2;
if( Layout.NetSynch == NETSYNCH::WARNING )
wxLogWarning(
_( "The selected file indicates that nets might be out of synchronisation "
"with the schematic. It is recommended that you carry out an 'Align Nets' "
"procedure in CADSTAR and re-import, to avoid inconsistencies between the "
"PCB and the schematic. " ) );
loadBoardStackup();
loadComponentLibrary();
@ -74,6 +80,9 @@ void CADSTAR_PCB_ARCHIVE_LOADER::Load( ::BOARD* aBoard )
loadFigures();
loadAreas();
loadComponents();
loadTemplates();
loadCoppers();
loadNets();
//TODO: process all other items
@ -166,6 +175,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadBoardStackup()
kicadLayerID = getKiCadCopperLayerID( ++numElecAndPowerLayers );
kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER;
layerTypeName = KEY_COPPER;
mPowerPlaneLayers.push_back( curLayer.ID ); //we will need to add a Copper zone
break;
case LAYER_TYPE::CONSTRUCTION:
@ -427,7 +437,8 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryPads( const SYMDEF& aComponent, MODU
PADCODE csPadcode = getPadCode( csPad.PadCodeID );
D_PAD* pad = new D_PAD( aModule );
aModule->Add( pad, ADD_MODE::APPEND );
aModule->Add( pad, ADD_MODE::INSERT ); // insert so that we get correct behaviour when finding pads
// in the module by PAD_ID - see loadNets()
switch( csPad.Side )
{
@ -460,7 +471,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryPads( const SYMDEF& aComponent, MODU
csPad.Identifier );
pad->SetPos0( getKiCadPoint( csPad.Position ) - aModule->GetPosition() );
pad->SetOrientation( getKiCadAngle( csPad.OrientAngle ) );
pad->SetOrientation( getAngleTenthDegree( csPad.OrientAngle ) );
switch( csPadcode.Shape.ShapeType )
{
@ -544,7 +555,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryPads( const SYMDEF& aComponent, MODU
if( csPadcode.ReliefWidth != UNDEFINED_VALUE )
pad->SetThermalWidth( getKiCadLength( csPadcode.ReliefWidth ) );
pad->SetOrientation( pad->GetOrientation() + getKiCadAngle( csPadcode.Shape.OrientAngle ) );
pad->SetOrientation( pad->GetOrientation() + getAngleTenthDegree( csPadcode.Shape.OrientAngle ) );
if( csPadcode.DrillDiameter != UNDEFINED_VALUE )
{
@ -665,7 +676,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadComponents()
m->SetValue( wxEmptyString );
m->SetPosition( getKiCadPoint( comp.Origin ) );
m->SetOrientation( getKiCadAngle( comp.OrientAngle ) );
m->SetOrientation( getAngleTenthDegree( comp.OrientAngle ) );
m->SetReference( comp.Name );
if( comp.Mirror )
@ -676,11 +687,305 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadComponents()
loadComponentAttributes( comp, m );
m->SetDescription( getPart( comp.PartID ).Definition.Name );
mComponentMap.insert( { comp.ID, m } );
}
}
void CADSTAR_PCB_ARCHIVE_LOADER::loadComponentAttributes( const COMPONENT& aComponent, MODULE* aModule )
void CADSTAR_PCB_ARCHIVE_LOADER::loadTemplates()
{
for( std::pair<TEMPLATE_ID, TEMPLATE> tempPair : Layout.Templates )
{
TEMPLATE& csTemplate = tempPair.second;
ZONE_CONTAINER* zone = getZoneFromCadstarShape(
csTemplate.Shape, getLineThickness( csTemplate.LineCodeID ) );
mBoard->Add( zone, ADD_MODE::APPEND );
zone->SetZoneName( csTemplate.Name );
zone->SetLayer( getKiCadLayer( csTemplate.LayerID ) );
if( !csTemplate.NetID.IsEmpty() )
zone->SetNet( getKiCadNet( csTemplate.NetID ) );
if( csTemplate.Pouring.AllowInNoRouting )
wxLogError( wxString::Format(
_( "The CADSTAR template '%s' has the setting 'Allow in No Routing Areas' "
"enabled. This setting has no KiCad equivalent, so it has been ignored." ),
csTemplate.Name ) );
if( csTemplate.Pouring.BoxIsolatedPins )
wxLogError( wxString::Format(
_( "The CADSTAR template '%s' has the setting 'Box Isolated Pins'"
"enabled. This setting has no KiCad equivalent, so it has been ignored." ),
csTemplate.Name ) );
if( csTemplate.Pouring.AutomaticRepour )
wxLogWarning( wxString::Format(
_( "The CADSTAR template '%s' has the setting 'Automatic Repour'"
"enabled. This setting has no KiCad equivalent, so it has been ignored." ),
csTemplate.Name ) );
// Sliver width has different behaviour to KiCad Zone's minimum thickness
// In Cadstar 'Sliver width' has to be greater than the Copper thickness, whereas in
// Kicad it is the opposite.
if( csTemplate.Pouring.SliverWidth != 0 )
wxLogError( wxString::Format(
_( "The CADSTAR template '%s' has a non-zero value defined for the "
"'Sliver Width' setting. There is no KiCad equivalent for "
"this, so this setting was ignored." ),
csTemplate.Name ) );
if( csTemplate.Pouring.MinIsolatedCopper != csTemplate.Pouring.MinDisjointCopper )
wxLogError( wxString::Format(
_( "The CADSTAR template '%s' has different settings for 'Retain Poured Copper "
"- Disjoint' and 'Retain Poured Copper - Isolated'. KiCad does not "
"distinguish between these two settings. The setting for disjoint copper "
"has been applied as the minimum island area of the KiCad Zone." ),
csTemplate.Name ) );
if( csTemplate.Pouring.MinDisjointCopper < 0 )
zone->SetMinIslandArea( -1 );
else
zone->SetMinIslandArea(
(long long) getKiCadLength( csTemplate.Pouring.MinDisjointCopper )
* (long long) getKiCadLength( csTemplate.Pouring.MinDisjointCopper ) );
zone->SetZoneClearance( getKiCadLength( csTemplate.Pouring.AdditionalIsolation ) );
if( csTemplate.Pouring.FillType == TEMPLATE::POURING::COPPER_FILL_TYPE::HATCHED )
{
zone->SetFillMode( ZONE_FILL_MODE::HATCH_PATTERN );
zone->SetHatchGap( getKiCadHatchCodeGap( csTemplate.Pouring.HatchCodeID ) );
zone->SetHatchThickness( getKiCadHatchCodeThickness( csTemplate.Pouring.HatchCodeID ) );
zone->SetHatchOrientation( getHatchCodeAngleDegrees( csTemplate.Pouring.HatchCodeID ) );
}
else
{
zone->SetFillMode( ZONE_FILL_MODE::POLYGONS );
}
if( csTemplate.Pouring.ThermalReliefOnPads != csTemplate.Pouring.ThermalReliefOnVias
|| csTemplate.Pouring.ThermalReliefPadsAngle
!= csTemplate.Pouring.ThermalReliefViasAngle )
wxLogWarning( wxString::Format(
_( "The CADSTAR template '%s' has different settings for thermal relief "
"in pads and vias. KiCad only supports one single setting for both. The "
"setting for pads has been applied." ),
csTemplate.Name ) );
if( csTemplate.Pouring.ThermalReliefOnPads )
{
zone->SetThermalReliefGap( getKiCadLength( csTemplate.Pouring.ClearanceWidth ) );
zone->SetThermalReliefCopperBridge( getKiCadLength(
getCopperCode( csTemplate.Pouring.ReliefCopperCodeID ).CopperWidth ) );
zone->SetPadConnection( ZONE_CONNECTION::THERMAL );
}
else
zone->SetPadConnection( ZONE_CONNECTION::FULL );
}
//Now create power plane layers:
for( LAYER_ID layer : mPowerPlaneLayers )
{
wxASSERT( Assignments.Layerdefs.Layers.find( layer ) != Assignments.Layerdefs.Layers.end() );
//The net name will equal the layer name
wxString powerPlaneLayerName = Assignments.Layerdefs.Layers.at( layer ).Name;
NET_ID netid = wxEmptyString;
for( std::pair<NET_ID, NET> netPair : Layout.Nets )
{
NET net = netPair.second;
if( net.Name == powerPlaneLayerName )
{
netid = net.ID;
break;
}
}
if( netid.IsEmpty() )
{
wxLogError( wxString::Format(
_( "The CADSTAR layer '%s' is defined as a power plane layer. However no "
"net with such name exists. The layer has been loaded but no copper zone "
"was created." ),
powerPlaneLayerName ) );
}
else
{
for( std::pair<BOARD_ID, BOARD> boardPair : Layout.Boards )
{
//create a zone in each board shape
BOARD& board = boardPair.second;
int defaultLineThicknesss =
mBoard->GetDesignSettings().GetLineThickness( PCB_LAYER_ID::Edge_Cuts );
ZONE_CONTAINER* zone =
getZoneFromCadstarShape( board.Shape, defaultLineThicknesss );
mBoard->Add( zone, ADD_MODE::APPEND );
zone->SetZoneName( powerPlaneLayerName );
zone->SetLayer( getKiCadLayer( layer ) );
zone->SetFillMode( ZONE_FILL_MODE::POLYGONS );
zone->SetPadConnection( ZONE_CONNECTION::FULL );
zone->SetMinIslandArea( -1 );
zone->SetNet( getKiCadNet( netid ) );
}
}
}
}
void CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers()
{
for( std::pair<COPPER_ID, COPPER> copPair : Layout.Coppers )
{
COPPER& csCopper = copPair.second;
if( !csCopper.PouredTemplateID.IsEmpty() )
continue; //ignore copper related to a template as we've already loaded it!
// For now we are going to load coppers to a KiCad zone however this isn't perfect
//TODO: Load onto a graphical polygon with a net (when KiCad has this feature)
if( !mDoneCopperWarning )
{
wxLogWarning(
_( "The CADSTAR design contains COPPER elements, which have no direct KiCad "
"equivalent. These have been imported as a KiCad Zone if solid or hatch "
"filled, or as a KiCad Track if the shape was an unfilled outline (open or "
"closed)." ) );
mDoneCopperWarning = true;
}
if( csCopper.Shape.Type == SHAPE_TYPE::OPENSHAPE
|| csCopper.Shape.Type == SHAPE_TYPE::OUTLINE )
{
std::vector<DRAWSEGMENT*> outlineSegments =
getDrawSegmentsFromVertices( csCopper.Shape.Vertices );
std::vector<TRACK*> outlineTracks = makeTracksFromDrawsegments( outlineSegments, mBoard,
getKiCadNet(csCopper.NetRef.NetID) , getKiCadLayer( csCopper.LayerID ),
getKiCadLength( getCopperCode( csCopper.CopperCodeID ).CopperWidth ) );
//cleanup
for( DRAWSEGMENT* ds : outlineSegments )
{
if( ds )
delete ds;
}
for( CUTOUT cutout : csCopper.Shape.Cutouts )
{
std::vector<DRAWSEGMENT*> cutoutSeg =
getDrawSegmentsFromVertices( cutout.Vertices );
std::vector<TRACK*> cutoutTracks = makeTracksFromDrawsegments( cutoutSeg, mBoard,
getKiCadNet( csCopper.NetRef.NetID ), getKiCadLayer( csCopper.LayerID ),
getKiCadLength( getCopperCode( csCopper.CopperCodeID ).CopperWidth ) );
//cleanup
for( DRAWSEGMENT* ds : cutoutSeg )
{
if( ds )
delete ds;
}
}
}
else
{
ZONE_CONTAINER* zone = getZoneFromCadstarShape( csCopper.Shape,
getKiCadLength( getCopperCode( csCopper.CopperCodeID ).CopperWidth ) );
mBoard->Add( zone, ADD_MODE::APPEND );
zone->SetZoneName( csCopper.ID );
zone->SetLayer( getKiCadLayer( csCopper.LayerID ) );
if( csCopper.Shape.Type == SHAPE_TYPE::HATCHED )
{
zone->SetFillMode( ZONE_FILL_MODE::HATCH_PATTERN );
zone->SetHatchGap( getKiCadHatchCodeGap( csCopper.Shape.HatchCodeID ) );
zone->SetHatchThickness( getKiCadHatchCodeThickness( csCopper.Shape.HatchCodeID ) );
zone->SetHatchOrientation( getHatchCodeAngleDegrees( csCopper.Shape.HatchCodeID ) );
}
else
{
zone->SetFillMode( ZONE_FILL_MODE::POLYGONS );
}
zone->SetPadConnection( ZONE_CONNECTION::FULL );
zone->SetNet( getKiCadNet( csCopper.NetRef.NetID ) );
}
}
}
void CADSTAR_PCB_ARCHIVE_LOADER::loadNets()
{
for( std::pair<NET_ID, NET> netPair : Layout.Nets )
{
NET net = netPair.second;
wxString netname = net.Name;
if( netname.IsEmpty() )
netname = "$" + net.SignalNum;
for( NET::CONNECTION connection : net.Connections )
{
if( !connection.Unrouted )
loadNetTracks( net.ID, connection.Route );
//TODO: all other elements
}
for( std::pair<NETELEMENT_ID, NET::VIA> viaPair : net.Vias )
{
NET::VIA via = viaPair.second;
loadNetVia( net.ID, via );
}
for( std::pair<NETELEMENT_ID, NET::PIN> pinPair : net.Pins )
{
NET::PIN pin = pinPair.second;
MODULE* m = getModuleFromCadstarID( pin.ComponentID );
if( m == nullptr )
{
wxLogWarning( wxString::Format(
_( "The net '%s' references component ID '%s' which does not exist. "
"This has been ignored," ),
netname, pin.ComponentID ) );
}
else if( ( pin.PadID - (long) 1 ) > m->Pads().size() )
{
wxLogWarning( wxString::Format(
_( "The net '%s' references non-existent pad index '%d' in component '%s'. "
"This has been ignored." ),
netname, pin.PadID, m->GetReference() ) );
}
else
{
// The below works because we have added the pads in the correct order to the module and
// it so happens that PAD_ID in Cadstar is a sequential, numerical ID
m->Pads().at( pin.PadID - (long) 1 )->SetNet( getKiCadNet( net.ID ) );
}
}
}
}
void CADSTAR_PCB_ARCHIVE_LOADER::loadComponentAttributes(
const COMPONENT& aComponent, MODULE* aModule )
{
for( std::pair<ATTRIBUTE_ID, ATTRIBUTE_VALUE> attrPair : aComponent.AttributeValues )
{
@ -715,9 +1020,88 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadComponentAttributes( const COMPONENT& aComp
}
void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarShape( const SHAPE& aCadstarShape, const PCB_LAYER_ID& aKiCadLayer,
const LINECODE_ID& aCadstarLinecodeID, const wxString& aShapeName,
BOARD_ITEM_CONTAINER* aContainer )
void CADSTAR_PCB_ARCHIVE_LOADER::loadNetTracks(
const NET_ID& aCadstarNetID, const NET::ROUTE& aCadstarRoute )
{
std::vector<DRAWSEGMENT*> dsVector;
POINT prevEnd = aCadstarRoute.StartPoint;
for( const NET::ROUTE_VERTEX& v : aCadstarRoute.RouteVertices )
{
DRAWSEGMENT* ds = getDrawSegmentFromVertex( prevEnd, v.Vertex );
ds->SetLayer( getKiCadLayer( aCadstarRoute.LayerID ) );
ds->SetWidth( getKiCadLength( v.RouteWidth ) );
dsVector.push_back( ds );
prevEnd = v.Vertex.End;
}
//Todo add real netcode to the tracks
std::vector<TRACK*> tracks =
makeTracksFromDrawsegments( dsVector, mBoard, getKiCadNet( aCadstarNetID ) );
//cleanup
for( DRAWSEGMENT* ds : dsVector )
{
if( ds )
delete ds;
}
}
void CADSTAR_PCB_ARCHIVE_LOADER::loadNetVia(
const NET_ID& aCadstarNetID, const NET::VIA& aCadstarVia )
{
VIA* via = new VIA( mBoard );
mBoard->Add( via, ADD_MODE::APPEND );
VIACODE csViaCode = getViaCode( aCadstarVia.ViaCodeID );
LAYERPAIR csLayerPair = getLayerPair( aCadstarVia.LayerPairID );
via->SetPosition( getKiCadPoint( aCadstarVia.Location ) );
via->SetDrill( getKiCadLength( csViaCode.DrillDiameter ) );
via->SetLocked( aCadstarVia.Fixed );
if( csViaCode.Shape.ShapeType != PAD_SHAPE_TYPE::CIRCLE )
wxLogError( wxString::Format(
_( "The CADSTAR via code '%s' has different shape from a circle defined. "
"KiCad only supports circular vias so this via type has been changed to "
"be a via with circular shape of %.2f mm diameter." ),
csViaCode.Name,
(double) ( (double) getKiCadLength( csViaCode.Shape.Size ) / 1E6 ) ) );
via->SetWidth( getKiCadLength( csViaCode.Shape.Size ) );
bool start_layer_outside =
csLayerPair.PhysicalLayerStart == 1
|| csLayerPair.PhysicalLayerStart == Assignments.Technology.MaxPhysicalLayer;
bool end_layer_outside =
csLayerPair.PhysicalLayerEnd == 1
|| csLayerPair.PhysicalLayerEnd == Assignments.Technology.MaxPhysicalLayer;
if( start_layer_outside && end_layer_outside )
{
via->SetViaType( VIATYPE::THROUGH );
}
else if( ( !start_layer_outside ) && ( !end_layer_outside ) )
{
via->SetViaType( VIATYPE::BLIND_BURIED );
}
else
{
via->SetViaType( VIATYPE::MICROVIA );
}
via->SetLayerPair( getKiCadCopperLayerID( csLayerPair.PhysicalLayerStart ),
getKiCadCopperLayerID( csLayerPair.PhysicalLayerEnd ) );
via->SetNet( getKiCadNet( aCadstarNetID ) );
///todo add netcode to the via
}
void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarShape( const SHAPE& aCadstarShape,
const PCB_LAYER_ID& aKiCadLayer, const LINECODE_ID& aCadstarLinecodeID,
const wxString& aShapeName, BOARD_ITEM_CONTAINER* aContainer )
{
int lineThickness = getLineThickness( aCadstarLinecodeID );
@ -772,9 +1156,9 @@ void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarCutoutsAsSegments( const std::vector
}
void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarVerticesAsSegments( const std::vector<VERTEX>& aCadstarVertices,
const PCB_LAYER_ID& aKiCadLayer, const int& aLineThickness,
BOARD_ITEM_CONTAINER* aContainer )
void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarVerticesAsSegments(
const std::vector<VERTEX>& aCadstarVertices, const PCB_LAYER_ID& aKiCadLayer,
const int& aLineThickness, BOARD_ITEM_CONTAINER* aContainer )
{
std::vector<DRAWSEGMENT*> drawSegments =
getDrawSegmentsFromVertices( aCadstarVertices, aContainer );
@ -799,26 +1183,37 @@ std::vector<DRAWSEGMENT*> CADSTAR_PCB_ARCHIVE_LOADER::getDrawSegmentsFromVertice
return drawSegments;
const VERTEX* prev = &aCadstarVertices.at( 0 ); // first one should always be a point vertex
double arcStartAngle, arcEndAngle, arcAngle;
bool cw = false;
const VERTEX* cur;
for( size_t i = 1; i < aCadstarVertices.size(); i++ )
{
const VERTEX* cur = &aCadstarVertices[i];
DRAWSEGMENT* ds;
cw = false;
cur = &aCadstarVertices.at( i );
drawSegments.push_back( getDrawSegmentFromVertex( prev->End, *cur, aContainer ) );
prev = cur;
}
wxPoint startPoint = getKiCadPoint( prev->End );
wxPoint endPoint = getKiCadPoint( cur->End );
return drawSegments;
}
DRAWSEGMENT* CADSTAR_PCB_ARCHIVE_LOADER::getDrawSegmentFromVertex( const POINT& aCadstarStartPoint,
const VERTEX& aCadstarVertex, BOARD_ITEM_CONTAINER* aContainer )
{
DRAWSEGMENT* ds;
bool cw = false;
double arcStartAngle, arcEndAngle, arcAngle;
wxPoint startPoint = getKiCadPoint( aCadstarStartPoint );
wxPoint endPoint = getKiCadPoint( aCadstarVertex.End );
wxPoint centerPoint;
if( cur->Type == VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE
|| cur->Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE )
if( aCadstarVertex.Type == VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE
|| aCadstarVertex.Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE )
centerPoint = ( startPoint + endPoint ) / 2;
else
centerPoint = getKiCadPoint( cur->Center );
centerPoint = getKiCadPoint( aCadstarVertex.Center );
switch( cur->Type )
switch( aCadstarVertex.Type )
{
case VERTEX_TYPE::POINT:
@ -868,11 +1263,7 @@ std::vector<DRAWSEGMENT*> CADSTAR_PCB_ARCHIVE_LOADER::getDrawSegmentsFromVertice
if( isModule( aContainer ) && ds != nullptr )
( (EDGE_MODULE*) ds )->SetLocalCoord();
drawSegments.push_back( ds );
prev = cur;
}
return drawSegments;
return ds;
}
@ -992,6 +1383,73 @@ SHAPE_LINE_CHAIN CADSTAR_PCB_ARCHIVE_LOADER::getLineChainFromDrawsegments(
}
std::vector<TRACK*> CADSTAR_PCB_ARCHIVE_LOADER::makeTracksFromDrawsegments(
const std::vector<DRAWSEGMENT*> aDrawsegments, BOARD_ITEM_CONTAINER* aParentContainer,
NETINFO_ITEM* aNet, const PCB_LAYER_ID& aLayerOverride, int aWidthOverride )
{
std::vector<TRACK*> tracks;
for( DRAWSEGMENT* ds : aDrawsegments )
{
TRACK* track;
switch( ds->GetShape() )
{
case STROKE_T::S_ARC:
if( ds->GetClass() == wxT( "MGRAPHIC" ) )
{
EDGE_MODULE* em = (EDGE_MODULE*) ds;
SHAPE_ARC arc( em->GetStart0(), em->GetEnd0(), (double) em->GetAngle() / 10.0 );
track = new ARC( aParentContainer, &arc );
}
else
{
SHAPE_ARC arc( ds->GetCenter(), ds->GetArcStart(), (double) ds->GetAngle() / 10.0 );
track = new ARC( aParentContainer, &arc );
}
break;
case STROKE_T::S_SEGMENT:
if( ds->GetClass() == wxT( "MGRAPHIC" ) )
{
EDGE_MODULE* em = (EDGE_MODULE*) ds;
track = new TRACK( aParentContainer );
track->SetStart( em->GetStart0() );
track->SetEnd( em->GetEnd0() );
}
else
{
track = new TRACK( aParentContainer );
track->SetStart( ds->GetStart() );
track->SetEnd( ds->GetEnd() );
}
break;
default:
wxASSERT_MSG( true, "Drawsegment type is unexpected. Ignored." );
continue;
}
if( aWidthOverride == -1 )
track->SetWidth( ds->GetWidth() );
else
track->SetWidth( aWidthOverride );
if( aLayerOverride == PCB_LAYER_ID::UNDEFINED_LAYER )
track->SetLayer( ds->GetLayer() );
else
track->SetLayer( aLayerOverride );
if( aNet != nullptr )
track->SetNet( aNet );
tracks.push_back( track );
aParentContainer->Add( track, ADD_MODE::APPEND );
}
return tracks;
}
void CADSTAR_PCB_ARCHIVE_LOADER::addAttribute( const ATTRIBUTE_LOCATION& aCadstarAttrLoc,
const ATTRIBUTE_ID& aCadstarAttributeID, MODULE* aModule, const wxString& aAttributeValue )
{
@ -1044,7 +1502,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::addAttribute( const ATTRIBUTE_LOCATION& aCadsta
txt->SetPos0( rotatedTextPos );
txt->SetLayer( getKiCadLayer( aCadstarAttrLoc.LayerID ) );
txt->SetMirrored( aCadstarAttrLoc.Mirror );
txt->SetTextAngle( getKiCadAngle( aCadstarAttrLoc.OrientAngle ) - aModule->GetOrientation() );
txt->SetTextAngle( getAngleTenthDegree( aCadstarAttrLoc.OrientAngle ) - aModule->GetOrientation() );
TEXTCODE tc = getTextCode( aCadstarAttrLoc.TextCodeID );
@ -1109,7 +1567,6 @@ void CADSTAR_PCB_ARCHIVE_LOADER::addAttribute( const ATTRIBUTE_LOCATION& aCadsta
int CADSTAR_PCB_ARCHIVE_LOADER::getLineThickness( const LINECODE_ID& aCadstarLineCodeID )
{
wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
!= Assignments.Codedefs.LineCodes.end(),
mBoard->GetDesignSettings().GetLineThickness( PCB_LAYER_ID::Edge_Cuts ) );
@ -1118,7 +1575,19 @@ int CADSTAR_PCB_ARCHIVE_LOADER::getLineThickness( const LINECODE_ID& aCadstarLin
}
CADSTAR_PCB_ARCHIVE_LOADER::TEXTCODE CADSTAR_PCB_ARCHIVE_LOADER::getTextCode( const TEXTCODE_ID& aCadstarTextCodeID )
CADSTAR_PCB_ARCHIVE_LOADER::COPPERCODE CADSTAR_PCB_ARCHIVE_LOADER::getCopperCode(
const COPPERCODE_ID& aCadstaCopperCodeID )
{
wxCHECK( Assignments.Codedefs.CopperCodes.find( aCadstaCopperCodeID )
!= Assignments.Codedefs.CopperCodes.end(),
COPPERCODE() );
return Assignments.Codedefs.CopperCodes.at( aCadstaCopperCodeID );
}
CADSTAR_PCB_ARCHIVE_LOADER::TEXTCODE CADSTAR_PCB_ARCHIVE_LOADER::getTextCode(
const TEXTCODE_ID& aCadstarTextCodeID )
{
wxCHECK( Assignments.Codedefs.TextCodes.find( aCadstarTextCodeID )
!= Assignments.Codedefs.TextCodes.end(),
@ -1128,7 +1597,8 @@ CADSTAR_PCB_ARCHIVE_LOADER::TEXTCODE CADSTAR_PCB_ARCHIVE_LOADER::getTextCode( co
}
CADSTAR_PCB_ARCHIVE_LOADER::PADCODE CADSTAR_PCB_ARCHIVE_LOADER::getPadCode( const PADCODE_ID& aCadstarPadCodeID )
CADSTAR_PCB_ARCHIVE_LOADER::PADCODE CADSTAR_PCB_ARCHIVE_LOADER::getPadCode(
const PADCODE_ID& aCadstarPadCodeID )
{
wxCHECK( Assignments.Codedefs.PadCodes.find( aCadstarPadCodeID )
!= Assignments.Codedefs.PadCodes.end(),
@ -1138,6 +1608,28 @@ CADSTAR_PCB_ARCHIVE_LOADER::PADCODE CADSTAR_PCB_ARCHIVE_LOADER::getPadCode( cons
}
CADSTAR_PCB_ARCHIVE_LOADER::VIACODE CADSTAR_PCB_ARCHIVE_LOADER::getViaCode(
const VIACODE_ID& aCadstarViaCodeID )
{
wxCHECK( Assignments.Codedefs.ViaCodes.find( aCadstarViaCodeID )
!= Assignments.Codedefs.ViaCodes.end(),
VIACODE() );
return Assignments.Codedefs.ViaCodes.at( aCadstarViaCodeID );
}
CADSTAR_PCB_ARCHIVE_LOADER::LAYERPAIR CADSTAR_PCB_ARCHIVE_LOADER::getLayerPair(
const LAYERPAIR_ID& aCadstarLayerPairID )
{
wxCHECK( Assignments.Codedefs.LayerPairs.find( aCadstarLayerPairID )
!= Assignments.Codedefs.LayerPairs.end(),
LAYERPAIR() );
return Assignments.Codedefs.LayerPairs.at( aCadstarLayerPairID );
}
wxString CADSTAR_PCB_ARCHIVE_LOADER::getAttributeName( const ATTRIBUTE_ID& aCadstarAttributeID )
{
wxCHECK( Assignments.Codedefs.AttributeNames.find( aCadstarAttributeID )
@ -1158,7 +1650,8 @@ wxString CADSTAR_PCB_ARCHIVE_LOADER::getAttributeValue( const ATTRIBUTE_ID& aCad
}
CADSTAR_PCB_ARCHIVE_LOADER::PART CADSTAR_PCB_ARCHIVE_LOADER::getPart( const PART_ID& aCadstarPartID )
CADSTAR_PCB_ARCHIVE_LOADER::PART CADSTAR_PCB_ARCHIVE_LOADER::getPart(
const PART_ID& aCadstarPartID )
{
wxCHECK( Parts.PartDefinitions.find( aCadstarPartID ) != Parts.PartDefinitions.end(), PART() );
@ -1166,6 +1659,127 @@ CADSTAR_PCB_ARCHIVE_LOADER::PART CADSTAR_PCB_ARCHIVE_LOADER::getPart( const PART
}
CADSTAR_PCB_ARCHIVE_LOADER::HATCHCODE CADSTAR_PCB_ARCHIVE_LOADER::getHatchCode(
const HATCHCODE_ID& aCadstarHatchcodeID )
{
wxCHECK( Assignments.Codedefs.HatchCodes.find( aCadstarHatchcodeID )
!= Assignments.Codedefs.HatchCodes.end(),
HATCHCODE() );
return Assignments.Codedefs.HatchCodes.at( aCadstarHatchcodeID );
}
double CADSTAR_PCB_ARCHIVE_LOADER::getHatchCodeAngleDegrees( const HATCHCODE_ID& aCadstarHatchcodeID )
{
checkAndLogHatchCode( aCadstarHatchcodeID );
HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
if( hcode.Hatches.size() < 1 )
return mBoard->GetDesignSettings().GetDefaultZoneSettings().m_HatchOrientation;
else
return getAngleDegrees( hcode.Hatches.at( 0 ).OrientAngle );
}
int CADSTAR_PCB_ARCHIVE_LOADER::getKiCadHatchCodeThickness(
const HATCHCODE_ID& aCadstarHatchcodeID )
{
checkAndLogHatchCode( aCadstarHatchcodeID );
HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
if( hcode.Hatches.size() < 1 )
return mBoard->GetDesignSettings().GetDefaultZoneSettings().m_HatchThickness;
else
return getKiCadLength( hcode.Hatches.at( 0 ).LineWidth );
}
int CADSTAR_PCB_ARCHIVE_LOADER::getKiCadHatchCodeGap( const HATCHCODE_ID& aCadstarHatchcodeID )
{
checkAndLogHatchCode( aCadstarHatchcodeID );
HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
if( hcode.Hatches.size() < 1 )
return mBoard->GetDesignSettings().GetDefaultZoneSettings().m_HatchGap;
else
return getKiCadLength( hcode.Hatches.at( 0 ).Step );
}
void CADSTAR_PCB_ARCHIVE_LOADER::checkAndLogHatchCode( const HATCHCODE_ID& aCadstarHatchcodeID )
{
if( mHatchcodesTested.find( aCadstarHatchcodeID ) != mHatchcodesTested.end() )
{
return; //already checked
}
else
{
HATCHCODE hcode = getHatchCode( aCadstarHatchcodeID );
if( hcode.Hatches.size() != 2 )
{
wxLogWarning( wxString::Format(
_( "The CADSTAR Hatching code '%s' has %d hatches defined. "
"KiCad only supports 2 hatches (crosshatching) 90 degrees apart. "
"The imported hatching is crosshatched." ),
hcode.Name, (int) hcode.Hatches.size() ) );
}
else
{
if( hcode.Hatches.at( 0 ).LineWidth != hcode.Hatches.at( 1 ).LineWidth )
{
wxLogWarning( wxString::Format(
_( "The CADSTAR Hatching code '%s' has different line widths for each "
"hatch. KiCad only supports one width for the haching. The imported "
"hatching uses the width defined in the first hatch definition, i.e. "
"%.2f mm." ),
hcode.Name,
(double) ((double) getKiCadLength( hcode.Hatches.at( 0 ).LineWidth ) ) / 1E6 ) );
}
if( hcode.Hatches.at( 0 ).Step != hcode.Hatches.at( 1 ).Step )
{
wxLogWarning( wxString::Format(
_( "The CADSTAR Hatching code '%s' has different step sizes for each "
"hatch. KiCad only supports one step size for the haching. The imported "
"hatching uses the step size defined in the first hatching definition, "
"i.e. %.2f mm." ),
hcode.Name,
(double) ( (double) getKiCadLength( hcode.Hatches.at( 0 ).Step ) )
/ 1E6 ) );
}
if( abs( hcode.Hatches.at( 0 ).OrientAngle - hcode.Hatches.at( 1 ).OrientAngle )
!= 90000 )
{
wxLogWarning( wxString::Format(
_( "The hatches in CADSTAR Hatching code '%s' have an angle "
"difference of %.1f degrees. KiCad only supports hatching 90 "
"degrees apart. The imported hatching has two hatches 90 "
"degrees apart, oriented %.1f degrees from horizontal." ),
hcode.Name,
getAngleDegrees( abs( hcode.Hatches.at( 0 ).OrientAngle
- hcode.Hatches.at( 1 ).OrientAngle ) ),
getAngleDegrees( hcode.Hatches.at( 0 ).OrientAngle ) ) );
}
}
mHatchcodesTested.insert( aCadstarHatchcodeID );
}
}
MODULE* CADSTAR_PCB_ARCHIVE_LOADER::getModuleFromCadstarID(
const COMPONENT_ID& aCadstarComponentID )
{
if( mComponentMap.find( aCadstarComponentID ) == mComponentMap.end() )
return nullptr;
else
return mComponentMap.at( aCadstarComponentID );
}
wxPoint CADSTAR_PCB_ARCHIVE_LOADER::getKiCadPoint( wxPoint aCadstarPoint )
{
wxPoint retval;
@ -1184,8 +1798,36 @@ double CADSTAR_PCB_ARCHIVE_LOADER::getPolarAngle( wxPoint aPoint )
}
NETINFO_ITEM* CADSTAR_PCB_ARCHIVE_LOADER::getKiCadNet( const NET_ID& aCadstarNetID )
{
if( aCadstarNetID.IsEmpty() )
return nullptr;
else if( mNetMap.find( aCadstarNetID ) != mNetMap.end() )
{
return mNetMap.at(aCadstarNetID);
}
else
{
wxCHECK( Layout.Nets.find( aCadstarNetID ) != Layout.Nets.end(), nullptr );
NET csNet = Layout.Nets.at( aCadstarNetID );
NETINFO_ITEM* netInfo = new NETINFO_ITEM( mBoard, csNet.Name, ++mNumNets );
mBoard->Add( netInfo, ADD_MODE::APPEND );
//todo also add the Netclass
return netInfo;
}
return nullptr;
}
PCB_LAYER_ID CADSTAR_PCB_ARCHIVE_LOADER::getKiCadCopperLayerID( unsigned int aLayerNum )
{
if(aLayerNum == Assignments.Technology.MaxPhysicalLayer)
return PCB_LAYER_ID::B_Cu;
switch( aLayerNum )
{
// clang-format off
@ -1229,6 +1871,10 @@ PCB_LAYER_ID CADSTAR_PCB_ARCHIVE_LOADER::getKiCadCopperLayerID( unsigned int aLa
bool CADSTAR_PCB_ARCHIVE_LOADER::isLayerSet( const LAYER_ID& aCadstarLayerID )
{
wxCHECK( Assignments.Layerdefs.Layers.find( aCadstarLayerID )
!= Assignments.Layerdefs.Layers.end(),
false );
LAYER& layer = Assignments.Layerdefs.Layers.at( aCadstarLayerID );
switch( layer.Type )
@ -1248,10 +1894,17 @@ bool CADSTAR_PCB_ARCHIVE_LOADER::isLayerSet( const LAYER_ID& aCadstarLayerID )
PCB_LAYER_ID CADSTAR_PCB_ARCHIVE_LOADER::getKiCadLayer( const LAYER_ID& aCadstarLayerID )
{
if( mLayermap.find( aCadstarLayerID ) == mLayermap.end() )
return PCB_LAYER_ID::UNDEFINED_LAYER; //Possibly should be an ASSERT?
else
return mLayermap[aCadstarLayerID];
if( Assignments.Layerdefs.Layers.find( aCadstarLayerID ) != Assignments.Layerdefs.Layers.end() )
{
if( Assignments.Layerdefs.Layers.at( aCadstarLayerID ).Type == LAYER_TYPE::NOLAYER )
//The "no layer" is common for CADSTAR documentation symbols
//map it to undefined layer for later processing
return PCB_LAYER_ID::UNDEFINED_LAYER;
}
wxCHECK( mLayermap.find( aCadstarLayerID ) != mLayermap.end(), PCB_LAYER_ID::UNDEFINED_LAYER );
return mLayermap.at(aCadstarLayerID);
}

View File

@ -28,19 +28,33 @@
#include <cadstar_pcb_archive_parser.h>
#include <class_board.h>
#include <set>
class BOARD;
class CADSTAR_PCB_ARCHIVE_LOADER : public CADSTAR_PCB_ARCHIVE_PARSER
{
public:
explicit CADSTAR_PCB_ARCHIVE_LOADER( wxString aFilename ) : CADSTAR_PCB_ARCHIVE_PARSER( aFilename )
explicit CADSTAR_PCB_ARCHIVE_LOADER( wxString aFilename )
: CADSTAR_PCB_ARCHIVE_PARSER( aFilename )
{
mBoard = nullptr;
mDesignCenter.x = 0;
mDesignCenter.y = 0;
mDoneCopperWarning = false;
mNumNets = 0;
}
~CADSTAR_PCB_ARCHIVE_LOADER()
{
for( std::pair<SYMDEF_ID, MODULE*> libItem : mLibraryMap )
{
MODULE* mod = libItem.second;
if( mod )
delete mod;
}
}
/**
* @brief Loads a CADSTAR PCB Archive file into the KiCad BOARD object given
@ -54,12 +68,27 @@ private:
///< Populated by loadBoardStackup().
std::map<SYMDEF_ID, MODULE*> mLibraryMap; ///< Map between Cadstar and KiCad
///< components in the library. Populated
///< by loadComponentLibrary().
///< by loadComponentLibrary(). Owns the
///< MODULE objects.
std::map<COMPONENT_ID, MODULE*> mComponentMap; ///< Map between Cadstar and KiCad
///< components on the board. Does NOT own
///< the MODULE objects (these should have
///< been loaded to mBoard).
std::map<NET_ID, NETINFO_ITEM*> mNetMap; ///< Map between Cadstar and KiCad Nets
std::map<PHYSICAL_LAYER_ID, LAYER_ID> mCopperLayers; ///< Map of CADSTAR Physical layers to
///< CADSTAR Layer IDs
std::vector<LAYER_ID> mPowerPlaneLayers; ///< List of layers that are marked as
///< power plane in CADSTAR. This is used
///< by "loadtemplates"
wxPoint mDesignCenter; ///< Used for calculating the required
///< offset to apply to the Cadstar design
///< so that it fits in KiCad canvas
std::set<HATCHCODE_ID> mHatchcodesTested; ///< Used by checkAndLogHatchCode() to
///< avoid multiple duplicate warnings
bool mDoneCopperWarning; ///< Used by loadCoppers() to avoid
///< multiple duplicate warnings
int mNumNets; ///< Number of nets loaded so far
// Functions for loading individual elements:
void loadBoardStackup();
@ -68,6 +97,9 @@ private:
void loadFigures();
void loadAreas();
void loadComponents();
void loadTemplates();
void loadCoppers();
void loadNets();
// Helper functions for loading:
void logBoardStackupWarning(
@ -75,6 +107,8 @@ private:
void loadLibraryFigures( const SYMDEF& aComponent, MODULE* aModule );
void loadLibraryPads( const SYMDEF& aComponent, MODULE* aModule );
void loadComponentAttributes( const COMPONENT& aComponent, MODULE* aModule );
void loadNetTracks( const NET_ID& aCadstarNetID, const NET::ROUTE& aCadstarRoute );
void loadNetVia( const NET_ID& aCadstarNetID, const NET::VIA& aCadstarVia );
/**
* @brief
@ -114,7 +148,7 @@ private:
/**
* @brief Returns a vector of pointers to DRAWSEGMENT objects. Caller owns the objects.
* @param aCadstarVertices *
* @param aCadstarVertices
* @param aContainer to draw on (e.g. mBoard). Can be nullptr.
* @return
*/
@ -122,6 +156,15 @@ private:
const std::vector<VERTEX>& aCadstarVertices,
BOARD_ITEM_CONTAINER* aContainer = nullptr );
/**
* @brief Returns a pointer to a DRAWSEGMENT object. Caller owns the object.
* @param aCadstarStartPoint
* @param aCadstarVertex
* @param aContainer to draw on (e.g. mBoard). Can be nullptr.
* @return
*/
DRAWSEGMENT* getDrawSegmentFromVertex( const POINT& aCadstarStartPoint,
const VERTEX& aCadstarVertex, BOARD_ITEM_CONTAINER* aContainer = nullptr );
/**
* @brief
@ -150,6 +193,22 @@ private:
*/
SHAPE_LINE_CHAIN getLineChainFromDrawsegments( const std::vector<DRAWSEGMENT*> aDrawSegments );
/**
* @brief Returns a vector of pointers to TRACK/ARC objects. Caller owns the objects
* @param aDrawsegments
* @param aParentContainer sets this as the parent of each TRACK object and Add()s it to the parent
* @param aNet sets all the tracks to this net, unless nullptr
* @param aLayerOverride Sets all tracks to this layer, or, if it is UNDEFINED_LAYER, uses the layers
* in the DrawSegments
* @param aWidthOverride Sets all tracks to this width, or, if it is UNDEFINED_LAYER, uses the width
* in the DrawSegments
* @return
*/
std::vector<TRACK*> makeTracksFromDrawsegments( const std::vector<DRAWSEGMENT*> aDrawsegments,
BOARD_ITEM_CONTAINER* aParentContainer, NETINFO_ITEM* aNet = nullptr,
const PCB_LAYER_ID& aLayerOverride = PCB_LAYER_ID::UNDEFINED_LAYER,
int aWidthOverride = -1 );
/**
* @brief Adds a CADSTAR Attribute to a KiCad module
* @param aCadstarAttrLoc
@ -170,11 +229,11 @@ private:
int getLineThickness( const LINECODE_ID& aCadstarLineCodeID );
COPPERCODE getCopperCode( const COPPERCODE_ID& aCadstaCopperCodeID );
TEXTCODE getTextCode( const TEXTCODE_ID& aCadstarTextCodeID );
PADCODE getPadCode( const PADCODE_ID& aCadstarPadCodeID );
VIACODE getViaCode( const VIACODE_ID& aCadstarViaCodeID );
LAYERPAIR getLayerPair( const LAYERPAIR_ID& aCadstarLayerPairID );
wxString getAttributeName( const ATTRIBUTE_ID& aCadstarAttributeID );
@ -184,6 +243,13 @@ private:
PART getPart( const PART_ID& aCadstarPartID );
HATCHCODE getHatchCode( const HATCHCODE_ID& aCadstarHatchcodeID );
void checkAndLogHatchCode( const HATCHCODE_ID& aCadstarHatchcodeID );
MODULE* getModuleFromCadstarID( const COMPONENT_ID& aCadstarComponentID );
double getHatchCodeAngleDegrees( const HATCHCODE_ID& aCadstarHatchcodeID );
int getKiCadHatchCodeThickness( const HATCHCODE_ID& aCadstarHatchcodeID );
int getKiCadHatchCodeGap( const HATCHCODE_ID& aCadstarHatchcodeID );
/**
* @brief Scales, offsets and inverts y axis to make the point usable directly in KiCad
* @param aCadstarPoint
@ -206,11 +272,21 @@ private:
* @param aCadstarAngle
* @return
*/
double getKiCadAngle( const long long& aCadstarAngle )
double getAngleTenthDegree( const long long& aCadstarAngle )
{
return (double) aCadstarAngle / 100.0;
}
/**
* @brief
* @param aCadstarAngle
* @return
*/
double getAngleDegrees( const long long& aCadstarAngle )
{
return (double) aCadstarAngle / 1000.0;
}
/**
* @brief
* @param aPoint
@ -218,6 +294,14 @@ private:
*/
double getPolarAngle( wxPoint aPoint );
/**
* @brief Searches mNetMap and returns the NETINFO_ITEM pointer if exists. Otherwise
* creates a new one and adds it to mBoard.
* @param aCadstarNetID
* @return
*/
NETINFO_ITEM* getKiCadNet( const NET_ID& aCadstarNetID );
/**
* @brief

View File

@ -268,9 +268,9 @@ void CADSTAR_PCB_ARCHIVE_PARSER::RULESET::Parse( XNODE* aNode )
AreaViaCodeID = GetXmlAttributeIDString( cNode, 0 );
else if( nodeName == wxT( "SPACINGCODE" ) )
{
SPACINGCODE scode;
scode.Parse( cNode );
SpacingCodes.push_back( scode );
SPACINGCODE spacingcode;
spacingcode.Parse( cNode );
SpacingCodes.insert( std::make_pair( spacingcode.ID, spacingcode ) );
}
else
THROW_UNKNOWN_NODE_IO_ERROR( nodeName, aNode->GetName() );
@ -322,7 +322,7 @@ void CADSTAR_PCB_ARCHIVE_PARSER::CODEDEFS::Parse( XNODE* aNode )
{
SPACINGCODE spacingcode;
spacingcode.Parse( cNode );
SpacingCodes.push_back( spacingcode );
SpacingCodes.insert( std::make_pair( spacingcode.ID, spacingcode ) );
}
else if( nodeName == wxT( "RULESET" ) )
{
@ -883,7 +883,7 @@ void CADSTAR_PCB_ARCHIVE_PARSER::SPACINGCODE::Parse( XNODE* aNode )
{
wxASSERT( aNode->GetName() == wxT( "SPACINGCODE" ) );
Code = GetXmlAttributeIDString( aNode, 0 );
ID = GetXmlAttributeIDString( aNode, 0 );
Spacing = GetXmlAttributeIDLong( aNode, 1 );
XNODE* cNode = aNode->GetChildren();
@ -1390,8 +1390,7 @@ void CADSTAR_PCB_ARCHIVE_PARSER::TECHNOLOGY_SECTION::Parse( XNODE* aNode )
ViaGrid = GetXmlAttributeIDLong( cNode, 0 );
else if( cNodeName == wxT( "DESIGNORIGIN" ) )
{
std::vector<POINT> pts = ParseAllChildPoints( cNode, true, 1 );
DesignOrigin = pts[0];
DesignOrigin.Parse( cNode->GetChildren() );
}
else if( cNodeName == wxT( "DESIGNAREA" ) )
{
@ -1400,13 +1399,11 @@ void CADSTAR_PCB_ARCHIVE_PARSER::TECHNOLOGY_SECTION::Parse( XNODE* aNode )
}
else if( cNodeName == wxT( "DESIGNREF" ) )
{
std::vector<POINT> pts = ParseAllChildPoints( cNode, true, 1 );
DesignRef = pts[0];
DesignOrigin.Parse( cNode->GetChildren() );
}
else if( cNodeName == wxT( "DESIGNLIMIT" ) )
{
std::vector<POINT> pts = ParseAllChildPoints( cNode, true, 1 );
DesignLimit = pts[0];
DesignLimit.Parse( cNode->GetChildren() );
}
else if( cNodeName == wxT( "BACKOFFJCTS" ) )
BackOffJunctions = true;

View File

@ -26,9 +26,8 @@
#ifndef CADSTAR_PCB_ARCHIVE_PARSER_H_
#define CADSTAR_PCB_ARCHIVE_PARSER_H_
#include <boost/serialization/strong_typedef.hpp>
#include <plugins/cadstar/cadstar_archive_parser.h>
#include <map>
#include <plugins/cadstar/cadstar_archive_parser.h>
#include <vector>
@ -39,10 +38,6 @@
#define UNDEFINED_MATERIAL_ID ( MATERIAL_ID ) wxEmptyString
#define UNDEFINED_PHYSICAL_LAYER ( PHYSICAL_LAYER_ID ) - 1
/**
* Default spacing class for all nets
*/
#define NO_SPACE_CLASS_ID ( SPACING_CLASS_ID ) wxT( "NO_SPACE_CLASS" )
/**
* Component Name Attribute ID - typically used for placement of designators on silk screen.
@ -86,6 +81,7 @@ public:
typedef wxString COPPERCODE_ID;
typedef wxString PADCODE_ID;
typedef wxString VIACODE_ID;
typedef wxString SPACINGCODE_ID;
typedef wxString LAYERPAIR_ID;
typedef wxString ATTRIBUTE_ID;
typedef wxString NETCLASS_ID;
@ -394,7 +390,45 @@ public:
void Parse( XNODE* aNode );
};
wxString Code; //TODO convert to an enum class containing all valid spacings
/**
* @brief Possible spacing rules:
* - A_A = Component Placement to Component Placement
* - C_B = Copper to Board
* - C_C = Copper to Copper
* - H_H = Hole to Hole
* - OT_P = Optimal Route to Pad (Optional Rule)
* - OT_T = Optimal Route to Route (Optional Rule)
* - OT_V = Optimal Route to Via (Optional Rule)
* - P_B = Pad to Board
* - P_C = Pad to Copper
* - P_P = Pad to Pad
* - P_S = Pad to SMD pad (Optional Rule)
* - P_V = Pad to Via
* - T_B = Route to Board outline
* - T_C = Route to Copper
* - T_P = Route to Pad
* - T_T = Route to Route
* - T_S = Route to SMD Pad (Optional Rule)
* - T_V = Route to Via
* - S_B = SMD Pad to Board (Optional Rule)
* - S_C = SMD Pad to Copper (Optional Rule)
* - S_S = SMD Pad to SMD Pad (Optional Rule)
* - L_B = Test Land to Board
* - L_O = Test Land to Component
* - L_L = Test Land to Test Land
* - V_B = Via to Board
* - V_C = Via to Copper
* - V_S = Via to SMD Pad (Optional Rule)
* - V_V = Via to Via
*
* Other design rules are in:
* TECHNOLOGY->MAXMITER = Maximum Mitre (This parameter is not actually checked in Cadstar)
* TECHNOLOGY->MINMITER = Minimum Mitre (This parameter is not actually checked in Cadstar)
* TECHNOLOGY->MINUNNECKED = Minimum Thicker Track Length
* TECHNOLOGY->MINNECKED = Minimum Thinner Track Length
* TECHNOLOGY->MINROUTEWIDTH = Thin Route Width
*/
SPACINGCODE_ID ID;
long Spacing;
std::vector<REASSIGN> Reassigns; ///< Can have different spacings on differnt layers
@ -720,7 +754,8 @@ public:
///< will be used when inserting new vias within an area that
///< has been assigned this rule set. ("VIACODEREF")
std::vector<SPACINGCODE> SpacingCodes; ///< Overrides these spacing rules in the specific
std::map<SPACINGCODE_ID, SPACINGCODE>
SpacingCodes; ///< Overrides these spacing rules in the specific
///< area.
void Parse( XNODE* aNode );
};
@ -733,7 +768,7 @@ public:
std::map<TEXTCODE_ID, TEXTCODE> TextCodes;
std::map<ROUTECODE_ID, ROUTECODE> RouteCodes;
std::map<COPPERCODE_ID, COPPERCODE> CopperCodes;
std::vector<SPACINGCODE> SpacingCodes; ///< Spacing Design Rules
std::map<SPACINGCODE_ID, SPACINGCODE> SpacingCodes; ///< Spacing Design Rules
std::map<RULESET_ID, RULESET> Rulesets; ///< Used for area design rules
std::map<PADCODE_ID, PADCODE> PadCodes;
std::map<VIACODE_ID, VIACODE> ViaCodes;
@ -790,10 +825,10 @@ public:
long TrackGrid; ///< Grid for Routes (equal X and Y steps)
long ViaGrid; ///< Grid for Vias (equal X and Y steps)
POINT DesignOrigin;
LONGPOINT DesignOrigin;
std::pair<POINT, POINT> DesignArea;
POINT DesignRef; ///< Appears to be 0,0 always
POINT DesignLimit;
LONGPOINT DesignRef; ///< Appears to be 0,0 always
LONGPOINT DesignLimit;
bool BackOffJunctions = false;
bool BackOffWidthChange = false;
@ -1850,13 +1885,20 @@ public:
///< aperture etc ...) used on a plotting machine"
///< (param1)
long ClearanceWidth; ///< (param2)
long SliverWidth; ///< (param3)
long AdditionalIsolation; ///< (param4)
long ThermalReliefPadsAngle; ///< Disabled when !ThermalReliefOnPads (param5)
long ClearanceWidth; ///< Specifies the space around pads when pouring
///< (i.e. Thermal relief clearance)
long SliverWidth; ///< Minimum width of copper that may be created
long AdditionalIsolation; ///< This is the gap to apply in routes and pads
///< in addition to the existing pad-to-copper or
///< route-to-copper spacing (see SPACINGCODE.ID)
long ThermalReliefPadsAngle; ///< Orientation for the thermal reliefs. Disabled when !ThermalReliefOnPads (param5)
long ThermalReliefViasAngle; ///< Disabled when !ThermalReliefOnVias (param6)
long MinIsolatedCopper = UNDEFINED_VALUE; ///< Disabled when UNDEFINED_VALUE (param7)
long MinDisjointCopper = UNDEFINED_VALUE; ///< Disabled when UNDEFINED_VALUE (param8)
long MinIsolatedCopper = UNDEFINED_VALUE; ///< The value is the length of one side of
///< a notional square. Disabled when
///< UNDEFINED_VALUE
long MinDisjointCopper = UNDEFINED_VALUE; ///< The value is the length of one side of
///< a notional square. Disabled when
///< UNDEFINED_VALUE
bool ThermalReliefOnPads = true; ///< false when subnode "NOPINRELIEF" is present
bool ThermalReliefOnVias = true; ///< false when subnode "NOVIARELIEF" is present

View File

@ -27,6 +27,7 @@
#include <cadstar_pcb_archive_loader.h>
#include <cadstar_pcb_archive_plugin.h>
#include <class_board.h>
#include <properties.h>
CADSTAR_PCB_ARCHIVE_PLUGIN::CADSTAR_PCB_ARCHIVE_PLUGIN()
@ -62,5 +63,26 @@ BOARD* CADSTAR_PCB_ARCHIVE_PLUGIN::Load(
CADSTAR_PCB_ARCHIVE_LOADER tempPCB( aFileName );
tempPCB.Load( m_board );
//center the board:
if( aProperties )
{
UTF8 page_width;
UTF8 page_height;
if( aProperties->Value( "page_width", &page_width )
&& aProperties->Value( "page_height", &page_height ) )
{
EDA_RECT bbbox = m_board->GetBoardEdgesBoundingBox();
int w = atoi( page_width.c_str() );
int h = atoi( page_height.c_str() );
int desired_x = ( w - bbbox.GetWidth() ) / 2;
int desired_y = ( h - bbbox.GetHeight() ) / 2;
m_board->Move( wxPoint( desired_x - bbbox.GetX(), desired_y - bbbox.GetY() ) );
}
}
return m_board;
}