KiCad PCB EDA Suite
Loading...
Searching...
No Matches
oval.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) 2014 CERN
5 * Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "geometry/oval.h"
27
28#include <trigo.h> // for RotatePoint
29#include <geometry/shape_arc.h>
32
33using namespace KIGEOM;
34
35OVAL::OVAL( const SEG& aSeg, int aWidth ) : m_seg( aSeg ), m_width( aWidth )
36{
37 // A negative width is meaningless
38 wxASSERT( aWidth > 0 );
39}
40
41OVAL::OVAL( const VECTOR2I& aOverallSize, const VECTOR2I& aCenter, const EDA_ANGLE& aRotation )
42{
43 VECTOR2I segVec{};
44
45 // Find the major axis, without endcaps
46 if( aOverallSize.x > aOverallSize.y )
47 segVec.x = ( aOverallSize.x - aOverallSize.y );
48 else
49 segVec.y = ( aOverallSize.y - aOverallSize.x );
50
51 RotatePoint( segVec, aRotation );
52
53 m_seg = SEG( aCenter - segVec / 2, aCenter + segVec / 2 );
54 m_width = std::min( aOverallSize.x, aOverallSize.y );
55}
56
57
58BOX2I OVAL::BBox( int aClearance ) const
59{
60 const int rad = m_width / 2 + aClearance;
61
62 const VECTOR2I& topleft = LexicographicalMin( m_seg.A, m_seg.B );
63 const VECTOR2I& bottomright = LexicographicalMax( m_seg.A, m_seg.B );
64
65 return BOX2I::ByCorners( topleft - VECTOR2I( rad, rad ), bottomright + VECTOR2I( rad, rad ) );
66}
67
68
70{
71 const SEG& seg = aOval.GetSegment();
72 const VECTOR2I perp = GetRotated( seg.B - seg.A, ANGLE_90 ).Resize( aOval.GetWidth() / 2 );
73
74 SHAPE_LINE_CHAIN chain;
75 chain.Append( seg.A - perp );
76 chain.Append( SHAPE_ARC( seg.A, seg.A - perp, ANGLE_180 ) );
77 chain.Append( seg.B + perp );
78 chain.Append( SHAPE_ARC( seg.B, seg.B + perp, ANGLE_180 ) );
79 chain.SetClosed( true );
80 return chain;
81}
82
83
84std::vector<TYPED_POINT2I> KIGEOM::GetOvalKeyPoints( const OVAL& aOval,
86{
87 const int half_width = aOval.GetWidth() / 2;
88 const int half_len = aOval.GetLength() / 2;
89 const EDA_ANGLE rotation = aOval.GetAngle() - ANGLE_90;
90
91 // Points on a non-rotated pad at the origin, long-axis is y
92 // (so for now, width is left/right, len is up/down)
93 std::vector<TYPED_POINT2I> pts;
94
95 if( aFlags & OVAL_CENTER )
96 {
97 // Centre is easy
98 pts.emplace_back( VECTOR2I{ 0, 0 }, POINT_TYPE::PT_CENTER );
99 };
100
101 if( aFlags & OVAL_SIDE_MIDPOINTS )
102 {
103 // Side midpoints
104 pts.emplace_back( VECTOR2I{ half_width, 0 }, POINT_TYPE::PT_MID );
105 pts.emplace_back( VECTOR2I{ -half_width, 0 }, POINT_TYPE::PT_MID );
106 }
107
108 if( aFlags & OVAL_CAP_TIPS )
109 {
110 // If the oval is square-on, the tips are quadrants
111 const POINT_TYPE pt_type = rotation.IsCardinal() ? PT_QUADRANT : PT_END;
112
113 // Cap ends
114 pts.emplace_back( VECTOR2I{ 0, half_len }, pt_type );
115 pts.emplace_back( VECTOR2I{ 0, -half_len }, pt_type );
116 }
117
118 // Distance from centre to cap centres
119 const int d_centre_to_cap_centre = half_len - half_width;
120
121 if( aFlags & OVAL_CAP_CENTERS )
122 {
123 // Cap centres
124 pts.emplace_back( VECTOR2I{ 0, d_centre_to_cap_centre }, POINT_TYPE::PT_CENTER );
125 pts.emplace_back( VECTOR2I{ 0, -d_centre_to_cap_centre }, POINT_TYPE::PT_CENTER );
126 }
127
128 if( aFlags & OVAL_SIDE_ENDS )
129 {
130 const auto add_end = [&]( const VECTOR2I& aPt )
131 {
132 pts.emplace_back( aPt, POINT_TYPE::PT_END );
133 };
134
135 // End points of flat sides (always vertical)
136 add_end( { half_width, d_centre_to_cap_centre } );
137 add_end( { half_width, -d_centre_to_cap_centre } );
138 add_end( { -half_width, d_centre_to_cap_centre } );
139 add_end( { -half_width, -d_centre_to_cap_centre } );
140 }
141
142 // Add the quadrant points to the caps only if rotated
143 // (otherwise they're just the tips)
144 if( ( aFlags & OVAL_CARDINAL_EXTREMES ) && !rotation.IsCardinal() )
145 {
146 // We need to find two perpendicular lines from the centres
147 // of each cap to the cap edge, which will hit the points
148 // where the cap is tangent to H/V lines when rotated into place.
149 //
150 // Because we know the oval is always vertical, this means the
151 // two lines are formed between _|, through \/ to |_
152 // where the apex is the cap centre.
153
154 // The vector from a cap centre to the tip (i.e. vertical)
155 const VECTOR2I cap_radial = { 0, half_width };
156
157 // Rotate in the opposite direction to the oval's rotation
158 // (that will be unwound later)
159 EDA_ANGLE radial_line_rotation = rotation;
160
161 radial_line_rotation.Normalize90();
162
163 VECTOR2I cap_radial_to_x_axis = cap_radial;
164 RotatePoint( cap_radial_to_x_axis, radial_line_rotation );
165
166 // Find the other line - it's 90 degrees away, but re-normalise
167 // as it could be to the left or right
168 radial_line_rotation -= ANGLE_90;
169 radial_line_rotation.Normalize90();
170
171 VECTOR2I cap_radial_to_y_axis = cap_radial;
172 RotatePoint( cap_radial_to_y_axis, radial_line_rotation );
173
174 const auto add_quadrant = [&]( const VECTOR2I& aPt )
175 {
176 pts.emplace_back( aPt, POINT_TYPE::PT_QUADRANT );
177 };
178
179 // The quadrant points are then the relevant offsets from each cap centre
180 add_quadrant( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_y_axis );
181 add_quadrant( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_x_axis );
182 // The opposite cap offsets go from the other cap centre, the other way
183 add_quadrant( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_y_axis );
184 add_quadrant( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_x_axis );
185 }
186
187 for( TYPED_POINT2I& pt : pts )
188 {
189 // Transform to the actual orientation
190 RotatePoint( pt.m_point, -rotation );
191
192 // Translate to the actual position
193 pt.m_point += aOval.GetCenter();
194 }
195
196 return pts;
197}
static constexpr BOX2< VECTOR2I > ByCorners(const VECTOR2I &aCorner1, const VECTOR2I &aCorner2)
Definition: box2.h:70
EDA_ANGLE Normalize90()
Definition: eda_angle.h:249
bool IsCardinal() const
Definition: eda_angle.cpp:40
Class that represents an oval shape (rectangle with semicircular end caps)
Definition: oval.h:45
SEG m_seg
Definition: oval.h:100
int GetLength() const
Get the overall length of the oval from endcap tip to endcap tip.
Definition: oval.h:73
EDA_ANGLE GetAngle() const
Get the angle of the oval's central segment.
Definition: oval.h:97
int m_width
Definition: oval.h:101
BOX2I BBox(int aClearance) const
Get the bounding box of the oval.
Definition: oval.cpp:58
OVAL(const SEG &aSeg, int aWidth)
Create an oval from the segment joining the centers of the semicircles and the diameter of the semici...
Definition: oval.cpp:35
VECTOR2I GetCenter() const
Get the center point of the oval.
Definition: oval.h:83
const SEG & GetSegment() const
Get the central segment of the oval.
Definition: oval.h:90
int GetWidth() const
Get the width of the oval (diameter of the semicircles)
Definition: oval.h:68
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:385
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:405
std::vector< TYPED_POINT2I > GetOvalKeyPoints(const OVAL &aOval, OVAL_KEY_POINT_FLAGS aFlags)
Get a list of interesting points on an oval (rectangle with semicircular end caps)
Definition: oval.cpp:84
@ OVAL_SIDE_ENDS
Definition: oval.h:116
@ OVAL_CAP_TIPS
Definition: oval.h:113
@ OVAL_SIDE_MIDPOINTS
Definition: oval.h:115
@ OVAL_CARDINAL_EXTREMES
Definition: oval.h:117
@ OVAL_CENTER
Definition: oval.h:112
@ OVAL_CAP_CENTERS
Definition: oval.h:114
unsigned int OVAL_KEY_POINT_FLAGS
Definition: oval.h:121
SHAPE_LINE_CHAIN ConvertToChain(const OVAL &aOval)
Definition: oval.cpp:69
POINT_TYPE
Meanings that can be assigned to a point in pure geometric terms.
Definition: point_types.h:38
@ PT_CENTER
The point is the center of something.
Definition: point_types.h:46
@ PT_QUADRANT
The point is on a quadrant of a circle (N, E, S, W points).
Definition: point_types.h:58
@ PT_END
The point is at the end of a segment, arc, etc.
Definition: point_types.h:50
@ PT_MID
The point is at the middle of a segment, arc, etc.
Definition: point_types.h:54
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:77
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
constexpr const VECTOR2< T > & LexicographicalMax(const VECTOR2< T > &aA, const VECTOR2< T > &aB)
Definition: vector2d.h:616
constexpr const VECTOR2< T > & LexicographicalMin(const VECTOR2< T > &aA, const VECTOR2< T > &aB)
Definition: vector2d.h:628