Bug fixes for PCB_TABLES.

In particular, rotated tables and tables in rotated
footprints.
This commit is contained in:
Jeff Young 2024-06-19 12:39:02 +01:00
parent 251ed2ee54
commit 8e349eedf0
8 changed files with 182 additions and 57 deletions

View File

@ -97,7 +97,7 @@ public:
KIGFX::COLOR4D GetColor() const { return m_color; }
void SetColor( const KIGFX::COLOR4D& aColor ) { m_color = aColor; }
bool operator!=( const STROKE_PARAMS& aOther )
bool operator!=( const STROKE_PARAMS& aOther ) const
{
return m_width != aOther.m_width
|| m_lineStyle != aOther.m_lineStyle

View File

@ -249,7 +249,7 @@ FOOTPRINT* BOARD_ITEM::GetParentFootprint() const
{
BOARD_ITEM_CONTAINER* ancestor = GetParent();
while( ancestor && ancestor->Type() == PCB_GROUP_T )
while( ancestor && ancestor->IsType( { PCB_GROUP_T, PCB_GENERATOR_T, PCB_TABLE_T } ) )
ancestor = ancestor->GetParent();
if( ancestor && ancestor->Type() == PCB_FOOTPRINT_T )

View File

@ -1982,14 +1982,27 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_TABLE* aTable, int aNestLevel ) const
{
wxCHECK_RET( aTable != nullptr && m_out != nullptr, "" );
m_out->Print( aNestLevel, "(table (column_count %d)\n",
m_out->Print( aNestLevel, "(table (column_count %d)",
aTable->GetColCount() );
if( aTable->IsLocked() )
KICAD_FORMAT::FormatBool( m_out, aNestLevel, "locked", aTable->IsLocked() );
KICAD_FORMAT::FormatBool( m_out, 0, "locked", aTable->IsLocked() );
EDA_ANGLE angle = aTable->GetOrientation();
if( FOOTPRINT* parentFP = aTable->GetParentFootprint() )
{
angle -= parentFP->GetOrientation();
angle.Normalize720();
}
if( !angle.IsZero() )
m_out->Print( 0, " (angle %s)", EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
formatLayer( aTable->GetLayer() );
m_out->Print( 0, "\n" );
m_out->Print( aNestLevel + 1, "(border (external %s) (header %s)",
aTable->StrokeExternal() ? "yes" : "no",
aTable->StrokeHeader() ? "yes" : "no" );

View File

@ -154,7 +154,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
//#define SEXPR_BOARD_FILE_VERSION 20240201 // Use nullable properties for overrides
//#define SEXPR_BOARD_FILE_VERSION 20240202 // Tables
//#define SEXPR_BOARD_FILE_VERSION 20240225 // Rationalization of solder_paste_margin
#define SEXPR_BOARD_FILE_VERSION 20240609 // Add 'tenting' keyword
//#define SEXPR_BOARD_FILE_VERSION 20240609 // Add 'tenting' keyword
#define SEXPR_BOARD_FILE_VERSION 20240617 // Table angles
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting

View File

@ -1190,26 +1190,27 @@ BOARD* PCB_IO_KICAD_SEXPR_PARSER::parseBOARD_unchecked()
void PCB_IO_KICAD_SEXPR_PARSER::resolveGroups( BOARD_ITEM* aParent )
{
auto getItem = [&]( const KIID& aId )
{
BOARD_ITEM* aItem = nullptr;
auto getItem =
[&]( const KIID& aId )
{
BOARD_ITEM* aItem = nullptr;
if( BOARD* board = dynamic_cast<BOARD*>( aParent ) )
{
aItem = board->GetItem( aId );
}
else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aParent ) )
{
footprint->RunOnChildren(
[&]( BOARD_ITEM* child )
{
if( child->m_Uuid == aId )
aItem = child;
} );
}
if( BOARD* board = dynamic_cast<BOARD*>( aParent ) )
{
aItem = board->GetItem( aId );
}
else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aParent ) )
{
footprint->RunOnChildren(
[&]( BOARD_ITEM* child )
{
if( child->m_Uuid == aId )
aItem = child;
} );
}
return aItem;
};
return aItem;
};
// Now that we've parsed the other Uuids in the file we can resolve the uuids referred
// to in the group declarations we saw.
@ -3081,7 +3082,7 @@ PCB_SHAPE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_SHAPE( BOARD_ITEM* aParent )
shape->SetStroke( stroke );
if( FOOTPRINT* parentFP = dynamic_cast<FOOTPRINT*>( aParent ) )
if( FOOTPRINT* parentFP = shape->GetParentFootprint() )
{
shape->Rotate( { 0, 0 }, parentFP->GetOrientation() );
shape->Move( parentFP->GetPosition() );
@ -3568,7 +3569,7 @@ void PCB_IO_KICAD_SEXPR_PARSER::parseTextBoxContent( PCB_TEXTBOX* aTextBox )
aTextBox->SetMarginBottom( margin );
}
if( FOOTPRINT* parentFP = dynamic_cast<FOOTPRINT*>( aTextBox->GetParent() ) )
if( FOOTPRINT* parentFP = aTextBox->GetParentFootprint() )
{
aTextBox->Rotate( { 0, 0 }, parentFP->GetOrientation() );
aTextBox->Move( parentFP->GetPosition() );
@ -3588,12 +3589,6 @@ PCB_TABLE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_TABLE( BOARD_ITEM* aParent )
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token == T_locked )
{
table->SetLocked( true );
token = NextTok();
}
if( token != T_LEFT )
Expecting( T_LEFT );
@ -3606,6 +3601,16 @@ PCB_TABLE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_TABLE( BOARD_ITEM* aParent )
NeedRIGHT();
break;
case T_locked:
table->SetLocked( parseBool() );
NeedRIGHT();
break;
case T_angle:
table->SetOrientation( EDA_ANGLE( parseDouble( "table angle" ), DEGREES_T ) );
NeedRIGHT();
break;
case T_layer:
table->SetLayer( parseBoardItemLayer() );
NeedRIGHT();
@ -3733,6 +3738,9 @@ PCB_TABLE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_TABLE( BOARD_ITEM* aParent )
}
}
if( FOOTPRINT* parentFP = table->GetParentFootprint() )
table->SetOrientation( table->GetOrientation() + parentFP->GetOrientation() );
return table.release();
}

