Altium importer: try to import elliptical arcs rather to skip them.

Some schematics use elliptical arcs to describe usual arcs.
This commit is contained in:
jean-pierre charras 2022-11-24 19:42:41 +01:00
parent 4a943facd0
commit a71c669543
3 changed files with 64 additions and 50 deletions

View File

@ -392,20 +392,25 @@ ASCH_ROUND_RECTANGLE::ASCH_ROUND_RECTANGLE( const std::map<wxString, wxString>&
ASCH_ARC::ASCH_ARC( const std::map<wxString, wxString>& aProps ) ASCH_ARC::ASCH_ARC( const std::map<wxString, wxString>& aProps )
{ {
wxASSERT( ReadRecord( aProps ) == ALTIUM_SCH_RECORD::ARC ); m_IsElliptical = ReadRecord( aProps ) == ALTIUM_SCH_RECORD::ELLIPTICAL_ARC;
wxASSERT( ReadRecord( aProps ) == ALTIUM_SCH_RECORD::ARC || m_IsElliptical );
ownerindex = ReadOwnerIndex( aProps ); ownerindex = ReadOwnerIndex( aProps );
ownerpartid = ReadOwnerPartId( aProps ); ownerpartid = ReadOwnerPartId( aProps );
ownerpartdisplaymode = ALTIUM_PARSER::ReadInt( aProps, "OWNERPARTDISPLAYMODE", 0 ); ownerpartdisplaymode = ALTIUM_PARSER::ReadInt( aProps, "OWNERPARTDISPLAYMODE", 0 );
center = VECTOR2I( ReadKiCadUnitFrac( aProps, "LOCATION.X" ), m_Center = VECTOR2I( ReadKiCadUnitFrac( aProps, "LOCATION.X" ),
-ReadKiCadUnitFrac( aProps, "LOCATION.Y" ) ); -ReadKiCadUnitFrac( aProps, "LOCATION.Y" ) );
radius = ReadKiCadUnitFrac( aProps, "RADIUS" ); m_Radius = ReadKiCadUnitFrac( aProps, "RADIUS" );
m_SecondaryRadius = m_Radius;
startAngle = ALTIUM_PARSER::ReadDouble( aProps, "STARTANGLE", 0 ); if( m_IsElliptical )
endAngle = ALTIUM_PARSER::ReadDouble( aProps, "ENDANGLE", 0 ); m_SecondaryRadius = ReadKiCadUnitFrac( aProps, "SECONDARYRADIUS" );
lineWidth = ReadKiCadUnitFrac( aProps, "LINEWIDTH" ); m_StartAngle = ALTIUM_PARSER::ReadDouble( aProps, "STARTANGLE", 0 );
m_EndAngle = ALTIUM_PARSER::ReadDouble( aProps, "ENDANGLE", 0 );
m_LineWidth = ReadKiCadUnitFrac( aProps, "LINEWIDTH" );
} }

View File

@ -397,12 +397,14 @@ struct ASCH_ARC
int ownerpartid; int ownerpartid;
int ownerpartdisplaymode; int ownerpartdisplaymode;
VECTOR2I center; bool m_IsElliptical;
int radius; VECTOR2I m_Center;
double startAngle; int m_Radius;
double endAngle; int m_SecondaryRadius;
double m_StartAngle;
double m_EndAngle;
int lineWidth; int m_LineWidth;
explicit ASCH_ARC( const std::map<wxString, wxString>& aProps ); explicit ASCH_ARC( const std::map<wxString, wxString>& aProps );
}; };

View File

