summaryrefslogtreecommitdiff
path: root/pcbnew/tools/grid_helper.cpp
diff options
context:
space:
mode:
authorsaurabhb172020-02-26 15:57:49 +0530
committersaurabhb172020-02-26 15:57:49 +0530
commitaa35045840b78d3f48212db45da59a2e5c69b223 (patch)
tree6acee185a4dc19113fcbf0f9a3d6941085dedaf7 /pcbnew/tools/grid_helper.cpp
parent0db48f6533517ecebfd9f0693f89deca28408b76 (diff)
downloadKiCad-eSim-aa35045840b78d3f48212db45da59a2e5c69b223.tar.gz
KiCad-eSim-aa35045840b78d3f48212db45da59a2e5c69b223.tar.bz2
KiCad-eSim-aa35045840b78d3f48212db45da59a2e5c69b223.zip
Added main execs
Diffstat (limited to 'pcbnew/tools/grid_helper.cpp')
-rw-r--r--pcbnew/tools/grid_helper.cpp393
1 files changed, 393 insertions, 0 deletions
diff --git a/pcbnew/tools/grid_helper.cpp b/pcbnew/tools/grid_helper.cpp
new file mode 100644
index 0000000..4e811ca
--- /dev/null
+++ b/pcbnew/tools/grid_helper.cpp
@@ -0,0 +1,393 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2014 CERN
+ * @author Tomasz Wlostowski <tomasz.wlostowski@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 <boost/foreach.hpp>
+#include <boost/bind.hpp>
+
+#include <wxPcbStruct.h>
+
+#include <class_board.h>
+#include <class_module.h>
+#include <class_edge_mod.h>
+#include <class_zone.h>
+#include <class_draw_panel_gal.h>
+
+#include <view/view_controls.h>
+#include <gal/graphics_abstraction_layer.h>
+
+#include <geometry/shape_line_chain.h>
+
+#include "grid_helper.h"
+
+GRID_HELPER::GRID_HELPER( PCB_BASE_FRAME* aFrame ) :
+ m_frame( aFrame )
+{
+ m_diagonalAuxAxesEnable = true;
+}
+
+
+GRID_HELPER::~GRID_HELPER()
+{
+}
+
+
+void GRID_HELPER::SetGrid( int aSize )
+{
+ assert( false );
+}
+
+
+void GRID_HELPER::SetOrigin( const VECTOR2I& aOrigin )
+{
+ assert( false );
+}
+
+
+VECTOR2I GRID_HELPER::GetGrid() const
+{
+ PCB_SCREEN* screen = m_frame->GetScreen();
+
+ const wxRealPoint& size = screen->GetGridSize();
+
+ return VECTOR2I( KiROUND( size.x ), KiROUND( size.y ) );
+}
+
+
+VECTOR2I GRID_HELPER::GetOrigin() const
+{
+ return VECTOR2I( m_frame->GetGridOrigin() );
+}
+
+
+void GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin, bool aEnableDiagonal )
+{
+ if( aEnable )
+ m_auxAxis = aOrigin;
+ else
+ m_auxAxis = boost::optional<VECTOR2I>();
+
+ m_diagonalAuxAxesEnable = aEnable;
+}
+
+
+VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint ) const
+{
+ const VECTOR2D gridOffset( GetOrigin() );
+ const VECTOR2D gridSize( GetGrid() );
+
+ VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
+ KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
+
+ if( !m_auxAxis )
+ return nearest;
+
+ if( std::abs( m_auxAxis->x - aPoint.x ) < std::abs( nearest.x - aPoint.x ) )
+ nearest.x = m_auxAxis->x;
+
+ if( std::abs( m_auxAxis->y - aPoint.y ) < std::abs( nearest.y - aPoint.y ) )
+ nearest.y = m_auxAxis->y;
+
+ return nearest;
+}
+
+
+VECTOR2I GRID_HELPER::AlignToSegment ( const VECTOR2I& aPoint, const SEG& aSeg )
+{
+ OPT_VECTOR2I pts[6];
+
+ VECTOR2I origin( GetOrigin() );
+ VECTOR2I grid( GetGrid() );
+
+ const VECTOR2D gridOffset( GetOrigin() );
+ const VECTOR2D gridSize( GetGrid() );
+
+ VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
+ KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
+
+ pts[0] = aSeg.A;
+ pts[1] = aSeg.B;
+ pts[2] = aSeg.IntersectLines( SEG( nearest, nearest + VECTOR2I( 1, 0 ) ) );
+ pts[3] = aSeg.IntersectLines( SEG( nearest, nearest + VECTOR2I( 0, 1 ) ) );
+
+ int min_d = std::numeric_limits<int>::max();
+
+ for( int i = 0; i < 4; i++ )
+ {
+ if( pts[i] && aSeg.Contains( *pts[i] ) )
+ {
+ int d = (*pts[i] - aPoint).EuclideanNorm();
+
+ if( d < min_d )
+ {
+ min_d = d;
+ nearest = *pts[i];
+ }
+ }
+ }
+
+ return nearest;
+}
+
+VECTOR2I GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, BOARD_ITEM* aItem )
+{
+ clearAnchors();
+ computeAnchors( aItem, aMousePos );
+
+ double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale();
+ double lineSnapMinCornerDistance = 50.0 / worldScale;
+
+ ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
+ ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
+ ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
+ ANCHOR* best = NULL;
+ double minDist = std::numeric_limits<double>::max();
+
+ if( nearestOrigin )
+ {
+ minDist = nearestOrigin->Distance( aMousePos );
+ best = nearestOrigin;
+ }
+
+ if( nearestCorner )
+ {
+ double dist = nearestCorner->Distance( aMousePos );
+
+ if( dist < minDist )
+ {
+ minDist = dist;
+ best = nearestCorner;
+ }
+ }
+
+ if( nearestOutline )
+ {
+ double dist = nearestOutline->Distance( aMousePos );
+
+ if( minDist > lineSnapMinCornerDistance && dist < minDist )
+ best = nearestOutline;
+ }
+
+ return best ? best->pos : aMousePos;
+}
+
+
+std::set<BOARD_ITEM*> GRID_HELPER::queryVisible( const BOX2I& aArea ) const
+{
+ std::set<BOARD_ITEM*> items;
+
+ std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
+ std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
+
+ m_frame->GetGalCanvas()->GetView()->Query( aArea, selectedItems ); // Get the list of selected items
+
+ for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
+ {
+ BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
+ if( item->ViewIsVisible() )
+ items.insert ( item );
+ }
+
+ return items;
+}
+
+
+VECTOR2I GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, BOARD_ITEM* aDraggedItem )
+{
+ double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale();
+ int snapRange = (int) ( 100.0 / worldScale );
+
+ BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ), VECTOR2I( snapRange, snapRange ) );
+
+ clearAnchors();
+
+ BOOST_FOREACH( BOARD_ITEM* item, queryVisible( bb ) )
+ {
+ computeAnchors( item, aOrigin );
+ }
+
+ LSET layers( aDraggedItem->GetLayer() );
+ ANCHOR* nearest = nearestAnchor( aOrigin, CORNER | SNAPPABLE, layers );
+
+ VECTOR2I nearestGrid = Align( aOrigin );
+ double gridDist = ( nearestGrid - aOrigin ).EuclideanNorm();
+ if( nearest )
+ {
+ double snapDist = nearest->Distance( aOrigin );
+
+ if( nearest && snapDist < gridDist )
+ return nearest->pos;
+ }
+
+ return nearestGrid;
+}
+
+
+void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos )
+{
+ VECTOR2I origin;
+
+ switch( aItem->Type() )
+ {
+ case PCB_MODULE_T:
+ {
+ MODULE* mod = static_cast<MODULE*>( aItem );
+ addAnchor( mod->GetPosition(), ORIGIN | SNAPPABLE, mod );
+
+ for( D_PAD* pad = mod->Pads(); pad; pad = pad->Next() )
+ addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad );
+
+ break;
+ }
+
+
+ case PCB_PAD_T:
+ {
+ D_PAD* pad = static_cast<D_PAD*>( aItem );
+ addAnchor( pad->GetPosition(), CORNER | SNAPPABLE, pad );
+
+ break;
+ }
+
+ case PCB_MODULE_EDGE_T:
+ case PCB_LINE_T:
+ {
+ DRAWSEGMENT* dseg = static_cast<DRAWSEGMENT*>( aItem );
+ VECTOR2I start = dseg->GetStart();
+ VECTOR2I end = dseg->GetEnd();
+ //LAYER_ID layer = dseg->GetLayer();
+
+ switch( dseg->GetShape() )
+ {
+ case S_CIRCLE:
+ {
+ int r = ( start - end ).EuclideanNorm();
+
+ addAnchor( start, ORIGIN | SNAPPABLE, dseg );
+ addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, dseg );
+ addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, dseg );
+ addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, dseg );
+ addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, dseg );
+ break;
+ }
+
+ case S_ARC:
+ {
+ origin = dseg->GetCenter();
+ addAnchor( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg );
+ addAnchor( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg );
+ addAnchor( origin, ORIGIN | SNAPPABLE, dseg );
+ break;
+ }
+
+ case S_SEGMENT:
+ {
+ origin.x = start.x + ( start.x - end.x ) / 2;
+ origin.y = start.y + ( start.y - end.y ) / 2;
+ addAnchor( start, CORNER | SNAPPABLE, dseg );
+ addAnchor( end, CORNER | SNAPPABLE, dseg );
+ addAnchor( origin, ORIGIN, dseg );
+ break;
+ }
+
+ default:
+ {
+ origin = dseg->GetStart();
+ addAnchor( origin, ORIGIN | SNAPPABLE, dseg );
+ break;
+ }
+ }
+ break;
+ }
+
+ case PCB_TRACE_T:
+ {
+ TRACK* track = static_cast<TRACK*>( aItem );
+ VECTOR2I start = track->GetStart();
+ VECTOR2I end = track->GetEnd();
+ origin.x = start.x + ( start.x - end.x ) / 2;
+ origin.y = start.y + ( start.y - end.y ) / 2;
+ addAnchor( start, CORNER | SNAPPABLE, track );
+ addAnchor( end, CORNER | SNAPPABLE, track );
+ addAnchor( origin, ORIGIN, track);
+ break;
+ }
+
+ case PCB_VIA_T:
+ addAnchor( aItem->GetPosition(), CORNER | SNAPPABLE, aItem );
+ break;
+
+ case PCB_ZONE_AREA_T:
+ {
+ const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline();
+ int cornersCount = outline->GetCornersCount();
+
+ SHAPE_LINE_CHAIN lc;
+ lc.SetClosed( true );
+
+ for( int i = 0; i < cornersCount; ++i )
+ {
+ const VECTOR2I p ( outline->GetPos( i ) );
+ addAnchor( p, CORNER, aItem );
+ lc.Append( p );
+ }
+
+ addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
+
+ break;
+ }
+
+ case PCB_MODULE_TEXT_T:
+ case PCB_TEXT_T:
+ addAnchor( aItem->GetPosition(), ORIGIN, aItem );
+ default:
+
+ break;
+ }
+}
+
+
+GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor( const VECTOR2I& aPos, int aFlags, LSET aMatchLayers )
+{
+ double minDist = std::numeric_limits<double>::max();
+ ANCHOR* best = NULL;
+
+ BOOST_FOREACH( ANCHOR& a, m_anchors )
+ {
+ if( !aMatchLayers[a.item->GetLayer()] )
+ continue;
+
+ if( ( aFlags & a.flags ) != aFlags )
+ continue;
+
+ double dist = a.Distance( aPos );
+
+ if( dist < minDist )
+ {
+ minDist = dist;
+ best = &a;
+ }
+ }
+
+ return best;
+}