Run pinning on sides as well as corners.

Also fixes a bug in LIB_SHAPE's Normalize() which wasn't handling the
upside-down coordinate system.

Fixes https://gitlab.com/kicad/code/kicad/issues/11339
This commit is contained in:
Jeff Young 2022-04-07 11:51:00 +01:00
parent dead84e7a1
commit c17b90c8dc
5 changed files with 122 additions and 97 deletions

View File

@ -95,7 +95,7 @@ void LIB_SHAPE::Normalize()
{
VECTOR2I size = GetEnd() - GetPosition();
if( size.y < 0 )
if( size.y > 0 )
{
SetStartY( GetStartY() + size.y );
SetEndY( GetStartY() - size.y );

View File

@ -530,7 +530,6 @@ int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
/**
* Update the coordinates of 4 corners of a rectangle, according to constraints
* and the moved corner
* @param aEditedPointIndex is the corner id
* @param minWidth is the minimal width constraint
* @param minHeight is the minimal height constraint
* @param topLeft is the RECT_TOPLEFT to constraint
@ -538,13 +537,12 @@ int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
* @param botLeft is the RECT_BOTLEFT to constraint
* @param botRight is the RECT_BOTRIGHT to constraint
*/
static void pinEditedCorner( int aEditedPointIndex, int minWidth, int minHeight,
VECTOR2I& topLeft, VECTOR2I& topRight, VECTOR2I& botLeft,
VECTOR2I& botRight, EE_GRID_HELPER* aGrid )
void EE_POINT_EDITOR::pinEditedCorner( int minWidth, int minHeight, VECTOR2I& topLeft,
VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight,
EE_GRID_HELPER* aGrid ) const
{
switch( aEditedPointIndex )
if( isModified( m_editPoints->Point( RECT_TOPLEFT ) ) )
{
case RECT_TOPLEFT:
// pin edited point within opposite corner
topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
@ -554,10 +552,9 @@ static void pinEditedCorner( int aEditedPointIndex, int minWidth, int minHeight,
// push edited point edges to adjacent corners
topRight.y = topLeft.y;
botLeft.x = topLeft.x;
break;
case RECT_TOPRIGHT:
}
else if( isModified( m_editPoints->Point( RECT_TOPRIGHT ) ) )
{
// pin edited point within opposite corner
topRight.x = std::max( topRight.x, botLeft.x + minWidth );
topRight.y = std::min( topRight.y, botLeft.y - minHeight );
@ -567,10 +564,9 @@ static void pinEditedCorner( int aEditedPointIndex, int minWidth, int minHeight,
// push edited point edges to adjacent corners
topLeft.y = topRight.y;
botRight.x = topRight.x;
break;
case RECT_BOTLEFT:
}
else if( isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
{
// pin edited point within opposite corner
botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
@ -580,10 +576,9 @@ static void pinEditedCorner( int aEditedPointIndex, int minWidth, int minHeight,
// push edited point edges to adjacent corners
botRight.y = botLeft.y;
topLeft.x = botLeft.x;
break;
case RECT_BOTRIGHT:
}
else if( isModified( m_editPoints->Point( RECT_BOTRIGHT ) ) )
{
// pin edited point within opposite corner
botRight.x = std::max( botRight.x, topLeft.x + minWidth );
botRight.y = std::max( botRight.y, topLeft.y + minHeight );
@ -593,8 +588,26 @@ static void pinEditedCorner( int aEditedPointIndex, int minWidth, int minHeight,
// push edited point edges to adjacent corners
botLeft.y = botRight.y;
topRight.x = botRight.x;
break;
}
else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
{
topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
topLeft = aGrid->AlignGrid( topLeft );
}
else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
{
topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
topLeft = aGrid->AlignGrid( topLeft );
}
else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
{
botRight.y = std::max( botRight.y, topLeft.y + minHeight );
botRight = aGrid->AlignGrid( botRight );
}
else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
{
botRight.x = std::max( botRight.x, topLeft.x + minWidth );
botRight = aGrid->AlignGrid( botRight );
}
}
@ -657,14 +670,14 @@ void EE_POINT_EDITOR::updateParentItem() const
VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
pinEditedCorner( Mils2iu( 1 ), Mils2iu( 1 ), topLeft, topRight, botLeft, botRight,
&gridHelper );
if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
|| isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
{
pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ),
topLeft, topRight, botLeft, botRight, &gridHelper );
shape->SetPosition( mapCoords( topLeft ) );
shape->SetEnd( mapCoords( botRight ) );
}
@ -717,14 +730,14 @@ void EE_POINT_EDITOR::updateParentItem() const
VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
pinEditedCorner( Mils2iu( 1 ), Mils2iu( 1 ), topLeft, topRight, botLeft, botRight,
&gridHelper );
if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
|| isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
{
pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ),
topLeft, topRight, botLeft, botRight, &gridHelper );
textbox->SetPosition( mapCoords( topLeft ) );
textbox->SetEnd( mapCoords( botRight ) );
}
@ -807,14 +820,14 @@ void EE_POINT_EDITOR::updateParentItem() const
VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
pinEditedCorner( Mils2iu( 1 ), Mils2iu( 1 ), topLeft, topRight, botLeft, botRight,
&gridHelper );
if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
|| isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
{
pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ),
topLeft, topRight, botLeft, botRight, &gridHelper );
shape->SetPosition( topLeft );
shape->SetEnd( botRight );
}
@ -867,14 +880,14 @@ void EE_POINT_EDITOR::updateParentItem() const
VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
pinEditedCorner( Mils2iu( 1 ), Mils2iu( 1 ), topLeft, topRight, botLeft, botRight,
&gridHelper );
if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
|| isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
{
pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ),
topLeft, topRight, botLeft, botRight, &gridHelper );
textBox->SetPosition( topLeft );
textBox->SetEnd( botRight );
}
@ -917,8 +930,8 @@ void EE_POINT_EDITOR::updateParentItem() const
VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
pinEditedCorner( getEditedPointIndex(), Mils2iu( 50 ), Mils2iu( 50 ),
topLeft, topRight, botLeft, botRight, &gridHelper );
pinEditedCorner( Mils2iu( 50 ), Mils2iu( 50 ), topLeft, topRight, botLeft, botRight,
&gridHelper );
double oldWidth = bitmap->GetSize().x;
double newWidth = topRight.x - topLeft.x;
@ -942,8 +955,7 @@ void EE_POINT_EDITOR::updateParentItem() const
VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
int edited = getEditedPointIndex();
pinEditedCorner( getEditedPointIndex(),
sheet->GetMinWidth( edited == RECT_TOPRIGHT || edited == RECT_BOTRIGHT ),
pinEditedCorner( sheet->GetMinWidth( edited == RECT_TOPRIGHT || edited == RECT_BOTRIGHT ),
sheet->GetMinHeight( edited == RECT_BOTLEFT || edited == RECT_BOTRIGHT ),
topLeft, topRight, botLeft, botRight, &gridHelper );

View File

@ -90,6 +90,9 @@ private:
return wxNOT_FOUND;
}
void pinEditedCorner( int minWidth, int minHeight, VECTOR2I& topLeft, VECTOR2I& topRight,
VECTOR2I& botLeft, VECTOR2I& botRight, EE_GRID_HELPER* aGrid ) const;
bool addCornerCondition( const SELECTION& aSelection );
bool removeCornerCondition( const SELECTION& aSelection );

