KiCad PCB EDA Suite
Loading...
Searching...
No Matches
grid_geometry.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
22#include <algorithm>
23#include <cmath>
24
25#include <trigo.h>
26#include <wx/log.h>
27
28
30{
31 const VECTOR2D local = GetRotated( aPoint - origin, EDA_ANGLE( -orientation, RADIANS_T ) );
32 VECTOR2D candidate;
33
34 switch( kind )
35 {
36 case KIND::POLAR:
37 {
38 const double dr = pitch.x;
39 const double dPhi = pitch.y;
40 const double rMax = extent.x;
41 const double phiMax = extent.y;
42
43 if( dr <= 0.0 || dPhi <= 0.0 )
44 return aPoint;
45
46 const double r = std::hypot( local.x, local.y );
47 const int maxRIdx = static_cast<int>( rMax / dr );
48 const int rIdx = std::clamp( static_cast<int>( std::round( r / dr ) ), 0, maxRIdx );
49
50 // Normalise phi to [0, 2*pi) and clamp to the last drawn spoke; otherwise
51 // a cursor just inside the wedge rounds up past the last spoke.
52 double phi = std::atan2( local.y, local.x );
53
54 if( phi < 0 )
55 phi += 2 * M_PI;
56
57 const int maxPIdx = static_cast<int>( phiMax / dPhi );
58 const int pIdx = std::clamp( static_cast<int>( std::round( phi / dPhi ) ), 0, maxPIdx );
59
60 const double phiQ = pIdx * dPhi;
61 const double rSnapped = rIdx * dr;
62
63 candidate = VECTOR2D( rSnapped * std::cos( phiQ ), rSnapped * std::sin( phiQ ) );
64 break;
65 }
66
67 case KIND::CARTESIAN:
68 {
69 const double dx = pitch.x;
70 const double dy = pitch.y;
71
72 if( dx <= 0.0 || dy <= 0.0 )
73 return aPoint;
74
75 // Centred on origin; extent is size/2. Indices go -N..+N.
76 const int nX = static_cast<int>( extent.x / dx );
77 const int nY = static_cast<int>( extent.y / dy );
78
79 const int xIdx = std::clamp( static_cast<int>( std::round( local.x / dx ) ), -nX, nX );
80 const int yIdx = std::clamp( static_cast<int>( std::round( local.y / dy ) ), -nY, nY );
81
82 candidate = VECTOR2D( xIdx * dx, yIdx * dy );
83 break;
84 }
85
86 default: wxFAIL_MSG( wxT( "GRID_GEOMETRY::Snap: unhandled KIND" ) ); return aPoint;
87 }
88
89 return GetRotated( candidate, EDA_ANGLE( orientation, RADIANS_T ) ) + origin;
90}
91
92
93bool GRID_GEOMETRY::Contains( const VECTOR2D& aPoint, double aTolerance ) const
94{
95 const VECTOR2D local = GetRotated( aPoint - origin, EDA_ANGLE( -orientation, RADIANS_T ) );
96
97 switch( kind )
98 {
99 case KIND::POLAR:
100 {
101 const double r = std::hypot( local.x, local.y );
102
103 if( r > extent.x + aTolerance )
104 return false;
105
106 const double phiMax = extent.y;
107 double phi = std::atan2( local.y, local.x );
108
109 while( phi < 0 )
110 phi += 2 * M_PI;
111
112 return phi <= std::abs( phiMax );
113 }
114
115 case KIND::CARTESIAN:
116 return local.x >= -extent.x - aTolerance && local.x <= extent.x + aTolerance
117 && local.y >= -extent.y - aTolerance && local.y <= extent.y + aTolerance;
118
119 default: wxFAIL_MSG( wxT( "GRID_GEOMETRY::Contains: unhandled KIND" ) ); return false;
120 }
121}
122
123
125{
126 switch( kind )
127 {
128 case KIND::POLAR:
129 // Polar wedge: 0.5 * r^2 * phi.
130 return 0.5 * extent.x * extent.x * std::abs( extent.y );
131
132 case KIND::CARTESIAN:
133 // Centred rectangle: 4 * (size/2).x * (size/2).y.
134 return std::abs( 4.0 * extent.x * extent.y );
135
136 default: wxFAIL_MSG( wxT( "GRID_GEOMETRY::Area: unhandled KIND" ) ); return 0.0;
137 }
138}
@ RADIANS_T
Definition eda_angle.h:32
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
double orientation
Rotation about origin, radians CCW.
double Area() const
VECTOR2D extent
Cartesian: (dx, dy) = size/2 from origin.
VECTOR2D pitch
Cartesian: (dx, dy); polar: (dr, dPhi rad).
bool Contains(const VECTOR2D &aPoint, double aTolerance=0.0) const
VECTOR2D Snap(const VECTOR2D &aPoint) const
Snap a point to the nearest on-grid position.
VECTOR2D origin
#define M_PI
VECTOR2I GetRotated(const VECTOR2I &aVector, const EDA_ANGLE &aAngle)
Return a new VECTOR2I that is the result of rotating aVector by aAngle.
Definition trigo.h:73
VECTOR2< double > VECTOR2D
Definition vector2d.h:682