1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2014 Cirilo Bernardo
5  * Copyright (C) 2021 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 <iostream>
26 #include <fstream>
27 #include <string>
28 #include <sstream>
29 #include <cmath>
30 #include <cstdio>
31 #include <list>
32 #include <utility>
33 #include <clocale>
34 
35 using namespace std;
36 
37 void writeLeaded( FILE* fp, double width, double length, double wireDia, double pitch, bool inch );
38 
39 void writeLeadless( FILE* fp, double width, double length, double chamfer, bool inch );
40 
main(int argc,char ** argv)41 int main( int argc, char** argv )
42 {
43     // IDF implicitly requires the C locale
44     setlocale( LC_ALL, "C" );
45 
46     if( argc == 1 )
47     {
48         cout << "idfrect: This program generates an outline for a rectangular component.\n";
49         cout << "         The component may have a single lead (axial) or a chamfer on the\n";
50         cout << "         upper left corner.\n";
51         cout << "Input:\n";
52         cout << "        Unit: mm, in (millimeters or inches)\n";
53         cout << "        Width:\n";
54         cout << "        Length:\n";
55         cout << "        Height:\n";
56         cout << "        Chamfer: length of the 45 deg. chamfer\n";
57         cout << "        *  Leaded: Y,N (lead is always to the right)\n";
58         cout << "        ** Wire diameter\n";
59         cout << "        ** Pitch\n";
60         cout << "        File name (must end in *.idf)\n\n";
61         cout << "        NOTES:\n";
62         cout << "            *   only required if chamfer = 0\n\n";
63         cout << "            **  only required for leaded components\n\n";
64     }
65 
66     bool   inch = false; // default mm
67     double width = 0.0;
68     double length = 0.0;
69     double height = 0.0;
70     double wireDia = 0.0;
71     double pitch = 0.0;
72     double chamfer = 0.0;
73     bool   leaded = false;
74     bool   ok = false;
75 
76     stringstream tstr;
77     string       line;
78 
79     line.clear();
80 
81     while( line.compare( "mm" ) && line.compare( "in" ) )
82     {
83         cout << "* Units (mm,in): ";
84         line.clear();
85         std::getline( cin, line );
86     }
87 
88     if( line.compare( "mm" ) )
89         inch = true;
90 
91     ok = false;
92 
93     while( !ok )
94     {
95         cout << "* Width: ";
96 
97         line.clear();
98         std::getline( cin, line );
99 
100         tstr.clear();
101         tstr.str( line );
102 
103         tstr >> width;
104 
105         if( !tstr.fail() && width >= 0.001 )
106             ok = true;
107     }
108 
109     ok = false;
110 
111     while( !ok )
112     {
113         cout << "* Length: ";
114 
115         line.clear();
116         std::getline( cin, line );
117 
118         tstr.clear();
119         tstr.str( line );
120 
121         tstr >> length;
122 
123         if( !tstr.fail() && length > 0.0 )
124             ok = true;
125     }
126 
127     ok = false;
128 
129     while( !ok )
130     {
131         cout << "* Height: ";
132 
133         line.clear();
134         std::getline( cin, line );
135 
136         tstr.clear();
137         tstr.str( line );
138 
139         tstr >> height;
140 
141         if( !tstr.fail() && height >= 0.001 )
142             ok = true;
143     }
144 
145     ok = false;
146 
147     while( !ok )
148     {
149         cout << "* Chamfer (0 for none): ";
150 
151         line.clear();
152         std::getline( cin, line );
153 
154         tstr.clear();
155         tstr.str( line );
156 
157         tstr >> chamfer;
158 
159         if( !tstr.fail() && chamfer >= 0.0 )
160         {
161             if( chamfer > width / 3.0 || chamfer > length / 3.0 )
162                 cout << "* WARNING: chamfer must be <= MIN( width, length )/3\n";
163             else
164                 ok = true;
165         }
166     }
167 
168     if( chamfer < 1e-6 )
169     {
170         ok = false;
171 
172         while( !ok )
173         {
174             cout << "* Leaded: Y, N: ";
175 
176             line.clear();
177             std::getline( cin, line );
178 
179             if( !line.compare( "Y" ) || !line.compare( "y" ) )
180             {
181                 leaded = true;
182                 ok = true;
183             }
184             else if( !line.compare( "N" ) || !line.compare( "n" ) )
185             {
186                 leaded = false;
187                 ok = true;
188             }
189         }
190     }
191 
192     ok = false;
193 
194     while( leaded && !ok )
195     {
196         cout << "* Wire dia.: ";
197 
198         line.clear();
199         std::getline( cin, line );
200 
201         tstr.clear();
202         tstr.str( line );
203 
204         tstr >> wireDia;
205 
206         if( !tstr.fail() && wireDia >= 0.001 )
207         {
208             if( wireDia >= length )
209                 cout << "* WARNING: wire diameter must be < length\n";
210             else
211                 ok = true;
212         }
213     }
214 
215     ok = false;
216 
217     while( leaded && !ok )
218     {
219         cout << "* Pitch: ";
220 
221         line.clear();
222         std::getline( cin, line );
223 
224         tstr.clear();
225         tstr.str( line );
226 
227         tstr >> pitch;
228 
229         if( !tstr.fail() && pitch >= 0.001 )
230         {
231             if( pitch <= ( length + wireDia ) / 2.0 )
232                 cout << "* WARNING: pitch must be > (length + wireDia)/2\n";
233             else
234                 ok = true;
235         }
236     }
237 
238     line.clear();
239 
240     while( line.empty() || line.find( ".idf" ) == string::npos )
241     {
242         cout << "* File name (*.idf): ";
243 
244         line.clear();
245         std::getline( cin, line );
246     }
247 
248     FILE* fp = fopen( line.c_str(), "w" );
249 
250     if( !fp )
251     {
252         cerr << "Could not open output file: " << line << "\n";
253     }
254     else
255     {
256         fprintf( fp, "# rectangular outline%s\n", leaded ? ", leaded" : "" );
257         fprintf( fp, "# file: \"%s\"\n", line.c_str() );
258 
259         if( inch )
260         {
261             width *= 1000.0;
262             length *= 1000.0;
263             height *= 1000.0;
264             wireDia *= 1000.0;
265             pitch *= 1000.0;
266             chamfer *= 1000.0;
267 
268             fprintf( fp, "# width: %d THOU\n", (int) width );
269             fprintf( fp, "# length: %d THOU\n", (int) length );
270             fprintf( fp, "# height: %d THOU\n", (int) height );
271 
272             if( leaded )
273             {
274                 fprintf( fp, "# wire dia: %d THOU\n", (int) wireDia );
275                 fprintf( fp, "# pitch: %d THOU\n", (int) pitch );
276             }
277             else
278             {
279                 fprintf( fp, "# chamfer: %d THOU\n", (int) chamfer );
280             }
281 
282             fprintf( fp, ".ELECTRICAL\n" );
283             fprintf( fp, "\"RECT%sIN\" \"W%d_L%d_H%d", leaded ? "L" : "", (int) width, (int) length,
284                      (int) height );
285 
286             if( leaded )
287                 fprintf( fp, "_D%d_P%d\" ", (int) wireDia, (int) pitch );
288             else
289                 fprintf( fp, "_C%d\" ", (int) chamfer );
290 
291             fprintf( fp, "THOU %d\n", (int) height );
292         }
293         else
294         {
295             fprintf( fp, "# width: %.3f mm\n", width );
296             fprintf( fp, "# length: %.3f mm\n", length );
297             fprintf( fp, "# height: %.3f mm\n", height );
298 
299             if( leaded )
300             {
301                 fprintf( fp, "# wire dia: %.3f mm\n", wireDia );
302                 fprintf( fp, "# pitch: %.3f mm\n", pitch );
303             }
304             else
305             {
306                 fprintf( fp, "# chamfer: %.3f mm\n", chamfer );
307             }
308 
309             fprintf( fp, ".ELECTRICAL\n" );
310             fprintf( fp, "\"RECT%sMM\" \"W%.3f_L%.3f_H%.3f_", leaded ? "L" : "", width, length,
311                      height );
312 
313             if( leaded )
314                 fprintf( fp, "D%.3f_P%.3f\" ", wireDia, pitch );
315             else
316                 fprintf( fp, "C%.3f\" ", chamfer );
317 
318             fprintf( fp, "MM %.3f\n", height );
319         }
320 
321         if( leaded )
322             writeLeaded( fp, width, length, wireDia, pitch, inch );
323         else
324             writeLeadless( fp, width, length, chamfer, inch );
325 
326         fprintf( fp, ".END_ELECTRICAL\n" );
327         fclose( fp );
328     }
329 
330     setlocale( LC_ALL, "" );
331     return 0;
332 }
333 
334 
writeLeaded(FILE * fp,double width,double length,double wireDia,double pitch,bool inch)335 void writeLeaded( FILE* fp, double width, double length, double wireDia, double pitch, bool inch )
336 {
337     if( inch )
338     {
339         int x1, x2, x3;
340         int y1, y2;
341 
342         x1 = static_cast<int>( pitch / 2.0 );
343         x2 = static_cast<int>( width / 2.0 - x1 );
344         x3 = static_cast<int>( x2 - width );
345 
346         y1 = static_cast<int>( wireDia / 2.0 );
347         y2 = static_cast<int>( length / 2.0 );
348 
349         fprintf( fp, "0 %d %d 0\n", x1, y1 );
350         fprintf( fp, "0 %d %d 0\n", x2, y1 );
351         fprintf( fp, "0 %d %d 0\n", x2, y2 );
352         fprintf( fp, "0 %d %d 0\n", x3, y2 );
353         fprintf( fp, "0 %d %d 0\n", x3, -y2 );
354         fprintf( fp, "0 %d %d 0\n", x2, -y2 );
355         fprintf( fp, "0 %d %d 0\n", x2, -y1 );
356         fprintf( fp, "0 %d %d 0\n", x1, -y1 );
357         fprintf( fp, "0 %d %d 180\n", x1, y1 );
358     }
359     else
360     {
361         double x1, x2, x3;
362         double y1, y2;
363 
364         x1 = pitch / 2.0;
365         x2 = width / 2.0 - x1;
366         x3 = x2 - width;
367 
368         y1 = wireDia / 2.0;
369         y2 = length / 2.0;
370 
371         fprintf( fp, "0 %.3f %.3f 0\n", x1, y1 );
372         fprintf( fp, "0 %.3f %.3f 0\n", x2, y1 );
373         fprintf( fp, "0 %.3f %.3f 0\n", x2, y2 );
374         fprintf( fp, "0 %.3f %.3f 0\n", x3, y2 );
375         fprintf( fp, "0 %.3f %.3f 0\n", x3, -y2 );
376         fprintf( fp, "0 %.3f %.3f 0\n", x2, -y2 );
377         fprintf( fp, "0 %.3f %.3f 0\n", x2, -y1 );
378         fprintf( fp, "0 %.3f %.3f 0\n", x1, -y1 );
379         fprintf( fp, "0 %.3f %.3f 180\n", x1, y1 );
380     }
381 }
382 
383 
writeLeadless(FILE * fp,double width,double length,double chamfer,bool inch)384 void writeLeadless( FILE* fp, double width, double length, double chamfer, bool inch )
385 {
386     if( chamfer < 0.001 )
387     {
388         if( inch )
389         {
390             int x = static_cast<int>( width / 2.0 );
391             int y = static_cast<int>( length / 2.0 );
392 
393             fprintf( fp, "0 %d %d 0\n", x, y );
394             fprintf( fp, "0 %d %d 0\n", -x, y );
395             fprintf( fp, "0 %d %d 0\n", -x, -y );
396             fprintf( fp, "0 %d %d 0\n", x, -y );
397             fprintf( fp, "0 %d %d 0\n", x, y );
398         }
399         else
400         {
401             double x = width / 2.0;
402             double y = length / 2.0;
403 
404             fprintf( fp, "0 %.3f %.3f 0\n", x, y );
405             fprintf( fp, "0 %.3f %.3f 0\n", -x, y );
406             fprintf( fp, "0 %.3f %.3f 0\n", -x, -y );
407             fprintf( fp, "0 %.3f %.3f 0\n", x, -y );
408             fprintf( fp, "0 %.3f %.3f 0\n", x, y );
409         }
410 
411         return;
412     }
413 
414     if( inch )
415     {
416         int x = static_cast<int>( width / 2.0 );
417         int y = static_cast<int>( length / 2.0 );
418         int x1 = static_cast<int>( x - chamfer );
419         int y1 = static_cast<int>( y - chamfer );
420 
421         fprintf( fp, "0 %d %d 0\n", x, y );
422         fprintf( fp, "0 %d %d 0\n", -x1, y );
423         fprintf( fp, "0 %d %d 0\n", -x, y1 );
424         fprintf( fp, "0 %d %d 0\n", -x, -y );
425         fprintf( fp, "0 %d %d 0\n", x, -y );
426         fprintf( fp, "0 %d %d 0\n", x, y );
427     }
428     else
429     {
430         double x = width / 2.0;
431         double y = length / 2.0;
432         double x1 = x - chamfer;
433         double y1 = y - chamfer;
434 
435         fprintf( fp, "0 %.3f %.3f 0\n", x, y );
436         fprintf( fp, "0 %.3f %.3f 0\n", -x1, y );
437         fprintf( fp, "0 %.3f %.3f 0\n", -x, y1 );
438         fprintf( fp, "0 %.3f %.3f 0\n", -x, -y );
439         fprintf( fp, "0 %.3f %.3f 0\n", x, -y );
440         fprintf( fp, "0 %.3f %.3f 0\n", x, y );
441     }
442 }
443