Try out a new arc-editing paradigm for LibEdit.

This is based on the notion that in Kicad the start and end-points
are far more important (as they usually connect to other segments)
than the center is.
This commit is contained in:
Jeff Young 2019-06-29 14:39:46 +01:00
parent bcf690f901
commit a498d7e9c5
5 changed files with 88 additions and 70 deletions

View File

@ -35,6 +35,7 @@
#include <general.h>
#include <lib_arc.h>
#include <transform.h>
#include <status_popup.h>
// Helper function
static inline wxPoint twoPointVector( const wxPoint &startPoint, const wxPoint &endPoint )
@ -52,10 +53,6 @@ LIB_ARC::LIB_ARC( LIB_PART* aParent ) : LIB_ITEM( LIB_ARC_T, aParent )
m_Fill = NO_FILL;
m_isFillable = true;
m_editState = 0;
m_lastEditState = 0;
m_editCenterDistance = 0.0;
m_editSelectPoint = ARC_STATUS_START;
m_editDirection = 0;
}
@ -426,64 +423,76 @@ BITMAP_DEF LIB_ARC::GetMenuImage() const
void LIB_ARC::BeginEdit( const wxPoint aPosition )
{
m_ArcStart = m_ArcEnd = aPosition;
m_editState = m_lastEditState = 1;
}
bool LIB_ARC::ContinueEdit( const wxPoint aPosition )
{
if( m_editState == 1 ) // Second position yields the arc segment length.
{
m_ArcEnd = aPosition;
m_editState = 2;
return true; // Need third position to calculate center point.
}
return false;
}
void LIB_ARC::EndEdit()
{
m_lastEditState = 0;
m_editState = 0;
m_editState = 1;
}
void LIB_ARC::CalcEdit( const wxPoint& aPosition )
{
if( m_editState == 1 )
// Edit state 0: drawing: place ArcStart
// Edit state 1: drawing: place ArcEnd (center calculated for 90-degree subtended angle)
// Edit state 2: point editing: move ArcStart (center calculated for invariant subtended angle)
// Edit state 3: point editing: move ArcEnd (center calculated for invariant subtended angle)
// Edit state 4: point editing: move center
switch( m_editState )
{
case 0:
m_ArcStart = aPosition;
m_ArcEnd = aPosition;
m_Pos = aPosition;
break;
case 1:
m_ArcEnd = aPosition;
m_Radius = KiROUND( sqrt( pow( GetLineLength( m_ArcStart, m_ArcEnd ), 2 ) / 2.0 ) );
break;
case 2:
case 3:
{
wxPoint v = m_ArcStart - m_ArcEnd;
double chordBefore = v.x * v.x + v.y * v.y;
if( m_editState == 2 )
m_ArcStart = aPosition;
else
m_ArcEnd = aPosition;
v = m_ArcStart - m_ArcEnd;
double chordAfter = v.x * v.x + v.y * v.y;
double ratio = chordAfter / chordBefore;
m_Radius = KiROUND( sqrt( m_Radius * m_Radius * ratio ) );
break;
}
if( m_editState != m_lastEditState )
m_lastEditState = m_editState;
case 4:
m_Radius = KiROUND( ( GetLineLength( m_ArcStart, aPosition )
+ GetLineLength( m_ArcEnd, aPosition ) ) / 2.0 );
break;
}
// Keep the arc center point up to date. Otherwise, there will be edit graphic
// artifacts left behind from the initial draw.
int dx, dy;
int cX, cY;
double angle;
// Calculate center based on start, end, and radius
//
// Let 'l' be the length of the chord and 'm' the middle point of the chord
double l = GetLineLength( m_ArcStart, m_ArcEnd );
wxPoint m = ( m_ArcStart + m_ArcEnd ) / 2;
cX = aPosition.x;
cY = aPosition.y;
// Calculate 'd', the vector from the chord midpoint to the center
wxPoint d;
d.x = KiROUND( sqrt( pow( m_Radius, 2 ) - pow( l/2, 2) ) * ( m_ArcStart.y - m_ArcEnd.y ) / l );
d.y = KiROUND( sqrt( pow( m_Radius, 2 ) - pow( l/2, 2) ) * ( m_ArcEnd.x - m_ArcStart.x ) / l );
dx = m_ArcEnd.x - m_ArcStart.x;
dy = m_ArcEnd.y - m_ArcStart.y;
cX -= m_ArcStart.x;
cY -= m_ArcStart.y;
angle = ArcTangente( dy, dx );
RotatePoint( &dx, &dy, angle ); /* The segment dx, dy is horizontal
* -> Length = dx, dy = 0 */
RotatePoint( &cX, &cY, angle );
cX = dx / 2; /* cX, cY is on the median segment 0.0 a dx, 0 */
if( d.x < 0 || d.y < 0 ) // sqrt() doesn't like really small numbers...
d = { 0, 0 };
wxPoint c1 = m + d;
wxPoint c2 = m - d;
wxPoint test = ( m_editState == 4 ) ? aPosition : m_Pos;
m_Pos = ( GetLineLength( c1, test ) < GetLineLength( c2, test ) ) ? c1 : c2;
RotatePoint( &cX, &cY, -angle );
cX += m_ArcStart.x;
cY += m_ArcStart.y;
m_Pos.x = cX;
m_Pos.y = cY;
CalcRadiusAngles();
}

