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, 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/roundrect.h"
27
30
31#include <wx/log.h>
32
33
34namespace
35{
36
37SHAPE_ARC MakeCornerArcCw90( const SHAPE_RECT& aRect, int aRadius, DIRECTION_45::Directions aDir )
38{
39 const VECTOR2I center = KIGEOM::GetPoint( aRect, aDir );
40 return KIGEOM::MakeArcCw90( center, aRadius, aDir );
41}
42
43
44SHAPE_ARC MakeSideArcCw180( const SHAPE_RECT& aRect, int aRadius, DIRECTION_45::Directions aDir )
45{
46 const VECTOR2I center = KIGEOM::GetPoint( aRect, aDir );
47 return KIGEOM::MakeArcCw180( center, aRadius, aDir );
48}
49
50} // namespace
51
52
53ROUNDRECT::ROUNDRECT( SHAPE_RECT aRect, int aRadius, bool aNormalizeOnCreate ) :
54 m_rect( std::move( aRect ) ),
55 m_radius( aRadius )
56{
57 if( aNormalizeOnCreate )
58 m_rect.Normalize();
59
60 // Ensure radius is compatible with rectangle size:
61 int min_radius = std::abs( m_rect.MinorDimension() )/2;
62
63 if( m_radius > min_radius )
64 m_radius = min_radius;
65
66 if( m_radius < 0 )
67 m_radius = 0;
68}
69
70
71ROUNDRECT ROUNDRECT::OutsetFrom( const SHAPE_RECT& aRect, int aOutset )
72{
73 return ROUNDRECT( aRect.GetInflated( aOutset ), aOutset );
74}
75
76
78{
79 return ROUNDRECT( m_rect.GetInflated( aOutset ), m_radius + aOutset );
80}
81
82
83void ROUNDRECT::TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aMaxError ) const
84{
85 // Roundrects won't have a gazillion points, so we use a higher definition than the
86 // typical maxError.
87 int maxError = aMaxError / 5;
88
90 const int idx = tmp.NewOutline();
91 SHAPE_LINE_CHAIN& outline = tmp.Outline( idx );
92
93 const int w = m_rect.GetWidth();
94 const int h = m_rect.GetHeight();
95
96 // Handle non normalized rect (i.e. w or h < 0 )
97 if( w < 0 || h < 0 )
98 {
99 ROUNDRECT norm_rr( m_rect, m_radius, true ); // build a normalized ROUNDRECT (w,h >= 0)
100 norm_rr.TransformToPolygon( aBuffer, aMaxError );
101 return;
102 }
103
104 // This code works fine only with normalized rect (i.e. w or h >= 0 )
105 const int x_edge = m_rect.GetWidth() - 2 * m_radius;
106 const int y_edge = m_rect.GetHeight() - 2 * m_radius;
107
108 // Handle degenerate cases where dimensions are invalid
109 // This can happen with negative inflate values or zero-size rectangles
110 if( x_edge < 0 || y_edge < 0 || m_radius < 0 || w <= 0 || h <= 0 )
111 {
112 wxLogDebug( "ROUNDRECT::TransformToPolygon: Degenerate roundrect, skipping polygon generation." );
113 return;
114 }
115
116 const VECTOR2I& m_p0 = m_rect.GetPosition();
117
118 if( m_radius == 0 )
119 {
120 // It's just a rectangle
121 outline.Append( m_p0 );
122 outline.Append( m_p0 + VECTOR2I( w, 0 ) );
123 outline.Append( m_p0 + VECTOR2I( w, h ) );
124 outline.Append( m_p0 + VECTOR2I( 0, h ) );
125 }
126 else if( x_edge == 0 && y_edge == 0 )
127 {
128 // It's a circle
129 outline.Append( SHAPE_ARC( m_p0 + VECTOR2I( m_radius, m_radius ),
130 m_p0 + VECTOR2I( -m_radius, 0 ), ANGLE_360 ), maxError );
131 }
132 else
133 {
134 const SHAPE_RECT inner_rect{ m_p0 + VECTOR2I( m_radius, m_radius ), x_edge, y_edge };
135
136 if( x_edge > 0 )
137 {
138 // Either a normal roundrect or an oval with x_edge > 0
139
140 // Start to the right of the top left radius
141 outline.Append( m_p0 + VECTOR2I( m_radius, 0 ) );
142
143 // Top side
144 outline.Append( m_p0 + VECTOR2I( m_radius + x_edge, 0 ) );
145
146 if( y_edge > 0 )
147 {
148 outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::NE ), maxError );
149 outline.Append( m_p0 + VECTOR2I( w, m_radius + y_edge ) );
150 outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::SE ), maxError );
151 }
152 else
153 {
154 outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::E ), maxError );
155 }
156
157 // Bottom side
158 outline.Append( m_p0 + VECTOR2I( m_radius, h ) );
159
160 if( y_edge > 0 )
161 {
162 outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::SW ), maxError );
163 outline.Append( m_p0 + VECTOR2I( 0, m_radius ) );
164 outline.Append( MakeCornerArcCw90( inner_rect, m_radius, DIRECTION_45::NW ), maxError );
165 }
166 else
167 {
168 outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::W ), maxError );
169 }
170 }
171 else
172 {
173 // x_edge is 0 but y_edge is not, so it's an oval the other way up
174 outline.Append( m_p0 + VECTOR2I( 0, m_radius ) );
175 outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::N ), maxError );
176 outline.Append( m_p0 + VECTOR2I( w, m_radius + y_edge ) );
177 outline.Append( MakeSideArcCw180( inner_rect, m_radius, DIRECTION_45::S ), maxError );
178 }
179 }
180
181 outline.SetClosed( true );
182 aBuffer = std::move( tmp );
183}
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:90
SHAPE_RECT m_rect
Definition roundrect.h:89
static ROUNDRECT OutsetFrom(const SHAPE_RECT &aRect, int aOutset)
Definition roundrect.cpp:71
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aMaxError) const
Get the polygonal representation of the roundrect.
Definition roundrect.cpp:83
ROUNDRECT GetInflated(int aOutset) const
Get the roundrect with the size increased by aOutset in all directions.
Definition roundrect.cpp:77
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:120
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:695