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
30
31std::vector<VECTOR2I> GetOvalKeyPoints( const VECTOR2I& aOvalSize, const EDA_ANGLE& aRotation,
33{
34 const VECTOR2I half_size = aOvalSize / 2;
35 const int half_width = std::min( half_size.x, half_size.y );
36 const int half_len = std::max( half_size.x, half_size.y );
37
38 // Points on a non-rotated pad at the origin, long-axis is y
39 // (so for now, width is left/right, len is up/down)
40 std::vector<VECTOR2I> pts;
41
42 if ( aFlags & OVAL_CENTER )
43 {
44 // Centre is easy
45 pts.emplace_back( 0, 0 );
46 };
47
48 if ( aFlags & OVAL_SIDE_MIDPOINTS )
49 {
50 // Side midpoints
51 pts.emplace_back( half_width, 0 );
52 pts.emplace_back( -half_width, 0 );
53 }
54
55 if ( aFlags & OVAL_CAP_TIPS )
56 {
57 // Cap ends
58 pts.emplace_back( 0, half_len );
59 pts.emplace_back( 0, -half_len );
60 }
61
62 // Distance from centre to cap centres
63 const int d_centre_to_cap_centre = half_len - half_width;
64
65 if ( aFlags & OVAL_CAP_CENTERS )
66 {
67 // Cap centres
68 pts.emplace_back( 0, d_centre_to_cap_centre );
69 pts.emplace_back( 0, -d_centre_to_cap_centre );
70 }
71
72 if ( aFlags & OVAL_SIDE_ENDS )
73 {
74 // End points of flat sides (always vertical)
75 pts.emplace_back( half_width, d_centre_to_cap_centre );
76 pts.emplace_back( half_width, -d_centre_to_cap_centre );
77 pts.emplace_back( -half_width, d_centre_to_cap_centre );
78 pts.emplace_back( -half_width, -d_centre_to_cap_centre );
79 }
80
81 // If the pad is horizontal (i.e. x > y), we'll rotate the whole thing
82 // 90 degrees and work with it as if it was vertical
83 const bool swap_xy = half_size.x > half_size.y;
84 const EDA_ANGLE rotation = aRotation + ( swap_xy ? -ANGLE_90 : ANGLE_0 );
85
86 // Add the quadrant points to the caps only if rotated
87 // (otherwise they're just the tips)
88 if( ( aFlags & OVAL_CARDINAL_EXTREMES ) && !rotation.IsCardinal() )
89 {
90 // We need to find two perpendicular lines from the centres
91 // of each cap to the cap edge, which will hit the points
92 // where the cap is tangent to H/V lines when rotated into place.
93 //
94 // Because we know the oval is always vertical, this means the
95 // two lines are formed between _|, through \/ to |_
96 // where the apex is the cap centre.
97
98 // The vector from a cap centre to the tip (i.e. vertical)
99 const VECTOR2I cap_radial = { 0, half_width };
100
101 // Rotate in the opposite direction to the oval's rotation
102 // (that will be unwound later)
103 EDA_ANGLE radial_line_rotation = -rotation;
104
105 radial_line_rotation.Normalize90();
106
107 VECTOR2I cap_radial_to_x_axis = cap_radial;
108 RotatePoint( cap_radial_to_x_axis, radial_line_rotation );
109
110 // Find the other line - it's 90 degrees away, but re-normalise
111 // as it could be to the left or right
112 radial_line_rotation -= ANGLE_90;
113 radial_line_rotation.Normalize90();
114
115 VECTOR2I cap_radial_to_y_axis = cap_radial;
116 RotatePoint( cap_radial_to_y_axis, radial_line_rotation );
117
118 // The quadrant points are then the relevant offsets from each cap centre
119 pts.emplace_back( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_y_axis );
120 pts.emplace_back( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_x_axis );
121 // The opposite cap offsets go from the other cap centre, the other way
122 pts.emplace_back( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_y_axis );
123 pts.emplace_back( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_x_axis );
124 }
125
126 for( VECTOR2I& pt : pts )
127 {
128 // Transform to the actual orientation
129 // Already includes the extra 90 to swap x/y if needed
130 RotatePoint( pt, rotation );
131 }
132
133 return pts;
134}
EDA_ANGLE Normalize90()
Definition: eda_angle.h:283
bool IsCardinal() const
Definition: eda_angle.cpp:40
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:435
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:437
std::vector< VECTOR2I > GetOvalKeyPoints(const VECTOR2I &aOvalSize, const EDA_ANGLE &aRotation, OVAL_KEY_POINT_FLAGS aFlags)
Get a list of interesting points on an oval (rectangle with semicircular end caps)
Definition: oval.cpp:31
unsigned int OVAL_KEY_POINT_FLAGS
Definition: oval.h:43
@ OVAL_CARDINAL_EXTREMES
Definition: oval.h:39
@ OVAL_SIDE_ENDS
Definition: oval.h:38
@ OVAL_CAP_TIPS
Definition: oval.h:35
@ OVAL_SIDE_MIDPOINTS
Definition: oval.h:37
@ OVAL_CAP_CENTERS
Definition: oval.h:36
@ OVAL_CENTER
Definition: oval.h:34
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:228