KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pads_arc_structures.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) 2025 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <boost/test/unit_test.hpp>
25#include <sstream>
27
28using namespace PADS_IO;
29
30
31BOOST_AUTO_TEST_SUITE( PadsArcStructures )
32
33
34BOOST_AUTO_TEST_CASE( Arc_DefaultConstruction )
35{
36 ARC arc{};
37 BOOST_CHECK_EQUAL( arc.cx, 0.0 );
38 BOOST_CHECK_EQUAL( arc.cy, 0.0 );
39 BOOST_CHECK_EQUAL( arc.radius, 0.0 );
40 BOOST_CHECK_EQUAL( arc.start_angle, 0.0 );
41 BOOST_CHECK_EQUAL( arc.delta_angle, 0.0 );
42}
43
44
45BOOST_AUTO_TEST_CASE( Arc_AggregateInitialization )
46{
47 ARC arc{ 100.0, 200.0, 50.0, 45.0, 90.0 };
48 BOOST_CHECK_EQUAL( arc.cx, 100.0 );
49 BOOST_CHECK_EQUAL( arc.cy, 200.0 );
50 BOOST_CHECK_EQUAL( arc.radius, 50.0 );
51 BOOST_CHECK_EQUAL( arc.start_angle, 45.0 );
52 BOOST_CHECK_EQUAL( arc.delta_angle, 90.0 );
53}
54
55
56BOOST_AUTO_TEST_CASE( ArcPoint_DefaultConstruction )
57{
58 ARC_POINT pt;
59 BOOST_CHECK_EQUAL( pt.x, 0.0 );
60 BOOST_CHECK_EQUAL( pt.y, 0.0 );
61 BOOST_CHECK_EQUAL( pt.is_arc, false );
62 BOOST_CHECK_EQUAL( pt.arc.cx, 0.0 );
63 BOOST_CHECK_EQUAL( pt.arc.cy, 0.0 );
64}
65
66
67BOOST_AUTO_TEST_CASE( ArcPoint_LineConstruction )
68{
69 ARC_POINT pt( 100.0, 200.0 );
70 BOOST_CHECK_EQUAL( pt.x, 100.0 );
71 BOOST_CHECK_EQUAL( pt.y, 200.0 );
72 BOOST_CHECK_EQUAL( pt.is_arc, false );
73}
74
75
76BOOST_AUTO_TEST_CASE( ArcPoint_ArcConstruction )
77{
78 ARC arc{ 50.0, 50.0, 25.0, 0.0, 180.0 };
79 ARC_POINT pt( 75.0, 50.0, arc );
80
81 BOOST_CHECK_EQUAL( pt.x, 75.0 );
82 BOOST_CHECK_EQUAL( pt.y, 50.0 );
83 BOOST_CHECK_EQUAL( pt.is_arc, true );
84 BOOST_CHECK_EQUAL( pt.arc.cx, 50.0 );
85 BOOST_CHECK_EQUAL( pt.arc.cy, 50.0 );
86 BOOST_CHECK_EQUAL( pt.arc.radius, 25.0 );
89}
90
91
92BOOST_AUTO_TEST_CASE( ArcPoint_EmplaceBack_Line )
93{
94 std::vector<ARC_POINT> points;
95 points.emplace_back( 10.0, 20.0 );
96 points.emplace_back( 30.0, 40.0 );
97
98 BOOST_REQUIRE_EQUAL( points.size(), 2 );
99 BOOST_CHECK_EQUAL( points[0].x, 10.0 );
100 BOOST_CHECK_EQUAL( points[0].y, 20.0 );
101 BOOST_CHECK_EQUAL( points[0].is_arc, false );
102 BOOST_CHECK_EQUAL( points[1].x, 30.0 );
103 BOOST_CHECK_EQUAL( points[1].y, 40.0 );
104 BOOST_CHECK_EQUAL( points[1].is_arc, false );
105}
106
107
108BOOST_AUTO_TEST_CASE( ArcPoint_EmplaceBack_Arc )
109{
110 std::vector<ARC_POINT> points;
111 points.emplace_back( 0.0, 0.0 );
112 points.emplace_back( 100.0, 0.0, ARC{ 50.0, 0.0, 50.0, 180.0, -180.0 } );
113
114 BOOST_REQUIRE_EQUAL( points.size(), 2 );
115 BOOST_CHECK_EQUAL( points[1].is_arc, true );
116 BOOST_CHECK_EQUAL( points[1].arc.cx, 50.0 );
117 BOOST_CHECK_EQUAL( points[1].arc.delta_angle, -180.0 );
118}
119
120
121BOOST_AUTO_TEST_CASE( Arc_FullCircle )
122{
123 // A 360-degree arc represents a full circle
124 ARC arc{ 0.0, 0.0, 100.0, 0.0, 360.0 };
125 BOOST_CHECK_EQUAL( arc.delta_angle, 360.0 );
126}
127
128
129BOOST_AUTO_TEST_CASE( Arc_NegativeDelta )
130{
131 // Negative delta angle means clockwise direction
132 ARC arc{ 0.0, 0.0, 50.0, 90.0, -90.0 };
133 BOOST_CHECK_EQUAL( arc.start_angle, 90.0 );
134 BOOST_CHECK_EQUAL( arc.delta_angle, -90.0 );
135}
136
137
138BOOST_AUTO_TEST_CASE( Polyline_DefaultConstruction )
139{
140 POLYLINE polyline;
141 polyline.layer = 0;
142 polyline.width = 10.0;
143 polyline.closed = true;
144
145 BOOST_CHECK( polyline.points.empty() );
146 BOOST_CHECK_EQUAL( polyline.closed, true );
147}
148
149
150BOOST_AUTO_TEST_CASE( Polyline_WithPoints )
151{
152 POLYLINE polyline;
153 polyline.layer = 1;
154 polyline.width = 5.0;
155 polyline.closed = false;
156 polyline.points.emplace_back( 0.0, 0.0 );
157 polyline.points.emplace_back( 100.0, 0.0 );
158 polyline.points.emplace_back( 100.0, 100.0 );
159
160 BOOST_REQUIRE_EQUAL( polyline.points.size(), 3 );
161 BOOST_CHECK_EQUAL( polyline.closed, false );
162 BOOST_CHECK_EQUAL( polyline.points[2].x, 100.0 );
163 BOOST_CHECK_EQUAL( polyline.points[2].y, 100.0 );
164}
165
166
167BOOST_AUTO_TEST_CASE( Track_UsesArcPoint )
168{
169 TRACK track;
170 track.layer = 1;
171 track.width = 10.0;
172 track.points.emplace_back( 0.0, 0.0 );
173 track.points.emplace_back( 50.0, 50.0 );
174 track.points.emplace_back( 100.0, 50.0, ARC{ 75.0, 50.0, 25.0, 180.0, -180.0 } );
175
176 BOOST_REQUIRE_EQUAL( track.points.size(), 3 );
177 BOOST_CHECK_EQUAL( track.points[0].is_arc, false );
178 BOOST_CHECK_EQUAL( track.points[1].is_arc, false );
179 BOOST_CHECK_EQUAL( track.points[2].is_arc, true );
180 BOOST_CHECK_EQUAL( track.points[2].arc.radius, 25.0 );
181}
182
183
184BOOST_AUTO_TEST_CASE( Pour_UsesArcPoint )
185{
186 POUR pour;
187 pour.net_name = "GND";
188 pour.layer = 1;
189 pour.priority = 0;
190 pour.width = 10.0;
191 pour.points.emplace_back( 0.0, 0.0 );
192 pour.points.emplace_back( 100.0, 0.0 );
193 pour.points.emplace_back( 100.0, 100.0 );
194 pour.points.emplace_back( 0.0, 100.0 );
195
196 BOOST_REQUIRE_EQUAL( pour.points.size(), 4 );
197 BOOST_CHECK_EQUAL( pour.net_name, "GND" );
198}
199
200
201BOOST_AUTO_TEST_CASE( DecalItem_UsesArcPoint )
202{
203 DECAL_ITEM item;
204 item.type = "CLOSED";
205 item.layer = 26; // Silkscreen Top
206 item.width = 8.0;
207 item.points.emplace_back( 0.0, 0.0 );
208 item.points.emplace_back( 50.0, 0.0 );
209 item.points.emplace_back( 50.0, 50.0 );
210 item.points.emplace_back( 0.0, 50.0 );
211
212 BOOST_REQUIRE_EQUAL( item.points.size(), 4 );
213 BOOST_CHECK_EQUAL( item.type, "CLOSED" );
214}
215
216
217BOOST_AUTO_TEST_CASE( Arc_FromBoundingBox )
218{
219 // PADS arc format: XLOC YLOC ISA IDA CX-R CY-R CX+R CY+R
220 // Example: 0 0 900 -900 -50 -50 50 50
221 // This represents arc from (0,0), center at (0,0), radius 50, 90deg start, -90deg delta
222 double bboxMinX = -50.0, bboxMinY = -50.0;
223 double bboxMaxX = 50.0, bboxMaxY = 50.0;
224 int startAngleTenths = 900; // 90.0 degrees
225 int deltaAngleTenths = -900; // -90.0 degrees (clockwise)
226
227 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
228 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
229 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
230 double startAngle = startAngleTenths / 10.0;
231 double deltaAngle = deltaAngleTenths / 10.0;
232
233 BOOST_CHECK_CLOSE( cx, 0.0, 0.001 );
234 BOOST_CHECK_CLOSE( cy, 0.0, 0.001 );
235 BOOST_CHECK_CLOSE( radius, 50.0, 0.001 );
236 BOOST_CHECK_CLOSE( startAngle, 90.0, 0.001 );
237 BOOST_CHECK_CLOSE( deltaAngle, -90.0, 0.001 );
238}
239
240
241BOOST_AUTO_TEST_CASE( Arc_FromBoundingBox_OffCenter )
242{
243 // Arc with center at (100, 200), radius 25
244 // Bounding box: (75, 175) to (125, 225)
245 double bboxMinX = 75.0, bboxMinY = 175.0;
246 double bboxMaxX = 125.0, bboxMaxY = 225.0;
247
248 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
249 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
250 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
251
252 BOOST_CHECK_CLOSE( cx, 100.0, 0.001 );
253 BOOST_CHECK_CLOSE( cy, 200.0, 0.001 );
254 BOOST_CHECK_CLOSE( radius, 25.0, 0.001 );
255}
256
257
258BOOST_AUTO_TEST_CASE( ArcPoint_ParseFromStream )
259{
260 // Simulate parsing a PADS arc line: "0 0 900 -900 -50 -50 50 50"
261 std::string line = "0 0 900 -900 -50 -50 50 50";
262 std::istringstream iss( line );
263
264 double dx, dy;
265 int startAngleTenths, deltaAngleTenths;
266 double bboxMinX, bboxMinY, bboxMaxX, bboxMaxY;
267
268 iss >> dx >> dy;
269 bool hasArc = static_cast<bool>( iss >> startAngleTenths >> deltaAngleTenths
270 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY );
271
272 BOOST_CHECK( hasArc );
273 BOOST_CHECK_EQUAL( startAngleTenths, 900 );
274 BOOST_CHECK_EQUAL( deltaAngleTenths, -900 );
275}
276
277
278BOOST_AUTO_TEST_CASE( ArcPoint_ParseFromStream_NoArc )
279{
280 // Simulate parsing a simple PADS line point: "100 200"
281 std::string line = "100 200";
282 std::istringstream iss( line );
283
284 double dx, dy;
285 int startAngleTenths, deltaAngleTenths;
286 double bboxMinX, bboxMinY, bboxMaxX, bboxMaxY;
287
288 iss >> dx >> dy;
289 bool hasArc = static_cast<bool>( iss >> startAngleTenths >> deltaAngleTenths
290 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY );
291
292 BOOST_CHECK( !hasArc );
293 BOOST_CHECK_CLOSE( dx, 100.0, 0.001 );
294 BOOST_CHECK_CLOSE( dy, 200.0, 0.001 );
295}
296
297
A point that may be either a line endpoint or an arc segment.
Definition pads_parser.h:72
ARC arc
Arc parameters (only valid when is_arc is true)
Definition pads_parser.h:76
bool is_arc
True if this segment is an arc, false for line.
Definition pads_parser.h:75
double y
Endpoint Y coordinate.
Definition pads_parser.h:74
double x
Endpoint X coordinate.
Definition pads_parser.h:73
Arc definition using center point, radius, and angles.
Definition pads_parser.h:57
double radius
Arc radius.
Definition pads_parser.h:60
double cx
Center X coordinate.
Definition pads_parser.h:58
double delta_angle
Arc sweep angle in degrees (positive = CCW)
Definition pads_parser.h:62
double start_angle
Start angle in degrees (0 = +X, CCW positive)
Definition pads_parser.h:61
double cy
Center Y coordinate.
Definition pads_parser.h:59
std::vector< ARC_POINT > points
Shape points, may include arc segments.
std::string type
CLOSED, OPEN, CIRCLE, COPCLS, TAG, etc.
A polyline that may contain arc segments.
bool closed
True if polyline forms a closed shape.
std::vector< ARC_POINT > points
Polyline vertices, may include arcs.
std::string net_name
std::vector< ARC_POINT > points
Pour outline, may include arc segments.
std::vector< ARC_POINT > points
Track points, may include arc segments.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(Arc_DefaultConstruction)
int radius
BOOST_CHECK_EQUAL(result, "25.4")