KiCad PCB EDA Suite
Loading...
Searching...
No Matches
easypc_classes_geometry.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 The 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, see <https://www.gnu.org/licenses/>.
18 */
19
22
23#include <climits>
24
25
26namespace EASYPC
27{
28
29namespace
30{
31
32 LOAD_TASK readUntilNull( ARCHIVE& aAr, std::vector<OBJECT*>& aItems )
33 {
34 while( OBJECT* obj = co_await aAr.Object() )
35 aItems.push_back( obj );
36 }
37
38
39 LOAD_TASK skipUntilNull( ARCHIVE& aAr )
40 {
41 while( co_await aAr.Object() )
42 {
43 }
44 }
45
46
47 bool isDesignItem( const OBJECT* aObject )
48 {
49 return dynamic_cast<const SOURCE_DESIGN_ITEM*>( aObject ) != nullptr;
50 }
51
52
53 // Classes whose fields no importer reads; dimensions import from their free copper parts
54 constexpr FIELD_ROW FREE_PAD_ARRAY[] = { { 0, INT_MAX, "b2 i" } };
55 constexpr FIELD_ROW RULER_STOP_SET[] = { { 0, INT_MAX, "s o2" } };
56 constexpr FIELD_ROW ERROR_MARK[] = { { 0, INT_MAX, "i o i4" }, { 8002, INT_MAX, "s" }, { 13000, INT_MAX, "1" } };
57
59 constexpr FIELD_ROW DIMENSION[] = { { 0, INT_MAX, "o i13" },
60 { 14003, INT_MAX, "s 12" },
61 { 18000, INT_MAX, "i5 1 i s2 i b2 i8 1" },
62 { 29000, INT_MAX, "i4" },
63 { 29002, INT_MAX, "o i o i f2 1 f" } };
64
65} // namespace
66
67
68// ---- vertices and shapes -----------------------------------------------------------------------------------------
69
71{
72 X = aAr.I32();
73 Y = aAr.I32();
74 ArcAngle = aAr.I32();
75 Anticlockwise = aAr.InBool();
76
77 // The shape format in force decides, after the flag, whether a next vertex follows
78 HasNextRef = aAr.ShapeFormat() < 3;
79
80 if( HasNextRef )
81 Next = co_await aAr.ObjectAs<SOURCE_SEGMENT>();
82
83 co_await LoadTail( aAr );
84}
85
86
88{
89 co_return;
90}
91
92
94{
95 Shape = co_await aAr.Object();
96}
97
98
100{
101 const SOURCE_COMMON_SHAPE* owner = dynamic_cast<const SOURCE_COMMON_SHAPE*>( Shape );
102
103 return owner && isDesignItem( owner->Parent ) ? owner->Parent->ItemFormat( aAr ) : 0;
104}
105
106
108{
109 Format = aFormat;
110
111 // The shape format persists across later shapes, nested ones included
112 aAr.SetShapeFormat( aFormat );
113
114 if( aFormat < 2 )
115 {
116 for( uint32_t i = aAr.Count(); i > 0; --i )
117 Segments.push_back( co_await aAr.Object() );
118
119 co_return;
120 }
121
122 SOURCE_SEGMENT* first = nullptr;
123 SOURCE_SEGMENT* prev = nullptr;
124
125 while( OBJECT* obj = co_await aAr.Object() )
126 {
127 Segments.push_back( obj );
128 SOURCE_SEGMENT* cur = dynamic_cast<SOURCE_SEGMENT*>( obj );
129
130 // Format 3 stores no next vertex, so the shape links them itself
131 if( prev && cur && aAr.ShapeFormat() > 2 )
132 prev->Next = cur;
133
134 if( !first )
135 first = cur;
136
137 prev = cur;
138 }
139
140 if( aAr.ShapeFormat() > 2 )
141 {
142 HasClosed = true;
143 Closed = aAr.U8() != 0;
144
145 if( Closed && prev && first )
146 prev->Next = first;
147 }
148}
149
150
152{
153 co_await LoadShape( aAr, aAr.ShapeFormat() );
154}
155
156
158{
159 if( HasClosed )
160 return Closed;
161
162 const SOURCE_SEGMENT* last = Segments.empty() ? nullptr : dynamic_cast<const SOURCE_SEGMENT*>( Segments.back() );
163 return last && last->Next;
164}
165
166
168{
169 const bool early = Schema > 1;
170 int fmt = 1;
171
172 if( early )
173 Parent = co_await aAr.Object();
174
175 if( isDesignItem( Parent ) )
176 {
177 int v = Parent->ItemFormat( aAr );
178 fmt = v >= 27001 ? 3 : ( v >= 2106 ? 2 : 1 );
179 }
180
181 co_await LoadShape( aAr, fmt );
182
183 if( !early )
184 Parent = co_await aAr.Object();
185}
186
187
189{
190 return isDesignItem( Parent ) ? Parent->ItemFormat( aAr ) : 0;
191}
192
193
195{
196 co_await SOURCE_COMMON_SHAPE::Load( aAr );
197
198 if( isDesignItem( Parent ) && Parent->ItemFormat( aAr ) > 12001 )
199 co_await readUntilNull( aAr, Cutouts );
200}
201
202
203// ---- shape items -------------------------------------------------------------------------------------------------
204
206{
207 co_await SOURCE_DESIGN_ITEM::Load( aAr );
208
209 const int v = ItemFormat( aAr );
210
211 Style = co_await aAr.Object();
212 Filled = aAr.InBool();
213 Shape = co_await aAr.Object();
214
215 if( v > 12000 )
216 co_await aAr.Object(); // hatch style
217
218 if( v >= 8000 )
219 aAr.Skip( 16 ); // fill type and colours
220}
221
222
224{
225 co_await SOURCE_SHAPE_ITEM::Load( aAr );
226 Layer = co_await aAr.Object();
227}
228
229
231{
232 co_await SOURCE_LAYERED_SHAPE_ITEM::Load( aAr );
233
234 const int v = ItemFormat( aAr );
235
236 if( v >= 4000 && v < 8000 )
237 {
238 aAr.SkipString();
239 Type = aAr.I32();
240 }
241 else if( v >= 8000 )
242 {
243 Type = aAr.I32();
244 Net = co_await aAr.Object();
245 Copper = co_await aAr.Object();
246
247 if( v > 11000 )
248 Flags = aAr.I32();
249
250 if( v > 8999 )
251 {
252 Height = aAr.I32();
253
254 if( v >= 12008 )
255 aAr.Skip( 1 );
256
257 if( v > 12999 )
258 Name = aAr.ReadString();
259 }
260 }
261
262 // Nested loads may update the archive's current item format.
263 if( ItemFormat( aAr ) > 17999 )
264 co_await SkipFields( aAr, THERMAL_RULE_SET );
265
266 if( v > 26000 )
267 aAr.Skip( 1 );
268
269 // The special-highlight bit is runtime state, cleared on load
270 Flags &= 0xbfffffff;
271}
272
273
275{
276 co_await SOURCE_LAYERED_SHAPE_ITEM::Load( aAr );
277
278 const int v = ItemFormat( aAr );
279
280 Terminals = co_await aAr.Object();
281
282 if( v > 3999 )
283 Type = aAr.I32();
284
285 if( v > 5999 )
286 aAr.InBool();
287
288 if( v > 10000 )
289 PinNumber = aAr.I32();
290
291 if( v > 17999 )
292 aAr.InBool();
293
294 if( v > 19999 )
295 aAr.InBool();
296}
297
298
300{
301 co_await SOURCE_CONNECT_POINT::Load( aAr );
302
303 const uint32_t v = static_cast<uint32_t>( ItemFormat( aAr ) );
304
305 Layer = co_await aAr.Object();
306
307 if( v < 10003 )
308 {
309 OldPinName = co_await aAr.Object();
310 OldPinNumber = co_await aAr.Object();
311 }
312 else
313 {
314 ValuePositions = co_await aAr.Object();
315 }
316
317 Number = aAr.I32();
318
319 if( v >= 6000 && v <= 8002 )
320 aAr.InBool();
321
322 // Flags, a BOOL before 11000
323 if( v > 8999 && v < 11000 )
324 aAr.InBool();
325 else if( v > 8999 )
326 aAr.Skip( 4 );
327}
328
329
330// ---- text --------------------------------------------------------------------------------------------------------
331
333{
334 TextStyle = co_await aAr.Object();
335 Mirrored = aAr.InBool();
336 Position = ReadPoint( aAr );
337 Rotation = aAr.I32();
338 Layer = co_await aAr.Object();
339 Alignment = aAr.I32();
340
341 if( ItemFormat( aAr ) > 18999 )
342 {
343 aAr.Skip( 9 ); // box type and colour
344 co_await aAr.Object();
345 }
346
347 // A schematic never shows mirrored text
348 if( aAr.Kind() == DOC_KIND::SCHEMATIC )
349 Mirrored = false;
350}
351
352
354{
355 co_await SOURCE_DESIGN_ITEM::Load( aAr );
356 co_await LoadRemainder( aAr );
357}
358
359
361{
362 co_await SOURCE_DESIGN_ITEM::Load( aAr );
363
364 const int v = ItemFormat( aAr );
365
366 if( v > 16000 )
367 {
368 co_await LoadRemainder( aAr );
369 Text = aAr.ReadString();
370 aAr.InBool();
371
372 if( v > 27999 )
373 {
374 aAr.InBool();
375 aAr.Skip( 4 );
376 }
377
378 co_return;
379 }
380
381 Text = aAr.ReadString();
382 Position = ReadPoint( aAr );
383 Mirrored = aAr.InBool() && aAr.Kind() != DOC_KIND::SCHEMATIC;
384 Rotation = aAr.I32();
385 TextStyle = co_await aAr.Object();
386 Layer = co_await aAr.Object();
387
388 if( ItemFormat( aAr ) > 5999 )
389 aAr.InBool();
390}
391
392
394{
395 co_await SOURCE_DESIGN_ITEM::Load( aAr );
396 co_await LoadRemainder( aAr );
397
398 const uint32_t v = static_cast<uint32_t>( ItemFormat( aAr ) );
399
400 Types = v < 19000 ? aAr.U32() : aAr.U64();
401 Displayed = aAr.Bool();
402
403 if( v >= 11002 )
404 Attribute = aAr.ReadString();
405
406 // An all-ones mask from these versions means reference only
407 if( v >= 19000 && v <= 20999 && Types == ~uint64_t( 0 ) )
408 Types = 0x80000000;
409}
410
411
413{
414 co_await SOURCE_DESIGN_ITEM::Load( aAr );
415 Text = co_await aAr.Object();
416}
417
418
419// ---- groups and origins ------------------------------------------------------------------------------------------
420
422{
423 co_await SOURCE_DESIGN_ITEM::Load( aAr );
424
425 const int v = ItemFormat( aAr );
426
427 if( v <= 10999 )
428 {
429 // A temporary design list serialized in place
431 co_await aAr.Embedded( list, "CDesignList" );
432 Members = list.Items;
433 co_return;
434 }
435
436 Name = aAr.ReadString();
437 Flags = v < 11003 ? ( aAr.Bool() ? 3 : 2 ) : aAr.I32();
438 co_await readUntilNull( aAr, Members );
439
440 if( v > 28999 )
441 {
442 co_await skipUntilNull( aAr );
443 co_await skipUntilNull( aAr );
444 }
445}
446
447
449{
450 co_await SOURCE_DESIGN_ITEM::Load( aAr );
451
452 Position = ReadPoint( aAr );
453 TextStyle = co_await aAr.Object();
454 Layer = co_await aAr.Object();
455
456 if( ItemFormat( aAr ) > 2001 )
457 {
458 Rotation = aAr.I32();
459 Mirrored = aAr.InBool();
460 }
461}
462
463
465{
466 Register<SOURCE_SEGMENT>( aReg, { "CSegment" } );
467 Register<SOURCE_COMMON_SEGMENT>( aReg, { "CCommonSegment", "CShapeSegment" } );
468 Register<SOURCE_SHAPE>( aReg, { "CShape" } );
469 Register<SOURCE_COMMON_SHAPE>( aReg, { "CCommonShape" } );
470 Register<SOURCE_DESIGN_SHAPE>( aReg, { "CDesignShape", "CDesignCutout" } );
471 Register<SOURCE_SHAPE_ITEM>( aReg, { "CShapeItem" } );
472 Register<SOURCE_LAYERED_SHAPE_ITEM>( aReg, { "CLayeredShapeItem" } );
473 Register<SOURCE_AREA>( aReg, { "CArea" } );
474 Register<SOURCE_FREE_COPPER>( aReg, { "CFreeCopper" } );
475 Register<SOURCE_FREE_PAD>( aReg, { "CFreePad" } );
476 RegisterSkipped<SOURCE_DESIGN_LIST>( aReg, "CFreePadArray", FREE_PAD_ARRAY );
477 Register<SOURCE_TEXT_POSITION>( aReg, { "CTextPosition" } );
478 Register<SOURCE_FREE_TEXT>( aReg, { "CFreeText" } );
479 Register<SOURCE_VALUE_POSITION>( aReg, { "CValuePosition" } );
480 Register<SOURCE_TEXT_INSTANCE>( aReg, { "CTextInstance" } );
481 Register<SOURCE_GROUP>( aReg, { "CGroup" } );
482 RegisterSkipped<SOURCE_GROUP>( aReg, "CDimension", DIMENSION );
483 Register<SOURCE_ORIGIN>( aReg, { "COrigin", "CPlaceOrigin" } );
484 RegisterSkipped<SOURCE_DESIGN_ITEM>( aReg, "CError", ERROR_MARK );
485 RegisterSkipped<SOURCE_DESIGN_ITEM>( aReg, "CRulerStopSet", RULER_STOP_SET );
486 Register<SOURCE_DESIGN_LIST>( aReg, { "CAreaArray", "CFreeCopperArray", "CFreeTextArray", "COverlayArray",
487 "CTextInstanceArray", "CValuePositionArray", "CRulerStopArray",
488 "CRulerStopSetArray", "COriginList", "CErrorArray", "CGroupList" } );
489}
490
491} // namespace EASYPC
One archive load stream; it owns every object it creates.
void Skip(size_t aLen)
DOC_KIND Kind() const
void SetShapeFormat(int aFormat)
EMBEDDED_AWAITER Embedded(OBJECT &aObject, const char *aClass)
wxString ReadString()
ANSI (windows-1252) or the 0xFF 0xFFFE UTF-16 form.
TYPED_AWAITER< T > ObjectAs()
int ShapeFormat() const
bool InBool()
one or four bytes, depending on the active format
uint32_t Count()
a 16-bit count, 0xFFFF escaping to 32 bits
OBJECT_AWAITER Object()
A loader coroutine. Awaiting one queues it on its archive's frame stack instead of nesting the call.
Shapes, vertices and the free-standing drawn items.
Free pads, apart because they derive from a connectivity class.
std::map< std::string, std::function< std::unique_ptr< OBJECT >()>, std::less<> > REGISTRY
void RegisterGeometryClasses(REGISTRY &aReg)
LOAD_TASK SkipFields(ARCHIVE &aAr, std::string_view aOps)
Read and drop a run of fields described by aOps, each letter optionally followed by a repeat count: b...
constexpr char THERMAL_RULE_SET[]
A thermal rule set as SkipFields ops: owner, four thermal rules (owner and an int array),...
void RegisterSkipped(REGISTRY &aReg, const char *aName, std::span< const FIELD_ROW > aRows)
void Register(REGISTRY &aReg, std::initializer_list< const char * > aNames)
Register the class names whose objects load as a T.
POINT32 ReadPoint(ARCHIVE &aAr)
A run of fields present from version since to until inclusive.
Root of every deserialized object.
uint16_t Schema
object schema from the class tag, 0 for an embedded member
virtual int ItemFormat(const ARCHIVE &aAr) const
The version this object gates on; the base is the archive's current read format.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
OBJECT * Copper
design list of the stored pour
int ItemFormat(const ARCHIVE &aAr) const override
The owning shape's parent's format, 0 without one.
LOAD_TASK LoadTail(ARCHIVE &aAr) override
The fields a subclass reads after the next vertex.
int ItemFormat(const ARCHIVE &aAr) const override
The version this object gates on; the base is the archive's current read format.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
The base of nearly every class.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
int ItemFormat(const ARCHIVE &aAr) const override
The version this object gates on; the base is the archive's current read format.
A list: owner tag, then the items.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
int32_t Type
0 shape, 1 poured, 2 teardrop, 5 to 7 dimension parts
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
OBJECT * OldPinNumber
version below 10003
OBJECT * OldPinName
version below 10003
OBJECT * ValuePositions
version 10003 on
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
std::vector< OBJECT * > Members
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
int32_t Flags
bit 0 tight, bit 1 local
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
bool HasNextRef
the stream carried a next vertex (shape format below 3)
virtual LOAD_TASK LoadTail(ARCHIVE &aAr)
The fields a subclass reads after the next vertex.
int32_t ArcAngle
swept angle, 0 for a straight span
SOURCE_SEGMENT * Next
null on an open shape's terminator
LOAD_TASK Load(ARCHIVE &aAr) final
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
bool IsClosed() const
The last vertex links back to the first (formats 1 and 2) or the closed byte is set (format 3)
LOAD_TASK LoadShape(ARCHIVE &aAr, int aFormat)
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
std::vector< OBJECT * > Segments
the vertex list as read
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK LoadRemainder(ARCHIVE &aAr)
The text position fields that follow the item fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.