KiCad PCB EDA Suite
Loading...
Searching...
No Matches
roundrect.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 * 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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "geometry/roundrect.h"
23
26
27#include <wx/log.h>
28
29
30namespace
31{
32
33SHAPE_ARC MakeCornerArcCw90( const SHAPE_RECT& aRect, int aRadius, DIRECTION_45::Directions aDir )
34{
35 const VECTOR2I center = KIGEOM::GetPoint( aRect, aDir );
36 return KIGEOM::MakeArcCw90( center, aRadius, aDir );
37}
38
39
40SHAPE_ARC MakeSideArcCw180( const SHAPE_RECT& aRect, int aRadius, DIRECTION_45::Directions aDir )
41{
42 const VECTOR2I center = KIGEOM::GetPoint( aRect, aDir );
43 return KIGEOM::MakeArcCw180( center, aRadius, aDir );
44}
45
46} // namespace
47
48
49ROUNDRECT::ROUNDRECT( SHAPE_RECT aRect, int aRadius, bool aNormalizeOnCreate ) :
50 m_rect( std::move( aRect ) ),
51 m_radius( aRadius )
52{
53 if( aNormalizeOnCreate )
54 m_rect.Normalize();
55
56 // Ensure radius is compatible with rectangle size:
57 int min_radius = std::abs( m_rect.MinorDimension() )/2;
58
59 if( m_radius > min_radius )
60 m_radius = min_radius;
61
62 if( m_radius < 0 )
63 m_radius = 0;
64}
65
66
67ROUNDRECT ROUNDRECT::OutsetFrom( const SHAPE_RECT& aRect, int aOutset )
68{
69 return ROUNDRECT( aRect.GetInflated( aOutset ), aOutset );
70}
71
72
74{
75 return ROUNDRECT( m_rect.GetInflated( aOutset ), m_radius + aOutset );
76}
77
78
79void ROUNDRECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aMaxError ) const
80{
81 // Roundrects won't have a gazillion points, so we use a higher definition than the
82 // typical maxError.
83 int maxError = aMaxError / 5;
84
86 const int idx = tmp.NewOutline();
87 SHAPE_LINE_CHAIN& outline = tmp.Outline( idx );
88
89 const int w = m_rect.GetWidth();
90 const int h = m_rect.GetHeight();
91
92 // Handle non normalized rect (i.e. w or h < 0 )
93 if( w < 0 || h < 0 )
94 {
95 ROUNDRECT norm_rr( m_rect, m_radius, true ); // build a normalized ROUNDRECT (w,h >= 0)
96 norm_rr.TransformToPolygon( aBuffer, aMaxError );
97 return;
98 }
99
100 // This code works fine only with normalized rect (i.e. w or h >= 0 )
101 const int x_edge = m_rect.GetWidth() - 2 * m_radius;
102 const int y_edge = m_rect.GetHeight() - 2 * m_radius;
103
104 // Handle degenerate cases where dimensions are invalid
105 // This can happen with negative inflate values or zero-size rectangles
106 if( x_edge < 0 || y_edge < 0 || m_radius < 0 || w <= 0 || h <= 0 )
107 return;
108
109 const VECTOR2I& m_p0 = m_rect.GetPosition();
110
111 if( m_radius == 0 )
112 {
113 // It's just a rectangle
114 outline.Append( m_p0 );
115 outline.Append( m_p0 + VECTOR2I( w, 0 ) );
116 outline.Append( m_p0 + VECTOR2I( w, h ) );
117 outline.Append( m_p0 + VECTOR2I( 0, h ) );
118 }
119 else if( x_edge == 0 && y_edge == 0 )
120 {
121 // It's a circle
122 outline.Append( SHAPE_ARC( m_p0 + VECTOR2I( m_radius, m_radius ), m_p0 + VECTOR2I( 0, m_radius ), ANGLE_360 ),
123 maxError );
124 }
125 else
126 {
127 const SHAPE_RECT inner_rect{ m_p0 + VECTOR2I( m_radius, m_radius ), x_edge, y_edge };
128
129 if( x_edge > 0 )
130 {
131 // Either a normal roundrect or an oval with x_edge > 0
132
133 // Start to the right of the top left radius
134 outline.Append( m_p0 + VECTOR2I( m_radius, 0 ) );
135
136 // Top side
137 outline.Append( m_p0 + VECTOR2I( m_radius + x_edge, 0 ) );
138
139 if( y_edge > 0 )
140 {
141 outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::NE ), maxError );
142 outline.Append( m_p0 + VECTOR2I( w, m_radius + y_edge ) );
143 outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::SE ), maxError );
144 }
145 else
146 {
147 outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::E ), maxError );
148 }
149
150 // Bottom side
151 outline.Append( m_p0 + VECTOR2I( m_radius, h ) );
152
153 if( y_edge > 0 )
154 {
155 outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::SW ), maxError );
156 outline.Append( m_p0 + VECTOR2I( 0, m_radius ) );
157 outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::NW ), maxError );
158 }
159 else
160 {
161 outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::W ), maxError );
162 }
163 }
164 else
165 {
166 // x_edge is 0 but y_edge is not, so it's an oval the other way up
167 outline.Append( m_p0 + VECTOR2I( 0, m_radius ) );
168 outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::N ), maxError );
169 outline.Append( m_p0 + VECTOR2I( w, m_radius + y_edge ) );
170 outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::S ), maxError );
171 }
172 }
173
174 outline.SetClosed( true );
175 aBuffer = std::move( tmp );
176}
Directions
Available directions, there are 8 of them, as on a rectilinear map (north = up) + an extra undefined ...
Definition direction45.h:49
int m_radius
Definition roundrect.h:86
SHAPE_RECT m_rect
Definition roundrect.h:85
static ROUNDRECT OutsetFrom(const SHAPE_RECT &aRect, int aOutset)
Definition roundrect.cpp:67
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aMaxError) const
Get the polygonal representation of the roundrect.
Definition roundrect.cpp:79
ROUNDRECT GetInflated(int aOutset) const
Get the roundrect with the size increased by aOutset in all directions.
Definition roundrect.cpp:73
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.
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
SHAPE_RECT GetInflated(int aOffset) const
Return a rectangle that is larger by aOffset in all directions, but still centered on the original re...
Definition shape_rect.h:116
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
VECTOR2I GetPoint(const SHAPE_RECT &aRect, DIRECTION_45::Directions aDir, int aOutset=0)
Get the point on a rectangle that corresponds to a given direction.
SHAPE_ARC MakeArcCw180(const VECTOR2I &aCenter, int aRadius, DIRECTION_45::Directions aDir)
Get a SHAPE_ARC representing a 180-degree arc in the clockwise direction with the midpoint in the giv...
SHAPE_ARC MakeArcCw90(const VECTOR2I &aCenter, int aRadius, DIRECTION_45::Directions aDir)
Get a SHAPE_ARC representing a 90-degree arc in the clockwise direction with the midpoint in the give...
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
Utility functions for working with shapes.
VECTOR2I center
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683