View File

@ -2301,8 +2301,9 @@ void PCB_PAINTER::draw( const PCB_TABLE* aTable, int aLayer )
for( PCB_TABLECELL* cell : aTable->GetCells() )
draw( static_cast<PCB_TEXTBOX*>( cell ), aLayer );
VECTOR2I pos = aTable->GetPosition();
VECTOR2I end = aTable->GetEnd();
VECTOR2I pos = aTable->GetPosition();
VECTOR2I end = aTable->GetEnd();
EDA_ANGLE drawOrientation = aTable->GetOrientation();
// Selection for tables is done with a background wash, so pass in nullptr to GetColor()
// so we just get the "normal" (un-selected/un-brightened) color for the borders.
@ -2326,8 +2327,11 @@ void PCB_PAINTER::draw( const PCB_TABLE* aTable, int aLayer )
[&]( const SHAPE& shape )
{
STROKE_PARAMS::Stroke( &shape, lineStyle, lineWidth, &m_pcbSettings,
[&]( const VECTOR2I& a, const VECTOR2I& b )
[&]( VECTOR2I a, VECTOR2I b )
{
RotatePoint( a, pos, drawOrientation );
RotatePoint( b, pos, drawOrientation );
// DrawLine has problem with 0 length lines so enforce minimum
if( a == b )
m_gal->DrawLine( a+1, b );
@ -2337,8 +2341,11 @@ void PCB_PAINTER::draw( const PCB_TABLE* aTable, int aLayer )
};
auto strokeLine =
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
[&]( VECTOR2I ptA, VECTOR2I ptB )
{
RotatePoint( ptA, pos, drawOrientation );
RotatePoint( ptB, pos, drawOrientation );
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
m_gal->DrawLine( ptA, ptB );
@ -2351,8 +2358,11 @@ void PCB_PAINTER::draw( const PCB_TABLE* aTable, int aLayer )
};
auto strokeRect =
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
[&]( VECTOR2I ptA, VECTOR2I ptB )
{
RotatePoint( ptA, pos, drawOrientation );
RotatePoint( ptB, pos, drawOrientation );
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
m_gal->DrawRectangle( ptA, ptB );
@ -2370,31 +2380,47 @@ void PCB_PAINTER::draw( const PCB_TABLE* aTable, int aLayer )
if( aTable->StrokeColumns() )
{
int x = pos.x;
for( int col = 0; col < aTable->GetColCount() - 1; ++col )
{
int y = pos.y;
for( int row = 0; row < aTable->GetRowCount(); ++row )
{
PCB_TABLECELL* cell = aTable->GetCell( row, col );
VECTOR2I topRight( cell->GetEndX(), cell->GetStartY() );
int rowHeight = aTable->GetRowHeight( row );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
strokeLine( topRight, cell->GetEnd() );
strokeLine( VECTOR2I( x, y ), VECTOR2I( x, y + rowHeight ) );
y += rowHeight;
}
x += aTable->GetColWidth( col );
}
}
if( aTable->StrokeRows() )
{
int y = pos.y;
for( int row = 0; row < aTable->GetRowCount() - 1; ++row )
{
int x = pos.x;
for( int col = 0; col < aTable->GetColCount(); ++col )
{
PCB_TABLECELL* cell = aTable->GetCell( row, col );
VECTOR2I botLeft( cell->GetStartX(), cell->GetEndY() );
int colWidth = aTable->GetColWidth( col );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
strokeLine( botLeft, cell->GetEnd() );
strokeLine( VECTOR2I( x, y ), VECTOR2I( x + colWidth, y ) );
x += colWidth;
}
y += aTable->GetRowHeight( row );
}
}
}
@ -2405,8 +2431,9 @@ void PCB_PAINTER::draw( const PCB_TABLE* aTable, int aLayer )
if( aTable->StrokeHeader() )
{
PCB_TABLECELL* cell = aTable->GetCell( 0, 0 );
strokeLine( VECTOR2I( pos.x, cell->GetEndY() ), VECTOR2I( end.x, cell->GetEndY() ) );
int headerBottom = pos.y + aTable->GetRowHeight( 0 );
strokeLine( VECTOR2I( pos.x, headerBottom ), VECTOR2I( end.x, headerBottom ) );
}
if( aTable->StrokeExternal() )

View File

@ -22,6 +22,7 @@
*/
#include <pcb_edit_frame.h>
#include <footprint.h>
#include <pcb_table.h>
#include <board.h>
#include <geometry/shape_simple.h>
@ -52,6 +53,7 @@ PCB_TABLE::PCB_TABLE( const PCB_TABLE& aTable ) :
m_strokeColumns = aTable.m_strokeColumns;
m_separatorsStroke = aTable.m_separatorsStroke;
m_orientation = aTable.m_orientation;
m_colCount = aTable.m_colCount;
m_colWidths = aTable.m_colWidths;
m_rowHeights = aTable.m_rowHeights;
@ -86,6 +88,7 @@ void PCB_TABLE::swapData( BOARD_ITEM* aImage )
std::swap( m_strokeColumns, table->m_strokeColumns );
std::swap( m_separatorsStroke, table->m_separatorsStroke );
std::swap( m_orientation, table->m_orientation );
std::swap( m_colCount, table->m_colCount );
std::swap( m_colWidths, table->m_colWidths );
std::swap( m_rowHeights, table->m_rowHeights );
@ -128,13 +131,37 @@ VECTOR2I PCB_TABLE::GetEnd() const
void PCB_TABLE::Normalize()
{
// JEY TODO: pukes on rotated tables...
VECTOR2I origin = GetPosition();
int y = GetPosition().y;
auto setCellStart =
[&]( PCB_TABLECELL* cell, VECTOR2I pt )
{
RotatePoint( pt, origin, m_orientation );
if( cell->GetPosition() != pt )
{
cell->SetPosition( pt );
cell->ClearRenderCache();
}
};
auto setCellEnd =
[&]( PCB_TABLECELL* cell, VECTOR2I pt )
{
RotatePoint( pt, origin, m_orientation );
if( cell->GetEnd() != pt )
{
cell->SetEnd( pt );
cell->ClearRenderCache();
}
};
int y = origin.y;
for( int row = 0; row < GetRowCount(); ++row )
{
int x = GetPosition().x;
int x = origin.x;
int rowHeight = m_rowHeights[ row ];
for( int col = 0; col < GetColCount(); ++col )
@ -144,13 +171,9 @@ void PCB_TABLE::Normalize()
PCB_TABLECELL* cell = GetCell( row, col );
VECTOR2I pos( x, y );
if( cell->GetPosition() != pos )
{
cell->SetPosition( pos );
cell->ClearRenderCache();
}
setCellStart( cell, pos );
VECTOR2I end = cell->GetStart() + VECTOR2I( colWidth, rowHeight );
VECTOR2I end = pos + VECTOR2I( colWidth, rowHeight );
if( cell->GetColSpan() > 1 || cell->GetRowSpan() > 1 )
{
@ -161,12 +184,7 @@ void PCB_TABLE::Normalize()
end.y += m_rowHeights[ii];
}
if( cell->GetEnd() != end )
{
cell->SetEnd( end );
cell->ClearRenderCache();
}
setCellEnd( cell, end );
x += colWidth;
}
@ -184,6 +202,8 @@ void PCB_TABLE::Move( const VECTOR2I& aMoveVector )
void PCB_TABLE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
{
m_orientation = ( m_orientation + aAngle ).Normalized();
for( PCB_TABLECELL* cell : m_cells )
cell->Rotate( aRotCentre, aAngle );
@ -428,6 +448,27 @@ bool PCB_TABLE::operator==( const BOARD_ITEM& aOther ) const
if( m_cells.size() != other.m_cells.size() )
return false;
if( m_strokeExternal != other.m_strokeExternal )
return false;
if( m_strokeHeader != other.m_strokeHeader )
return false;
if( m_borderStroke != other.m_borderStroke )
return false;
if( m_strokeRows != other.m_strokeRows )
return false;
if( m_strokeColumns != other.m_strokeColumns )
return false;
if( m_separatorsStroke != other.m_separatorsStroke )
return false;
if( m_orientation != other.m_orientation )
return false;
if( m_colWidths != other.m_colWidths )
return false;
@ -456,6 +497,33 @@ double PCB_TABLE::Similarity( const BOARD_ITEM& aOther ) const
double similarity = 1.0;
if( m_strokeExternal != other.m_strokeExternal )
similarity *= 0.9;
if( m_strokeHeader != other.m_strokeHeader )
similarity *= 0.9;
if( m_borderStroke != other.m_borderStroke )
similarity *= 0.9;
if( m_strokeRows != other.m_strokeRows )
similarity *= 0.9;
if( m_strokeColumns != other.m_strokeColumns )
similarity *= 0.9;
if( m_separatorsStroke != other.m_separatorsStroke )
similarity *= 0.9;
if( m_orientation != other.m_orientation )
similarity *= 0.9;
if( m_colWidths != other.m_colWidths )
similarity *= 0.9;
if( m_rowHeights != other.m_rowHeights )
similarity *= 0.9;
for( int ii = 0; ii < (int) m_cells.size(); ++ii )
similarity *= m_cells[ii]->Similarity( *other.m_cells[ii] );
@ -494,6 +562,10 @@ static struct PCB_TABLE_DESC
&PCB_TABLE::SetPositionY, &PCB_TABLE::GetPositionY, PROPERTY_DISPLAY::PT_COORD,
ORIGIN_TRANSFORMS::ABS_Y_COORD ) );
propMgr.AddProperty( new PROPERTY<PCB_TABLE, EDA_ANGLE>( _HKI( "Orientation" ),
&PCB_TABLE::SetOrientation, &PCB_TABLE::GetOrientation,
PROPERTY_DISPLAY::PT_DEGREE ) );
const wxString tableProps = _( "Table Properties" );
propMgr.AddProperty( new PROPERTY<PCB_TABLE, bool>( _HKI( "External Border" ),

View File

@ -97,6 +97,9 @@ public:
int GetPositionX() const { return GetPosition().x; }
int GetPositionY() const { return GetPosition().y; }
void SetOrientation( const EDA_ANGLE& aAngle ) { m_orientation = aAngle; }
EDA_ANGLE GetOrientation() const { return m_orientation; }
void SetColCount( int aCount ) { m_colCount = aCount; }
int GetColCount() const { return m_colCount; }
@ -245,6 +248,7 @@ protected:
bool m_strokeColumns;
STROKE_PARAMS m_separatorsStroke;
EDA_ANGLE m_orientation;
int m_colCount;
std::map<int, int> m_colWidths;
std::map<int, int> m_rowHeights;