kicad-source/pcbnew/tools/point_editor.cpp
John Beard 796f3219d0 Draw zone hatching in GAL
This just uses the same hatch lines that are built into the zone as
legacy.

They are always drawn, even when there is a fill, as if the fill
doesn't reach the corners, the hatches can be seen.

Fixes: lp:1487043
* https://bugs.launchpad.net/kicad/+bug/1487043
2017-02-27 18:00:46 +01:00

904 lines
28 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013-2017 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <functional>
using namespace std::placeholders;
#include <tool/tool_manager.h>
#include <view/view_controls.h>
#include <gal/graphics_abstraction_layer.h>
#include <geometry/seg.h>
#include <confirm.h>
#include "pcb_actions.h"
#include "selection_tool.h"
#include "point_editor.h"
#include <board_commit.h>
#include <bitmaps.h>
#include <wxPcbStruct.h>
#include <class_edge_mod.h>
#include <class_dimension.h>
#include <class_zone.h>
#include <class_board.h>
#include <class_module.h>
#include <ratsnest_data.h>
// Point editor
TOOL_ACTION PCB_ACTIONS::pointEditorAddCorner( "pcbnew.PointEditor.addCorner",
AS_GLOBAL, 0,
_( "Create Corner" ), _( "Create a corner" ), add_corner_xpm );
TOOL_ACTION PCB_ACTIONS::pointEditorRemoveCorner( "pcbnew.PointEditor.removeCorner",
AS_GLOBAL, 0,
_( "Remove Corner" ), _( "Remove corner" ), delete_xpm );
// Few constants to avoid using bare numbers for point indices
enum SEG_POINTS
{
SEG_START, SEG_END
};
enum ARC_POINTS
{
ARC_CENTER, ARC_START, ARC_END
};
enum CIRCLE_POINTS
{
CIRC_CENTER, CIRC_END
};
enum DIMENSION_POINTS
{
DIM_CROSSBARO,
DIM_CROSSBARF,
DIM_FEATUREGO,
DIM_FEATUREDO,
};
class EDIT_POINTS_FACTORY
{
public:
static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem, KIGFX::GAL* aGal )
{
std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
// Generate list of edit points basing on the item type
switch( aItem->Type() )
{
case PCB_LINE_T:
case PCB_MODULE_EDGE_T:
{
const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( aItem );
switch( segment->GetShape() )
{
case S_SEGMENT:
points->AddPoint( segment->GetStart() );
points->AddPoint( segment->GetEnd() );
break;
case S_ARC:
points->AddPoint( segment->GetCenter() );
points->AddPoint( segment->GetArcStart() );
points->AddPoint( segment->GetArcEnd() );
// Set constraints
// Arc end has to stay at the same radius as the start
points->Point( ARC_END ).SetConstraint( new EC_CIRCLE( points->Point( ARC_END ),
points->Point( ARC_CENTER ),
points->Point( ARC_START ) ) );
break;
case S_CIRCLE:
points->AddPoint( segment->GetCenter() );
points->AddPoint( segment->GetEnd() );
break;
default: // suppress warnings
break;
}
break;
}
case PCB_ZONE_AREA_T:
{
const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline();
int cornersCount = outline->GetCornersCount();
for( int i = 0; i < cornersCount; ++i )
{
points->AddPoint( outline->GetPos( i ) );
if( outline->IsEndContour( i ) )
points->AddBreak();
}
// Lines have to be added after creating edit points,
// as they use EDIT_POINT references
for( int i = 0; i < cornersCount - 1; ++i )
{
if( points->IsContourEnd( i ) )
{
points->AddLine( points->Point( i ),
points->Point( points->GetContourStartIdx( i ) ) );
}
else
{
points->AddLine( points->Point( i ), points->Point( i + 1 ) );
}
points->Line( i ).SetConstraint( new EC_SNAPLINE( points->Line( i ),
std::bind( &KIGFX::GAL::GetGridPoint, aGal, _1 ) ) );
}
// The last missing line, connecting the last and the first polygon point
points->AddLine( points->Point( cornersCount - 1 ),
points->Point( points->GetContourStartIdx( cornersCount - 1 ) ) );
points->Line( points->LinesSize() - 1 ).SetConstraint(
new EC_SNAPLINE( points->Line( points->LinesSize() - 1 ),
std::bind( &KIGFX::GAL::GetGridPoint, aGal, _1 ) ) );
break;
}
case PCB_DIMENSION_T:
{
const DIMENSION* dimension = static_cast<const DIMENSION*>( aItem );
points->AddPoint( dimension->m_crossBarO );
points->AddPoint( dimension->m_crossBarF );
points->AddPoint( dimension->m_featureLineGO );
points->AddPoint( dimension->m_featureLineDO );
// Dimension height setting - edit points should move only along the feature lines
points->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARO ),
points->Point( DIM_FEATUREGO ) ) );
points->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARF ),
points->Point( DIM_FEATUREDO ) ) );
break;
}
default:
points.reset();
break;
}
return points;
}
private:
EDIT_POINTS_FACTORY() {};
};
POINT_EDITOR::POINT_EDITOR() :
TOOL_INTERACTIVE( "pcbnew.PointEditor" ), m_selectionTool( NULL ), m_editedPoint( NULL ),
m_original( VECTOR2I( 0, 0 ) ), m_altConstrainer( VECTOR2I( 0, 0 ) )
{
}
void POINT_EDITOR::Reset( RESET_REASON aReason )
{
m_editPoints.reset();
m_altConstraint.reset();
}
bool POINT_EDITOR::Init()
{
// Find the selection tool, so they can cooperate
m_selectionTool = static_cast<SELECTION_TOOL*>( m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ) );
if( !m_selectionTool )
{
DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) );
return false;
}
auto& menu = m_selectionTool->GetToolMenu().GetMenu();
menu.AddItem( PCB_ACTIONS::pointEditorAddCorner, POINT_EDITOR::addCornerCondition );
menu.AddItem( PCB_ACTIONS::pointEditorRemoveCorner,
std::bind( &POINT_EDITOR::removeCornerCondition, this, _1 ) );
return true;
}
void POINT_EDITOR::updateEditedPoint( const TOOL_EVENT& aEvent )
{
EDIT_POINT* point = m_editedPoint;
if( aEvent.IsMotion() )
{
point = m_editPoints->FindPoint( aEvent.Position(), getView() );
}
else if( aEvent.IsDrag( BUT_LEFT ) )
{
point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
}
if( m_editedPoint != point )
setEditedPoint( point );
}
int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent )
{
const SELECTION& selection = m_selectionTool->GetSelection();
if( selection.Size() == 1 )
{
Activate();
KIGFX::VIEW_CONTROLS* controls = getViewControls();
KIGFX::VIEW* view = getView();
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
auto item = selection.Front();
m_editPoints = EDIT_POINTS_FACTORY::Make( item, getView()->GetGAL() );
if( !m_editPoints )
return 0;
view->Add( m_editPoints.get() );
m_editedPoint = NULL;
bool modified = false;
BOARD_COMMIT commit( editFrame );
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
if( !m_editPoints ||
evt->Matches( m_selectionTool->ClearedEvent ) ||
evt->Matches( m_selectionTool->UnselectedEvent ) ||
evt->Matches( m_selectionTool->SelectedEvent ) )
{
break;
}
if ( !modified )
updateEditedPoint( *evt );
if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
{
if( !modified )
{
commit.StageItems( selection, CHT_MODIFY );
controls->ForceCursorPosition( false );
m_original = *m_editedPoint; // Save the original position
controls->SetAutoPan( true );
modified = true;
}
bool enableAltConstraint = !!evt->Modifier( MD_CTRL );
if( enableAltConstraint != (bool) m_altConstraint ) // alternative constraint
setAltConstraint( enableAltConstraint );
m_editedPoint->SetPosition( controls->GetCursorPosition() );
if( m_altConstraint )
m_altConstraint->Apply();
else
m_editedPoint->ApplyConstraint();
updateItem();
updatePoints();
}
else if( evt->IsMouseUp( BUT_LEFT ) )
{
controls->SetAutoPan( false );
setAltConstraint( false );
if( modified )
{
commit.Push( _( "Drag a line ending" ) );
modified = false;
}
m_toolMgr->PassEvent();
}
else if( evt->IsCancel() )
{
if( modified ) // Restore the last change
{
commit.Revert();
updatePoints();
modified = false;
}
// Let the selection tool receive the event too
m_toolMgr->PassEvent();
break;
}
else
{
m_toolMgr->PassEvent();
}
}
if( m_editPoints )
{
finishItem();
view->Remove( m_editPoints.get() );
m_editPoints.reset();
}
controls->ShowCursor( false );
controls->SetAutoPan( false );
controls->SetSnapping( false );
}
return 0;
}
void POINT_EDITOR::updateItem() const
{
EDA_ITEM* item = m_editPoints->GetParent();
switch( item->Type() )
{
case PCB_LINE_T:
case PCB_MODULE_EDGE_T:
{
DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item );
switch( segment->GetShape() )
{
case S_SEGMENT:
if( isModified( m_editPoints->Point( SEG_START ) ) )
segment->SetStart( wxPoint( m_editPoints->Point( SEG_START ).GetPosition().x,
m_editPoints->Point( SEG_START ).GetPosition().y ) );
else if( isModified( m_editPoints->Point( SEG_END ) ) )
segment->SetEnd( wxPoint( m_editPoints->Point( SEG_END ).GetPosition().x,
m_editPoints->Point( SEG_END ).GetPosition().y ) );
break;
case S_ARC:
{
const VECTOR2I& center = m_editPoints->Point( ARC_CENTER ).GetPosition();
const VECTOR2I& start = m_editPoints->Point( ARC_START ).GetPosition();
const VECTOR2I& end = m_editPoints->Point( ARC_END ).GetPosition();
if( center != segment->GetCenter() )
{
wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter();
segment->Move( moveVector );
m_editPoints->Point( ARC_START ).SetPosition( segment->GetArcStart() );
m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() );
}
else
{
segment->SetArcStart( wxPoint( start.x, start.y ) );
VECTOR2D startLine = start - center;
VECTOR2I endLine = end - center;
double newAngle = RAD2DECIDEG( endLine.Angle() - startLine.Angle() );
// Adjust the new angle to (counter)clockwise setting
bool clockwise = ( segment->GetAngle() > 0 );
if( clockwise && newAngle < 0.0 )
newAngle += 3600.0;
else if( !clockwise && newAngle > 0.0 )
newAngle -= 3600.0;
segment->SetAngle( newAngle );
}
break;
}
case S_CIRCLE:
{
const VECTOR2I& center = m_editPoints->Point( CIRC_CENTER ).GetPosition();
const VECTOR2I& end = m_editPoints->Point( CIRC_END ).GetPosition();
if( isModified( m_editPoints->Point( CIRC_CENTER ) ) )
{
wxPoint moveVector = wxPoint( center.x, center.y ) - segment->GetCenter();
segment->Move( moveVector );
}
else
{
segment->SetEnd( wxPoint( end.x, end.y ) );
}
break;
}
default: // suppress warnings
break;
}
// Update relative coordinates for module edges
if( EDGE_MODULE* edge = dyn_cast<EDGE_MODULE*>( item ) )
edge->SetLocalCoord();
break;
}
case PCB_ZONE_AREA_T:
{
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
zone->ClearFilledPolysList();
CPolyLine* outline = zone->Outline();
for( int i = 0; i < outline->GetCornersCount(); ++i )
{
VECTOR2I point = m_editPoints->Point( i ).GetPosition();
outline->SetX( i, point.x );
outline->SetY( i, point.y );
}
outline->Hatch();
break;
}
case PCB_DIMENSION_T:
{
DIMENSION* dimension = static_cast<DIMENSION*>( item );
// Check which point is currently modified and updated dimension's points respectively
if( isModified( m_editPoints->Point( DIM_CROSSBARO ) ) )
{
VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetOrigin() );
VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() );
if( featureLine.Cross( crossBar ) > 0 )
dimension->SetHeight( -featureLine.EuclideanNorm() );
else
dimension->SetHeight( featureLine.EuclideanNorm() );
}
else if( isModified( m_editPoints->Point( DIM_CROSSBARF ) ) )
{
VECTOR2D featureLine( m_editedPoint->GetPosition() - dimension->GetEnd() );
VECTOR2D crossBar( dimension->GetEnd() - dimension->GetOrigin() );
if( featureLine.Cross( crossBar ) > 0 )
dimension->SetHeight( -featureLine.EuclideanNorm() );
else
dimension->SetHeight( featureLine.EuclideanNorm() );
}
else if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) )
{
dimension->SetOrigin( wxPoint( m_editedPoint->GetPosition().x, m_editedPoint->GetPosition().y ) );
m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ),
m_editPoints->Point( DIM_FEATUREGO ) ) );
m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ),
m_editPoints->Point( DIM_FEATUREDO ) ) );
}
else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) )
{
dimension->SetEnd( wxPoint( m_editedPoint->GetPosition().x, m_editedPoint->GetPosition().y ) );
m_editPoints->Point( DIM_CROSSBARO ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARO ),
m_editPoints->Point( DIM_FEATUREGO ) ) );
m_editPoints->Point( DIM_CROSSBARF ).SetConstraint( new EC_LINE( m_editPoints->Point( DIM_CROSSBARF ),
m_editPoints->Point( DIM_FEATUREDO ) ) );
}
break;
}
default:
break;
}
}
void POINT_EDITOR::finishItem() const
{
EDA_ITEM* item = m_editPoints->GetParent();
if( item->Type() == PCB_ZONE_AREA_T )
{
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
if( zone->IsFilled() )
{
getEditFrame<PCB_EDIT_FRAME>()->Fill_Zone( zone );
zone->GetBoard()->GetRatsnest()->Recalculate( zone->GetNetCode() );
}
}
}
void POINT_EDITOR::updatePoints()
{
if( !m_editPoints )
return;
EDA_ITEM* item = m_editPoints->GetParent();
switch( item->Type() )
{
case PCB_LINE_T:
case PCB_MODULE_EDGE_T:
{
const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( item );
{
switch( segment->GetShape() )
{
case S_SEGMENT:
m_editPoints->Point( SEG_START ).SetPosition( segment->GetStart() );
m_editPoints->Point( SEG_END ).SetPosition( segment->GetEnd() );
break;
case S_ARC:
m_editPoints->Point( ARC_CENTER ).SetPosition( segment->GetCenter() );
m_editPoints->Point( ARC_START).SetPosition( segment->GetArcStart() );
m_editPoints->Point( ARC_END ).SetPosition( segment->GetArcEnd() );
break;
case S_CIRCLE:
m_editPoints->Point( CIRC_CENTER ).SetPosition( segment->GetCenter() );
m_editPoints->Point( CIRC_END ).SetPosition( segment->GetEnd() );
break;
default: // suppress warnings
break;
}
break;
}
}
case PCB_ZONE_AREA_T:
{
const ZONE_CONTAINER* zone = static_cast<const ZONE_CONTAINER*>( item );
const CPolyLine* outline = zone->Outline();
if( m_editPoints->PointsSize() != (unsigned) outline->GetCornersCount() )
{
getView()->Remove( m_editPoints.get() );
m_editPoints = EDIT_POINTS_FACTORY::Make( item, getView()->GetGAL() );
getView()->Add( m_editPoints.get() );
}
else
{
for( int i = 0; i < outline->GetCornersCount(); ++i )
m_editPoints->Point( i ).SetPosition( outline->GetPos( i ) );
}
break;
}
case PCB_DIMENSION_T:
{
const DIMENSION* dimension = static_cast<const DIMENSION*>( item );
m_editPoints->Point( DIM_CROSSBARO ).SetPosition( dimension->m_crossBarO );
m_editPoints->Point( DIM_CROSSBARF ).SetPosition( dimension->m_crossBarF );
m_editPoints->Point( DIM_FEATUREGO ).SetPosition( dimension->m_featureLineGO );
m_editPoints->Point( DIM_FEATUREDO ).SetPosition( dimension->m_featureLineDO );
break;
}
default:
break;
}
getView()->Update( m_editPoints.get() );
}
void POINT_EDITOR::setEditedPoint( EDIT_POINT* aPoint )
{
KIGFX::VIEW_CONTROLS* controls = getViewControls();
if( aPoint )
{
controls->ForceCursorPosition( true, aPoint->GetPosition() );
controls->ShowCursor( true );
controls->SetSnapping( true );
}
else
{
controls->ShowCursor( false );
controls->SetSnapping( false );
controls->ForceCursorPosition( false );
}
m_editedPoint = aPoint;
}
void POINT_EDITOR::setAltConstraint( bool aEnabled )
{
if( aEnabled )
{
EDIT_LINE* line = dynamic_cast<EDIT_LINE*>( m_editedPoint );
if( line )
{
if( m_editPoints->GetParent()->Type() == PCB_ZONE_AREA_T )
m_altConstraint.reset( (EDIT_CONSTRAINT<EDIT_POINT>*)( new EC_CONVERGING( *line, *m_editPoints ) ) );
}
else
{
// Find a proper constraining point for 45 degrees mode
m_altConstrainer = get45DegConstrainer();
m_altConstraint.reset( new EC_45DEGREE( *m_editedPoint, m_altConstrainer ) );
}
}
else
{
m_altConstraint.reset();
}
}
EDIT_POINT POINT_EDITOR::get45DegConstrainer() const
{
EDA_ITEM* item = m_editPoints->GetParent();
switch( item->Type() )
{
case PCB_LINE_T:
case PCB_MODULE_EDGE_T:
{
const DRAWSEGMENT* segment = static_cast<const DRAWSEGMENT*>( item );
{
switch( segment->GetShape() )
{
case S_SEGMENT:
return *( m_editPoints->Next( *m_editedPoint ) ); // select the other end of line
case S_ARC:
case S_CIRCLE:
return m_editPoints->Point( CIRC_CENTER );
default: // suppress warnings
break;
}
}
break;
}
case PCB_DIMENSION_T:
{
// Constraint for crossbar
if( isModified( m_editPoints->Point( DIM_FEATUREGO ) ) )
return m_editPoints->Point( DIM_FEATUREDO );
else if( isModified( m_editPoints->Point( DIM_FEATUREDO ) ) )
return m_editPoints->Point( DIM_FEATUREGO );
else
return EDIT_POINT( m_editedPoint->GetPosition() ); // no constraint
break;
}
default:
break;
}
// In any other case we may align item to its original position
return m_original;
}
void POINT_EDITOR::SetTransitions()
{
Go( &POINT_EDITOR::addCorner, PCB_ACTIONS::pointEditorAddCorner.MakeEvent() );
Go( &POINT_EDITOR::removeCorner, PCB_ACTIONS::pointEditorRemoveCorner.MakeEvent() );
Go( &POINT_EDITOR::modifiedSelection, PCB_ACTIONS::editModifiedSelection.MakeEvent() );
Go( &POINT_EDITOR::OnSelectionChange, SELECTION_TOOL::SelectedEvent );
Go( &POINT_EDITOR::OnSelectionChange, SELECTION_TOOL::UnselectedEvent );
}
bool POINT_EDITOR::addCornerCondition( const SELECTION& aSelection )
{
if( aSelection.Size() != 1 )
return false;
auto item = aSelection.Front();
// Works only for zones and line segments
return item->Type() == PCB_ZONE_AREA_T ||
( ( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T ) &&
static_cast<DRAWSEGMENT*>( item )->GetShape() == S_SEGMENT );
}
bool POINT_EDITOR::removeCornerCondition( const SELECTION& )
{
if( !m_editPoints )
return false;
EDA_ITEM* item = m_editPoints->GetParent();
if( item->Type() != PCB_ZONE_AREA_T )
return false;
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
if( zone->GetNumCorners() <= 3 )
return false;
// Remove corner does not work with lines
if( dynamic_cast<EDIT_LINE*>( m_editedPoint ) )
return false;
return m_editedPoint != NULL;
}
int POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent )
{
EDA_ITEM* item = m_editPoints->GetParent();
PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
BOARD_COMMIT commit( frame );
if( item->Type() == PCB_ZONE_AREA_T )
{
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
CPolyLine* outline = zone->Outline();
commit.Modify( zone );
// Handle the last segment, so other segments can be easily handled in a loop
unsigned int nearestIdx = outline->GetCornersCount() - 1, nextNearestIdx = 0;
SEG side( VECTOR2I( outline->GetPos( nearestIdx ) ),
VECTOR2I( outline->GetPos( nextNearestIdx ) ) );
unsigned int nearestDist = side.Distance( cursorPos );
for( int i = 0; i < outline->GetCornersCount() - 1; ++i )
{
side = SEG( VECTOR2I( outline->GetPos( i ) ), VECTOR2I( outline->GetPos( i + 1 ) ) );
unsigned int distance = side.Distance( cursorPos );
if( distance < nearestDist )
{
nearestDist = distance;
nearestIdx = i;
nextNearestIdx = i + 1;
}
}
// Find the point on the closest segment
VECTOR2I sideOrigin( outline->GetPos( nearestIdx ) );
VECTOR2I sideEnd( outline->GetPos( nextNearestIdx ) );
SEG nearestSide( sideOrigin, sideEnd );
VECTOR2I nearestPoint = nearestSide.NearestPoint( cursorPos );
// Do not add points that have the same coordinates as ones that already belong to polygon
// instead, add a point in the middle of the side
if( nearestPoint == sideOrigin || nearestPoint == sideEnd )
nearestPoint = ( sideOrigin + sideEnd ) / 2;
outline->InsertCorner( nearestIdx, nearestPoint.x, nearestPoint.y );
commit.Push( _( "Add a zone corner" ) );
}
else if( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T )
{
bool moduleEdge = item->Type() == PCB_MODULE_EDGE_T;
DRAWSEGMENT* segment = static_cast<DRAWSEGMENT*>( item );
if( segment->GetShape() == S_SEGMENT )
{
commit.Modify( segment );
SEG seg( segment->GetStart(), segment->GetEnd() );
VECTOR2I nearestPoint = seg.NearestPoint( cursorPos );
// Move the end of the line to the break point..
segment->SetEnd( wxPoint( nearestPoint.x, nearestPoint.y ) );
// and add another one starting from the break point
DRAWSEGMENT* newSegment;
if( moduleEdge )
{
EDGE_MODULE* edge = static_cast<EDGE_MODULE*>( segment );
assert( edge->Type() == PCB_MODULE_EDGE_T );
assert( edge->GetParent()->Type() == PCB_MODULE_T );
newSegment = new EDGE_MODULE( *edge );
}
else
{
newSegment = new DRAWSEGMENT( *segment );
}
newSegment->ClearSelected();
newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) );
newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) );
commit.Add( newSegment );
commit.Push( _( "Split segment" ) );
}
}
updatePoints();
return 0;
}
int POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
{
if( !m_editedPoint )
return 0;
EDA_ITEM* item = m_editPoints->GetParent();
if( item->Type() == PCB_ZONE_AREA_T )
{
PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
BOARD_COMMIT commit( frame );
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
CPolyLine* outline = zone->Outline();
commit.Modify( zone );
for( int i = 0; i < outline->GetCornersCount(); ++i )
{
if( VECTOR2I( outline->GetPos( i ) ) == m_editedPoint->GetPosition() )
{
outline->DeleteCorner( i );
setEditedPoint( NULL );
commit.Push( _( "Remove a zone corner" ) );
break;
}
}
updatePoints();
}
return 0;
}
int POINT_EDITOR::modifiedSelection( const TOOL_EVENT& aEvent )
{
updatePoints();
return 0;
}