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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include "easyeda_parser_base.h"
22
23#include <bezier_curves.h>
24#include <ki_exception.h>
25#include <wx/translation.h>
26#include <eda_text.h>
27
28
29double EASYEDA_PARSER_BASE::Convert( const wxString& aValue )
30{
31 double value = 0;
32
33 if( !aValue.ToCDouble( &value ) )
34 THROW_IO_ERROR( wxString::Format( _( "Failed to parse number from '%s'" ), aValue ) );
35
36 return value;
37}
38
39
40double EASYEDA_PARSER_BASE::RelPosX( double aValue )
41{
42 double value = aValue - m_relOrigin.x;
43 return ScaleSize( value );
44}
45
46
47double EASYEDA_PARSER_BASE::RelPosY( double aValue )
48{
49 double value = aValue - m_relOrigin.y;
50 return ScaleSize( value );
51}
52
53
54double EASYEDA_PARSER_BASE::RelPosX( const wxString& aValue )
55{
56 return RelPosX( Convert( aValue ) );
57}
58
59
60double EASYEDA_PARSER_BASE::RelPosY( const wxString& aValue )
61{
62 return RelPosY( Convert( aValue ) );
63}
64
65
67 const wxString& baselineAlign )
68{
69 int upOffset = 0;
70
71 if( baselineAlign == wxS( "" ) || baselineAlign == wxS( "auto" )
72 || baselineAlign == wxS( "use-script" ) || baselineAlign == wxS( "no-change" )
73 || baselineAlign == wxS( "reset-size" ) || baselineAlign == wxS( "alphabetic" )
74 || baselineAlign == wxS( "inherit" ) )
75 {
76 upOffset = textItem->GetTextSize().y;
77 }
78 else if( baselineAlign == wxS( "ideographic" ) || baselineAlign == wxS( "text-after-edge" ) )
79 {
80 upOffset = textItem->GetTextSize().y * 1.2;
81 }
82 else if( baselineAlign == wxS( "central" ) )
83 {
84 upOffset = textItem->GetTextSize().y * 0.5;
85 }
86 else if( baselineAlign == wxS( "middle" ) )
87 {
88 upOffset = textItem->GetTextSize().y * 0.6;
89 }
90 else if( baselineAlign == wxS( "mathematical" ) )
91 {
92 upOffset = textItem->GetTextSize().y * 0.1;
93 }
94 else if( baselineAlign == wxS( "hanging" ) || baselineAlign == wxS( "text-before-edge" ) )
95 {
96 upOffset = 0;
97 }
98
99 VECTOR2I offset( 0, -upOffset );
100 RotatePoint( offset, textItem->GetTextAngle() );
101
102 textItem->SetTextPos( textItem->GetTextPos() + offset );
103}
104
105
106std::vector<SHAPE_LINE_CHAIN>
107EASYEDA_PARSER_BASE::ParseLineChains( const wxString& data, int aMaxError, bool aForceClosed )
108{
109 std::vector<SHAPE_LINE_CHAIN> result;
110
111 VECTOR2D prevPt;
113
114 size_t pos = 0;
115 auto readNumber = [&]( wxString& aOut )
116 {
117 wxUniChar ch = data[pos];
118
119 while( ch == ' ' || ch == ',' )
120 ch = data[++pos];
121
122 while( isdigit( ch ) || ch == '.' || ch == '-' )
123 {
124 aOut += ch;
125 pos++;
126
127 if( pos == data.size() )
128 break;
129
130 ch = data[pos];
131 }
132 };
133
134 do
135 {
136 wxUniChar sym = data[pos++];
137
138 if( sym == ' ' )
139 continue;
140
141 if( sym == 'M' )
142 {
143 wxString xStr, yStr;
144
145 readNumber( xStr );
146 readNumber( yStr );
147
148 if( chain.PointCount() > 1 )
149 {
150 if( aForceClosed )
151 chain.SetClosed( true );
152
153 result.emplace_back( chain );
154 }
155
156 chain.Clear();
157
158 VECTOR2D pt( Convert( xStr ), Convert( yStr ) );
159 chain.Append( RelPos( pt ) );
160
161 prevPt = pt;
162 }
163 else if( sym == 'Z' )
164 {
165 if( chain.PointCount() > 2 )
166 {
167 chain.SetClosed( true );
168 result.emplace_back( chain );
169 }
170 chain.Clear();
171 }
172 else if( sym == 'L' || isdigit( sym ) || sym == '-' )
173 {
174 // We may not have a command, just coordinates:
175 // M 4108.8 3364.1 3982.598 3295.6914
176 if( isdigit( sym ) || sym == '-' )
177 pos--;
178
179 while( true )
180 {
181 if( pos >= data.size() )
182 break;
183
184 wxUniChar ch = data[pos];
185
186 while( ch == ' ' || ch == ',' )
187 {
188 if( ++pos >= data.size() )
189 break;
190
191 ch = data[pos];
192 }
193
194 if( !isdigit( ch ) && ch != '-' )
195 break;
196
197 wxString xStr, yStr;
198
199 readNumber( xStr );
200 readNumber( yStr );
201
202 VECTOR2D pt( Convert( xStr ), Convert( yStr ) );
203 chain.Append( RelPos( pt ) );
204
205 prevPt = pt;
206 };
207 }
208 else if( sym == 'A' )
209 {
210 // Arc command can have multiple consecutive arc parameter sets
211 while( true )
212 {
213 if( pos >= data.size() )
214 break;
215
216 wxUniChar ch = data[pos];
217
218 while( ch == ' ' || ch == ',' )
219 {
220 if( ++pos >= data.size() )
221 break;
222
223 ch = data[pos];
224 }
225
226 if( !isdigit( ch ) && ch != '-' )
227 break;
228
229 wxString radX, radY, unknown, farFlag, cwFlag, endX, endY;
230
231 readNumber( radX );
232 readNumber( radY );
233 readNumber( unknown );
234 readNumber( farFlag );
235 readNumber( cwFlag );
236 readNumber( endX );
237 readNumber( endY );
238
239 bool isFar = farFlag == wxS( "1" );
240 bool cw = cwFlag == wxS( "1" );
241 VECTOR2D rad( Convert( radX ), Convert( radY ) );
242 VECTOR2D end( Convert( endX ), Convert( endY ) );
243
244 VECTOR2D start = prevPt;
245 VECTOR2D delta = end - start;
246
247 double d = delta.EuclideanNorm();
248 double h = sqrt( std::max( 0.0, rad.x * rad.x - d * d / 4 ) );
249
250 //( !far && cw ) => h
251 //( far && cw ) => -h
252 //( !far && !cw ) => -h
253 //( far && !cw ) => h
254 VECTOR2D arcCenter = start + delta / 2 + delta.Perpendicular().Resize( ( isFar ^ cw ) ? h : -h );
255
256 SHAPE_ARC arc;
257 arc.ConstructFromStartEndCenter( RelPos( start ), RelPos( end ), RelPos( arcCenter ), !cw );
258
259 chain.Append( arc, aMaxError );
260
261 prevPt = end;
262 }
263 }
264 else if( sym == 'C' )
265 {
266 wxString p1_xStr, p1_yStr, p2_xStr, p2_yStr, p3_xStr, p3_yStr;
267 readNumber( p1_xStr );
268 readNumber( p1_yStr );
269 readNumber( p2_xStr );
270 readNumber( p2_yStr );
271 readNumber( p3_xStr );
272 readNumber( p3_yStr );
273
274 VECTOR2D pt1( Convert( p1_xStr ), Convert( p1_yStr ) );
275 VECTOR2D pt2( Convert( p2_xStr ), Convert( p2_yStr ) );
276 VECTOR2D pt3( Convert( p3_xStr ), Convert( p3_yStr ) );
277
278 std::vector<VECTOR2I> ctrlPoints = { RelPos( prevPt ), RelPos( pt1 ), RelPos( pt2 ),
279 RelPos( pt3 ) };
280 BEZIER_POLY converter( ctrlPoints );
281
282 std::vector<VECTOR2I> bezierPoints;
283 converter.GetPoly( bezierPoints, aMaxError );
284
285 chain.Append( bezierPoints );
286
287 prevPt = pt3;
288 }
289 } while( pos < data.size() );
290
291 if( chain.PointCount() > 1 )
292 {
293 if( aForceClosed )
294 chain.SetClosed( true );
295
296 result.emplace_back( chain );
297 }
298
299 return result;
300}
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:89
virtual VECTOR2I GetTextSize() const
Definition eda_text.h:282
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:294
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:576
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:168
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:225
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682