View File

@ -816,9 +816,6 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
/**
* Update the coordinates of 4 corners of a rectangle, according to pad constraints and the
* moved corner
* @param aEditedPointIndex is the corner id
* @param aMinWidth is the minimal width constraint
* @param aMinHeight is the minimal height constraint
* @param aTopLeft [in/out] is the RECT_TOPLEFT to constraint
* @param aTopRight [in/out] is the RECT_TOPRIGHT to constraint
* @param aBotLeft [in/out] is the RECT_BOTLEFT to constraint
@ -826,91 +823,104 @@ void PCB_POINT_EDITOR::editArcEndpointKeepTangent( PCB_SHAPE* aArc, const VECTOR
* @param aHole the location of the pad's hole
* @param aHoleSize the pad's hole size (or {0,0} if it has no hole)
*/
static void pinEditedCorner( int aEditedPointIndex, int aMinWidth, int aMinHeight,
VECTOR2I& aTopLeft, VECTOR2I& aTopRight, VECTOR2I& aBotLeft,
VECTOR2I& aBotRight, VECTOR2I& aHole, VECTOR2I& aHoleSize )
void PCB_POINT_EDITOR::pinEditedCorner( VECTOR2I& aTopLeft, VECTOR2I& aTopRight,
VECTOR2I& aBotLeft, VECTOR2I& aBotRight,
const VECTOR2I& aHole, const VECTOR2I& aHoleSize ) const
{
switch( aEditedPointIndex )
int minWidth = Mils2iu( 1 );
int minHeight = Mils2iu( 1 );
if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) ) )
{
case RECT_TOP_LEFT:
if( aHoleSize.x )
{
// pin edited point to the top/left of the hole
aTopLeft.x = std::min( aTopLeft.x, aHole.x - aHoleSize.x / 2 - aMinWidth );
aTopLeft.y = std::min( aTopLeft.y, aHole.y - aHoleSize.y / 2 - aMinHeight );
aTopLeft.x = std::min( aTopLeft.x, aHole.x - aHoleSize.x / 2 - minWidth );
aTopLeft.y = std::min( aTopLeft.y, aHole.y - aHoleSize.y / 2 - minHeight );
}
else
{
// pin edited point within opposite corner
aTopLeft.x = std::min( aTopLeft.x, aBotRight.x - aMinWidth );
aTopLeft.y = std::min( aTopLeft.y, aBotRight.y - aMinHeight );
aTopLeft.x = std::min( aTopLeft.x, aBotRight.x - minWidth );
aTopLeft.y = std::min( aTopLeft.y, aBotRight.y - minHeight );
}
// push edited point edges to adjacent corners
aTopRight.y = aTopLeft.y;
aBotLeft.x = aTopLeft.x;
break;
case RECT_TOP_RIGHT:
}
else if( isModified( m_editPoints->Point( RECT_TOP_RIGHT ) ) )
{
if( aHoleSize.x )
{
// pin edited point to the top/right of the hole
aTopRight.x = std::max( aTopRight.x, aHole.x + aHoleSize.x / 2 + aMinWidth );
aTopRight.y = std::min( aTopRight.y, aHole.y - aHoleSize.y / 2 - aMinHeight );
aTopRight.x = std::max( aTopRight.x, aHole.x + aHoleSize.x / 2 + minWidth );
aTopRight.y = std::min( aTopRight.y, aHole.y - aHoleSize.y / 2 - minHeight );
}
else
{
// pin edited point within opposite corner
aTopRight.x = std::max( aTopRight.x, aBotLeft.x + aMinWidth );
aTopRight.y = std::min( aTopRight.y, aBotLeft.y - aMinHeight );
aTopRight.x = std::max( aTopRight.x, aBotLeft.x + minWidth );
aTopRight.y = std::min( aTopRight.y, aBotLeft.y - minHeight );
}
// push edited point edges to adjacent corners
aTopLeft.y = aTopRight.y;
aBotRight.x = aTopRight.x;
break;
case RECT_BOT_LEFT:
}
else if( isModified( m_editPoints->Point( RECT_BOT_LEFT ) ) )
{
if( aHoleSize.x )
{
// pin edited point to the bottom/left of the hole
aBotLeft.x = std::min( aBotLeft.x, aHole.x - aHoleSize.x / 2 - aMinWidth );
aBotLeft.y = std::max( aBotLeft.y, aHole.y + aHoleSize.y / 2 + aMinHeight );
aBotLeft.x = std::min( aBotLeft.x, aHole.x - aHoleSize.x / 2 - minWidth );
aBotLeft.y = std::max( aBotLeft.y, aHole.y + aHoleSize.y / 2 + minHeight );
}
else
{
// pin edited point within opposite corner
aBotLeft.x = std::min( aBotLeft.x, aTopRight.x - aMinWidth );
aBotLeft.y = std::max( aBotLeft.y, aTopRight.y + aMinHeight );
aBotLeft.x = std::min( aBotLeft.x, aTopRight.x - minWidth );
aBotLeft.y = std::max( aBotLeft.y, aTopRight.y + minHeight );
}
// push edited point edges to adjacent corners
aBotRight.y = aBotLeft.y;
aTopLeft.x = aBotLeft.x;
break;
case RECT_BOT_RIGHT:
}
else if( isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
{
if( aHoleSize.x )
{
// pin edited point to the bottom/right of the hole
aBotRight.x = std::max( aBotRight.x, aHole.x + aHoleSize.x / 2 + aMinWidth );
aBotRight.y = std::max( aBotRight.y, aHole.y + aHoleSize.y / 2 + aMinHeight );
aBotRight.x = std::max( aBotRight.x, aHole.x + aHoleSize.x / 2 + minWidth );
aBotRight.y = std::max( aBotRight.y, aHole.y + aHoleSize.y / 2 + minHeight );
}
else
{
// pin edited point within opposite corner
aBotRight.x = std::max( aBotRight.x, aTopLeft.x + aMinWidth );
aBotRight.y = std::max( aBotRight.y, aTopLeft.y + aMinHeight );
aBotRight.x = std::max( aBotRight.x, aTopLeft.x + minWidth );
aBotRight.y = std::max( aBotRight.y, aTopLeft.y + minHeight );
}
// push edited point edges to adjacent corners
aBotLeft.y = aBotRight.y;
aTopRight.x = aBotRight.x;
break;
}
else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
{
aTopLeft.y = std::min( aTopLeft.y, aBotRight.y - minHeight );
}
else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
{
aTopLeft.x = std::min( aTopLeft.x, aBotRight.x - minWidth );
}
else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
{
aBotRight.y = std::max( aBotRight.y, aTopLeft.y + minHeight );
}
else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
{
aBotRight.x = std::max( aBotRight.x, aTopLeft.x + minWidth );
}
}
@ -1089,39 +1099,36 @@ void PCB_POINT_EDITOR::updateItem() const
case SHAPE_T::RECT:
{
if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) ) )
VECTOR2I topLeft = m_editPoints->Point( RECT_TOP_LEFT ).GetPosition();
VECTOR2I topRight = m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition();
VECTOR2I botLeft = m_editPoints->Point( RECT_BOT_LEFT ).GetPosition();
VECTOR2I botRight = m_editPoints->Point( RECT_BOT_RIGHT ).GetPosition();
pinEditedCorner( topLeft, topRight, botLeft, botRight );
if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) )
|| isModified( m_editPoints->Point( RECT_TOP_RIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOT_RIGHT ) )
|| isModified( m_editPoints->Point( RECT_BOT_LEFT ) ) )
{
shape->SetStart( m_editPoints->Point( RECT_TOP_LEFT ).GetPosition() );
}
else if( isModified( m_editPoints->Point( RECT_TOP_RIGHT ) ) )
{
shape->SetStartY( m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition().y );
shape->SetEndX( m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition().x );
}
else if( isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
{
shape->SetEnd( m_editPoints->Point( RECT_BOT_RIGHT ).GetPosition() );
}
else if( isModified( m_editPoints->Point( RECT_BOT_LEFT ) ) )
{
shape->SetStartX( m_editPoints->Point( RECT_BOT_LEFT ).GetPosition().x );
shape->SetEndY( m_editPoints->Point( RECT_BOT_LEFT ).GetPosition().y );
shape->SetPosition( topLeft );
shape->SetEnd( botRight );
}
else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
{
shape->SetStartY( m_editPoints->Point( RECT_TOP_LEFT ).GetPosition().y );
shape->SetStartY( topLeft.y );
}
else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
{
shape->SetStartX( m_editPoints->Point( RECT_BOT_LEFT ).GetPosition().x );
shape->SetStartX( topLeft.x );
}
else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
{
shape->SetEndY( m_editPoints->Point( RECT_BOT_RIGHT ).GetPosition().y );
shape->SetEndY( botRight.y );
}
else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
{
shape->SetEndX( m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition().x );
shape->SetEndX( botRight.x );
}
for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
@ -1268,8 +1275,7 @@ void PCB_POINT_EDITOR::updateItem() const
VECTOR2I holeCenter = pad->GetPosition();
VECTOR2I holeSize = pad->GetDrillSize();
pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ), topLeft, topRight,
botLeft, botRight, holeCenter, holeSize );
pinEditedCorner( topLeft, topRight, botLeft, botRight, holeCenter, holeSize );
if( ( pad->GetOffset().x || pad->GetOffset().y )
|| ( pad->GetDrillSize().x && pad->GetDrillSize().y ) )

View File

@ -108,6 +108,10 @@ private:
return m_editedPoint == &aPoint;
}
void pinEditedCorner( VECTOR2I& aTopLeft, VECTOR2I& aTopRight, VECTOR2I& aBotLeft,
VECTOR2I& aBotRight, const VECTOR2I& aHole = { 0, 0 },
const VECTOR2I& aHoleSize = { 0, 0 } ) const;
///< Set up an alternative constraint (typically enabled upon a modifier key being pressed).
void setAltConstraint( bool aEnabled );