KiCad PCB EDA Suite
Loading...
Searching...
No Matches
bitmap2component.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) 1992-2019 jean-pierre.charras
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <algorithm> // std::max
22#include <cerrno>
23#include <cmath>
24#include <cstdio>
25#include <cstdlib>
26#include <cstring>
27#include <memory>
28#include <string>
29#include <vector>
30#include <kiid.h>
31
32#include <build_version.h>
36#include <io/kicad/sexpr_file_versions.h>
37#include <locale_io.h>
38#include <macros.h>
39#include <potracelib.h>
40#include <reporter.h>
41#include <fmt/format.h>
42#include <wx/translation.h>
43
44#include "bitmap2component.h"
45
46
47/* free a potrace bitmap */
48static void bm_free( potrace_bitmap_t* bm )
49{
50 if( bm )
51 free( bm->map );
52
53 free( bm );
54}
55
56
57static void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer,
58 potrace_dpoint_t p1, potrace_dpoint_t p2,
59 potrace_dpoint_t p3, potrace_dpoint_t p4 );
60
61
62BITMAPCONV_INFO::BITMAPCONV_INFO( std::string& aData, REPORTER& aReporter ):
63 m_Data( aData ),
64 m_reporter( aReporter )
65{
67 m_PixmapWidth = 0;
69 m_ScaleX = 1.0;
70 m_ScaleY = 1.0;
71 m_Paths = nullptr;
72 m_CmpName = "LOGO";
73}
74
75
76int BITMAPCONV_INFO::ConvertBitmap( potrace_bitmap_t* aPotrace_bitmap, OUTPUT_FMT_ID aFormat,
77 int aDpi_X, int aDpi_Y, const wxString& aLayer )
78{
79 potrace_param_t* param;
80 potrace_state_t* st;
81
82 // set tracing parameters, starting from defaults
83 param = potrace_param_default();
84
85 if( !param )
86 {
87 m_reporter.Report( fmt::format( "Error allocating parameters: {}\n", strerror( errno ) ),
89 return 1;
90 }
91
92 // For parameters: see http://potrace.sourceforge.net/potracelib.pdf
93 param->turdsize = 0; // area (in pixels) of largest path to be ignored.
94 // Potrace default is 2
95 param->opttolerance = 0.2; // curve optimization tolerance. Potrace default is 0.2
96
97 /* convert the bitmap to curves */
98 st = potrace_trace( param, aPotrace_bitmap );
99
100 if( !st || st->status != POTRACE_STATUS_OK )
101 {
102 if( st )
103 potrace_state_free( st );
104
105 potrace_param_free( param );
106
107 m_reporter.Report( fmt::format( "Error tracing bitmap: {}\n", strerror( errno ) ),
109 return 1;
110 }
111
112 m_PixmapWidth = aPotrace_bitmap->w;
113 m_PixmapHeight = aPotrace_bitmap->h; // the bitmap size in pixels
114 m_Paths = st->plist;
115 m_Format = aFormat;
116
117 switch( aFormat )
118 {
120 m_ScaleX = PL_IU_PER_MM * 25.4 / aDpi_X; // the conversion scale from PPI to micron
121 m_ScaleY = PL_IU_PER_MM * 25.4 / aDpi_Y; // Y axis is top to bottom
123 break;
124
125 case POSTSCRIPT_FMT:
126 m_ScaleX = 1.0; // the conversion scale
129 break;
130
131 case SYMBOL_FMT:
132 case SYMBOL_PASTE_FMT:
133 m_ScaleX = SCH_IU_PER_MM * 25.4 / aDpi_X; // the conversion scale from PPI to eeschema iu
134 m_ScaleY = -SCH_IU_PER_MM * 25.4 / aDpi_Y; // Y axis is bottom to Top for components in libs
136 break;
137
138 case FOOTPRINT_FMT:
139 m_ScaleX = PCB_IU_PER_MM * 25.4 / aDpi_X; // the conversion scale from PPI to IU
140 m_ScaleY = PCB_IU_PER_MM * 25.4 / aDpi_Y; // Y axis is top to bottom in Footprint Editor
141 createOutputData( aLayer );
142 break;
143 }
144
145 bm_free( aPotrace_bitmap );
146 potrace_state_free( st );
147 potrace_param_free( param );
148
149 return 0;
150}
151
152
153void BITMAPCONV_INFO::outputDataHeader( const wxString& aBrdLayerName )
154{
155 double Ypos = ( m_PixmapHeight / 2.0 * m_ScaleY ); // fields Y position in mm
156 double fieldSize; // fields text size in mm
157
158 switch( m_Format )
159 {
160 case POSTSCRIPT_FMT:
161 m_Data += "%!PS-Adobe-3.0 EPSF-3.0\n";
162 m_Data += fmt::format( "%%BoundingBox: 0 0 {} {}\n", m_PixmapWidth, m_PixmapHeight );
163 m_Data += "gsave\n";
164 break;
165
166 case FOOTPRINT_FMT:
167 // fields text size = 1.5 mm
168 // fields text thickness = 1.5 / 5 = 0.3mm
169 m_Data += fmt::format( "(footprint \"{}\" (version {}) (generator \"bitmap2component\") (generator_version \"{}\")\n"
170 " (layer \"F.Cu\")\n",
171 m_CmpName.c_str(),
172 SEXPR_FOOTPRINT_FILE_VERSION,
173 GetMajorMinorVersion().ToStdString() );
174
175 m_Data += fmt::format( " (attr board_only exclude_from_pos_files exclude_from_bom)\n" );
176 m_Data += fmt::format( " (fp_text reference \"G***\" (at 0 0) (layer \"{}\")\n"
177 " (effects (font (size 1.5 1.5) (thickness 0.3)))\n"
178 " (uuid {})\n )\n",
179 aBrdLayerName.ToStdString().c_str(),
180 KIID().AsString().ToStdString().c_str() );
181
182 m_Data += fmt::format( " (fp_text value \"{}\" (at 0.75 0) (layer \"{}\") hide\n"
183 " (effects (font (size 1.5 1.5) (thickness 0.3)))\n"
184 " (uuid {})\n )\n",
185 m_CmpName.c_str(),
186 aBrdLayerName.ToStdString().c_str(),
187 KIID().AsString().ToStdString().c_str() );
188 break;
189
191 break;
192
193 case SYMBOL_FMT:
194 m_Data += fmt::format( "(kicad_symbol_lib (version {}) (generator \"bitmap2component\") (generator_version \"{}\")\n",
196 GetMajorMinorVersion().ToStdString() );
198
199 case SYMBOL_PASTE_FMT:
200 fieldSize = 1.27; // fields text size in mm (= 50 mils)
201 Ypos /= SCH_IU_PER_MM;
202 Ypos += fieldSize / 2;
203 m_Data += fmt::format( " (symbol \"{}\" (pin_names (offset 1.016)) (in_bom yes) (on_board yes)\n",
204 m_CmpName.c_str() );
205
206 m_Data += fmt::format( " (property \"Reference\" \"#G\" (at 0 {:g} 0)\n"
207 " (effects (font (size {:g} {:g})) hide)\n )\n",
208 -Ypos,
209 fieldSize,
210 fieldSize );
211
212 m_Data += fmt::format( " (property \"Value\" \"{}\" (at 0 {:g} 0)\n"
213 " (effects (font (size {:g} {:g})) hide)\n )\n",
214 m_CmpName.c_str(),
215 Ypos,
216 fieldSize,
217 fieldSize );
218
219 m_Data += fmt::format( " (property \"Footprint\" \"\" (at 0 0 0)\n"
220 " (effects (font (size {:g} {:g})) hide)\n )\n",
221 fieldSize,
222 fieldSize );
223
224 m_Data += fmt::format( " (property \"Datasheet\" \"\" (at 0 0 0)\n"
225 " (effects (font (size {:g} {:g})) hide)\n )\n",
226 fieldSize,
227 fieldSize );
228
229 m_Data += fmt::format( " (symbol \"{}_0_0\"\n", m_CmpName.c_str() );
230 break;
231 }
232}
233
234
236{
237 switch( m_Format )
238 {
239 case POSTSCRIPT_FMT:
240 m_Data += "grestore\n";
241 m_Data += "%%EOF\n";
242 break;
243
244 case FOOTPRINT_FMT:
245 m_Data += ")\n";
246 break;
247
249 break;
250
251 case SYMBOL_PASTE_FMT:
252 m_Data += " )\n"; // end symbol_0_0
253 m_Data += " )\n"; // end symbol
254 break;
255
256 case SYMBOL_FMT:
257 m_Data += " )\n"; // end symbol_0_0
258 m_Data += " )\n"; // end symbol
259 m_Data += ")\n"; // end lib
260 break;
261 }
262}
263
264
265void BITMAPCONV_INFO::outputOnePolygon( SHAPE_LINE_CHAIN& aPolygon, const wxString& aBrdLayerName )
266{
267 // write one polygon to output file.
268 // coordinates are expected in target unit.
269 int ii, jj;
270 VECTOR2I currpoint;
271 int offsetX = KiROUND( m_PixmapWidth / 2.0 * m_ScaleX );
272 int offsetY = KiROUND( m_PixmapHeight / 2.0 * m_ScaleY );
273
274 const VECTOR2I startpoint = aPolygon.CPoint( 0 );
275
276 switch( m_Format )
277 {
278 case POSTSCRIPT_FMT:
279 offsetY = (int)( m_PixmapHeight * m_ScaleY );
280 m_Data += fmt::format( "newpath\n{} {} moveto\n", startpoint.x, offsetY - startpoint.y );
281 jj = 0;
282
283 for( ii = 1; ii < aPolygon.PointCount(); ii++ )
284 {
285 currpoint = aPolygon.CPoint( ii );
286 m_Data += fmt::format( " {} {} lineto", currpoint.x, offsetY - currpoint.y );
287
288 if( jj++ > 6 )
289 {
290 jj = 0;
291 m_Data += "\n";
292 }
293 }
294
295 m_Data += "\nclosepath fill\n";
296 break;
297
298 case FOOTPRINT_FMT:
299 m_Data += " (fp_poly\n (pts\n";
300
301 jj = 0;
302
303 for( ii = 0; ii < aPolygon.PointCount(); ii++ )
304 {
305 currpoint = aPolygon.CPoint( ii );
306 m_Data += fmt::format( " (xy {} {})\n",
307 ( currpoint.x - offsetX ) / PCB_IU_PER_MM,
308 ( currpoint.y - offsetY ) / PCB_IU_PER_MM );
309 }
310 // No need to close polygon
311
312 m_Data += " )\n\n";
313 m_Data += fmt::format( " (stroke (width {:f}) (type solid)) (fill solid) (layer \"{}\") (uuid {}))\n",
314 0.0,
315 aBrdLayerName.ToStdString().c_str(),
316 KIID().AsString().ToStdString().c_str() );
317 break;
318
320 break;
321
322 case SYMBOL_FMT:
323 case SYMBOL_PASTE_FMT:
324 // The polygon outline thickness is fixed here to 0.01 ( 0.0 is the default thickness)
325#define SCH_LINE_THICKNESS_MM 0.01
326 //snprintf( strbuf, sizeof(strbuf), "P %d 0 0 %d", (int) aPolygon.PointCount() + 1, EE_LINE_THICKNESS );
327 m_Data += " (polyline\n (pts\n";
328
329 for( ii = 0; ii < aPolygon.PointCount(); ii++ )
330 {
331 currpoint = aPolygon.CPoint( ii );
332 m_Data += fmt::format( " (xy {:f} {:f})\n",
333 ( currpoint.x - offsetX ) / SCH_IU_PER_MM,
334 ( currpoint.y - offsetY ) / SCH_IU_PER_MM );
335 }
336
337 // Close polygon
338 m_Data += fmt::format( " (xy {:f} {:f})\n",
339 ( startpoint.x - offsetX ) / SCH_IU_PER_MM,
340 ( startpoint.y - offsetY ) / SCH_IU_PER_MM );
341 m_Data += " )\n"; // end pts
342
343 m_Data += fmt::format( " (stroke (width {:g}) (type default))\n"
344 " (fill (type outline))\n",
346 m_Data += " )\n"; // end polyline
347 break;
348 }
349}
350
351
352void BITMAPCONV_INFO::createOutputData( const wxString& aLayer )
353{
354 std::vector <potrace_dpoint_t> cornersBuffer;
355
356 // polyset_areas is a set of polygon to draw
357 SHAPE_POLY_SET polyset_areas;
358
359 // polyset_holes is the set of holes inside polyset_areas outlines
360 SHAPE_POLY_SET polyset_holes;
361
362 // For DRAWING_SHEET_FMT, collect all output polygons so we can serialize
363 // them through DS_DATA_MODEL instead of writing hardcoded S-expression strings.
364 SHAPE_POLY_SET outputPolygons;
365
366 potrace_dpoint_t( *c )[3];
367
369 {
370 // The layer name has meaning only for .kicad_mod files.
371 // For these files the header creates 2 invisible texts: value and ref
372 // (needed but not useful) on silk screen layer
373 outputDataHeader( "F.SilkS" );
374 }
375
376 bool main_outline = true;
377
378 /* draw each as a polygon with no hole.
379 * Bezier curves are approximated by a polyline
380 */
381 potrace_path_t* paths = m_Paths; // the list of paths
382
383 if( !m_Paths )
384 {
385 m_reporter.Report( _( "No shape in black and white image to convert: no outline created." ),
387 }
388
389 while( paths != nullptr )
390 {
391 int cnt = paths->curve.n;
392 int* tag = paths->curve.tag;
393 c = paths->curve.c;
394 potrace_dpoint_t startpoint = c[cnt - 1][2];
395
396 for( int i = 0; i < cnt; i++ )
397 {
398 switch( tag[i] )
399 {
400 case POTRACE_CORNER:
401 cornersBuffer.push_back( c[i][1] );
402 cornersBuffer.push_back( c[i][2] );
403 startpoint = c[i][2];
404 break;
405
406 case POTRACE_CURVETO:
407 BezierToPolyline( cornersBuffer, startpoint, c[i][0], c[i][1], c[i][2] );
408 startpoint = c[i][2];
409 break;
410 }
411 }
412
413 // Store current path
414 if( main_outline )
415 {
416 main_outline = false;
417
418 // build the current main polygon
419 polyset_areas.NewOutline();
420
421 for( const potrace_dpoint_s& pt : cornersBuffer )
422 {
423 polyset_areas.Append( int( pt.x * m_ScaleX ),
424 int( pt.y * m_ScaleY ) );
425 }
426 }
427 else
428 {
429 // Add current hole in polyset_holes
430 polyset_holes.NewOutline();
431
432 for( const potrace_dpoint_s& pt : cornersBuffer )
433 {
434 polyset_holes.Append( int( pt.x * m_ScaleX ),
435 int( pt.y * m_ScaleY ) );
436 }
437 }
438
439 cornersBuffer.clear();
440
441 // at the end of a group of a positive path and its negative children, fill.
442 if( paths->next == nullptr || paths->next->sign == '+' )
443 {
444 polyset_areas.Simplify();
445 polyset_holes.Simplify();
446 polyset_areas.BooleanSubtract( polyset_holes );
447
448 // Ensure there are no self intersecting polygons
449 if( polyset_areas.NormalizeAreaOutlines() )
450 {
451 // Convert polygon with holes to a unique polygon
452 polyset_areas.Fracture();
453
455 {
456 // Collect polygons for serialization through DS_DATA_MODEL
457 for( int ii = 0; ii < polyset_areas.OutlineCount(); ii++ )
458 outputPolygons.AddOutline( polyset_areas.Outline( ii ) );
459 }
460 else
461 {
462 for( int ii = 0; ii < polyset_areas.OutlineCount(); ii++ )
463 {
464 SHAPE_LINE_CHAIN& poly = polyset_areas.Outline( ii );
465 outputOnePolygon( poly, aLayer );
466 }
467 }
468
469 polyset_areas.RemoveAllContours();
470 polyset_holes.RemoveAllContours();
471 main_outline = true;
472 }
473 }
474
475 paths = paths->next;
476 }
477
479 {
480 createDrawingSheetData( outputPolygons );
481 }
482 else
483 {
485 }
486}
487
488
490{
492 model.SetGenerator( wxT( "bitmap2component" ) );
493 model.SetLeftMargin( 10 );
494 model.SetRightMargin( 10 );
495 model.SetTopMargin( 10 );
496 model.SetBottomMargin( 10 );
497 model.m_DefaultTextSize = VECTOR2D( 1.5, 1.5 );
498 model.m_DefaultLineWidth = 0.15;
499 model.m_DefaultTextThickness = 0.15;
500
501 auto polyItem = std::make_unique<DS_DATA_ITEM_POLYGONS>();
502 polyItem->m_Name = wxEmptyString;
503 polyItem->SetStart( 0, 0, RB_CORNER );
504 polyItem->m_LineWidth = 0.01;
505
506 int offsetX = KiROUND( m_PixmapWidth / 2.0 * m_ScaleX );
507 int offsetY = KiROUND( m_PixmapHeight / 2.0 * m_ScaleY );
508
509 for( int ii = 0; ii < aPolyset.OutlineCount(); ii++ )
510 {
511 SHAPE_LINE_CHAIN& poly = aPolyset.Outline( ii );
512
513 if( poly.PointCount() == 0 )
514 continue;
515
516 for( int jj = 0; jj < poly.PointCount(); jj++ )
517 {
518 VECTOR2I pt = poly.CPoint( jj );
519 polyItem->AppendCorner( VECTOR2D( ( pt.x - offsetX ) / PL_IU_PER_MM,
520 ( pt.y - offsetY ) / PL_IU_PER_MM ) );
521 }
522
523 // Close polygon by repeating the first point
524 VECTOR2I startPt = poly.CPoint( 0 );
525 polyItem->AppendCorner( VECTOR2D( ( startPt.x - offsetX ) / PL_IU_PER_MM,
526 ( startPt.y - offsetY ) / PL_IU_PER_MM ) );
527 polyItem->CloseContour();
528 }
529
530 if( polyItem->GetPolyCount() > 0 )
531 model.Append( polyItem.release() );
532
533 wxString output;
534 model.SaveInString( &output );
535
536 std::string result = output.ToStdString();
538 m_Data += result;
539}
540
541
542// a helper function to calculate a square value
543inline double square( double x )
544{
545 return x * x;
546}
547
548
549// a helper function to calculate a cube value
550inline double cube( double x )
551{
552 return x * x * x;
553}
554
555
556/* render a Bezier curve. */
557void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer,
558 potrace_dpoint_t p1,
559 potrace_dpoint_t p2,
560 potrace_dpoint_t p3,
561 potrace_dpoint_t p4 )
562{
563 double dd0, dd1, dd, delta, e2, epsilon, t;
564
565 // p1 = starting point
566
567 /* we approximate the curve by small line segments. The interval
568 * size, epsilon, is determined on the fly so that the distance
569 * between the true curve and its approximation does not exceed the
570 * desired accuracy delta. */
571
572 delta = 0.25; /* desired accuracy, in pixels */
573
574 /* let dd = maximal value of 2nd derivative over curve - this must
575 * occur at an endpoint. */
576 dd0 = square( p1.x - 2 * p2.x + p3.x ) + square( p1.y - 2 * p2.y + p3.y );
577 dd1 = square( p2.x - 2 * p3.x + p4.x ) + square( p2.y - 2 * p3.y + p4.y );
578 dd = 6 * sqrt( std::max( dd0, dd1 ) );
579 e2 = 8 * delta <= dd ? 8 * delta / dd : 1;
580 epsilon = sqrt( e2 ); /* necessary interval size */
581
582 for( t = epsilon; t<1; t += epsilon )
583 {
584 potrace_dpoint_t intermediate_point;
585 intermediate_point.x = p1.x * cube( 1 - t ) +
586 3* p2.x* square( 1 - t ) * t +
587 3 * p3.x * (1 - t) * square( t ) +
588 p4.x* cube( t );
589
590 intermediate_point.y = p1.y * cube( 1 - t ) +
591 3* p2.y* square( 1 - t ) * t +
592 3 * p3.y * (1 - t) * square( t ) + p4.y* cube( t );
593
594 aCornersBuffer.push_back( intermediate_point );
595 }
596
597 aCornersBuffer.push_back( p4 );
598}
constexpr double SCH_IU_PER_MM
Schematic internal units 1=100nm.
Definition base_units.h:70
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
Definition base_units.h:68
constexpr double PL_IU_PER_MM
Internal units in micron (should be enough).
Definition base_units.h:69
double square(double x)
static void BezierToPolyline(std::vector< potrace_dpoint_t > &aCornersBuffer, potrace_dpoint_t p1, potrace_dpoint_t p2, potrace_dpoint_t p3, potrace_dpoint_t p4)
double cube(double x)
static void bm_free(potrace_bitmap_t *bm)
#define SCH_LINE_THICKNESS_MM
OUTPUT_FMT_ID
@ DRAWING_SHEET_FMT
@ SYMBOL_FMT
@ SYMBOL_PASTE_FMT
@ POSTSCRIPT_FMT
@ FOOTPRINT_FMT
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
void outputDataEnd()
Function outputDataEnd write to file the last strings depending on file format.
std::string & m_Data
REPORTER & m_reporter
BITMAPCONV_INFO(std::string &aData, REPORTER &aReporter)
potrace_path_t * m_Paths
void outputOnePolygon(SHAPE_LINE_CHAIN &aPolygon, const wxString &aBrdLayerName)
Function outputOnePolygon write one polygon to output file.
std::string m_CmpName
void outputDataHeader(const wxString &aBrdLayerName)
Function outputDataHeader write to file the header depending on file format.
enum OUTPUT_FMT_ID m_Format
int ConvertBitmap(potrace_bitmap_t *aPotrace_bitmap, OUTPUT_FMT_ID aFormat, int aDpi_X, int aDpi_Y, const wxString &aLayer)
Run the conversion of the bitmap.
void createDrawingSheetData(SHAPE_POLY_SET &aPolyset)
Generate drawing sheet output using the DS_DATA_MODEL serialization instead of hardcoded S-expression...
void createOutputData(const wxString &aBrdLayerName=wxT("F.SilkS"))
Creates the data specified by m_Format.
Handle the graphic items list to draw/plot the frame and title block.
Definition kiid.h:44
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:71
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
int NormalizeAreaOutlines()
Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s).
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
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.
int OutlineCount() const
Return the number of outlines in the set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
@ RB_CORNER
#define _(s)
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:79
void Prettify(std::string &aSource, FORMAT_MODE aMode)
Pretty-prints s-expression text according to KiCad format rules.
@ RPT_SEVERITY_ERROR
const double epsilon
#define SEXPR_SYMBOL_LIB_FILE_VERSION
This file contains the file format version information for the s-expression schematic and symbol libr...
KIBIS_MODEL * model
nlohmann::json output
wxString result
Test unit parsing edge cases and error handling.
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682