KiCad PCB EDA Suite
shape_arc.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 (C) 2017 CERN
5  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <vector>
26 
28 #include <geometry/shape_arc.h>
30 
31 bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
32 {
33  int minDist = aClearance + m_width / 2;
34  auto centerDist = aSeg.Distance( m_pc );
35  auto p1 = GetP1();
36 
37  if( centerDist < minDist )
38  return true;
39 
40  auto ab = (aSeg.B - aSeg.A );
41  auto ac = ( m_pc - aSeg.A );
42 
43  auto lenAbSq = ab.SquaredEuclideanNorm();
44 
45  auto lambda = (double) ac.Dot( ab ) / (double) lenAbSq;
46 
47 
48  if( lambda >= 0.0 && lambda <= 1.0 )
49  {
50  VECTOR2I p;
51 
52  p.x = (double) aSeg.A.x * lambda + (double) aSeg.B.x * (1.0 - lambda);
53  p.y = (double) aSeg.A.y * lambda + (double) aSeg.B.y * (1.0 - lambda);
54 
55  auto p0pdist = ( m_p0 - p ).EuclideanNorm();
56 
57  if( p0pdist < minDist )
58  return true;
59 
60  auto p1pdist = ( p1 - p ).EuclideanNorm();
61 
62  if( p1pdist < minDist )
63  return true;
64  }
65 
66  auto p0dist = aSeg.Distance( m_p0 );
67 
68  if( p0dist > minDist )
69  return true;
70 
71  auto p1dist = aSeg.Distance( p1 );
72 
73  if( p1dist > minDist )
74  return false;
75 
76 
77  return true;
78 }
79 
80 #if 0
81 bool SHAPE_ARC::ConstructFromCorners( VECTOR2I aP0, VECTOR2I aP1, double aCenterAngle )
82 {
83  VECTOR2D mid = ( VECTOR2D( aP0 ) + VECTOR2D( aP1 ) ) * 0.5;
84  VECTOR2D chord = VECTOR2D( aP1 ) - VECTOR2D( aP0 );
85  double c = (aP1 - aP0).EuclideanNorm() / 2;
86  VECTOR2D d = chord.Rotate( M_PI / 2.0 ).Resize( c );
87 
88  m_pc = mid + d * ( 1.0 / tan( aCenterAngle / 2.0 * M_PI / 180.0 ) );
89  m_p0 = aP0;
90  m_p1 = aP1;
91 
92  return true;
93 }
94 
95 bool SHAPE_ARC::ConstructFromCornerAndAngles( VECTOR2I aP0,
96  double aStartAngle,
97  double aCenterAngle,
98  double aRadius )
99 {
100  m_p0 = aP0;
101  auto d1 = VECTOR2D( 1.0, 0.0 ).Rotate( aStartAngle * M_PI / 180.0 ) * aRadius;
102  auto d2 =
103  VECTOR2D( 1.0, 0.0 ).Rotate( (aStartAngle + aCenterAngle) * M_PI / 180.0 ) * aRadius;
104 
105  m_pc = m_p0 - (VECTOR2I) d1;
106  m_p1 = m_pc + (VECTOR2I) d2;
107 
108  if( aCenterAngle < 0 )
109  std::swap( m_p0, m_p1 );
110 
111  return true;
112 }
113 
114 bool SHAPE_ARC::ConstructFromCenterAndAngles( VECTOR2I aCenter, double aRadius, double aStartAngle, double aCenterAngle )
115 {
116  double ea = aStartAngle + aCenterAngle;
117 
118  m_fullCircle = false;
119  m_pc = aCenter;
120  m_p0.x = (int) ( (double) aCenter.x + aRadius * cos( aStartAngle * M_PI / 180.0 ) );
121  m_p0.y = (int) ( (double) aCenter.y + aRadius * sin( aStartAngle * M_PI / 180.0 ) );
122  m_p1.x = (int) ( (double) aCenter.x + aRadius * cos( ea * M_PI / 180.0 ) );
123  m_p1.y = (int) ( (double) aCenter.y + aRadius * sin( ea * M_PI / 180.0 ) );
124 
125  if( aCenterAngle == 360.0 )
126  {
127  m_fullCircle = true;
128  return true;
129  }
130  else if ( aCenterAngle < 0.0 )
131  {
132  std::swap(m_p0, m_p1);
133  }
134 
135  return true;
136 }
137 #endif
138 
139 
141 {
142  VECTOR2D rvec = m_p0 - m_pc;
143  auto ca = m_centralAngle * M_PI / 180.0;
144  VECTOR2I p1;
145 
146  p1.x = (int) ( m_pc.x + rvec.x * cos( ca ) - rvec.y * sin( ca ) );
147  p1.y = (int) ( m_pc.y + rvec.x * sin( ca ) + rvec.y * cos( ca ) );
148 
149  return p1;
150 }
151 
152 
153 const BOX2I SHAPE_ARC::BBox( int aClearance ) const
154 {
155  BOX2I bbox;
156  std::vector<VECTOR2I> points;
157  points.push_back( m_pc );
158  points.push_back( m_p0 );
159  points.push_back( GetP1() );
160 
161  bbox.Compute( points );
162 
163  if( aClearance != 0 )
164  bbox.Inflate( aClearance );
165 
166  return bbox;
167 }
168 
169 
170 bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance ) const
171 {
172  assert( false );
173  return false;
174 }
175 
176 
178 {
179  VECTOR2D d( m_p0 - m_pc );
180 
181  auto ang = 180.0 / M_PI * atan2( d.y, d.x );
182 
183  return ang;
184 }
185 
187 {
188  double a = GetStartAngle() + m_centralAngle;
189 
190  if( a < 0.0 )
191  a += 360.0;
192  else if ( a >= 360.0 )
193  a -= 360.0;
194 
195  return a;
196 }
197 
199 {
200  return m_centralAngle;
201 }
202 
204 {
205  return (m_p0 - m_pc).EuclideanNorm();
206 }
207 
208 const SHAPE_LINE_CHAIN SHAPE_ARC::ConvertToPolyline( double aAccuracy ) const
209 {
210  SHAPE_LINE_CHAIN rv;
211  double r = GetRadius();
212  double sa = GetStartAngle();
213  auto c = GetCenter();
214  int n;
215 
216  if( r == 0.0 )
217  {
218  n = 0;
219  }
220  else
221  {
222  n = GetArcToSegmentCount( r, aAccuracy, m_centralAngle );
223  }
224 
225  for( int i = 0; i <= n ; i++ )
226  {
227  double a = sa + m_centralAngle * (double) i / (double) n;
228  double x = c.x + r * cos( a * M_PI / 180.0 );
229  double y = c.y + r * sin( a * M_PI / 180.0 );
230 
231  rv.Append( (int) x, (int) y );
232  }
233 
234  return rv;
235 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:112
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
VECTOR2< T > Resize(T aNewLength) const
Function Resize returns a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:385
double GetStartAngle() const
Definition: shape_arc.cpp:177
VECTOR2< T > Rotate(double aAngle) const
Function Rotate rotates the vector by a given angle.
Definition: vector2d.h:370
void Compute(const Container &aPointList)
Compute the bounding box from a given list of points.
Definition: box2.h:89
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
const VECTOR2I GetP1() const
Definition: shape_arc.cpp:140
double GetCentralAngle() const
Definition: shape_arc.cpp:198
double GetEndAngle() const
Definition: shape_arc.cpp:186
VECTOR2< double > VECTOR2D
Definition: vector2d.h:586
bool Collide(const SEG &aSeg, int aClearance=0) const override
Function Collide()
Definition: shape_arc.cpp:31
VECTOR2I m_p0
Definition: shape_arc.h:136
a few functions useful in geometry calculations.
const VECTOR2I & GetCenter() const
Definition: shape_arc.h:64
Definition: seg.h:36
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:300
int GetRadius() const
Definition: shape_arc.cpp:203
Class SHAPE_LINE_CHAIN.
size_t i
Definition: json11.cpp:597
VECTOR2I A
Definition: seg.h:46
VECTOR2I m_pc
Definition: shape_arc.h:136
const BOX2I BBox(int aClearance=0) const override
Function BBox()
Definition: shape_arc.cpp:153
int m_width
Definition: shape_arc.h:139
int Distance(const SEG &aSeg) const
Function Distance()
Definition: seg.h:195
double m_centralAngle
Definition: shape_arc.h:137
const SHAPE_LINE_CHAIN ConvertToPolyline(double aAccuracy=500.0) const
Constructs a SHAPE_LINE_CHAIN of segments from a given arc.
Definition: shape_arc.cpp:208
VECTOR2I B
Definition: seg.h:47