mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-04-19 23:21:41 +00:00
Point editor single-corner chamfer tool
Come up with a plausible default chamfer size, rather than prompting every time with a modal (and then you have to handle when the chanfer doesn't fit). This could be changed if it's more annoying this way. But if we had proper edge-dragging in zones, probably would be better than setting a chanfer manually. Also fix the GetNeighbourIndexes which seems to have always been broken (but is not actually used by anything at present). Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/16771
This commit is contained in:
parent
4455f2a5ac
commit
201b60c670
libs/kimath/src/geometry
pcbnew/tools
qa/tests/libs/kimath/geometry
@ -439,8 +439,8 @@ bool SHAPE_POLY_SET::GetNeighbourIndexes( int aGlobalIndex, int* aPrevious, int*
|
||||
|
||||
if( index.m_vertex == 0 )
|
||||
{
|
||||
index.m_vertex = lastpoint;
|
||||
inext.m_vertex = 1;
|
||||
index.m_vertex = lastpoint - 1;
|
||||
inext.m_vertex = 1;
|
||||
}
|
||||
else if( index.m_vertex == lastpoint )
|
||||
{
|
||||
@ -451,6 +451,9 @@ bool SHAPE_POLY_SET::GetNeighbourIndexes( int aGlobalIndex, int* aPrevious, int*
|
||||
{
|
||||
inext.m_vertex++;
|
||||
index.m_vertex--;
|
||||
|
||||
if( inext.m_vertex == lastpoint )
|
||||
inext.m_vertex = 0;
|
||||
}
|
||||
|
||||
if( aPrevious )
|
||||
|
@ -1973,6 +1973,13 @@ TOOL_ACTION PCB_ACTIONS::pointEditorRemoveCorner( TOOL_ACTION_ARGS()
|
||||
.Tooltip( _( "Remove corner" ) )
|
||||
.Icon( BITMAPS::delete_cursor ) );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::pointEditorChamferCorner( TOOL_ACTION_ARGS()
|
||||
.Name( "pcbnew.PointEditor.chamferCorner" )
|
||||
.Scope( AS_GLOBAL )
|
||||
.FriendlyName( _( "Chamfer Corner" ) )
|
||||
.Tooltip( _( "Chamfer corner" ) )
|
||||
.Icon( BITMAPS::chamfer ) );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::pointEditorArcKeepCenter( TOOL_ACTION_ARGS()
|
||||
.Name( "pcbnew.PointEditor.arcKeepCenter" )
|
||||
.Scope( AS_GLOBAL )
|
||||
|
@ -294,6 +294,7 @@ public:
|
||||
// Point Editor
|
||||
static TOOL_ACTION pointEditorAddCorner;
|
||||
static TOOL_ACTION pointEditorRemoveCorner;
|
||||
static TOOL_ACTION pointEditorChamferCorner;
|
||||
|
||||
static TOOL_ACTION pointEditorArcKeepCenter;
|
||||
static TOOL_ACTION pointEditorArcKeepEndpoint;
|
||||
|
@ -32,6 +32,7 @@ using namespace std::placeholders;
|
||||
#include <tool/tool_manager.h>
|
||||
#include <view/view_controls.h>
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <geometry/corner_operations.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/vector_utils.h>
|
||||
@ -154,6 +155,7 @@ bool PCB_POINT_EDITOR::Init()
|
||||
menu.AddItem( PCB_ACTIONS::pointEditorAddCorner, PCB_POINT_EDITOR::addCornerCondition );
|
||||
menu.AddItem( PCB_ACTIONS::pointEditorRemoveCorner,
|
||||
std::bind( &PCB_POINT_EDITOR::removeCornerCondition, this, _1 ) );
|
||||
menu.AddItem( PCB_ACTIONS::pointEditorChamferCorner, PCB_POINT_EDITOR::addCornerCondition );
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2824,6 +2826,105 @@ int PCB_POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
|
||||
|
||||
int PCB_POINT_EDITOR::chamferCorner( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
if( !m_editPoints || !m_editedPoint )
|
||||
return 0;
|
||||
|
||||
EDA_ITEM* item = m_editPoints->GetParent();
|
||||
|
||||
if( !item )
|
||||
return 0;
|
||||
|
||||
SHAPE_POLY_SET* polygon = nullptr;
|
||||
|
||||
if( item->Type() == PCB_ZONE_T )
|
||||
{
|
||||
ZONE* zone = static_cast<ZONE*>( item );
|
||||
polygon = zone->Outline();
|
||||
zone->SetNeedRefill( true );
|
||||
}
|
||||
else if( item->Type() == PCB_SHAPE_T )
|
||||
{
|
||||
PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
|
||||
|
||||
if( shape->GetShape() == SHAPE_T::POLY )
|
||||
polygon = &shape->GetPolyShape();
|
||||
}
|
||||
|
||||
if( !polygon )
|
||||
return 0;
|
||||
|
||||
// Search the best outline corner to break
|
||||
|
||||
PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
|
||||
BOARD_COMMIT commit( frame );
|
||||
const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
|
||||
|
||||
unsigned int nearestIdx = 0;
|
||||
unsigned int nearestDist = INT_MAX;
|
||||
|
||||
int curr_idx = 0;
|
||||
// Object to iterate through the corners of the outlines (main contour and its holes)
|
||||
SHAPE_POLY_SET::ITERATOR iterator = polygon->Iterate( 0, polygon->OutlineCount() - 1,
|
||||
/* IterateHoles */ true );
|
||||
|
||||
// Iterate through all the corners of the outlines and search the best segment
|
||||
for( ; iterator; iterator++, curr_idx++ )
|
||||
{
|
||||
unsigned int distance = polygon->CVertex( curr_idx ).Distance( cursorPos );
|
||||
|
||||
if( distance < nearestDist )
|
||||
{
|
||||
nearestDist = distance;
|
||||
nearestIdx = curr_idx;
|
||||
}
|
||||
}
|
||||
|
||||
int prevIdx, nextIdx;
|
||||
if( polygon->GetNeighbourIndexes( nearestIdx, &prevIdx, &nextIdx ) )
|
||||
{
|
||||
const SEG segA{ polygon->CVertex( prevIdx ), polygon->CVertex( nearestIdx ) };
|
||||
const SEG segB{ polygon->CVertex( nextIdx ), polygon->CVertex( nearestIdx ) };
|
||||
|
||||
// A plausible setback that won't consume a whole edge
|
||||
int setback = pcbIUScale.mmToIU( 5 );
|
||||
setback = std::min( setback, (int) ( segA.Length() * 0.8 ) );
|
||||
setback = std::min( setback, (int) ( segB.Length() * 0.8 ) );
|
||||
|
||||
CHAMFER_PARAMS chamferParams{ setback, setback };
|
||||
|
||||
std::optional<CHAMFER_RESULT> chamferResult =
|
||||
ComputeChamferPoints( segA, segB, chamferParams );
|
||||
|
||||
if( chamferResult && chamferResult->m_updated_seg_a && chamferResult->m_updated_seg_b )
|
||||
{
|
||||
commit.Modify( item );
|
||||
polygon->RemoveVertex( nearestIdx );
|
||||
|
||||
// The two end points of the chamfer are the new corners
|
||||
polygon->InsertVertex( nearestIdx, chamferResult->m_updated_seg_b->B );
|
||||
polygon->InsertVertex( nearestIdx, chamferResult->m_updated_seg_a->B );
|
||||
}
|
||||
}
|
||||
|
||||
setEditedPoint( nullptr );
|
||||
|
||||
if( item->Type() == PCB_ZONE_T )
|
||||
commit.Push( _( "Break Zone Corner" ) );
|
||||
else
|
||||
commit.Push( _( "Break Polygon Corner" ) );
|
||||
|
||||
// Refresh zone hatching
|
||||
if( item->Type() == PCB_ZONE_T )
|
||||
static_cast<ZONE*>( item )->HatchBorder();
|
||||
|
||||
updatePoints();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PCB_POINT_EDITOR::modifiedSelection( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
updatePoints();
|
||||
@ -2873,6 +2974,7 @@ void PCB_POINT_EDITOR::setTransitions()
|
||||
Go( &PCB_POINT_EDITOR::movePoint, PCB_ACTIONS::pointEditorMoveMidpoint.MakeEvent() );
|
||||
Go( &PCB_POINT_EDITOR::addCorner, PCB_ACTIONS::pointEditorAddCorner.MakeEvent() );
|
||||
Go( &PCB_POINT_EDITOR::removeCorner, PCB_ACTIONS::pointEditorRemoveCorner.MakeEvent() );
|
||||
Go( &PCB_POINT_EDITOR::chamferCorner, PCB_ACTIONS::pointEditorChamferCorner.MakeEvent() );
|
||||
Go( &PCB_POINT_EDITOR::changeArcEditMode, PCB_ACTIONS::pointEditorArcKeepCenter.MakeEvent() );
|
||||
Go( &PCB_POINT_EDITOR::changeArcEditMode, PCB_ACTIONS::pointEditorArcKeepEndpoint.MakeEvent() );
|
||||
Go( &PCB_POINT_EDITOR::changeArcEditMode, ACTIONS::cycleArcEditMode.MakeEvent() );
|
||||
|
@ -126,6 +126,7 @@ private:
|
||||
int movePoint( const TOOL_EVENT& aEvent );
|
||||
int addCorner( const TOOL_EVENT& aEvent );
|
||||
int removeCorner( const TOOL_EVENT& aEvent );
|
||||
int chamferCorner( const TOOL_EVENT& aEvent );
|
||||
int modifiedSelection( const TOOL_EVENT& aEvent );
|
||||
|
||||
/**
|
||||
|
@ -61,7 +61,106 @@ BOOST_AUTO_TEST_CASE( RemoveNullSegments )
|
||||
|
||||
BOOST_CHECK_EQUAL( removed, 4 );
|
||||
BOOST_CHECK_EQUAL( base_set.VertexCount(), 4 );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( GetNeighbourIndexes )
|
||||
{
|
||||
SHAPE_POLY_SET base_set;
|
||||
|
||||
base_set.NewOutline();
|
||||
base_set.Append( 0, 0, -1, -1, true );
|
||||
base_set.Append( 0, 10, -1, -1, true );
|
||||
base_set.Append( 10, 10, -1, -1, true );
|
||||
base_set.Append( 10, 0, -1, -1, true );
|
||||
|
||||
// Check we're testing what we think
|
||||
BOOST_REQUIRE( base_set.OutlineCount() == 1 );
|
||||
BOOST_REQUIRE( base_set.FullPointCount() == 4 );
|
||||
|
||||
int prev = 0;
|
||||
int next = 0;
|
||||
bool ok = false;
|
||||
|
||||
ok = base_set.GetNeighbourIndexes( 0, &prev, &next );
|
||||
BOOST_TEST( ok );
|
||||
BOOST_TEST( prev == 3 );
|
||||
BOOST_TEST( next == 1 );
|
||||
|
||||
ok = base_set.GetNeighbourIndexes( 1, &prev, &next );
|
||||
BOOST_TEST( ok );
|
||||
BOOST_TEST( prev == 0 );
|
||||
BOOST_TEST( next == 2 );
|
||||
|
||||
ok = base_set.GetNeighbourIndexes( 2, &prev, &next );
|
||||
BOOST_TEST( ok );
|
||||
BOOST_TEST( prev == 1 );
|
||||
BOOST_TEST( next == 3 );
|
||||
|
||||
ok = base_set.GetNeighbourIndexes( 3, &prev, &next );
|
||||
BOOST_TEST( ok );
|
||||
BOOST_TEST( prev == 2 );
|
||||
BOOST_TEST( next == 0 );
|
||||
|
||||
ok = base_set.GetNeighbourIndexes( 4, &prev, &next );
|
||||
BOOST_TEST( !ok );
|
||||
|
||||
ok = base_set.GetNeighbourIndexes( -1, &prev, &next );
|
||||
BOOST_TEST( !ok );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( GetNeighbourIndexes_MultiOutline )
|
||||
{
|
||||
SHAPE_POLY_SET base_set;
|
||||
|
||||
base_set.NewOutline();
|
||||
base_set.Append( 0, 0, -1, -1, true );
|
||||
base_set.Append( 0, 10, -1, -1, true );
|
||||
base_set.Append( 10, 10, -1, -1, true );
|
||||
base_set.Append( 10, 0, -1, -1, true );
|
||||
|
||||
base_set.NewOutline();
|
||||
base_set.Append( 20, 0, -1, -1, true );
|
||||
base_set.Append( 20, 10, -1, -1, true );
|
||||
base_set.Append( 30, 10, -1, -1, true );
|
||||
base_set.Append( 30, 0, -1, -1, true );
|
||||
|
||||
// Check we're testing what we think
|
||||
BOOST_TEST_REQUIRE( base_set.OutlineCount() == 2 );
|
||||
BOOST_TEST_REQUIRE( base_set.FullPointCount() == 8 );
|
||||
|
||||
int next = 0;
|
||||
int prev = 0;
|
||||
bool ok = false;
|
||||
|
||||
// Can we still get outline 0?
|
||||
ok = base_set.GetNeighbourIndexes( 0, &prev, &next );
|
||||
BOOST_TEST( ok );
|
||||
BOOST_TEST( prev == 3 );
|
||||
BOOST_TEST( next == 1 );
|
||||
|
||||
// End out outline 0
|
||||
ok = base_set.GetNeighbourIndexes( 3, &prev, &next );
|
||||
BOOST_TEST( ok );
|
||||
BOOST_TEST( prev == 2 );
|
||||
BOOST_TEST( next == 0 );
|
||||
|
||||
// Check outline 1
|
||||
ok = base_set.GetNeighbourIndexes( 4, &prev, &next );
|
||||
BOOST_TEST( ok );
|
||||
BOOST_TEST( prev == 7 );
|
||||
BOOST_TEST( next == 5 );
|
||||
|
||||
// End out outline 1
|
||||
ok = base_set.GetNeighbourIndexes( 7, &prev, &next );
|
||||
BOOST_TEST( ok );
|
||||
BOOST_TEST( prev == 6 );
|
||||
BOOST_TEST( next == 4 );
|
||||
|
||||
// Bad indexes
|
||||
ok = base_set.GetNeighbourIndexes( 8, &prev, &next );
|
||||
BOOST_TEST( !ok );
|
||||
ok = base_set.GetNeighbourIndexes( -1, &prev, &next );
|
||||
BOOST_TEST( !ok );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
Loading…
Reference in New Issue
Block a user