View File

@ -47,11 +47,7 @@ class LIB_ARC : public LIB_ITEM
wxPoint m_ArcEnd; /* Arc end position. */
wxPoint m_Pos; /* Radius center point. */
int m_Width; /* Line width */
double m_editCenterDistance;
SELECT_T m_editSelectPoint;
int m_editState;
int m_editDirection;
int m_lastEditState;
void print( wxDC* aDC, const wxPoint& aOffset, void* aData,
const TRANSFORM& aTransform ) override;
@ -84,8 +80,7 @@ public:
void BeginEdit( const wxPoint aStartPoint ) override;
void CalcEdit( const wxPoint& aPosition ) override;
bool ContinueEdit( const wxPoint aNextPoint ) override;
void EndEdit() override;
void SetEditState( int aState ) { m_editState = aState; }
void Offset( const wxPoint& aOffset ) override;

View File

@ -249,9 +249,6 @@ void EE_POINT_EDITOR::updateEditedPoint( const TOOL_EVENT& aEvent )
if( m_editedPoint != point )
setEditedPoint( point );
if( point )
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
}
@ -427,10 +424,24 @@ void EE_POINT_EDITOR::updateItem() const
case LIB_ARC_T:
{
LIB_ARC* arc = (LIB_ARC*) item;
int i = getEditedPointIndex();
if( i == ARC_CENTER )
{
arc->SetEditState( 4 );
arc->CalcEdit( mapCoords( m_editPoints->Point( ARC_CENTER ).GetPosition() ) );
}
else if( i == ARC_START )
{
arc->SetEditState( 2 );
arc->CalcEdit( mapCoords( m_editPoints->Point( ARC_START ).GetPosition() ) );
}
else if( i == ARC_END )
{
arc->SetEditState( 3 );
arc->CalcEdit( mapCoords( m_editPoints->Point( ARC_END ).GetPosition() ) );
}
arc->SetPosition( mapCoords( m_editPoints->Point( ARC_CENTER ).GetPosition() ) );
arc->SetStart( mapCoords( m_editPoints->Point( ARC_START ).GetPosition() ) );
arc->SetEnd( mapCoords( m_editPoints->Point( ARC_END ).GetPosition() ) );
break;
}
@ -685,12 +696,15 @@ void EE_POINT_EDITOR::setEditedPoint( EDIT_POINT* aPoint )
if( aPoint )
{
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
controls->ForceCursorPosition( true, aPoint->GetPosition() );
controls->ShowCursor( true );
}
else
{
controls->ShowCursor( false );
if( m_frame->ToolStackIsEmpty() )
controls->ShowCursor( false );
controls->ForceCursorPosition( false );
}

View File

@ -144,9 +144,6 @@ void PL_POINT_EDITOR::updateEditedPoint( const TOOL_EVENT& aEvent )
if( m_editedPoint != point )
setEditedPoint( point );
if( point )
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
}
@ -396,12 +393,15 @@ void PL_POINT_EDITOR::setEditedPoint( EDIT_POINT* aPoint )
if( aPoint )
{
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
controls->ForceCursorPosition( true, aPoint->GetPosition() );
controls->ShowCursor( true );
}
else
{
controls->ShowCursor( false );
if( m_frame->ToolStackIsEmpty() )
controls->ShowCursor( false );
controls->ForceCursorPosition( false );
}

View File

@ -287,9 +287,6 @@ void POINT_EDITOR::updateEditedPoint( const TOOL_EVENT& aEvent )
if( m_editedPoint != point )
setEditedPoint( point );
if( point )
frame()->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
}
@ -788,12 +785,15 @@ void POINT_EDITOR::setEditedPoint( EDIT_POINT* aPoint )
if( aPoint )
{
frame()->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
controls->ForceCursorPosition( true, aPoint->GetPosition() );
controls->ShowCursor( true );
}
else
{
controls->ShowCursor( false );
if( frame()->ToolStackIsEmpty() )
controls->ShowCursor( false );
controls->ForceCursorPosition( false );
}