kicad/eeschema/tools/rule_area_create_helper.cpp

176 lines
5.6 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 <core/spinlock.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_line_chain.h>
#include <sch_commit.h>
#include <sch_edit_frame.h>
#include <sch_rule_area.h>
#include <tool/tool_manager.h>
#include <tools/ee_actions.h>
#include <tools/rule_area_create_helper.h>
RULE_AREA_CREATE_HELPER::RULE_AREA_CREATE_HELPER( KIGFX::VIEW& aView, SCH_EDIT_FRAME* aFrame,
TOOL_MANAGER* aMgr ) :
m_parentView( aView ),
m_frame( aFrame ), m_toolManager( aMgr )
{
m_parentView.Add( &m_previewItem );
}
RULE_AREA_CREATE_HELPER::~RULE_AREA_CREATE_HELPER()
{
// remove the preview from the view
m_parentView.SetVisible( &m_previewItem, false );
m_parentView.Remove( &m_previewItem );
}
std::unique_ptr<SCH_RULE_AREA> RULE_AREA_CREATE_HELPER::createNewRuleArea()
{
std::unique_ptr<SCH_RULE_AREA> ruleArea = std::make_unique<SCH_RULE_AREA>();
ruleArea->SetLineStyle( LINE_STYLE::DASH );
ruleArea->SetLineColor( COLOR4D::UNSPECIFIED );
return ruleArea;
}
void RULE_AREA_CREATE_HELPER::commitRuleArea( std::unique_ptr<SCH_RULE_AREA> aRuleArea )
{
SCH_COMMIT commit( m_toolManager );
SCH_RULE_AREA* ruleArea = aRuleArea.release();
commit.Add( ruleArea, m_frame->GetScreen() );
commit.Push( _( "Draw Rule Area" ) );
m_toolManager->RunAction<EDA_ITEM*>( EE_ACTIONS::addItemToSel, ruleArea );
m_parentView.ClearPreview();
}
bool RULE_AREA_CREATE_HELPER::OnFirstPoint( POLYGON_GEOM_MANAGER& aMgr )
{
m_rule_area = createNewRuleArea();
if( m_rule_area )
{
m_toolManager->RunAction( EE_ACTIONS::clearSelection );
SCH_RENDER_SETTINGS renderSettings;
COLOR_SETTINGS* colorSettings = m_frame->GetColorSettings();
renderSettings.LoadColors( colorSettings );
COLOR4D color = renderSettings.GetLayerColor( LAYER_RULE_AREAS );
m_previewItem.SetLineColor( color );
m_previewItem.SetLeaderColor( color );
m_previewItem.SetFillColor( color.WithAlpha( 0.2 ) );
m_parentView.SetVisible( &m_previewItem, true );
aMgr.SetLeaderMode( POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 );
}
return m_rule_area != nullptr;
}
void RULE_AREA_CREATE_HELPER::OnGeometryChange( const POLYGON_GEOM_MANAGER& aMgr )
{
// Handle a cancel-interactive
if( m_rule_area && !aMgr.IsPolygonInProgress() )
{
m_rule_area = nullptr;
m_parentView.SetVisible( &m_previewItem, false );
return;
}
// send the points to the preview item
m_previewItem.SetPoints( aMgr.GetLockedInPoints(), aMgr.GetLeaderLinePoints(),
aMgr.GetLoopLinePoints() );
m_parentView.Update( &m_previewItem, KIGFX::GEOMETRY );
}
void RULE_AREA_CREATE_HELPER::OnComplete( const POLYGON_GEOM_MANAGER& aMgr )
{
auto& finalPoints = aMgr.GetLockedInPoints();
if( finalPoints.PointCount() < 3 )
{
// Just scrap the rule area in progress
m_rule_area = nullptr;
}
else
{
SHAPE_POLY_SET ruleShape;
ruleShape.NewOutline();
auto& outline = ruleShape.Outline( 0 );
for( int i = 0; i < finalPoints.PointCount(); ++i )
outline.Append( finalPoints.CPoint( i ) );
// In DEG45 mode, we may have intermediate points in the leader that should be included
// as they are shown in the preview. These typically maintain the 45 constraint
if( aMgr.GetLeaderMode() == POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 )
{
const SHAPE_LINE_CHAIN leaderPts = aMgr.GetLeaderLinePoints();
for( int i = 1; i < leaderPts.PointCount(); i++ )
outline.Append( leaderPts.CPoint( i ) );
const SHAPE_LINE_CHAIN loopPts = aMgr.GetLoopLinePoints();
for( int i = 1; i < loopPts.PointCount() - 1; i++ )
outline.Append( loopPts.CPoint( i ) );
}
outline.SetClosed( true );
outline.Simplify( true );
// Remove the start point if it lies on the line between neighbouring points.
// Simplify doesn't handle that currently.
if( outline.PointCount() >= 3 )
{
SEG seg( outline.CPoint( -1 ), outline.CPoint( 1 ) );
if( seg.LineDistance( outline.CPoint( 0 ) ) <= 1 )
outline.Remove( 0 );
}
m_rule_area->SetPolyShape( ruleShape );
// hand the rule area over to the committer
commitRuleArea( std::move( m_rule_area ) );
m_rule_area = nullptr;
}
m_parentView.SetVisible( &m_previewItem, false );
}