altium: Refactor pad parsing to make it reusable for footprint import

This commit is contained in:
Thomas Pointhuber 2022-01-16 15:37:25 +01:00
parent efb0e9f98f
commit 7f667764bf
2 changed files with 330 additions and 266 deletions

View File

@ -133,6 +133,25 @@ void ALTIUM_PCB::HelperShapeSetLocalCoord( PCB_SHAPE* aShape, uint16_t aComponen
} }
void ALTIUM_PCB::HelperShapeSetLocalCoord( FP_SHAPE* aShape )
{
aShape->SetLocalCoord();
// TODO: SetLocalCoord() does not update the polygon shape!
// This workaround converts the poly shape into the local coordinates
SHAPE_POLY_SET& polyShape = aShape->GetPolyShape();
if( !polyShape.IsEmpty() )
{
FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aShape->GetParent() );
if( fp )
{
polyShape.Move( -fp->GetPosition() );
polyShape.Rotate( -fp->GetOrientation().AsRadians() );
}
}
}
void HelperShapeLineChainFromAltiumVertices( SHAPE_LINE_CHAIN& aLine, void HelperShapeLineChainFromAltiumVertices( SHAPE_LINE_CHAIN& aLine,
const std::vector<ALTIUM_VERTICE>& aVertices ) const std::vector<ALTIUM_VERTICE>& aVertices )
{ {
@ -684,11 +703,13 @@ FOOTPRINT* ALTIUM_PCB::ParseFootprint( const ALTIUM_COMPOUND_FILE& altiumLibFile
case ALTIUM_RECORD::PAD: case ALTIUM_RECORD::PAD:
{ {
APAD6 pad( parser ); APAD6 pad( parser );
ConvertPads6ToFootprintItem( footprint.get(), pad );
break; break;
} }
case ALTIUM_RECORD::VIA: case ALTIUM_RECORD::VIA:
{ {
AVIA6 via( parser ); AVIA6 via( parser );
// TODO: implement
break; break;
} }
case ALTIUM_RECORD::TRACK: case ALTIUM_RECORD::TRACK:
@ -706,16 +727,19 @@ FOOTPRINT* ALTIUM_PCB::ParseFootprint( const ALTIUM_COMPOUND_FILE& altiumLibFile
case ALTIUM_RECORD::FILL: case ALTIUM_RECORD::FILL:
{ {
AFILL6 fill( parser ); AFILL6 fill( parser );
// TODO: implement
break; break;
} }
case ALTIUM_RECORD::REGION: case ALTIUM_RECORD::REGION:
{ {
AREGION6 region( parser, false /* TODO */ ); AREGION6 region( parser, false /* TODO */ );
// TODO: implement
break; break;
} }
case ALTIUM_RECORD::MODEL: case ALTIUM_RECORD::MODEL:
{ {
ACOMPONENTBODY6 componentBody( parser ); ACOMPONENTBODY6 componentBody( parser );
// Won't be supported for now, as we would need to extract the model
break; break;
} }
default: default:
@ -2203,71 +2227,95 @@ void ALTIUM_PCB::ParsePads6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
checkpoint(); checkpoint();
APAD6 elem( reader ); APAD6 elem( reader );
// It is possible to place altium pads on non-copper layers -> we need to interpolate them using drawings!
if( !IsAltiumLayerCopper( elem.layer ) && !IsAltiumLayerAPlane( elem.layer )
&& elem.layer != ALTIUM_LAYER::MULTI_LAYER )
{
HelperParsePad6NonCopper( elem );
continue;
}
// Create Pad
FOOTPRINT* footprint = nullptr;
if( elem.component == ALTIUM_COMPONENT_NONE ) if( elem.component == ALTIUM_COMPONENT_NONE )
{ {
footprint = new FOOTPRINT( m_board ); // We cannot add a pad directly into the PCB ConvertPads6ToBoardItem( elem );
m_board->Add( footprint, ADD_MODE::APPEND );
footprint->SetPosition( elem.position );
} }
else else
{ {
if( m_components.size() <= elem.component ) FOOTPRINT* footprint = HelperGetFootprint( elem.component );
ConvertPads6ToFootprintItem( footprint, elem );
}
}
if( reader.GetRemainingBytes() != 0 )
{ {
THROW_IO_ERROR( wxString::Format( "Pads6 stream tries to access component id %d " THROW_IO_ERROR( "Pads6 stream is not fully parsed" );
"of %d existing components",
elem.component,
m_components.size() ) );
} }
footprint = m_components.at( elem.component );
} }
PAD* pad = new PAD( footprint );
footprint->Add( pad, ADD_MODE::APPEND );
pad->SetNumber( elem.name ); void ALTIUM_PCB::ConvertPads6ToBoardItem( const APAD6& aElem )
pad->SetNetCode( GetNetCode( elem.net ) ); {
pad->SetLocked( elem.is_locked ); // It is possible to place altium pads on non-copper layers -> we need to interpolate them using drawings!
if( !IsAltiumLayerCopper( aElem.layer ) && !IsAltiumLayerAPlane( aElem.layer )
&& aElem.layer != ALTIUM_LAYER::MULTI_LAYER )
{
ConvertPads6ToBoardItemOnNonCopper( aElem );
}
else
{
// We cannot add a pad directly into the PCB
FOOTPRINT* footprint = new FOOTPRINT( m_board );
footprint->SetPosition( aElem.position );
pad->SetPosition( elem.position ); ConvertPads6ToFootprintItemOnCopper( footprint, aElem );
pad->SetOrientationDegrees( elem.direction );
m_board->Add( footprint, ADD_MODE::APPEND );
}
}
void ALTIUM_PCB::ConvertPads6ToFootprintItem( FOOTPRINT* aFootprint, const APAD6& aElem )
{
// It is possible to place altium pads on non-copper layers -> we need to interpolate them using drawings!
if( !IsAltiumLayerCopper( aElem.layer ) && !IsAltiumLayerAPlane( aElem.layer )
&& aElem.layer != ALTIUM_LAYER::MULTI_LAYER )
{
ConvertPads6ToFootprintItemOnNonCopper( aFootprint, aElem );
}
else
{
ConvertPads6ToFootprintItemOnCopper( aFootprint, aElem );
}
}
void ALTIUM_PCB::ConvertPads6ToFootprintItemOnCopper( FOOTPRINT* aFootprint, const APAD6& aElem )
{
PAD* pad = new PAD( aFootprint );
pad->SetNumber( aElem.name );
pad->SetNetCode( GetNetCode( aElem.net ) );
pad->SetLocked( aElem.is_locked );
pad->SetPosition( aElem.position );
pad->SetOrientationDegrees( aElem.direction );
pad->SetLocalCoord(); pad->SetLocalCoord();
pad->SetSize( elem.topsize ); pad->SetSize( aElem.topsize );
if( elem.holesize == 0 ) if( aElem.holesize == 0 )
{ {
pad->SetAttribute( PAD_ATTRIB::SMD ); pad->SetAttribute( PAD_ATTRIB::SMD );
} }
else else
{ {
if( elem.layer != ALTIUM_LAYER::MULTI_LAYER ) if( aElem.layer != ALTIUM_LAYER::MULTI_LAYER )
{ {
// TODO: I assume other values are possible as well? // TODO: I assume other values are possible as well?
wxLogError( _( "Footprint %s pad %s is not marked as multilayer, but is a TH pad." ), wxLogError( _( "Footprint %s pad %s is not marked as multilayer, but is a TH pad." ),
footprint->GetReference(), aFootprint->GetReference(), aElem.name );
elem.name );
} }
pad->SetAttribute( elem.plated ? PAD_ATTRIB::PTH : pad->SetAttribute( aElem.plated ? PAD_ATTRIB::PTH : PAD_ATTRIB::NPTH );
PAD_ATTRIB::NPTH ); if( !aElem.sizeAndShape || aElem.sizeAndShape->holeshape == ALTIUM_PAD_HOLE_SHAPE::ROUND )
if( !elem.sizeAndShape || elem.sizeAndShape->holeshape == ALTIUM_PAD_HOLE_SHAPE::ROUND )
{ {
pad->SetDrillShape( PAD_DRILL_SHAPE_T::PAD_DRILL_SHAPE_CIRCLE ); pad->SetDrillShape( PAD_DRILL_SHAPE_T::PAD_DRILL_SHAPE_CIRCLE );
pad->SetDrillSize( wxSize( elem.holesize, elem.holesize ) ); pad->SetDrillSize( wxSize( aElem.holesize, aElem.holesize ) );
} }
else else
{ {
switch( elem.sizeAndShape->holeshape ) switch( aElem.sizeAndShape->holeshape )
{ {
case ALTIUM_PAD_HOLE_SHAPE::ROUND: case ALTIUM_PAD_HOLE_SHAPE::ROUND:
wxFAIL_MSG( "Round holes are handled before the switch" ); wxFAIL_MSG( "Round holes are handled before the switch" );
@ -2275,23 +2323,22 @@ void ALTIUM_PCB::ParsePads6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
case ALTIUM_PAD_HOLE_SHAPE::SQUARE: case ALTIUM_PAD_HOLE_SHAPE::SQUARE:
wxLogWarning( _( "Footprint %s pad %s has a square hole (not yet supported)." ), wxLogWarning( _( "Footprint %s pad %s has a square hole (not yet supported)." ),
footprint->GetReference(), aFootprint->GetReference(), aElem.name );
elem.name );
pad->SetDrillShape( PAD_DRILL_SHAPE_T::PAD_DRILL_SHAPE_CIRCLE ); pad->SetDrillShape( PAD_DRILL_SHAPE_T::PAD_DRILL_SHAPE_CIRCLE );
pad->SetDrillSize( wxSize( elem.holesize, elem.holesize ) ); // Workaround pad->SetDrillSize( wxSize( aElem.holesize, aElem.holesize ) ); // Workaround
// TODO: elem.sizeAndShape->slotsize was 0 in testfile. Either use holesize in this case or rect holes have a different id // TODO: elem.sizeAndShape->slotsize was 0 in testfile. Either use holesize in this case or rect holes have a different id
break; break;
case ALTIUM_PAD_HOLE_SHAPE::SLOT: case ALTIUM_PAD_HOLE_SHAPE::SLOT:
{ {
pad->SetDrillShape( PAD_DRILL_SHAPE_T::PAD_DRILL_SHAPE_OBLONG ); pad->SetDrillShape( PAD_DRILL_SHAPE_T::PAD_DRILL_SHAPE_OBLONG );
EDA_ANGLE slotRotation( elem.sizeAndShape->slotrotation, DEGREES_T ); EDA_ANGLE slotRotation( aElem.sizeAndShape->slotrotation, DEGREES_T );
slotRotation.Normalize(); slotRotation.Normalize();
if( slotRotation == ANGLE_0 || slotRotation == ANGLE_180 ) if( slotRotation == ANGLE_0 || slotRotation == ANGLE_180 )
{ {
pad->SetDrillSize( wxSize( elem.sizeAndShape->slotsize, elem.holesize ) ); pad->SetDrillSize( wxSize( aElem.sizeAndShape->slotsize, aElem.holesize ) );
} }
else else
{ {
@ -2299,12 +2346,11 @@ void ALTIUM_PCB::ParsePads6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
{ {
wxLogWarning( _( "Footprint %s pad %s has a hole-rotation of %f " wxLogWarning( _( "Footprint %s pad %s has a hole-rotation of %f "
"degrees. KiCad only supports 90 degree rotations." ), "degrees. KiCad only supports 90 degree rotations." ),
footprint->GetReference(), aFootprint->GetReference(), aElem.name,
elem.name,
slotRotation.AsDegrees() ); slotRotation.AsDegrees() );
} }
pad->SetDrillSize( wxSize( elem.holesize, elem.sizeAndShape->slotsize ) ); pad->SetDrillSize( wxSize( aElem.holesize, aElem.sizeAndShape->slotsize ) );
} }
} }
break; break;
@ -2312,42 +2358,37 @@ void ALTIUM_PCB::ParsePads6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
default: default:
case ALTIUM_PAD_HOLE_SHAPE::UNKNOWN: case ALTIUM_PAD_HOLE_SHAPE::UNKNOWN:
wxLogError( _( "Footprint %s pad %s uses a hole of unknown kind %d." ), wxLogError( _( "Footprint %s pad %s uses a hole of unknown kind %d." ),
footprint->GetReference(), aFootprint->GetReference(), aElem.name, aElem.sizeAndShape->holeshape );
elem.name,
elem.sizeAndShape->holeshape );
pad->SetDrillShape( PAD_DRILL_SHAPE_T::PAD_DRILL_SHAPE_CIRCLE ); pad->SetDrillShape( PAD_DRILL_SHAPE_T::PAD_DRILL_SHAPE_CIRCLE );
pad->SetDrillSize( wxSize( elem.holesize, elem.holesize ) ); // Workaround pad->SetDrillSize( wxSize( aElem.holesize, aElem.holesize ) ); // Workaround
break; break;
} }
} }
if( elem.sizeAndShape ) if( aElem.sizeAndShape )
{ {
pad->SetOffset( elem.sizeAndShape->holeoffset[0] ); pad->SetOffset( aElem.sizeAndShape->holeoffset[0] );
} }
} }
if( elem.padmode != ALTIUM_PAD_MODE::SIMPLE ) if( aElem.padmode != ALTIUM_PAD_MODE::SIMPLE )
{ {
wxLogError( _( "Footprint %s pad %s uses a complex pad stack (not yet supported.)" ), wxLogError( _( "Footprint %s pad %s uses a complex pad stack (not yet supported.)" ),
footprint->GetReference(), aFootprint->GetReference(), aElem.name );
elem.name );
} }
switch( elem.topshape ) switch( aElem.topshape )
{ {
case ALTIUM_PAD_SHAPE::RECT: case ALTIUM_PAD_SHAPE::RECT: pad->SetShape( PAD_SHAPE::RECT ); break;
pad->SetShape( PAD_SHAPE::RECT );
break;
case ALTIUM_PAD_SHAPE::CIRCLE: case ALTIUM_PAD_SHAPE::CIRCLE:
if( elem.sizeAndShape if( aElem.sizeAndShape
&& elem.sizeAndShape->alt_shape[0] == ALTIUM_PAD_SHAPE_ALT::ROUNDRECT ) && aElem.sizeAndShape->alt_shape[0] == ALTIUM_PAD_SHAPE_ALT::ROUNDRECT )
{ {
pad->SetShape( PAD_SHAPE::ROUNDRECT ); // 100 = round, 0 = rectangular pad->SetShape( PAD_SHAPE::ROUNDRECT ); // 100 = round, 0 = rectangular
double ratio = elem.sizeAndShape->cornerradius[0] / 200.; double ratio = aElem.sizeAndShape->cornerradius[0] / 200.;
pad->SetRoundRectRadiusRatio( ratio ); pad->SetRoundRectRadiusRatio( ratio );
} }
else if( elem.topsize.x == elem.topsize.y ) else if( aElem.topsize.x == aElem.topsize.y )
{ {
pad->SetShape( PAD_SHAPE::CIRCLE ); pad->SetShape( PAD_SHAPE::CIRCLE );
} }
@ -2364,12 +2405,11 @@ void ALTIUM_PCB::ParsePads6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
case ALTIUM_PAD_SHAPE::UNKNOWN: case ALTIUM_PAD_SHAPE::UNKNOWN:
default: default:
wxLogError( _( "Footprint %s pad %s uses an unknown pad-shape." ), wxLogError( _( "Footprint %s pad %s uses an unknown pad-shape." ),
footprint->GetReference(), aFootprint->GetReference(), aElem.name );
elem.name );
break; break;
} }
switch( elem.layer ) switch( aElem.layer )
{ {
case ALTIUM_LAYER::TOP_LAYER: case ALTIUM_LAYER::TOP_LAYER:
pad->SetLayer( F_Cu ); pad->SetLayer( F_Cu );
@ -2380,55 +2420,84 @@ void ALTIUM_PCB::ParsePads6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
pad->SetLayerSet( FlipLayerMask( PAD::SMDMask() ) ); pad->SetLayerSet( FlipLayerMask( PAD::SMDMask() ) );
break; break;
case ALTIUM_LAYER::MULTI_LAYER: case ALTIUM_LAYER::MULTI_LAYER:
pad->SetLayerSet( elem.plated ? PAD::PTHMask() : PAD::UnplatedHoleMask() ); pad->SetLayerSet( aElem.plated ? PAD::PTHMask() : PAD::UnplatedHoleMask() );
break; break;
default: default:
PCB_LAYER_ID klayer = GetKicadLayer( elem.layer ); PCB_LAYER_ID klayer = GetKicadLayer( aElem.layer );
pad->SetLayer( klayer ); pad->SetLayer( klayer );
pad->SetLayerSet( LSET( 1, klayer ) ); pad->SetLayerSet( LSET( 1, klayer ) );
break; break;
} }
if( elem.pastemaskexpansionmode == ALTIUM_PAD_RULE::MANUAL ) if( aElem.pastemaskexpansionmode == ALTIUM_PAD_RULE::MANUAL )
{ {
pad->SetLocalSolderPasteMargin( elem.pastemaskexpansionmanual ); pad->SetLocalSolderPasteMargin( aElem.pastemaskexpansionmanual );
} }
if( elem.soldermaskexpansionmode == ALTIUM_PAD_RULE::MANUAL ) if( aElem.soldermaskexpansionmode == ALTIUM_PAD_RULE::MANUAL )
{ {
pad->SetLocalSolderMaskMargin( elem.soldermaskexpansionmanual ); pad->SetLocalSolderMaskMargin( aElem.soldermaskexpansionmanual );
} }
if( elem.is_tent_top ) if( aElem.is_tent_top )
{ {
pad->SetLayerSet( pad->GetLayerSet().reset( F_Mask ) ); pad->SetLayerSet( pad->GetLayerSet().reset( F_Mask ) );
} }
if( elem.is_tent_bottom ) if( aElem.is_tent_bottom )
{ {
pad->SetLayerSet( pad->GetLayerSet().reset( B_Mask ) ); pad->SetLayerSet( pad->GetLayerSet().reset( B_Mask ) );
} }
}
if( reader.GetRemainingBytes() != 0 ) aFootprint->Add( pad, ADD_MODE::APPEND );
{
THROW_IO_ERROR( "Pads6 stream is not fully parsed" );
}
} }
void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem ) void ALTIUM_PCB::ConvertPads6ToBoardItemOnNonCopper( const APAD6& aElem )
{ {
PCB_LAYER_ID klayer = GetKicadLayer( aElem.layer ); PCB_LAYER_ID klayer = GetKicadLayer( aElem.layer );
if( klayer == UNDEFINED_LAYER ) if( klayer == UNDEFINED_LAYER )
{ {
wxLogWarning( _( "Non-copper pad %s found on an Altium layer (%d) with no KiCad equivalent. " wxLogWarning(
_( "Non-copper pad %s found on an Altium layer (%d) with no KiCad equivalent. "
"It has been moved to KiCad layer Eco1_User." ), "It has been moved to KiCad layer Eco1_User." ),
aElem.name, aElem.name, aElem.layer );
aElem.layer );
klayer = Eco1_User; klayer = Eco1_User;
} }
PCB_SHAPE* pad = new PCB_SHAPE( m_board );
HelperParsePad6NonCopper( aElem, klayer, pad );
m_board->Add( pad, ADD_MODE::APPEND );
}
void ALTIUM_PCB::ConvertPads6ToFootprintItemOnNonCopper( FOOTPRINT* aFootprint, const APAD6& aElem )
{
PCB_LAYER_ID klayer = GetKicadLayer( aElem.layer );
if( klayer == UNDEFINED_LAYER )
{
wxLogWarning(
_( "Non-copper pad %s found on an Altium layer (%d) with no KiCad equivalent. "
"It has been moved to KiCad layer Eco1_User." ),
aElem.name, aElem.layer );
klayer = Eco1_User;
}
FP_SHAPE* pad = new FP_SHAPE( aFootprint );
HelperParsePad6NonCopper( aElem, klayer, pad );
HelperShapeSetLocalCoord( pad );
aFootprint->Add( pad, ADD_MODE::APPEND );
}
void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem, PCB_LAYER_ID aLayer,
PCB_SHAPE* aShape )
{
if( aElem.net != ALTIUM_NET_UNCONNECTED ) if( aElem.net != ALTIUM_NET_UNCONNECTED )
{ {
wxLogError( _( "Non-copper pad %s is connected to a net, which is not supported." ), wxLogError( _( "Non-copper pad %s is connected to a net, which is not supported." ),
@ -2451,21 +2520,19 @@ void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem )
case ALTIUM_PAD_SHAPE::RECT: case ALTIUM_PAD_SHAPE::RECT:
{ {
// filled rect // filled rect
PCB_SHAPE* shape = HelperCreateAndAddShape( aElem.component ); aShape->SetShape( SHAPE_T::POLY );
shape->SetShape( SHAPE_T::POLY ); aShape->SetFilled( true );
shape->SetFilled( true ); aShape->SetLayer( aLayer );
shape->SetLayer( klayer ); aShape->SetStroke( STROKE_PARAMS( 0 ) );
shape->SetStroke( STROKE_PARAMS( 0 ) );
shape->SetPolyPoints( { aElem.position + VECTOR2I( aElem.topsize.x / 2, aElem.topsize.y / 2 ), aShape->SetPolyPoints(
{ aElem.position + VECTOR2I( aElem.topsize.x / 2, aElem.topsize.y / 2 ),
aElem.position + VECTOR2I( aElem.topsize.x / 2, -aElem.topsize.y / 2 ), aElem.position + VECTOR2I( aElem.topsize.x / 2, -aElem.topsize.y / 2 ),
aElem.position + VECTOR2I( -aElem.topsize.x / 2, -aElem.topsize.y / 2 ), aElem.position + VECTOR2I( -aElem.topsize.x / 2, -aElem.topsize.y / 2 ),
aElem.position + VECTOR2I( -aElem.topsize.x / 2, aElem.topsize.y / 2 ) } ); aElem.position + VECTOR2I( -aElem.topsize.x / 2, aElem.topsize.y / 2 ) } );
if( aElem.direction != 0 ) if( aElem.direction != 0 )
shape->Rotate( aElem.position, EDA_ANGLE( aElem.direction, DEGREES_T ) ); aShape->Rotate( aElem.position, EDA_ANGLE( aElem.direction, DEGREES_T ) );
HelperShapeSetLocalCoord( shape, aElem.component );
} }
break; break;
@ -2477,9 +2544,8 @@ void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem )
int cornerradius = aElem.sizeAndShape->cornerradius[0]; int cornerradius = aElem.sizeAndShape->cornerradius[0];
int offset = ( std::min( aElem.topsize.x, aElem.topsize.y ) * cornerradius ) / 200; int offset = ( std::min( aElem.topsize.x, aElem.topsize.y ) * cornerradius ) / 200;
PCB_SHAPE* shape = HelperCreateAndAddShape( aElem.component ); aShape->SetLayer( aLayer );
shape->SetLayer( klayer ); aShape->SetStroke( STROKE_PARAMS( offset * 2, PLOT_DASH_TYPE::SOLID ) );
shape->SetStroke( STROKE_PARAMS( offset * 2, PLOT_DASH_TYPE::SOLID ) );
if( cornerradius < 100 ) if( cornerradius < 100 )
{ {
@ -2491,90 +2557,82 @@ void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem )
VECTOR2I p22 = aElem.position + VECTOR2I( -offsetX, -offsetY ); VECTOR2I p22 = aElem.position + VECTOR2I( -offsetX, -offsetY );
VECTOR2I p21 = aElem.position + VECTOR2I( -offsetX, offsetY ); VECTOR2I p21 = aElem.position + VECTOR2I( -offsetX, offsetY );
shape->SetShape( SHAPE_T::POLY ); aShape->SetShape( SHAPE_T::POLY );
shape->SetFilled( true ); aShape->SetFilled( true );
shape->SetPolyPoints( { p11, p12, p22, p21 } ); aShape->SetPolyPoints( { p11, p12, p22, p21 } );
} }
else if( aElem.topsize.x == aElem.topsize.y ) else if( aElem.topsize.x == aElem.topsize.y )
{ {
// circle // circle
shape->SetShape( SHAPE_T::CIRCLE ); aShape->SetShape( SHAPE_T::CIRCLE );
shape->SetFilled( true ); aShape->SetFilled( true );
shape->SetStart( aElem.position ); aShape->SetStart( aElem.position );
shape->SetEnd( aElem.position - VECTOR2I( 0, aElem.topsize.x / 4 ) ); aShape->SetEnd( aElem.position - VECTOR2I( 0, aElem.topsize.x / 4 ) );
shape->SetStroke( STROKE_PARAMS( aElem.topsize.x / 2, PLOT_DASH_TYPE::SOLID ) ); aShape->SetStroke( STROKE_PARAMS( aElem.topsize.x / 2, PLOT_DASH_TYPE::SOLID ) );
} }
else if( aElem.topsize.x < aElem.topsize.y ) else if( aElem.topsize.x < aElem.topsize.y )
{ {
// short vertical line // short vertical line
shape->SetShape( SHAPE_T::SEGMENT ); aShape->SetShape( SHAPE_T::SEGMENT );
VECTOR2I pointOffset( 0, ( aElem.topsize.y - aElem.topsize.x ) / 2 ); VECTOR2I pointOffset( 0, ( aElem.topsize.y - aElem.topsize.x ) / 2 );
shape->SetStart( aElem.position + pointOffset ); aShape->SetStart( aElem.position + pointOffset );
shape->SetEnd( aElem.position - pointOffset ); aShape->SetEnd( aElem.position - pointOffset );
} }
else else
{ {
// short horizontal line // short horizontal line
shape->SetShape( SHAPE_T::SEGMENT ); aShape->SetShape( SHAPE_T::SEGMENT );
VECTOR2I pointOffset( ( aElem.topsize.x - aElem.topsize.y ) / 2, 0 ); VECTOR2I pointOffset( ( aElem.topsize.x - aElem.topsize.y ) / 2, 0 );
shape->SetStart( aElem.position + pointOffset ); aShape->SetStart( aElem.position + pointOffset );
shape->SetEnd( aElem.position - pointOffset ); aShape->SetEnd( aElem.position - pointOffset );
} }
if( aElem.direction != 0 ) if( aElem.direction != 0 )
shape->Rotate( aElem.position, EDA_ANGLE( aElem.direction, DEGREES_T ) ); aShape->Rotate( aElem.position, EDA_ANGLE( aElem.direction, DEGREES_T ) );
HelperShapeSetLocalCoord( shape, aElem.component );
} }
else if( aElem.topsize.x == aElem.topsize.y ) else if( aElem.topsize.x == aElem.topsize.y )
{ {
// filled circle // filled circle
PCB_SHAPE* shape = HelperCreateAndAddShape( aElem.component ); aShape->SetShape( SHAPE_T::CIRCLE );
shape->SetShape( SHAPE_T::CIRCLE ); aShape->SetFilled( true );
shape->SetFilled( true ); aShape->SetLayer( aLayer );
shape->SetLayer( klayer ); aShape->SetStart( aElem.position );
shape->SetStart( aElem.position ); aShape->SetEnd( aElem.position - VECTOR2I( 0, aElem.topsize.x / 4 ) );
shape->SetEnd( aElem.position - VECTOR2I( 0, aElem.topsize.x / 4 ) ); aShape->SetStroke( STROKE_PARAMS( aElem.topsize.x / 2, PLOT_DASH_TYPE::SOLID ) );
shape->SetStroke( STROKE_PARAMS( aElem.topsize.x / 2, PLOT_DASH_TYPE::SOLID ) );
HelperShapeSetLocalCoord( shape, aElem.component );
} }
else else
{ {
// short line // short line
PCB_SHAPE* shape = HelperCreateAndAddShape( aElem.component ); aShape->SetShape( SHAPE_T::SEGMENT );
shape->SetShape( SHAPE_T::SEGMENT ); aShape->SetLayer( aLayer );
shape->SetLayer( klayer ); aShape->SetStroke( STROKE_PARAMS( std::min( aElem.topsize.x, aElem.topsize.y ),
shape->SetStroke( STROKE_PARAMS( std::min( aElem.topsize.x, aElem.topsize.y ),
PLOT_DASH_TYPE::SOLID ) ); PLOT_DASH_TYPE::SOLID ) );
if( aElem.topsize.x < aElem.topsize.y ) if( aElem.topsize.x < aElem.topsize.y )
{ {
VECTOR2I offset( 0, ( aElem.topsize.y - aElem.topsize.x ) / 2 ); VECTOR2I offset( 0, ( aElem.topsize.y - aElem.topsize.x ) / 2 );
shape->SetStart( aElem.position + offset ); aShape->SetStart( aElem.position + offset );
shape->SetEnd( aElem.position - offset ); aShape->SetEnd( aElem.position - offset );
} }
else else
{ {
VECTOR2I offset( ( aElem.topsize.x - aElem.topsize.y ) / 2, 0 ); VECTOR2I offset( ( aElem.topsize.x - aElem.topsize.y ) / 2, 0 );
shape->SetStart( aElem.position + offset ); aShape->SetStart( aElem.position + offset );
shape->SetEnd( aElem.position - offset ); aShape->SetEnd( aElem.position - offset );
} }
if( aElem.direction != 0 ) if( aElem.direction != 0 )
shape->Rotate( aElem.position, EDA_ANGLE( aElem.direction, DEGREES_T ) ); aShape->Rotate( aElem.position, EDA_ANGLE( aElem.direction, DEGREES_T ) );
HelperShapeSetLocalCoord( shape, aElem.component );
} }
break; break;
case ALTIUM_PAD_SHAPE::OCTAGONAL: case ALTIUM_PAD_SHAPE::OCTAGONAL:
{ {
// filled octagon // filled octagon
PCB_SHAPE* shape = HelperCreateAndAddShape( aElem.component ); aShape->SetShape( SHAPE_T::POLY );
shape->SetShape( SHAPE_T::POLY ); aShape->SetFilled( true );
shape->SetFilled( true ); aShape->SetLayer( aLayer );
shape->SetLayer( klayer ); aShape->SetStroke( STROKE_PARAMS( 0 ) );
shape->SetStroke( STROKE_PARAMS( 0 ) );
VECTOR2I p11 = aElem.position + VECTOR2I( aElem.topsize.x / 2, aElem.topsize.y / 2 ); VECTOR2I p11 = aElem.position + VECTOR2I( aElem.topsize.x / 2, aElem.topsize.y / 2 );
VECTOR2I p12 = aElem.position + VECTOR2I( aElem.topsize.x / 2, -aElem.topsize.y / 2 ); VECTOR2I p12 = aElem.position + VECTOR2I( aElem.topsize.x / 2, -aElem.topsize.y / 2 );
@ -2585,13 +2643,11 @@ void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem )
VECTOR2I chamferX( chamfer, 0 ); VECTOR2I chamferX( chamfer, 0 );
VECTOR2I chamferY( 0, chamfer ); VECTOR2I chamferY( 0, chamfer );
shape->SetPolyPoints( { p11 - chamferX, p11 - chamferY, p12 + chamferY, p12 - chamferX, aShape->SetPolyPoints( { p11 - chamferX, p11 - chamferY, p12 + chamferY, p12 - chamferX,
p22 + chamferX, p22 + chamferY, p21 - chamferY, p21 + chamferX } ); p22 + chamferX, p22 + chamferY, p21 - chamferY, p21 + chamferX } );
if( aElem.direction != 0. ) if( aElem.direction != 0. )
shape->Rotate( aElem.position, EDA_ANGLE( aElem.direction, DEGREES_T ) ); aShape->Rotate( aElem.position, EDA_ANGLE( aElem.direction, DEGREES_T ) );
HelperShapeSetLocalCoord( shape, aElem.component );
} }
break; break;
@ -2602,6 +2658,7 @@ void ALTIUM_PCB::HelperParsePad6NonCopper( const APAD6& aElem )
} }
} }
void ALTIUM_PCB::ParseVias6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile, void ALTIUM_PCB::ParseVias6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
const CFB::COMPOUND_FILE_ENTRY* aEntry ) const CFB::COMPOUND_FILE_ENTRY* aEntry )
{ {

View File

@ -82,6 +82,7 @@ enum class ALTIUM_PCB_DIR
class BOARD; class BOARD;
class FP_SHAPE;
class PCB_SHAPE; class PCB_SHAPE;
class FOOTPRINT; class FOOTPRINT;
class ZONE; class ZONE;
@ -157,6 +158,11 @@ private:
const CFB::COMPOUND_FILE_ENTRY* aEntry ); const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParsePads6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile, void ParsePads6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
const CFB::COMPOUND_FILE_ENTRY* aEntry ); const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ConvertPads6ToBoardItem( const APAD6& aElem );
void ConvertPads6ToFootprintItem( FOOTPRINT* aFootprint, const APAD6& aElem );
void ConvertPads6ToBoardItemOnNonCopper( const APAD6& aElem );
void ConvertPads6ToFootprintItemOnCopper( FOOTPRINT* aFootprint, const APAD6& aElem );
void ConvertPads6ToFootprintItemOnNonCopper( FOOTPRINT* aFootprint, const APAD6& aElem );
void ParseVias6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile, void ParseVias6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
const CFB::COMPOUND_FILE_ENTRY* aEntry ); const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseTracks6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile, void ParseTracks6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
@ -193,7 +199,7 @@ private:
void HelperParseDimensions6Datum( const ADIMENSION6& aElem ); void HelperParseDimensions6Datum( const ADIMENSION6& aElem );
void HelperParseDimensions6Center( const ADIMENSION6& aElem ); void HelperParseDimensions6Center( const ADIMENSION6& aElem );
void HelperParsePad6NonCopper( const APAD6& aElem ); void HelperParsePad6NonCopper( const APAD6& aElem, PCB_LAYER_ID aLayer, PCB_SHAPE* aShape );
void HelperCreateBoardOutline( const std::vector<ALTIUM_VERTICE>& aVertices ); void HelperCreateBoardOutline( const std::vector<ALTIUM_VERTICE>& aVertices );
@ -204,6 +210,7 @@ private:
FOOTPRINT* HelperGetFootprint( uint16_t aComponent ) const; FOOTPRINT* HelperGetFootprint( uint16_t aComponent ) const;
PCB_SHAPE* HelperCreateAndAddShape( uint16_t aComponent ); PCB_SHAPE* HelperCreateAndAddShape( uint16_t aComponent );
void HelperShapeSetLocalCoord( PCB_SHAPE* aShape, uint16_t aComponent ); void HelperShapeSetLocalCoord( PCB_SHAPE* aShape, uint16_t aComponent );
void HelperShapeSetLocalCoord( FP_SHAPE* aShape );
BOARD* m_board; BOARD* m_board;
std::vector<FOOTPRINT*> m_components; std::vector<FOOTPRINT*> m_components;