~ubuntu-branches/ubuntu/oneiric/gerbv/oneiric

« back to all changes in this revision

Viewing changes to src/pick-and-place.c

  • Committer: Bazaar Package Importer
  • Author(s): Ramakrishnan Muthukrishnan
  • Date: 2008-02-12 22:44:38 UTC
  • mfrom: (3.1.5 hardy)
  • Revision ID: james.westby@ubuntu.com-20080212224438-zfxpim9ax1huyf65
Tags: 2.0.1-3
debian/control: made extra-xdg-menus as a recommendation instead of
dependency.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * gEDA - GNU Electronic Design Automation
 
3
 * This file is a part of gerbv.
 
4
 *
 
5
 *   Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (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, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
 
20
 */
 
21
 
 
22
 
 
23
/** @file pick-and-place.c
 
24
    @contains the pick and place parser and renderer
 
25
 */ 
 
26
 
 
27
#ifdef HAVE_CONFIG_H
 
28
#include <config.h>
 
29
#endif /* HAVE_CONFIG_H */
 
30
 
 
31
#include <assert.h>
 
32
#include <stdio.h>
 
33
#include <stdlib.h>
 
34
#include <math.h>
 
35
#include <errno.h>
 
36
#include <sys/stat.h>
 
37
#include <glib.h>
 
38
#include <gtk/gtk.h> /* What's this for? */
 
39
 
 
40
#ifdef HAVE_STRING_H
 
41
#include <string.h>
 
42
#endif
 
43
 
 
44
#ifdef HAVE_UNISTD_H
 
45
#include <unistd.h>
 
46
#endif /* HAVE_UNISTD_H */
 
47
 
 
48
#include <ctype.h>
 
49
#include <locale.h>
 
50
 
 
51
#ifdef HAVE_GETOPT_H
 
52
#include <getopt.h>
 
53
#endif /* HAVE_GETOPT_H */
 
54
 
 
55
#include <assert.h>
 
56
 
 
57
#include "gerber.h"
 
58
#include "gerb_error.h"
 
59
 
 
60
#ifdef RENDER_USING_GDK
 
61
  #include "draw-gdk.h"
 
62
#else
 
63
  #include "draw.h"
 
64
#endif
 
65
 
 
66
#include "log.h"
 
67
#include "setup.h"
 
68
#include "csv.h"
 
69
#include "pick-and-place.h"
 
70
/* CHECKME - here gi18n is disabled */
 
71
#define _(String) (String)
 
72
 
 
73
#undef max
 
74
#define max(a,b) ((a) > (b) ? (a) : (b))
 
75
#undef min
 
76
#define min(a,b) ((a) < (b) ? (a) : (b))
 
77
 
 
78
/* DEBUG printing.  #define DEBUG 1 in config.h to use this fcn. */
 
79
#define dprintf if(DEBUG) printf
 
80
 
 
81
//! Parses a string representing float number with a unit, default is mil
 
82
/** @param char a string to be screened for unit
 
83
    @return a correctly converted double */
 
84
static double 
 
85
pick_and_place_get_float_unit(char *str)
 
86
{
 
87
    double x = 0.0;
 
88
    char unit[41];
 
89
 
 
90
    /* float, optional space, optional unit mm,cm,in,mil */
 
91
    sscanf(str, "%lf %40s", &x, unit);
 
92
    if(strstr(unit,"in")) {
 
93
        ;
 
94
    } else if(strstr(unit, "cm")) {
 
95
        x /= 2.54;
 
96
    } else { /* default to mils */
 
97
        x /= 1000;      
 
98
    }
 
99
 
 
100
    return x;
 
101
} /* pick_and_place_get_float_unit*/
 
102
 
 
103
 
 
104
/** search a string for a delimiter.
 
105
 Must occur at least n times. */
 
106
int 
 
107
pick_and_place_screen_for_delimiter(char *str, int n)
 
108
{
 
109
    char *ptr;
 
110
    char delimiter[4] = "|,;:";
 
111
    int counter[4];
 
112
    int idx, idx_max = 0;
 
113
 
 
114
    memset(counter, 0, sizeof(counter));
 
115
    for(ptr = str; *ptr; ptr++) {
 
116
        switch(*ptr) {
 
117
        case '|':
 
118
            idx = 0;
 
119
            break;
 
120
        case ',':
 
121
            idx = 1;
 
122
            break;
 
123
        case ';':
 
124
            idx = 2;
 
125
            break;
 
126
        case ':':
 
127
            idx = 3;
 
128
            break;
 
129
        default:
 
130
            continue;
 
131
            break;
 
132
        }
 
133
        counter[idx]++;
 
134
        if(counter[idx] > counter[idx_max]) {
 
135
            idx_max = idx;
 
136
        }
 
137
    }
 
138
    
 
139
    if (counter[idx_max] > n) {
 
140
        return (unsigned char) delimiter[idx_max];
 
141
    } else {
 
142
        return -1;
 
143
    }
 
144
} /* pnp_screen_for_delimiter */
 
145
 
 
146
 
 
147
/**Parses the PNP data.
 
148
   two lists are filled with the row data.\n One for the scrollable list in the search and select parts interface, the other one a mere two columned list, which drives the autocompletion when entering a search.\n
 
149
   It also tries to determine the shape of a part and sets  pnp_state->shape accordingly which will be used when drawing the selections as an overlay on screen.
 
150
   @return the initial node of the pnp_state netlist
 
151
 */
 
152
 
 
153
GArray *
 
154
pick_and_place_parse_file(gerb_file_t *fd)
 
155
{
 
156
    PnpPartData   pnpPartData;
 
157
    int           lineCounter = 0, parsedLines = 0;
 
158
    int           ret;
 
159
    char          *row[12];
 
160
    char          buf[MAXL+2], buf0[MAXL+2];
 
161
    double        tmp_x, tmp_y;
 
162
    gerb_transf_t *tr_rot = gerb_transf_new();
 
163
    GArray      *pnpParseDataArray = g_array_new (FALSE, FALSE, sizeof(PnpPartData));
 
164
    gboolean foundValidDataRow = FALSE;
 
165
    
 
166
    /*
 
167
     * many locales redefine "." as "," and so on, so sscanf has problems when
 
168
     * reading Pick and Place files using %f format 
 
169
     */
 
170
    setlocale(LC_NUMERIC, "C" );
 
171
 
 
172
    while ( fgets(buf, MAXL, fd->fd) != NULL ) {
 
173
        int len = strlen(buf)-1;
 
174
        int i_length = 0, i_width = 0;
 
175
        
 
176
        lineCounter += 1; /*next line*/
 
177
        if(lineCounter < 2) {
 
178
            /* 
 
179
             * TODO in principle column names could be read and interpreted
 
180
             * but we skip the first line with names of columns for this time
 
181
             */
 
182
            continue;
 
183
        }
 
184
        if(len >= 0 && buf[len] == '\n') {
 
185
            buf[len--] = 0;
 
186
        }
 
187
        if(len >= 0 && buf[len] == '\r') {
 
188
            buf[len--] = 0;
 
189
        }
 
190
        if (len <= 11)  {  //lets check a minimum length of 11
 
191
            continue;
 
192
        }
 
193
 
 
194
        if ((len > 0) && (buf[0] == '%')) {
 
195
            continue;
 
196
        }
 
197
 
 
198
        /* Abort if we see a G54 */
 
199
        if ((len > 4) && (strncmp(buf,"G54 ", 4) == 0)) {
 
200
            g_array_free (pnpParseDataArray, TRUE);
 
201
            return NULL;  
 
202
        }
 
203
 
 
204
        /* abort if we see a G04 code */
 
205
        if ((len > 4) && (strncmp(buf,"G04 ", 4) == 0)) {
 
206
            g_array_free (pnpParseDataArray, TRUE);
 
207
            return NULL;  
 
208
        }
 
209
 
 
210
        /* this accepts file both with and without quotes */
 
211
/*      if (!pnp_state) { /\* we are in first line *\/ */
 
212
/*         if ((delimiter = pnp_screen_for_delimiter(buf, 8)) < 0) { */
 
213
/*         continue; */
 
214
/*         } */
 
215
/*      } */
 
216
 
 
217
        ret = csv_row_parse(buf, MAXL,  buf0, MAXL, row, 11, ',',   CSV_QUOTES);
 
218
 
 
219
        if (ret > 0) {
 
220
            foundValidDataRow = TRUE;
 
221
        } else {
 
222
            continue;
 
223
        }
 
224
/*      printf("direct:%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,  %s, ret %d\n", row[0], row[1], row[2],row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], ret);        */
 
225
/*      g_warning ("FFF %s %s\n",row[8],row[6]); */
 
226
 
 
227
        if (row[0] && row[8]) { // here could be some better check for the syntax
 
228
            snprintf (pnpPartData.designator, sizeof(pnpPartData.designator)-1, "%s", row[0]);
 
229
            snprintf (pnpPartData.footprint, sizeof(pnpPartData.footprint)-1, "%s", row[1]);
 
230
            snprintf (pnpPartData.layer, sizeof(pnpPartData.layer)-1, "%s", row[8]);
 
231
            if (row[10] != NULL) {
 
232
                if ( ! g_utf8_validate(row[10], -1, NULL)) {
 
233
                    gchar * str = g_convert(row[10], strlen(row[10]), "UTF-8", "ISO-8859-1",
 
234
                                            NULL, NULL, NULL);
 
235
                    // I have not decided yet whether it is better to use always
 
236
                    // "ISO-8859-1" or current locale.
 
237
                    // str = g_locale_to_utf8(row[10], -1, NULL, NULL, NULL);
 
238
                    snprintf (pnpPartData.comment, sizeof(pnpPartData.comment)-1, "%s", str);
 
239
                    g_free(str);
 
240
                } else {
 
241
                    snprintf (pnpPartData.comment, sizeof(pnpPartData.comment)-1, "%s", row[10]);
 
242
                }
 
243
            }
 
244
            /*
 
245
              gchar* g_convert(const gchar *str, gssize len, const gchar *to_codeset, const gchar *from_codeset, gsize *bytes_read, gsize *bytes_written, GError **error);
 
246
            */
 
247
            pnpPartData.mid_x = pick_and_place_get_float_unit(row[2]);
 
248
            pnpPartData.mid_y = pick_and_place_get_float_unit(row[3]);
 
249
            pnpPartData.ref_x = pick_and_place_get_float_unit(row[4]);
 
250
            pnpPartData.ref_y = pick_and_place_get_float_unit(row[5]);
 
251
            pnpPartData.pad_x = pick_and_place_get_float_unit(row[6]);
 
252
            pnpPartData.pad_y = pick_and_place_get_float_unit(row[7]);
 
253
            /* This line causes segfault if we accidently starts parsing 
 
254
             * a gerber file. It is crap crap crap */
 
255
            if (row[9])
 
256
                sscanf(row[9], "%lf", &pnpPartData.rotation); // no units, always deg
 
257
        }
 
258
        /* for now, default back to PCB program format
 
259
         * TODO: implement better checking for format
 
260
         */
 
261
        else if (row[0] && row[1] && row[2] && row[3] && row[4] && row[5] && row[6]) {
 
262
            snprintf (pnpPartData.designator, sizeof(pnpPartData.designator)-1, "%s", row[0]);
 
263
            snprintf (pnpPartData.footprint, sizeof(pnpPartData.footprint)-1, "%s", row[1]);            
 
264
            snprintf (pnpPartData.layer, sizeof(pnpPartData.layer)-1, "%s", row[6]);    
 
265
            pnpPartData.mid_x = pick_and_place_get_float_unit(row[3]);
 
266
            pnpPartData.mid_y = pick_and_place_get_float_unit(row[4]);
 
267
            pnpPartData.pad_x = pnpPartData.mid_x + 0.03;
 
268
            pnpPartData.pad_y = pnpPartData.mid_y + 0.03;
 
269
            sscanf(row[5], "%lf", &pnpPartData.rotation); // no units, always deg
 
270
            /* check for coordinate sanity, and abort if it fails
 
271
             * Note: this is mainly to catch comment lines that get parsed
 
272
             */
 
273
            if ((fabs(pnpPartData.mid_x) < 0.001)&&(fabs(pnpPartData.mid_y) < 0.001)) {
 
274
                continue;                       
 
275
            }
 
276
        } else {
 
277
            continue;
 
278
        }
 
279
 
 
280
 
 
281
        /* 
 
282
         * now, try and figure out the actual footprint shape to draw, or just
 
283
         * guess something reasonable
 
284
         */
 
285
        if(sscanf(pnpPartData.footprint, "%02d%02d", &i_length, &i_width) == 2) {
 
286
            // parse footprints like 0805 or 1206
 
287
            pnpPartData.length = 0.01 * i_length;
 
288
            pnpPartData.width = 0.01 * i_width;
 
289
            pnpPartData.shape = PART_SHAPE_RECTANGLE;
 
290
        } else { 
 
291
            gerb_transf_reset(tr_rot);
 
292
            gerb_transf_rotate(tr_rot, -pnpPartData.rotation * M_PI/180);/* rotate it back to get dimensions */
 
293
            gerb_transf_apply( pnpPartData.pad_x -  pnpPartData.mid_x, 
 
294
                               pnpPartData.pad_y - pnpPartData.mid_y, tr_rot, &tmp_x, &tmp_y);
 
295
            if ((fabs(tmp_y) > fabs(tmp_x/100)) && (fabs(tmp_x) > fabs(tmp_y/100))){
 
296
                pnpPartData.length = 2 * tmp_x;/* get dimensions*/
 
297
                pnpPartData.width = 2 * tmp_y;
 
298
                pnpPartData.shape = PART_SHAPE_STD;
 
299
            } else {
 
300
                pnpPartData.length = 0.015;
 
301
                pnpPartData.width = 0.015;
 
302
                pnpPartData.shape = PART_SHAPE_UNKNOWN;
 
303
            }
 
304
        }  
 
305
        g_array_append_val (pnpParseDataArray, pnpPartData);
 
306
        parsedLines += 1;
 
307
    }   
 
308
    gerb_transf_free(tr_rot);
 
309
    /* fd->ptr=0; */
 
310
    /* rewind(fd->fd); */
 
311
        
 
312
    /* so a sanity check and see if this is a valid pnp file */
 
313
    if ((((float) parsedLines / (float) lineCounter) < 0.3) ||
 
314
        (!foundValidDataRow)) {
 
315
        /* this doesn't look like a valid PNP file, so return error */
 
316
        g_array_free (pnpParseDataArray, TRUE);
 
317
        return NULL;
 
318
    }     
 
319
    return pnpParseDataArray;
 
320
} /* pick_and_place_parse_file */
 
321
 
 
322
 
 
323
/*      ------------------------------------------------------------------
 
324
 *      pick_and_place_check_file_type
 
325
 *      ------------------------------------------------------------------
 
326
 *      Description: Tries to parse the given file into a pick-and-place
 
327
 *              data set. If it fails to read any good rows, then returns
 
328
 *              FALSE, otherwise it returns TRUE.
 
329
 *      Notes: 
 
330
 *      ------------------------------------------------------------------
 
331
 */
 
332
gboolean
 
333
pick_and_place_check_file_type(gerb_file_t *fd, gboolean *returnFoundBinary)
 
334
{
 
335
    char *buf;
 
336
    int len = 0;
 
337
    int i;
 
338
    char *letter;
 
339
    gboolean found_binary = FALSE;
 
340
    gboolean found_G54 = FALSE;
 
341
    gboolean found_M0 = FALSE;
 
342
    gboolean found_M2 = FALSE;
 
343
    gboolean found_G2 = FALSE;
 
344
    gboolean found_ADD = FALSE;
 
345
    gboolean found_comma = FALSE;
 
346
    gboolean found_R = FALSE;
 
347
    gboolean found_U = FALSE;
 
348
    gboolean found_C = FALSE;
 
349
    gboolean found_boardside = FALSE;
 
350
 
 
351
    buf = malloc(MAXL);
 
352
    if (buf == NULL)
 
353
        GERB_FATAL_ERROR("malloc buf failed while checking for pick-place file.\n");
 
354
 
 
355
    while (fgets(buf, MAXL, fd->fd) != NULL) {
 
356
        len = strlen(buf);
 
357
     
 
358
        /* First look through the file for indications of its type */
 
359
        
 
360
        /* check for non-binary file */
 
361
        for (i = 0; i < len; i++) {
 
362
            if (!isprint((int) buf[i]) && (buf[i] != '\r') && 
 
363
                (buf[i] != '\n') && (buf[i] != '\t')) {
 
364
                found_binary = TRUE;
 
365
            }
 
366
        }
 
367
        
 
368
        if (g_strstr_len(buf, len, "G54")) {
 
369
            found_G54 = TRUE;
 
370
        }
 
371
        if (g_strstr_len(buf, len, "M00")) {
 
372
            found_M0 = TRUE;
 
373
        }
 
374
        if (g_strstr_len(buf, len, "M02")) {
 
375
            found_M2 = TRUE;
 
376
        }
 
377
        if (g_strstr_len(buf, len, "G02")) {
 
378
            found_G2 = TRUE;
 
379
        }
 
380
        if (g_strstr_len(buf, len, "ADD")) {
 
381
            found_ADD = TRUE;
 
382
        }
 
383
        if (g_strstr_len(buf, len, ",")) {
 
384
            found_comma = TRUE;
 
385
        }
 
386
        /* Semicolon can be separator too */
 
387
        if (g_strstr_len(buf, len, ";")) {
 
388
            found_comma = TRUE;
 
389
        }
 
390
        
 
391
        /* Look for refdes -- This is dumb, but what else can we do? */
 
392
        if ((letter = g_strstr_len(buf, len, "R")) != NULL) {
 
393
            if (isdigit((int) letter[1])) { /* grab char after R */
 
394
                found_R = TRUE;
 
395
            }
 
396
        }
 
397
        if ((letter = g_strstr_len(buf, len, "C")) != NULL) {
 
398
            if (isdigit((int) letter[1])) { /* grab char after C */
 
399
                found_C = TRUE;
 
400
            }
 
401
        }
 
402
        if ((letter = g_strstr_len(buf, len, "U")) != NULL) {
 
403
            if (isdigit((int) letter[1])) { /* grab char after U */
 
404
                found_U = TRUE;
 
405
            }
 
406
        }
 
407
        
 
408
        /* Look for board side indicator since this is required
 
409
         * by many vendors */
 
410
        if (g_strstr_len(buf, len, "top")) {
 
411
            found_boardside = TRUE;
 
412
        }
 
413
        if (g_strstr_len(buf, len, "Top")) {
 
414
            found_boardside = TRUE;
 
415
        }
 
416
        if (g_strstr_len(buf, len, "TOP")) {
 
417
            found_boardside = TRUE;
 
418
        }
 
419
        /* Also look for evidence of "Layer" in header.... */
 
420
        if (g_strstr_len(buf, len, "ayer")) {
 
421
            found_boardside = TRUE;
 
422
        }
 
423
        if (g_strstr_len(buf, len, "AYER")) {
 
424
            found_boardside = TRUE;
 
425
        }
 
426
        
 
427
    }
 
428
    rewind(fd->fd);
 
429
    free(buf);
 
430
 
 
431
    /* Now form logical expression determining if this is a pick-place file */
 
432
    *returnFoundBinary = found_binary;
 
433
    if (found_G54) 
 
434
        return FALSE;
 
435
    if (found_M0) 
 
436
        return FALSE;
 
437
    if (found_M2) 
 
438
        return FALSE;
 
439
    if (found_G2) 
 
440
        return FALSE;
 
441
    if (found_ADD) 
 
442
        return FALSE;
 
443
    if (found_comma && (found_R || found_C || found_U) && 
 
444
        found_boardside) 
 
445
        return TRUE;
 
446
    
 
447
    return FALSE;
 
448
    
 
449
} /* pick_and_place_check_file_type */
 
450
 
 
451
 
 
452
/*      ------------------------------------------------------------------
 
453
 *      pick_and_place_convert_pnp_data_to_image
 
454
 *      ------------------------------------------------------------------
 
455
 *      Description: Render a parsedPickAndPlaceData array into a gerb_image.
 
456
 *      Notes:
 
457
 *      ------------------------------------------------------------------
 
458
 */
 
459
gerb_image_t *
 
460
pick_and_place_convert_pnp_data_to_image(GArray *parsedPickAndPlaceData, gint boardSide) 
 
461
{
 
462
    gerb_image_t *image = NULL;
 
463
    gerb_net_t *curr_net = NULL;
 
464
    int i;
 
465
    gerb_transf_t *tr_rot = gerb_transf_new();
 
466
    drill_stats_t *stats;  /* Eventually replace with pick_place_stats */
 
467
    gboolean foundElement = FALSE;
 
468
    
 
469
    /* step through and make sure we have an element on the layer before
 
470
       we actually create a new image for it and fill it */
 
471
    for (i = 0; i < parsedPickAndPlaceData->len; i++) {
 
472
        PnpPartData partData = g_array_index(parsedPickAndPlaceData, PnpPartData, i);
 
473
        
 
474
        if ((boardSide == 0) && !((partData.layer[0]=='b') || (partData.layer[0]=='B')))
 
475
                continue;
 
476
        if ((boardSide == 1) && !((partData.layer[0]=='t') || (partData.layer[0]=='T')))
 
477
                continue;
 
478
                
 
479
        foundElement = TRUE;
 
480
    }
 
481
    if (!foundElement)
 
482
        return NULL;
 
483
 
 
484
    image = new_gerb_image(image);
 
485
    if (image == NULL) {
 
486
        GERB_FATAL_ERROR("malloc image failed\n");
 
487
    }
 
488
        
 
489
    image->format = (gerb_format_t *)g_malloc(sizeof(gerb_format_t));
 
490
    if (image->format == NULL) {
 
491
        GERB_FATAL_ERROR("malloc format failed\n");
 
492
    }
 
493
    memset((void *)image->format, 0, sizeof(gerb_format_t));
 
494
    
 
495
    image->layertype = PICK_AND_PLACE;
 
496
    stats = drill_stats_new();
 
497
    if (stats == NULL)
 
498
        GERB_FATAL_ERROR("malloc pick_place_stats failed\n");
 
499
    image->drill_stats = stats;
 
500
 
 
501
 
 
502
    curr_net = image->netlist;
 
503
    curr_net->layer = image->layers;
 
504
    curr_net->state = image->states;    
 
505
    image->info->min_x = HUGE_VAL;
 
506
    image->info->min_y = HUGE_VAL;
 
507
    image->info->max_x = -HUGE_VAL;
 
508
    image->info->max_y = -HUGE_VAL;
 
509
 
 
510
    image->aperture[0] = (gerb_aperture_t *)g_malloc(sizeof(gerb_aperture_t));
 
511
    memset((void *) image->aperture[0], 0, sizeof(gerb_aperture_t));
 
512
    image->aperture[0]->type = CIRCLE;
 
513
    image->aperture[0]->amacro = NULL;
 
514
    image->aperture[0]->parameter[0] = 0.02;
 
515
    image->aperture[0]->nuf_parameters = 1;
 
516
 
 
517
    for (i = 0; i < parsedPickAndPlaceData->len; i++) {
 
518
        PnpPartData partData = g_array_index(parsedPickAndPlaceData, PnpPartData, i);
 
519
        float radius;                         
 
520
        curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
 
521
        curr_net = curr_net->next;
 
522
        assert(curr_net);
 
523
        memset((void *)curr_net, 0, sizeof(gerb_net_t));
 
524
        curr_net->layer = image->layers;
 
525
        curr_net->state = image->states;        
 
526
        partData.rotation *= M_PI/180; /* convert deg to rad */
 
527
        /* check if the entry is on the specified layer */
 
528
        if ((boardSide == 0) && !((partData.layer[0]=='b') || (partData.layer[0]=='B')))
 
529
                continue;
 
530
        if ((boardSide == 1) && !((partData.layer[0]=='t') || (partData.layer[0]=='T')))
 
531
                continue;       
 
532
        if ((partData.shape == PART_SHAPE_RECTANGLE) ||
 
533
            (partData.shape == PART_SHAPE_STD)) {
 
534
            // TODO: draw rectangle length x width taking into account rotation or pad x,y
 
535
            gerb_transf_reset(tr_rot);
 
536
            
 
537
            gerb_transf_shift(tr_rot, partData.mid_x, partData.mid_y);
 
538
            /* unrotate the part to make sure the label is in the same location */
 
539
            gerb_transf_rotate(tr_rot, -partData.rotation);
 
540
            /* this first net is just a label holder, so calculate the lower
 
541
               left location to line up above the element */
 
542
            gerb_transf_apply(-partData.length/2,partData.width/2, tr_rot, 
 
543
                              &curr_net->start_x, &curr_net->start_y);
 
544
            gerb_transf_apply(-partData.length/2,partData.width/2, tr_rot, 
 
545
                              &curr_net->stop_x, &curr_net->stop_y);
 
546
            /* re-rotate back to the correct orientation */
 
547
            gerb_transf_rotate(tr_rot, partData.rotation);
 
548
            
 
549
            curr_net->aperture = 0;
 
550
            curr_net->aperture_state = OFF;
 
551
            curr_net->interpolation = LINEARx1;
 
552
            curr_net->layer = image->layers;
 
553
            curr_net->state = image->states;
 
554
            
 
555
            /* assign a label to this first draw primitive, in case we want
 
556
             * to render some text next to the mark
 
557
             */
 
558
            if (strlen (partData.designator) > 0) {
 
559
                curr_net->label = g_string_new (partData.designator);
 
560
            }
 
561
            
 
562
            /* rotate 180 to line up with PCB standard notation */
 
563
            gerb_transf_rotate(tr_rot, M_PI);
 
564
            
 
565
            curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
 
566
            curr_net = curr_net->next;
 
567
            assert(curr_net);
 
568
            memset((void *)curr_net, 0, sizeof(gerb_net_t));
 
569
            gerb_transf_apply(partData.length/2, partData.width/2, tr_rot, 
 
570
                              &curr_net->start_x, &curr_net->start_y);
 
571
            gerb_transf_apply(-partData.length/2, partData.width/2, tr_rot, 
 
572
                              &curr_net->stop_x, &curr_net->stop_y);
 
573
            
 
574
            curr_net->aperture = 0;
 
575
            curr_net->aperture_state = ON;
 
576
            curr_net->interpolation = LINEARx1;
 
577
            curr_net->layer = image->layers;
 
578
            curr_net->state = image->states;
 
579
            
 
580
            
 
581
            curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
 
582
            curr_net = curr_net->next;
 
583
            assert(curr_net);
 
584
            memset((void *)curr_net, 0, sizeof(gerb_net_t));
 
585
            
 
586
            gerb_transf_apply(-partData.length/2, partData.width/2, tr_rot, 
 
587
                              &curr_net->start_x, &curr_net->start_y);
 
588
            gerb_transf_apply(-partData.length/2, -partData.width/2, tr_rot, 
 
589
                              &curr_net->stop_x, &curr_net->stop_y);
 
590
            
 
591
            curr_net->aperture = 0;
 
592
            curr_net->aperture_state = ON;
 
593
            curr_net->interpolation = LINEARx1;
 
594
            curr_net->layer = image->layers;
 
595
            curr_net->state = image->states;
 
596
            
 
597
            curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
 
598
            curr_net = curr_net->next;
 
599
            assert(curr_net);
 
600
            memset((void *)curr_net, 0, sizeof(gerb_net_t));
 
601
            
 
602
            gerb_transf_apply(-partData.length/2, -partData.width/2, tr_rot, 
 
603
                              &curr_net->start_x, &curr_net->start_y);
 
604
            gerb_transf_apply(partData.length/2, -partData.width/2, tr_rot, 
 
605
                              &curr_net->stop_x, &curr_net->stop_y);
 
606
            
 
607
            curr_net->aperture = 0;
 
608
            curr_net->aperture_state = ON;
 
609
            curr_net->interpolation = LINEARx1;
 
610
            curr_net->layer = image->layers;
 
611
            curr_net->state = image->states;
 
612
            
 
613
            curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
 
614
            curr_net = curr_net->next;
 
615
            assert(curr_net);
 
616
            memset((void *)curr_net, 0, sizeof(gerb_net_t));
 
617
            
 
618
            gerb_transf_apply(partData.length/2, -partData.width/2, tr_rot, 
 
619
                              &curr_net->start_x, &curr_net->start_y);
 
620
            gerb_transf_apply(partData.length/2, partData.width/2, tr_rot, 
 
621
                              &curr_net->stop_x, &curr_net->stop_y);
 
622
            
 
623
            curr_net->aperture = 0;
 
624
            curr_net->aperture_state = ON;
 
625
            curr_net->interpolation = LINEARx1;
 
626
            curr_net->layer = image->layers;
 
627
            curr_net->state = image->states;
 
628
            
 
629
            curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
 
630
            curr_net = curr_net->next;
 
631
            assert(curr_net);
 
632
            memset((void *)curr_net, 0, sizeof(gerb_net_t));
 
633
            
 
634
            if (partData.shape == PART_SHAPE_RECTANGLE) {
 
635
                gerb_transf_apply(partData.length/4, -partData.width/2, tr_rot, 
 
636
                                  &curr_net->start_x, &curr_net->start_y);
 
637
                gerb_transf_apply(partData.length/4, partData.width/2, tr_rot, 
 
638
                                  &curr_net->stop_x, &curr_net->stop_y);
 
639
            } else {
 
640
                gerb_transf_apply(partData.length/4, partData.width/2, tr_rot, 
 
641
                                  &curr_net->start_x, &curr_net->start_y);
 
642
                gerb_transf_apply(partData.length/4, partData.width/4, tr_rot, 
 
643
                                  &curr_net->stop_x, &curr_net->stop_y);
 
644
                
 
645
                curr_net->aperture = 0;
 
646
                curr_net->aperture_state = ON;
 
647
                curr_net->interpolation = LINEARx1;
 
648
                curr_net->layer = image->layers;
 
649
                curr_net->state = image->states;
 
650
                
 
651
                curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
 
652
                curr_net = curr_net->next;
 
653
                assert(curr_net);
 
654
                memset((void *)curr_net, 0, sizeof(gerb_net_t));
 
655
                gerb_transf_apply(partData.length/2, partData.width/4, tr_rot, 
 
656
                                  &curr_net->start_x, &curr_net->start_y);
 
657
                gerb_transf_apply(partData.length/4, partData.width/4, tr_rot, 
 
658
                                  &curr_net->stop_x, &curr_net->stop_y);     
 
659
            }
 
660
            curr_net->aperture = 0;
 
661
            curr_net->aperture_state = ON;
 
662
            curr_net->interpolation = LINEARx1;
 
663
            curr_net->layer = image->layers;
 
664
            curr_net->state = image->states;
 
665
            /* calculate a rough radius for the min/max screen calcs later */
 
666
            radius = max (partData.length/2, partData.width/2);
 
667
        } else {
 
668
            curr_net->start_x = partData.mid_x;
 
669
            curr_net->start_y = partData.mid_y;
 
670
            curr_net->stop_x = partData.pad_x;
 
671
            curr_net->stop_y = partData.pad_y;
 
672
            
 
673
            curr_net->aperture = 0;
 
674
            curr_net->aperture_state = ON;
 
675
            curr_net->interpolation = LINEARx1;
 
676
            curr_net->layer = image->layers;
 
677
            curr_net->state = image->states;
 
678
            
 
679
            curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
 
680
            curr_net = curr_net->next;
 
681
            assert(curr_net);
 
682
            memset((void *)curr_net, 0, sizeof(gerb_net_t));
 
683
            
 
684
            curr_net->start_x = partData.mid_x;
 
685
            curr_net->start_y = partData.mid_y;
 
686
            curr_net->stop_x = partData.pad_x;
 
687
            curr_net->stop_y = partData.pad_y;
 
688
            
 
689
            curr_net->aperture = 0;
 
690
            curr_net->aperture_state = ON;
 
691
            curr_net->interpolation = CW_CIRCULAR;
 
692
            curr_net->layer = image->layers;
 
693
            curr_net->state = image->states;
 
694
            
 
695
            curr_net->cirseg = (gerb_cirseg_t *)g_malloc(sizeof(gerb_cirseg_t));
 
696
            memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
 
697
            curr_net->cirseg->angle1 = 0.0;
 
698
            curr_net->cirseg->angle2 = 360.0;
 
699
            curr_net->cirseg->cp_x = partData.mid_x;
 
700
            curr_net->cirseg->cp_y = partData.mid_y;
 
701
            radius = sqrt((partData.pad_x-partData.mid_x)*(partData.pad_x-partData.mid_x) +
 
702
                          (partData.pad_y-partData.mid_y)*(partData.pad_y-partData.mid_y));
 
703
            if (radius < 0.001)
 
704
                radius = 0.1;
 
705
            curr_net->cirseg->width = 2*radius; /* fabs(pad_x-mid_x) */
 
706
            curr_net->cirseg->height = 2*radius;
 
707
        }
 
708
 
 
709
        /* 
 
710
         * update min and max numbers so the screen zoom-to-fit 
 
711
         *function will work
 
712
         */
 
713
        image->info->min_x = min(image->info->min_x, (partData.mid_x - radius - 0.02));
 
714
        image->info->min_y = min(image->info->min_y, (partData.mid_y - radius - 0.02));
 
715
        image->info->max_x = max(image->info->max_x, (partData.mid_x + radius + 0.02));
 
716
        image->info->max_y = max(image->info->max_y, (partData.mid_y + radius + 0.02));
 
717
    }
 
718
    curr_net->next = NULL;
 
719
    
 
720
    gerb_transf_free(tr_rot);
 
721
    return image;
 
722
} /* pick_and_place_parse_file_to_image */
 
723
 
 
724
 
 
725
/*      ------------------------------------------------------------------
 
726
 *      pick_and_place_parse_file_to_image
 
727
 *      ------------------------------------------------------------------
 
728
 *      Description: Renders a pick and place file to a gerb_image.
 
729
 *      Notes: The file format should already be verified before calling
 
730
 *       this function, since it does very little sanity checking itself.
 
731
 *      ------------------------------------------------------------------
 
732
 */
 
733
void
 
734
pick_and_place_parse_file_to_images(gerb_file_t *fd, gerb_image_t **topImage,
 
735
                        gerb_image_t **bottomImage) 
 
736
 
737
    GArray *parsedPickAndPlaceData = pick_and_place_parse_file (fd);
 
738
 
 
739
    *bottomImage = pick_and_place_convert_pnp_data_to_image(parsedPickAndPlaceData, 0);
 
740
    *topImage = pick_and_place_convert_pnp_data_to_image(parsedPickAndPlaceData, 1);
 
741
 
 
742
    g_array_free (parsedPickAndPlaceData, TRUE);
 
743
} /* pick_and_place_parse_file_to_image */
 
744