/* * 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 #include #include #include #include #include #include #include #include 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 RULE_AREA_CREATE_HELPER::createNewRuleArea() { std::unique_ptr ruleArea = std::make_unique(); ruleArea->SetLineStyle( LINE_STYLE::DASH ); ruleArea->SetLineColor( COLOR4D::UNSPECIFIED ); return ruleArea; } void RULE_AREA_CREATE_HELPER::commitRuleArea( std::unique_ptr 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( 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 ); }