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.
Definition: bezier_curves.h:38
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:270
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:144
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:578
VECTOR2I GetTextSize() const
Definition: eda_text.h:258
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.
Definition: shape_arc.cpp:213
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Clear()
Remove all points from the line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
bool cw
const SHAPE_LINE_CHAIN chain
VECTOR2I end
constexpr 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