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 The 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>
31
32using namespace KIGEOM;
33
34
36{
37 const SEG& seg = aOval.GetSeg();
38 const VECTOR2I perp = GetRotated( seg.B - seg.A, ANGLE_90 ).Resize( aOval.GetWidth() / 2 );
39
41 chain.Append( seg.A - perp );
42 chain.Append( SHAPE_ARC( seg.A, seg.A - perp, ANGLE_180 ) );
43 chain.Append( seg.B + perp );
44 chain.Append( SHAPE_ARC( seg.B, seg.B + perp, ANGLE_180 ) );
45 chain.SetClosed( true );
46 return chain;
47}
48
49
50std::vector<TYPED_POINT2I> KIGEOM::GetOvalKeyPoints( const SHAPE_SEGMENT& aOval, OVAL_KEY_POINT_FLAGS aFlags )
51{
52 const int half_width = aOval.GetWidth() / 2;
53 const int half_len = aOval.GetTotalLength() / 2;
54 const EDA_ANGLE rotation = aOval.GetAngle() - ANGLE_90;
55
56 // Points on a non-rotated pad at the origin, long-axis is y
57 // (so for now, width is left/right, len is up/down)
58 std::vector<TYPED_POINT2I> pts;
59
60 if( aFlags & OVAL_CENTER )
61 {
62 // Centre is easy
63 pts.emplace_back( VECTOR2I{ 0, 0 }, POINT_TYPE::PT_CENTER );
64 };
65
66 if( aFlags & OVAL_SIDE_MIDPOINTS )
67 {
68 // Side midpoints
69 pts.emplace_back( VECTOR2I{ half_width, 0 }, POINT_TYPE::PT_MID );
70 pts.emplace_back( VECTOR2I{ -half_width, 0 }, POINT_TYPE::PT_MID );
71 }
72
73 if( aFlags & OVAL_CAP_TIPS )
74 {
75 // If the oval is square-on, the tips are quadrants
76 const POINT_TYPE pt_type = rotation.IsCardinal() ? PT_QUADRANT : PT_END;
77
78 // Cap ends
79 pts.emplace_back( VECTOR2I{ 0, half_len }, pt_type );
80 pts.emplace_back( VECTOR2I{ 0, -half_len }, pt_type );
81 }
82
83 // Distance from centre to cap centres
84 const int d_centre_to_cap_centre = half_len - half_width;
85
86 if( aFlags & OVAL_CAP_CENTERS )
87 {
88 // Cap centres
89 pts.emplace_back( VECTOR2I{ 0, d_centre_to_cap_centre }, POINT_TYPE::PT_CENTER );
90 pts.emplace_back( VECTOR2I{ 0, -d_centre_to_cap_centre }, POINT_TYPE::PT_CENTER );
91 }
92
93 if( aFlags & OVAL_SIDE_ENDS )
94 {
95 const auto add_end = [&]( const VECTOR2I& aPt )
96 {
97 pts.emplace_back( aPt, POINT_TYPE::PT_END );
98 };
99
100 // End points of flat sides (always vertical)
101 add_end( { half_width, d_centre_to_cap_centre } );
102 add_end( { half_width, -d_centre_to_cap_centre } );
103 add_end( { -half_width, d_centre_to_cap_centre } );
104 add_end( { -half_width, -d_centre_to_cap_centre } );
105 }
106
107 // Add the quadrant points to the caps only if rotated
108 // (otherwise they're just the tips)
109 if( ( aFlags & OVAL_CARDINAL_EXTREMES ) && !rotation.IsCardinal() )
110 {
111 // We need to find two perpendicular lines from the centres
112 // of each cap to the cap edge, which will hit the points
113 // where the cap is tangent to H/V lines when rotated into place.
114 //
115 // Because we know the oval is always vertical, this means the
116 // two lines are formed between _|, through \/ to |_
117 // where the apex is the cap centre.
118
119 // The vector from a cap centre to the tip (i.e. vertical)
120 const VECTOR2I cap_radial = { 0, half_width };
121
122 // Rotate in the opposite direction to the oval's rotation
123 // (that will be unwound later)
124 EDA_ANGLE radial_line_rotation = rotation;
125
126 radial_line_rotation.Normalize90();
127
128 VECTOR2I cap_radial_to_x_axis = cap_radial;
129 RotatePoint( cap_radial_to_x_axis, radial_line_rotation );
130
131 // Find the other line - it's 90 degrees away, but re-normalise
132 // as it could be to the left or right
133 radial_line_rotation -= ANGLE_90;
134 radial_line_rotation.Normalize90();
135
136 VECTOR2I cap_radial_to_y_axis = cap_radial;
137 RotatePoint( cap_radial_to_y_axis, radial_line_rotation );
138
139 const auto add_quadrant = [&]( const VECTOR2I& aPt )
140 {
141 pts.emplace_back( aPt, POINT_TYPE::PT_QUADRANT );
142 };
143
144 // The quadrant points are then the relevant offsets from each cap centre
145 add_quadrant( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_y_axis );
146 add_quadrant( VECTOR2I{ 0, d_centre_to_cap_centre } + cap_radial_to_x_axis );
147 // The opposite cap offsets go from the other cap centre, the other way
148 add_quadrant( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_y_axis );
149 add_quadrant( VECTOR2I{ 0, -d_centre_to_cap_centre } - cap_radial_to_x_axis );
150 }
151
152 for( TYPED_POINT2I& pt : pts )
153 {
154 // Transform to the actual orientation
155 RotatePoint( pt.m_point, -rotation );
156
157 // Translate to the actual position
158 pt.m_point += aOval.GetCenter();
159 }
160
161 return pts;
162}
EDA_ANGLE Normalize90()
Definition eda_angle.h:257
bool IsCardinal() const
Definition eda_angle.cpp:40
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...
const SEG & GetSeg() const
EDA_ANGLE GetAngle() const
int GetWidth() const override
int GetTotalLength() const
Get the total length of the segment, from tip to tip.
VECTOR2I GetCenter() const
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:413
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
std::vector< TYPED_POINT2I > GetOvalKeyPoints(const SHAPE_SEGMENT &aOval, OVAL_KEY_POINT_FLAGS aFlags)
Get a list of interesting points on an oval (rectangle with semicircular end caps)
Definition oval.cpp:50
SHAPE_LINE_CHAIN ConvertToChain(const SHAPE_SEGMENT &aOval)
Definition oval.cpp:35
@ OVAL_SIDE_ENDS
Definition oval.h:52
@ OVAL_CAP_TIPS
Definition oval.h:49
@ OVAL_SIDE_MIDPOINTS
Definition oval.h:51
@ OVAL_CARDINAL_EXTREMES
Definition oval.h:53
@ OVAL_CENTER
Definition oval.h:48
@ OVAL_CAP_CENTERS
Definition oval.h:50
unsigned int OVAL_KEY_POINT_FLAGS
Definition oval.h:57
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
const SHAPE_LINE_CHAIN chain
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:695