KiCad PCB EDA Suite
Loading...
Searching...
No Matches
easyeda_parser_base.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) 2023 Alex Shvartzkop <[email protected]>
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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include "easyeda_parser_base.h"
26
27#include <bezier_curves.h>
28#include <ki_exception.h>
29#include <wx/translation.h>
30#include <eda_text.h>
31
32
33double EASYEDA_PARSER_BASE::Convert( const wxString& aValue )
34{
35 double value = 0;
36
37 if( !aValue.ToCDouble( &value ) )
38 THROW_IO_ERROR( wxString::Format( _( "Failed to parse number from '%s'" ), aValue ) );
39
40 return value;
41}
42
43
44double EASYEDA_PARSER_BASE::RelPosX( double aValue )
45{
46 double value = aValue - m_relOrigin.x;
47 return ScaleSize( value );
48}
49
50
51double EASYEDA_PARSER_BASE::RelPosY( double aValue )
52{
53 double value = aValue - m_relOrigin.y;
54 return ScaleSize( value );
55}
56
57
58double EASYEDA_PARSER_BASE::RelPosX( const wxString& aValue )
59{
60 return RelPosX( Convert( aValue ) );
61}
62
63
64double EASYEDA_PARSER_BASE::RelPosY( const wxString& aValue )
65{
66 return RelPosY( Convert( aValue ) );
67}
68
69
71 const wxString& baselineAlign )
72{
73 int upOffset = 0;
74
75 if( baselineAlign == wxS( "" ) || baselineAlign == wxS( "auto" )
76 || baselineAlign == wxS( "use-script" ) || baselineAlign == wxS( "no-change" )
77 || baselineAlign == wxS( "reset-size" ) || baselineAlign == wxS( "alphabetic" )
78 || baselineAlign == wxS( "inherit" ) )
79 {
80 upOffset = textItem->GetTextSize().y;
81 }
82 else if( baselineAlign == wxS( "ideographic" ) || baselineAlign == wxS( "text-after-edge" ) )
83 {
84 upOffset = textItem->GetTextSize().y * 1.2;
85 }
86 else if( baselineAlign == wxS( "central" ) )
87 {
88 upOffset = textItem->GetTextSize().y * 0.5;
89 }
90 else if( baselineAlign == wxS( "middle" ) )
91 {
92 upOffset = textItem->GetTextSize().y * 0.6;
93 }
94 else if( baselineAlign == wxS( "mathematical" ) )
95 {
96 upOffset = textItem->GetTextSize().y * 0.1;
97 }
98 else if( baselineAlign == wxS( "hanging" ) || baselineAlign == wxS( "text-before-edge" ) )
99 {
100 upOffset = 0;
101 }
102
103 VECTOR2I offset( 0, -upOffset );
104 RotatePoint( offset, textItem->GetTextAngle() );
105
106 textItem->SetTextPos( textItem->GetTextPos() + offset );
107}
108
109
110std::vector<SHAPE_LINE_CHAIN>
111EASYEDA_PARSER_BASE::ParseLineChains( const wxString& data, int aMaxError, bool aForceClosed )
112{
113 std::vector<SHAPE_LINE_CHAIN> result;
114
115 VECTOR2D prevPt;
117
118 size_t pos = 0;
119 auto readNumber = [&]( wxString& aOut )
120 {
121 wxUniChar ch = data[pos];
122
123 while( ch == ' ' || ch == ',' )
124 ch = data[++pos];
125
126 while( isdigit( ch ) || ch == '.' || ch == '-' )
127 {
128 aOut += ch;
129 pos++;
130
131 if( pos == data.size() )
132 break;
133
134 ch = data[pos];
135 }
136 };
137
138 do
139 {
140 wxUniChar sym = data[pos++];
141
142 if( sym == ' ' )
143 continue;
144
145 if( sym == 'M' )
146 {
147 wxString xStr, yStr;
148
149 readNumber( xStr );
150 readNumber( yStr );
151
152 if( chain.PointCount() > 1 )
153 {
154 if( aForceClosed )
155 chain.SetClosed( true );
156
157 result.emplace_back( chain );
158 }
159
160 chain.Clear();
161
162 VECTOR2D pt( Convert( xStr ), Convert( yStr ) );
163 chain.Append( RelPos( pt ) );
164
165 prevPt = pt;
166 }
167 else if( sym == 'Z' )
168 {
169 if( chain.PointCount() > 2 )
170 {
171 chain.SetClosed( true );
172 result.emplace_back( chain );
173 }
174 chain.Clear();
175 }
176 else if( sym == 'L' || isdigit( sym ) || sym == '-' )
177 {
178 // We may not have a command, just coordinates:
179 // M 4108.8 3364.1 3982.598 3295.6914
180 if( isdigit( sym ) || sym == '-' )
181 pos--;
182
183 while( true )
184 {
185 if( pos >= data.size() )
186 break;
187
188 wxUniChar ch = data[pos];
189
190 while( ch == ' ' || ch == ',' )
191 {
192 if( ++pos >= data.size() )
193 break;
194
195 ch = data[pos];
196 }
197
198 if( !isdigit( ch ) && ch != '-' )
199 break;
200
201 wxString xStr, yStr;
202
203 readNumber( xStr );
204 readNumber( yStr );
205
206 VECTOR2D pt( Convert( xStr ), Convert( yStr ) );
207 chain.Append( RelPos( pt ) );
208
209 prevPt = pt;
210 };
211 }
212 else if( sym == 'A' )
213 {
214 // Arc command can have multiple consecutive arc parameter sets
215 while( true )
216 {
217 if( pos >= data.size() )
218 break;
219
220 wxUniChar ch = data[pos];
221
222 while( ch == ' ' || ch == ',' )
223 {
224 if( ++pos >= data.size() )
225 break;
226
227 ch = data[pos];
228 }
229
230 if( !isdigit( ch ) && ch != '-' )
231 break;
232
233 wxString radX, radY, unknown, farFlag, cwFlag, endX, endY;
234
235 readNumber( radX );
236 readNumber( radY );
237 readNumber( unknown );
238 readNumber( farFlag );
239 readNumber( cwFlag );
240 readNumber( endX );
241 readNumber( endY );
242
243 bool isFar = farFlag == wxS( "1" );
244 bool cw = cwFlag == wxS( "1" );
245 VECTOR2D rad( Convert( radX ), Convert( radY ) );
246 VECTOR2D end( Convert( endX ), Convert( endY ) );
247
248 VECTOR2D start = prevPt;
249 VECTOR2D delta = end - start;
250
251 double d = delta.EuclideanNorm();
252 double h = sqrt( std::max( 0.0, rad.x * rad.x - d * d / 4 ) );
253
254 //( !far && cw ) => h
255 //( far && cw ) => -h
256 //( !far && !cw ) => -h
257 //( far && !cw ) => h
258 VECTOR2D arcCenter = start + delta / 2 + delta.Perpendicular().Resize( ( isFar ^ cw ) ? h : -h );
259
260 SHAPE_ARC arc;
261 arc.ConstructFromStartEndCenter( RelPos( start ), RelPos( end ), RelPos( arcCenter ), !cw );
262
263 chain.Append( arc, aMaxError );
264
265 prevPt = end;
266 }
267 }
268 else if( sym == 'C' )
269 {
270 wxString p1_xStr, p1_yStr, p2_xStr, p2_yStr, p3_xStr, p3_yStr;
271 readNumber( p1_xStr );
272 readNumber( p1_yStr );
273 readNumber( p2_xStr );
274 readNumber( p2_yStr );
275 readNumber( p3_xStr );
276 readNumber( p3_yStr );
277
278 VECTOR2D pt1( Convert( p1_xStr ), Convert( p1_yStr ) );
279 VECTOR2D pt2( Convert( p2_xStr ), Convert( p2_yStr ) );
280 VECTOR2D pt3( Convert( p3_xStr ), Convert( p3_yStr ) );
281
282 std::vector<VECTOR2I> ctrlPoints = { RelPos( prevPt ), RelPos( pt1 ), RelPos( pt2 ),
283 RelPos( pt3 ) };
284 BEZIER_POLY converter( ctrlPoints );
285
286 std::vector<VECTOR2I> bezierPoints;
287 converter.GetPoly( bezierPoints, aMaxError );
288
289 chain.Append( bezierPoints );
290
291 prevPt = pt3;
292 }
293 } while( pos < data.size() );
294
295 if( chain.PointCount() > 1 )
296 {
297 if( aForceClosed )
298 chain.SetClosed( true );
299
300 result.emplace_back( chain );
301 }
302
303 return result;
304}
Bezier curves to polygon converter.
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
static double Convert(const wxString &aValue)
double RelPosX(double aValue)
double RelPosY(double aValue)
VECTOR2< T > RelPos(const VECTOR2< T > &aVec)
void TransformTextToBaseline(EDA_TEXT *textItem, const wxString &baselineAlign)
std::vector< SHAPE_LINE_CHAIN > ParseLineChains(const wxString &aData, int aMaxError, bool aForceClosed)
virtual double ScaleSize(double aValue)=0
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:79
const VECTOR2I & GetTextPos() const
Definition eda_text.h:272
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:146
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:579
VECTOR2I GetTextSize() const
Definition eda_text.h:260
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
bool cw
const SHAPE_LINE_CHAIN chain
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
int delta
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694