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 (C) 2023 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
31
32double EASYEDA_PARSER_BASE::Convert( const wxString& aValue )
33{
34 double value = 0;
35
36 if( !aValue.ToCDouble( &value ) )
37 THROW_IO_ERROR( wxString::Format( _( "Failed to parse number from '%s'" ), aValue ) );
38
39 return value;
40}
41
42
43double EASYEDA_PARSER_BASE::RelPosX( double aValue )
44{
45 double value = aValue - m_relOrigin.x;
46 return ScaleSize( value );
47}
48
49
50double EASYEDA_PARSER_BASE::RelPosY( double aValue )
51{
52 double value = aValue - m_relOrigin.y;
53 return ScaleSize( value );
54}
55
56
57double EASYEDA_PARSER_BASE::RelPosX( const wxString& aValue )
58{
59 return RelPosX( Convert( aValue ) );
60}
61
62
63double EASYEDA_PARSER_BASE::RelPosY( const wxString& aValue )
64{
65 return RelPosY( Convert( aValue ) );
66}
67
68
69std::vector<SHAPE_LINE_CHAIN> EASYEDA_PARSER_BASE::ParseLineChains( const wxString& data,
70 int aArcMinSegLen )
71{
72 std::vector<SHAPE_LINE_CHAIN> result;
73
74 VECTOR2D prevPt;
75 SHAPE_LINE_CHAIN chain;
76
77 size_t pos = 0;
78 auto readNumber = [&]( wxString& aOut )
79 {
80 wxUniChar ch = data[pos];
81
82 while( ch == ' ' || ch == ',' )
83 ch = data[++pos];
84
85 while( isdigit( ch ) || ch == '.' || ch == '-' )
86 {
87 aOut += ch;
88 pos++;
89
90 if( pos == data.size() )
91 break;
92
93 ch = data[pos];
94 }
95 };
96
97 do
98 {
99 wxUniChar sym = data[pos++];
100
101 if( sym == ' ' )
102 continue;
103
104 if( sym == 'M' )
105 {
106 wxString xStr, yStr;
107
108 readNumber( xStr );
109 readNumber( yStr );
110
111 if( chain.PointCount() > 2 )
112 {
113 chain.SetClosed( true );
114 result.emplace_back( chain );
115 }
116
117 chain.Clear();
118
119 VECTOR2D pt( Convert( xStr ), Convert( yStr ) );
120 chain.Append( RelPos( pt ) );
121
122 prevPt = pt;
123 }
124 else if( sym == 'Z' )
125 {
126 if( chain.PointCount() > 2 )
127 {
128 chain.SetClosed( true );
129 result.emplace_back( chain );
130 }
131 chain.Clear();
132 }
133 else if( sym == 'L' )
134 {
135 while( true )
136 {
137 if( pos >= data.size() )
138 break;
139
140 wxUniChar ch = data[pos];
141
142 while( ch == ' ' || ch == ',' )
143 {
144 if( ++pos >= data.size() )
145 break;
146
147 ch = data[pos];
148 }
149
150 if( !isdigit( ch ) )
151 break;
152
153 wxString xStr, yStr;
154
155 readNumber( xStr );
156 readNumber( yStr );
157
158 VECTOR2D pt( Convert( xStr ), Convert( yStr ) );
159 chain.Append( RelPos( pt ) );
160
161 prevPt = pt;
162 };
163 }
164 else if( sym == 'A' )
165 {
166 wxString radX, radY, unknown, farFlag, cwFlag, endX, endY;
167
168 readNumber( radX );
169 readNumber( radY );
170 readNumber( unknown );
171 readNumber( farFlag );
172 readNumber( cwFlag );
173 readNumber( endX );
174 readNumber( endY );
175
176 bool isFar = farFlag == wxS( "1" );
177 bool cw = cwFlag == wxS( "1" );
178 VECTOR2D rad( Convert( radX ), Convert( radY ) );
179 VECTOR2D end( Convert( endX ), Convert( endY ) );
180
181 VECTOR2D start = prevPt;
182 VECTOR2D delta = end - start;
183
184 double d = delta.EuclideanNorm();
185 double h = sqrt( std::max( 0.0, rad.x * rad.x - d * d / 4 ) );
186
187 //( !far && cw ) => h
188 //( far && cw ) => -h
189 //( !far && !cw ) => -h
190 //( far && !cw ) => h
191 VECTOR2D arcCenter =
192 start + delta / 2 + delta.Perpendicular().Resize( ( isFar ^ cw ) ? h : -h );
193
194 SHAPE_ARC arc;
195 arc.ConstructFromStartEndCenter( RelPos( start ), RelPos( end ), RelPos( arcCenter ),
196 !cw );
197
198 chain.Append( arc );
199
200 prevPt = end;
201 }
202 else if( sym == 'C' )
203 {
204 wxString p1_xStr, p1_yStr, p2_xStr, p2_yStr, p3_xStr, p3_yStr;
205 readNumber( p1_xStr );
206 readNumber( p1_yStr );
207 readNumber( p2_xStr );
208 readNumber( p2_yStr );
209 readNumber( p3_xStr );
210 readNumber( p3_yStr );
211
212 VECTOR2D pt1( Convert( p1_xStr ), Convert( p1_yStr ) );
213 VECTOR2D pt2( Convert( p2_xStr ), Convert( p2_yStr ) );
214 VECTOR2D pt3( Convert( p3_xStr ), Convert( p3_yStr ) );
215
216 std::vector<VECTOR2I> ctrlPoints = { RelPos( prevPt ), RelPos( pt1 ), RelPos( pt2 ),
217 RelPos( pt3 ) };
218 BEZIER_POLY converter( ctrlPoints );
219
220 std::vector<VECTOR2I> bezierPoints;
221 converter.GetPoly( bezierPoints, aArcMinSegLen, 16 );
222
223 chain.Append( bezierPoints );
224
225 prevPt = pt3;
226 }
227 } while( pos < data.size() );
228
229 if( chain.PointCount() > 2 )
230 {
231 result.emplace_back( chain );
232 }
233
234 return result;
235}
Bezier curves to polygon converter.
Definition: bezier_curves.h:38
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMinSegLen=0, int aMaxSegCount=32)
Convert a Bezier curve to a polygon.
std::vector< SHAPE_LINE_CHAIN > ParseLineChains(const wxString &aData, int aArcMinSegLen)
static double Convert(const wxString &aValue)
double RelPosX(double aValue)
double RelPosY(double aValue)
VECTOR2< T > RelPos(const VECTOR2< T > &aVec)
virtual double ScaleSize(double aValue)=0
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:210
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
constexpr int delta