@ -583,8 +583,6 @@ void SCH_ALTIUM_PLUGIN::ParseFileHeader( const ALTIUM_COMPOUND_FILE& aAltiumSchF
break; break;
case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC: case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC:
break;
case ALTIUM_SCH_RECORD::ARC: case ALTIUM_SCH_RECORD::ARC:
ParseArc( properties ); ParseArc( properties );
break; break;
@ -810,7 +808,7 @@ void SCH_ALTIUM_PLUGIN::ParseComponent( int aIndex,
symbol->SetPosition( elem.location + m_sheetOffset ); symbol->SetPosition( elem.location + m_sheetOffset );
// TODO: keep it simple for now, and only set position. // TODO: keep it simple for now, and only set position.
//component->SetOrientation( elem.orientation ); // component->SetOrientation( elem.orientation );
symbol->SetLibId( libId ); symbol->SetLibId( libId );
symbol->SetUnit( std::max( 0, elem.currentpartid ) ); symbol->SetUnit( std::max( 0, elem.currentpartid ) );
@ -1521,36 +1519,47 @@ void SCH_ALTIUM_PLUGIN::ParseRoundRectangle( const std::map<wxString, wxString>&
void SCH_ALTIUM_PLUGIN::ParseArc( const std::map<wxString, wxString>& aProperties ) void SCH_ALTIUM_PLUGIN::ParseArc( const std::map<wxString, wxString>& aProperties )
{ {
// The Arc can be ALTIUM_SCH_RECORD::ELLIPTICAL_ARC or ALTIUM_SCH_RECORD::ARC
// Elliptical arcs are not handled in kicad. So use an arc instead
// TODO: handle elliptical arc better.
ASCH_ARC elem( aProperties ); ASCH_ARC elem( aProperties );
SCH_SCREEN* screen = getCurrentScreen(); SCH_SCREEN* screen = getCurrentScreen();
wxCHECK( screen, /* void */ ); wxCHECK( screen, /* void */ );
int arc_radius = elem.m_Radius;
// Try to approxiammate this ellipse by an arc. use the biggest of radius and secondary radius
// One can of course use another recipe
if( elem.m_IsElliptical )
arc_radius = std::max( elem.m_Radius, elem.m_SecondaryRadius );
if( elem.ownerpartid == ALTIUM_COMPONENT_NONE ) if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
{ {
if( elem.startAngle == 0 && ( elem.endAngle == 0 || elem.endAngle == 360 ) ) if( elem.m_StartAngle == 0 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
{ {
SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE ); SCH_SHAPE* circle = new SCH_SHAPE( SHAPE_T::CIRCLE );
circle->SetPosition( elem.center + m_sheetOffset ); circle->SetPosition( elem.m_Center + m_sheetOffset );
circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.radius, 0 ) ); circle->SetEnd( circle->GetPosition() + VECTOR2I( arc_radius, 0 ) );
circle->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) ); circle->SetStroke( STROKE_PARAMS( elem.m_LineWidth, PLOT_DASH_TYPE::SOLID ) );
screen->Append( circle ); screen->Append( circle );
} }
else else
{ {
SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC ); SCH_SHAPE* arc = new SCH_SHAPE( SHAPE_T::ARC );
EDA_ANGLE includedAngle( elem.endAngle - elem.startAngle, DEGREES_T ); EDA_ANGLE includedAngle( elem.m_EndAngle - elem.m_StartAngle, DEGREES_T );
EDA_ANGLE startAngle( elem.endAngle, DEGREES_T ); EDA_ANGLE startAngle( elem.m_EndAngle, DEGREES_T );
VECTOR2I startOffset( KiROUND( elem.radius * startAngle.Cos() ), VECTOR2I startOffset( KiROUND( arc_radius * startAngle.Cos() ),
-KiROUND( elem.radius * startAngle.Sin() ) ); -KiROUND( arc_radius * startAngle.Sin() ) );
arc->SetCenter( elem.center + m_sheetOffset ); arc->SetCenter( elem.m_Center + m_sheetOffset );
arc->SetStart( elem.center + startOffset + m_sheetOffset ); arc->SetStart( elem.m_Center + startOffset + m_sheetOffset );
arc->SetArcAngleAndEnd( includedAngle.Normalize(), true ); arc->SetArcAngleAndEnd( includedAngle.Normalize(), true );
arc->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) ); arc->SetStroke( STROKE_PARAMS( elem.m_LineWidth, PLOT_DASH_TYPE::SOLID ) );
screen->Append( arc ); screen->Append( arc );
} }
@ -1573,16 +1582,16 @@ void SCH_ALTIUM_PLUGIN::ParseArc( const std::map<wxString, wxString>& aPropertie
SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first ); SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
if( elem.startAngle == 0 && ( elem.endAngle == 0 || elem.endAngle == 360 ) ) if( elem.m_StartAngle == 0 && ( elem.m_EndAngle == 0 || elem.m_EndAngle == 360 ) )
{ {
LIB_SHAPE* circle = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::CIRCLE ); LIB_SHAPE* circle = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::CIRCLE );
libSymbolIt->second->AddDrawItem( circle ); libSymbolIt->second->AddDrawItem( circle );
circle->SetUnit( std::max( 0, elem.ownerpartid ) ); circle->SetUnit( std::max( 0, elem.ownerpartid ) );
circle->SetPosition( GetRelativePosition( elem.center + m_sheetOffset, symbol ) ); circle->SetPosition( GetRelativePosition( elem.m_Center + m_sheetOffset, symbol ) );
circle->SetEnd( circle->GetPosition() + VECTOR2I( elem.radius, 0 ) ); circle->SetEnd( circle->GetPosition() + VECTOR2I( arc_radius, 0 ) );
circle->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) ); circle->SetStroke( STROKE_PARAMS( elem.m_LineWidth, PLOT_DASH_TYPE::SOLID ) );
} }
else else
{ {
@ -1590,19 +1599,19 @@ void SCH_ALTIUM_PLUGIN::ParseArc( const std::map<wxString, wxString>& aPropertie
libSymbolIt->second->AddDrawItem( arc ); libSymbolIt->second->AddDrawItem( arc );
arc->SetUnit( std::max( 0, elem.ownerpartid ) ); arc->SetUnit( std::max( 0, elem.ownerpartid ) );
arc->SetCenter( GetRelativePosition( elem.center + m_sheetOffset, symbol ) ); arc->SetCenter( GetRelativePosition( elem.m_Center + m_sheetOffset, symbol ) );
VECTOR2I arcStart( elem.radius, 0 ); VECTOR2I arcStart( arc_radius, 0 );
RotatePoint( arcStart, -EDA_ANGLE( elem.startAngle, DEGREES_T ) ); RotatePoint( arcStart, -EDA_ANGLE( elem.m_StartAngle, DEGREES_T ) );
arcStart += arc->GetCenter(); arcStart += arc->GetCenter();
arc->SetStart( arcStart ); arc->SetStart( arcStart );
VECTOR2I arcEnd( elem.radius, 0 ); VECTOR2I arcEnd( arc_radius, 0 );
RotatePoint( arcEnd, -EDA_ANGLE( elem.endAngle, DEGREES_T ) ); RotatePoint( arcEnd, -EDA_ANGLE( elem.m_EndAngle, DEGREES_T ) );
arcEnd += arc->GetCenter(); arcEnd += arc->GetCenter();
arc->SetEnd( arcEnd ); arc->SetEnd( arcEnd );
arc->SetStroke( STROKE_PARAMS( elem.lineWidth, PLOT_DASH_TYPE::SOLID ) ); arc->SetStroke( STROKE_PARAMS( elem.m_LineWidth, PLOT_DASH_TYPE::SOLID ) );
} }
} }
} }
@ -2463,11 +2472,13 @@ void SCH_ALTIUM_PLUGIN::ParsePort( const ASCH_PORT& aElem )
SCH_LABEL_BASE* label; SCH_LABEL_BASE* label;
// TODO: detect correct label type depending on sheet settings, etc. // TODO: detect correct label type depending on sheet settings, etc.
//{ #if 0 // Set to 1 to use SCH_HIERLABEL label, 0 to use SCH_GLOBALLABEL
// label = new SCH_HIERLABEL( elem.location + m_sheetOffset, elem.name ); {
//} label = new SCH_HIERLABEL label, 0 to use ( position, aElem.Name );
}
#else
label = new SCH_GLOBALLABEL( position, aElem.Name ); label = new SCH_GLOBALLABEL( position, aElem.Name );
#endif
switch( aElem.IOtype ) switch( aElem.IOtype )
{ {
@ -2516,7 +2527,9 @@ void SCH_ALTIUM_PLUGIN::ParsePort( const ASCH_PORT& aElem )
label->AutoplaceFields( screen, false ); label->AutoplaceFields( screen, false );
// Default "Sheet References" field should be hidden, at least for now // Default "Sheet References" field should be hidden, at least for now
label->GetFields()[0].SetVisible( false ); if( label->GetFields().size() > 0 )
label->GetFields()[0].SetVisible( false );
label->SetFlags( IS_NEW ); label->SetFlags( IS_NEW );
screen->Append( label ); screen->Append( label );
@ -2832,20 +2845,14 @@ void SCH_ALTIUM_PLUGIN::ParseDesignator( const std::map<wxString, wxString>& aPr
bool emptyRef = elem.text.IsEmpty(); bool emptyRef = elem.text.IsEmpty();
symbol->SetRef( &m_sheetPath, emptyRef ? "#GRAPHIC" : elem.text ); symbol->SetRef( &m_sheetPath, emptyRef ? "#GRAPHIC" : elem.text );
SCH_FIELD* field = symbol->GetField( VALUE_FIELD );
#if 0
// I am not sure value and ref should be invisible just because emptyRef is true // I am not sure value and ref should be invisible just because emptyRef is true
// I have examples with this criteria fully incorrect. // I have examples with this criteria fully incorrect.
if ( emptyRef ) bool visible = !emptyRef;
field->SetVisible( false );
field = symbol->GetField( REFERENCE_FIELD ); symbol->GetField( VALUE_FIELD )->SetVisible( visible );
symbol->GetField( REFERENCE_FIELD )->SetVisible( visible );
if ( emptyRef )
field->SetVisible( false );
#endif
SCH_FIELD* field = symbol->GetField( REFERENCE_FIELD );
field->SetPosition( elem.location + m_sheetOffset ); field->SetPosition( elem.location + m_sheetOffset );
SetTextPositioning( field, elem.justification, elem.orientation ); SetTextPositioning( field, elem.justification, elem.orientation );
} }