Removed use of fgets() to read files and gerb_file approved file operations.
[geda-gerbv/spe.git] / src / pick-and-place.c
blob52f39aeffc6cec2a176016efab504ac05f403711
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
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.
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.
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
22 /** \file pick-and-place.c
23 \brief PNP (pick-and-place) parsing functions
24 \ingroup libgerbv
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif /* HAVE_CONFIG_H */
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? */
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif /* HAVE_UNISTD_H */
48 #include <ctype.h>
49 #include <locale.h>
51 #ifdef HAVE_GETOPT_H
52 #include <getopt.h>
53 #endif /* HAVE_GETOPT_H */
55 #include <assert.h>
57 #include "gerbv.h"
58 #include "gerber.h"
59 #ifdef RENDER_USING_GDK
60 #include "draw-gdk.h"
61 #else
62 #include "draw.h"
63 #endif
65 #include "csv.h"
66 #include "pick-and-place.h"
68 /* CHECKME - here gi18n is disabled */
69 #define _(String) (String)
71 #undef max
72 #define max(a,b) ((a) > (b) ? (a) : (b))
73 #undef min
74 #define min(a,b) ((a) < (b) ? (a) : (b))
76 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
77 #define dprintf if(DEBUG) printf
79 void gerb_transf_free(gerbv_transf_t *transf)
81 g_free(transf);
83 }/*gerbv_transf_t*/
86 void gerb_transf_reset(gerbv_transf_t* transf)
88 memset(transf,0,sizeof(gerbv_transf_t));
90 transf->r_mat[0][0] = transf->r_mat[1][1] = 1.0; /*off-diagonals 0 diagonals 1 */
91 //transf->r_mat[1][0] = transf->r_mat[0][1] = 0.0;
92 transf->scale = 1.0;
93 //transf->offset[0] = transf->offset[1] = 0.0;
95 } /*gerb_transf_reset*/
98 gerbv_transf_t* gerb_transf_new(void)
100 gerbv_transf_t *transf;
102 transf = g_malloc(sizeof(gerbv_transf_t));
103 gerb_transf_reset(transf);
104 return transf;
107 } /*gerb_transf_new*/
110 //!Rotation
111 /*! append rotation to transformation.
112 @param transf transformation to be modified
113 @param angle in rad (counterclockwise rotation) */
115 void gerb_transf_rotate(gerbv_transf_t* transf, double angle)
117 double m[2][2];
118 double s = sin(angle), c = cos(angle);
120 memcpy(m, transf->r_mat, sizeof(m));
121 transf->r_mat[0][0] = c * m[0][0] - s * m[1][0];
122 transf->r_mat[0][1] = c * m[0][1] - s * m[1][1];
123 transf->r_mat[1][0] = s * m[0][0] + c * m[1][0];
124 transf->r_mat[1][1] = s * m[0][1] + c * m[1][1];
125 // transf->offset[0] = transf->offset[1] = 0.0; CHECK ME
127 } /*gerb_transf_rotate*/
129 //!Translation
130 /*! append translation to transformation.
131 @param transf transformation to be modified
132 @param shift_x translation in x direction
133 @param shift_y translation in y direction */
135 void gerb_transf_shift(gerbv_transf_t* transf, double shift_x, double shift_y)
138 transf->offset[0] += shift_x;
139 transf->offset[1] += shift_y;
141 } /*gerb_transf_shift*/
143 void gerb_transf_apply(double x, double y, gerbv_transf_t* transf, double *out_x, double *out_y)
146 // x += transf->offset[0];
147 // y += transf->offset[1];
148 *out_x = (x * transf->r_mat[0][0] + y * transf->r_mat[0][1]) * transf->scale;
149 *out_y = (x * transf->r_mat[1][0] + y * transf->r_mat[1][1]) * transf->scale;
150 *out_x += transf->offset[0];
151 *out_y += transf->offset[1];
154 }/*gerb_transf_apply*/
156 void
157 pick_and_place_reset_bounding_box (gerbv_net_t *net) {
158 net->boundingBox.left = -HUGE_VAL;
159 net->boundingBox.right = HUGE_VAL;
160 net->boundingBox.bottom = -HUGE_VAL;
161 net->boundingBox.top = HUGE_VAL;
164 //! Parses a string representing float number with a unit, default is mil
165 static double
166 pick_and_place_get_float_unit(char *str)
168 double x = 0.0;
169 char unit[41];
171 /* float, optional space, optional unit mm,cm,in,mil */
172 sscanf(str, "%lf %40s", &x, unit);
173 if(strstr(unit,"in")) {
175 } else if(strstr(unit, "cm")) {
176 x /= 2.54;
177 } else { /* default to mils */
178 x /= 1000;
181 return x;
182 } /* pick_and_place_get_float_unit*/
185 /** search a string for a delimiter.
186 Must occur at least n times. */
187 int
188 pick_and_place_screen_for_delimiter(char *str, int n)
190 char *ptr;
191 char delimiter[4] = "|,;:";
192 int counter[4];
193 int idx, idx_max = 0;
195 memset(counter, 0, sizeof(counter));
196 for(ptr = str; *ptr; ptr++) {
197 switch(*ptr) {
198 case '|':
199 idx = 0;
200 break;
201 case ',':
202 idx = 1;
203 break;
204 case ';':
205 idx = 2;
206 break;
207 case ':':
208 idx = 3;
209 break;
210 default:
211 continue;
212 break;
214 counter[idx]++;
215 if(counter[idx] > counter[idx_max]) {
216 idx_max = idx;
220 if (counter[idx_max] > n) {
221 return (unsigned char) delimiter[idx_max];
222 } else {
223 return -1;
225 } /* pnp_screen_for_delimiter */
228 /**Parses the PNP data.
229 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
230 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.
231 @return the initial node of the pnp_state netlist
234 GArray *
235 pick_and_place_parse_file(gerb_file_t *fd)
237 PnpPartData pnpPartData;
238 int lineCounter = 0, parsedLines = 0;
239 int len;
240 int i_length = 0, i_width = 0;
241 int ret;
242 char *row[12];
243 char *buf = NULL, buf0[MAXL+2];
244 double tmp_x, tmp_y;
245 gerbv_transf_t *tr_rot = gerb_transf_new();
246 GArray *pnpParseDataArray = g_array_new (FALSE, FALSE, sizeof(PnpPartData));
247 gboolean foundValidDataRow = FALSE;
250 * many locales redefine "." as "," and so on, so sscanf has problems when
251 * reading Pick and Place files using %f format
253 setlocale(LC_NUMERIC, "C" );
255 while (1) {
256 /* Read out one row */
257 buf = gerb_fgetstring(fd, '\n');
258 if (buf == NULL) {
259 break;
262 /* Remove the \n too */
263 gerb_fgetc(fd);
265 len = strlen(buf);
266 i_length = 0, i_width = 0;
268 lineCounter += 1; /* next line */
269 if(lineCounter < 2) {
271 * TODO in principle column names could be read and interpreted
272 * but we skip the first line with names of columns for this time
274 g_free(buf);
275 continue;
277 if(len >= 0 && buf[len] == '\n') {
278 buf[len--] = 0;
280 if(len >= 0 && buf[len] == '\r') {
281 buf[len--] = 0;
283 if (len <= 11) { //lets check a minimum length of 11
284 continue;
287 if ((len > 0) && (buf[0] == '%')) {
288 continue;
291 /* Abort if we see a G54 */
292 if ((len > 4) && (strncmp(buf,"G54 ", 4) == 0)) {
293 g_array_free (pnpParseDataArray, TRUE);
294 g_free(buf);
295 return NULL;
298 /* abort if we see a G04 code */
299 if ((len > 4) && (strncmp(buf,"G04 ", 4) == 0)) {
300 g_array_free (pnpParseDataArray, TRUE);
301 g_free(buf);
302 return NULL;
305 /* this accepts file both with and without quotes */
306 /* if (!pnp_state) { /\* we are in first line *\/ */
307 /* if ((delimiter = pnp_screen_for_delimiter(buf, 8)) < 0) { */
308 /* continue; */
309 /* } */
310 /* } */
312 ret = csv_row_parse(buf, MAXL, buf0, MAXL, row, 11, ',', CSV_QUOTES);
314 if (ret > 0) {
315 foundValidDataRow = TRUE;
316 } else {
317 g_free(buf);
318 continue;
320 /* 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); */
321 /* g_warning ("FFF %s %s\n",row[8],row[6]); */
323 if (row[0] && row[8]) { // here could be some better check for the syntax
324 snprintf (pnpPartData.designator, sizeof(pnpPartData.designator)-1, "%s", row[0]);
325 snprintf (pnpPartData.footprint, sizeof(pnpPartData.footprint)-1, "%s", row[1]);
326 snprintf (pnpPartData.layer, sizeof(pnpPartData.layer)-1, "%s", row[8]);
327 if (row[10] != NULL) {
328 if ( ! g_utf8_validate(row[10], -1, NULL)) {
329 gchar * str = g_convert(row[10], strlen(row[10]), "UTF-8", "ISO-8859-1",
330 NULL, NULL, NULL);
331 // I have not decided yet whether it is better to use always
332 // "ISO-8859-1" or current locale.
333 // str = g_locale_to_utf8(row[10], -1, NULL, NULL, NULL);
334 snprintf (pnpPartData.comment, sizeof(pnpPartData.comment)-1, "%s", str);
335 g_free(str);
336 } else {
337 snprintf (pnpPartData.comment, sizeof(pnpPartData.comment)-1, "%s", row[10]);
341 gchar* g_convert(const gchar *str, gssize len, const gchar *to_codeset, const gchar *from_codeset, gsize *bytes_read, gsize *bytes_written, GError **error);
343 pnpPartData.mid_x = pick_and_place_get_float_unit(row[2]);
344 pnpPartData.mid_y = pick_and_place_get_float_unit(row[3]);
345 pnpPartData.ref_x = pick_and_place_get_float_unit(row[4]);
346 pnpPartData.ref_y = pick_and_place_get_float_unit(row[5]);
347 pnpPartData.pad_x = pick_and_place_get_float_unit(row[6]);
348 pnpPartData.pad_y = pick_and_place_get_float_unit(row[7]);
349 /* This line causes segfault if we accidently starts parsing
350 * a gerber file. It is crap crap crap */
351 if (row[9])
352 sscanf(row[9], "%lf", &pnpPartData.rotation); // no units, always deg
354 /* for now, default back to PCB program format
355 * TODO: implement better checking for format
357 else if (row[0] && row[1] && row[2] && row[3] && row[4] && row[5] && row[6]) {
358 snprintf (pnpPartData.designator, sizeof(pnpPartData.designator)-1, "%s", row[0]);
359 snprintf (pnpPartData.footprint, sizeof(pnpPartData.footprint)-1, "%s", row[1]);
360 snprintf (pnpPartData.layer, sizeof(pnpPartData.layer)-1, "%s", row[6]);
361 pnpPartData.mid_x = pick_and_place_get_float_unit(row[3]);
362 pnpPartData.mid_y = pick_and_place_get_float_unit(row[4]);
363 pnpPartData.pad_x = pnpPartData.mid_x + 0.03;
364 pnpPartData.pad_y = pnpPartData.mid_y + 0.03;
365 sscanf(row[5], "%lf", &pnpPartData.rotation); // no units, always deg
366 /* check for coordinate sanity, and abort if it fails
367 * Note: this is mainly to catch comment lines that get parsed
369 if ((fabs(pnpPartData.mid_x) < 0.001)&&(fabs(pnpPartData.mid_y) < 0.001)) {
370 g_free(buf);
371 continue;
373 } else {
374 g_free(buf);
375 continue;
380 * now, try and figure out the actual footprint shape to draw, or just
381 * guess something reasonable
383 if(sscanf(pnpPartData.footprint, "%02d%02d", &i_length, &i_width) == 2) {
384 // parse footprints like 0805 or 1206
385 pnpPartData.length = 0.01 * i_length;
386 pnpPartData.width = 0.01 * i_width;
387 pnpPartData.shape = PART_SHAPE_RECTANGLE;
388 } else {
389 gerb_transf_reset(tr_rot);
390 gerb_transf_rotate(tr_rot, -pnpPartData.rotation * M_PI/180);/* rotate it back to get dimensions */
391 gerb_transf_apply( pnpPartData.pad_x - pnpPartData.mid_x,
392 pnpPartData.pad_y - pnpPartData.mid_y, tr_rot, &tmp_x, &tmp_y);
393 if ((fabs(tmp_y) > fabs(tmp_x/100)) && (fabs(tmp_x) > fabs(tmp_y/100))){
394 pnpPartData.length = 2 * fabs(tmp_x);/* get dimensions*/
395 pnpPartData.width = 2 * fabs(tmp_y);
396 pnpPartData.shape = PART_SHAPE_STD;
397 } else {
398 pnpPartData.length = 0.015;
399 pnpPartData.width = 0.015;
400 pnpPartData.shape = PART_SHAPE_UNKNOWN;
403 g_array_append_val (pnpParseDataArray, pnpPartData);
404 parsedLines += 1;
406 g_free(buf);
407 gerb_transf_free(tr_rot);
409 /* so a sanity check and see if this is a valid pnp file */
410 if ((((float) parsedLines / (float) lineCounter) < 0.3) ||
411 (!foundValidDataRow)) {
412 /* this doesn't look like a valid PNP file, so return error */
413 g_array_free (pnpParseDataArray, TRUE);
414 return NULL;
416 return pnpParseDataArray;
417 } /* pick_and_place_parse_file */
420 /* ------------------------------------------------------------------
421 * pick_and_place_check_file_type
422 * ------------------------------------------------------------------
423 * Description: Tries to parse the given file into a pick-and-place
424 * data set. If it fails to read any good rows, then returns
425 * FALSE, otherwise it returns TRUE.
426 * Notes:
427 * ------------------------------------------------------------------
429 gboolean
430 pick_and_place_check_file_type(gerb_file_t *fd, gboolean *returnFoundBinary)
432 char *buf;
433 int len = 0;
434 int idx = 0;
435 int i;
436 char *letter;
437 gboolean found_binary = FALSE;
438 gboolean found_G54 = FALSE;
439 gboolean found_M0 = FALSE;
440 gboolean found_M2 = FALSE;
441 gboolean found_G2 = FALSE;
442 gboolean found_ADD = FALSE;
443 gboolean found_comma = FALSE;
444 gboolean found_R = FALSE;
445 gboolean found_U = FALSE;
446 gboolean found_C = FALSE;
447 gboolean found_boardside = FALSE;
449 dprintf ("pick_and_place_check_file_type(%p, %p), fd->fd = %p, fd->zfd = %p %s\n",
450 fd, returnFoundBinary, fd->fd, fd->zfd, fd->filename);
452 buf = malloc(MAXL);
453 if (buf == NULL) {
454 GERB_FATAL_ERROR("malloc buf failed while checking for pick-place file.\n");
457 while (1) {
458 if (fd->datalen == idx) {
459 break;
462 len = ((fd->datalen - idx) < MAXL)? (fd->datalen - idx) : MAXL;
463 memset(buf, 0, MAXL);
464 memcpy(buf, &fd->data[idx], len);
465 idx += len;
466 dprintf ("buf = \"%s\"\n", buf);
468 /* First look through the file for indications of its type */
470 /* check for non-binary file */
471 for (i = 0; i < len; i++) {
472 if (!isprint((int) buf[i]) && (buf[i] != '\r') &&
473 (buf[i] != '\n') && (buf[i] != '\t')) {
474 found_binary = TRUE;
478 if (g_strstr_len(buf, len, "G54")) {
479 found_G54 = TRUE;
481 if (g_strstr_len(buf, len, "M00")) {
482 found_M0 = TRUE;
484 if (g_strstr_len(buf, len, "M02")) {
485 found_M2 = TRUE;
487 if (g_strstr_len(buf, len, "G02")) {
488 found_G2 = TRUE;
490 if (g_strstr_len(buf, len, "ADD")) {
491 found_ADD = TRUE;
493 if (g_strstr_len(buf, len, ",")) {
494 found_comma = TRUE;
496 /* Semicolon can be separator too */
497 if (g_strstr_len(buf, len, ";")) {
498 found_comma = TRUE;
501 /* Look for refdes -- This is dumb, but what else can we do? */
502 if ((letter = g_strstr_len(buf, len, "R")) != NULL) {
503 if (isdigit((int) letter[1])) { /* grab char after R */
504 found_R = TRUE;
507 if ((letter = g_strstr_len(buf, len, "C")) != NULL) {
508 if (isdigit((int) letter[1])) { /* grab char after C */
509 found_C = TRUE;
512 if ((letter = g_strstr_len(buf, len, "U")) != NULL) {
513 if (isdigit((int) letter[1])) { /* grab char after U */
514 found_U = TRUE;
518 /* Look for board side indicator since this is required
519 * by many vendors */
520 if (g_strstr_len(buf, len, "top")) {
521 found_boardside = TRUE;
523 if (g_strstr_len(buf, len, "Top")) {
524 found_boardside = TRUE;
526 if (g_strstr_len(buf, len, "TOP")) {
527 found_boardside = TRUE;
529 /* Also look for evidence of "Layer" in header.... */
530 if (g_strstr_len(buf, len, "ayer")) {
531 found_boardside = TRUE;
533 if (g_strstr_len(buf, len, "AYER")) {
534 found_boardside = TRUE;
538 free(buf);
540 /* Now form logical expression determining if this is a pick-place file */
541 *returnFoundBinary = found_binary;
542 if (found_G54)
543 return FALSE;
544 if (found_M0)
545 return FALSE;
546 if (found_M2)
547 return FALSE;
548 if (found_G2)
549 return FALSE;
550 if (found_ADD)
551 return FALSE;
552 if (found_comma && (found_R || found_C || found_U) &&
553 found_boardside)
554 return TRUE;
556 return FALSE;
558 } /* pick_and_place_check_file_type */
561 /* ------------------------------------------------------------------
562 * pick_and_place_convert_pnp_data_to_image
563 * ------------------------------------------------------------------
564 * Description: Render a parsedPickAndPlaceData array into a gerb_image.
565 * Notes:
566 * ------------------------------------------------------------------
568 gerbv_image_t *
569 pick_and_place_convert_pnp_data_to_image(GArray *parsedPickAndPlaceData, gint boardSide)
571 gerbv_image_t *image = NULL;
572 gerbv_net_t *curr_net = NULL;
573 int i;
574 gerbv_transf_t *tr_rot = gerb_transf_new();
575 gerbv_drill_stats_t *stats; /* Eventually replace with pick_place_stats */
576 gboolean foundElement = FALSE;
578 if (parsedPickAndPlaceData == NULL) {
579 return NULL;
582 /* step through and make sure we have an element on the layer before
583 we actually create a new image for it and fill it */
584 for (i = 0; i < parsedPickAndPlaceData->len; i++) {
585 PnpPartData partData = g_array_index(parsedPickAndPlaceData, PnpPartData, i);
587 if ((boardSide == 0) && !((partData.layer[0]=='b') || (partData.layer[0]=='B')))
588 continue;
589 if ((boardSide == 1) && !((partData.layer[0]=='t') || (partData.layer[0]=='T')))
590 continue;
592 foundElement = TRUE;
594 if (!foundElement)
595 return NULL;
597 image = gerbv_create_image(image, "Pick and Place (X-Y) File");
598 if (image == NULL) {
599 GERB_FATAL_ERROR("malloc image failed\n");
602 image->format = (gerbv_format_t *)g_malloc(sizeof(gerbv_format_t));
603 if (image->format == NULL) {
604 GERB_FATAL_ERROR("malloc format failed\n");
606 memset((void *)image->format, 0, sizeof(gerbv_format_t));
608 image->layertype = GERBV_LAYERTYPE_PICKANDPLACE;
609 stats = gerbv_drill_stats_new();
610 if (stats == NULL)
611 GERB_FATAL_ERROR("malloc pick_place_stats failed\n");
612 image->drill_stats = stats;
615 curr_net = image->netlist;
616 curr_net->layer = image->layers;
617 curr_net->state = image->states;
618 pick_and_place_reset_bounding_box (curr_net);
619 image->info->min_x = HUGE_VAL;
620 image->info->min_y = HUGE_VAL;
621 image->info->max_x = -HUGE_VAL;
622 image->info->max_y = -HUGE_VAL;
624 image->aperture[0] = (gerbv_aperture_t *)g_malloc(sizeof(gerbv_aperture_t));
625 memset((void *) image->aperture[0], 0, sizeof(gerbv_aperture_t));
626 image->aperture[0]->type = GERBV_APTYPE_CIRCLE;
627 image->aperture[0]->amacro = NULL;
628 image->aperture[0]->parameter[0] = 0.01;
629 image->aperture[0]->nuf_parameters = 1;
631 for (i = 0; i < parsedPickAndPlaceData->len; i++) {
632 PnpPartData partData = g_array_index(parsedPickAndPlaceData, PnpPartData, i);
633 float radius,labelOffset;
635 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
636 curr_net = curr_net->next;
638 assert(curr_net);
639 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
640 curr_net->layer = image->layers;
641 curr_net->state = image->states;
642 if ((partData.rotation > 89) && (partData.rotation < 91))
643 labelOffset = fabs(partData.length/2);
644 else if ((partData.rotation > 179) && (partData.rotation < 181))
645 labelOffset = fabs(partData.width/2);
646 else if ((partData.rotation > 269) && (partData.rotation < 271))
647 labelOffset = fabs(partData.length/2);
648 else if ((partData.rotation > -91) && (partData.rotation < -89))
649 labelOffset = fabs(partData.length/2);
650 else if ((partData.rotation > -181) && (partData.rotation < -179))
651 labelOffset = fabs(partData.width/2);
652 else if ((partData.rotation > -271) && (partData.rotation < -269))
653 labelOffset = fabs(partData.length/2);
654 else labelOffset = fabs(partData.width/2);
656 partData.rotation *= M_PI/180; /* convert deg to rad */
657 /* check if the entry is on the specified layer */
658 if ((boardSide == 0) && !((partData.layer[0]=='b') || (partData.layer[0]=='B')))
659 continue;
660 if ((boardSide == 1) && !((partData.layer[0]=='t') || (partData.layer[0]=='T')))
661 continue;
663 /* this first net is just a label holder, so calculate the lower
664 left location to line up above the element */
666 curr_net->start_x = curr_net->stop_x = partData.mid_x;
667 curr_net->start_y = curr_net->stop_y = partData.mid_y + labelOffset + 0.01;
668 curr_net->aperture = 0;
669 curr_net->aperture_state = GERBV_APERTURE_STATE_OFF;
670 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
671 curr_net->layer = image->layers;
672 curr_net->state = image->states;
673 pick_and_place_reset_bounding_box (curr_net);
675 /* assign a label to this first draw primitive, in case we want
676 * to render some text next to the mark
678 if (strlen (partData.designator) > 0) {
679 curr_net->label = g_string_new (partData.designator);
682 gerb_transf_reset(tr_rot);
683 gerb_transf_shift(tr_rot, partData.mid_x, partData.mid_y);
684 gerb_transf_rotate(tr_rot, -partData.rotation);
686 if ((partData.shape == PART_SHAPE_RECTANGLE) ||
687 (partData.shape == PART_SHAPE_STD)) {
688 // TODO: draw rectangle length x width taking into account rotation or pad x,y
692 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
693 curr_net = curr_net->next;
694 assert(curr_net);
695 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
696 gerb_transf_apply(partData.length/2, partData.width/2, tr_rot,
697 &curr_net->start_x, &curr_net->start_y);
698 gerb_transf_apply(-partData.length/2, partData.width/2, tr_rot,
699 &curr_net->stop_x, &curr_net->stop_y);
701 curr_net->aperture = 0;
702 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
703 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
704 curr_net->layer = image->layers;
705 curr_net->state = image->states;
706 pick_and_place_reset_bounding_box (curr_net);
708 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
709 curr_net = curr_net->next;
710 assert(curr_net);
711 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
713 gerb_transf_apply(-partData.length/2, partData.width/2, tr_rot,
714 &curr_net->start_x, &curr_net->start_y);
715 gerb_transf_apply(-partData.length/2, -partData.width/2, tr_rot,
716 &curr_net->stop_x, &curr_net->stop_y);
718 curr_net->aperture = 0;
719 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
720 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
721 curr_net->layer = image->layers;
722 curr_net->state = image->states;
723 pick_and_place_reset_bounding_box (curr_net);
725 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
726 curr_net = curr_net->next;
727 assert(curr_net);
728 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
730 gerb_transf_apply(-partData.length/2, -partData.width/2, tr_rot,
731 &curr_net->start_x, &curr_net->start_y);
732 gerb_transf_apply(partData.length/2, -partData.width/2, tr_rot,
733 &curr_net->stop_x, &curr_net->stop_y);
735 curr_net->aperture = 0;
736 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
737 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
738 curr_net->layer = image->layers;
739 curr_net->state = image->states;
740 pick_and_place_reset_bounding_box (curr_net);
742 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
743 curr_net = curr_net->next;
744 assert(curr_net);
745 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
747 gerb_transf_apply(partData.length/2, -partData.width/2, tr_rot,
748 &curr_net->start_x, &curr_net->start_y);
749 gerb_transf_apply(partData.length/2, partData.width/2, tr_rot,
750 &curr_net->stop_x, &curr_net->stop_y);
752 curr_net->aperture = 0;
753 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
754 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
755 curr_net->layer = image->layers;
756 curr_net->state = image->states;
757 pick_and_place_reset_bounding_box (curr_net);
759 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
760 curr_net = curr_net->next;
761 assert(curr_net);
762 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
764 if (partData.shape == PART_SHAPE_RECTANGLE) {
765 gerb_transf_apply(partData.length/4, -partData.width/2, tr_rot,
766 &curr_net->start_x, &curr_net->start_y);
767 gerb_transf_apply(partData.length/4, partData.width/2, tr_rot,
768 &curr_net->stop_x, &curr_net->stop_y);
769 } else {
770 gerb_transf_apply(partData.length/4, partData.width/2, tr_rot,
771 &curr_net->start_x, &curr_net->start_y);
772 gerb_transf_apply(partData.length/4, partData.width/4, tr_rot,
773 &curr_net->stop_x, &curr_net->stop_y);
775 curr_net->aperture = 0;
776 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
777 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
778 curr_net->layer = image->layers;
779 curr_net->state = image->states;
780 pick_and_place_reset_bounding_box (curr_net);
782 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
783 curr_net = curr_net->next;
784 assert(curr_net);
785 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
786 gerb_transf_apply(partData.length/2, partData.width/4, tr_rot,
787 &curr_net->start_x, &curr_net->start_y);
788 gerb_transf_apply(partData.length/4, partData.width/4, tr_rot,
789 &curr_net->stop_x, &curr_net->stop_y);
791 curr_net->aperture = 0;
792 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
793 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
794 curr_net->layer = image->layers;
795 curr_net->state = image->states;
796 pick_and_place_reset_bounding_box (curr_net);
798 /* calculate a rough radius for the min/max screen calcs later */
799 radius = max (partData.length/2, partData.width/2);
800 } else {
801 gdouble tmp_x,tmp_y;
803 curr_net->start_x = partData.mid_x;
804 curr_net->start_y = partData.mid_y;
805 gerb_transf_apply( partData.pad_x - partData.mid_x,
806 partData.pad_y - partData.mid_y, tr_rot, &tmp_x, &tmp_y);
808 curr_net->stop_x = tmp_x;
809 curr_net->stop_y = tmp_y;
811 curr_net->aperture = 0;
812 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
813 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
814 curr_net->layer = image->layers;
815 curr_net->state = image->states;
817 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
818 curr_net = curr_net->next;
819 assert(curr_net);
820 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
822 curr_net->start_x = partData.mid_x;
823 curr_net->start_y = partData.mid_y;
824 curr_net->stop_x = partData.pad_x;
825 curr_net->stop_y = partData.pad_y;
827 curr_net->aperture = 0;
828 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
829 curr_net->interpolation = GERBV_INTERPOLATION_CW_CIRCULAR;
830 curr_net->layer = image->layers;
831 curr_net->state = image->states;
832 pick_and_place_reset_bounding_box (curr_net);
834 curr_net->cirseg = g_new0 (gerbv_cirseg_t,1);
835 curr_net->cirseg->angle1 = 0.0;
836 curr_net->cirseg->angle2 = 360.0;
837 curr_net->cirseg->cp_x = partData.mid_x;
838 curr_net->cirseg->cp_y = partData.mid_y;
839 radius = sqrt((partData.pad_x-partData.mid_x)*(partData.pad_x-partData.mid_x) +
840 (partData.pad_y-partData.mid_y)*(partData.pad_y-partData.mid_y));
841 if (radius < 0.001)
842 radius = 0.1;
843 curr_net->cirseg->width = 2*radius; /* fabs(pad_x-mid_x) */
844 curr_net->cirseg->height = 2*radius;
848 * update min and max numbers so the screen zoom-to-fit
849 *function will work
851 image->info->min_x = min(image->info->min_x, (partData.mid_x - radius - 0.02));
852 image->info->min_y = min(image->info->min_y, (partData.mid_y - radius - 0.02));
853 image->info->max_x = max(image->info->max_x, (partData.mid_x + radius + 0.02));
854 image->info->max_y = max(image->info->max_y, (partData.mid_y + radius + 0.02));
856 curr_net->next = NULL;
858 gerb_transf_free(tr_rot);
859 return image;
860 } /* pick_and_place_parse_file_to_image */
863 /* ------------------------------------------------------------------
864 * pick_and_place_parse_file_to_image
865 * ------------------------------------------------------------------
866 * Description: Renders a pick and place file to a gerb_image.
867 * Notes: The file format should already be verified before calling
868 * this function, since it does very little sanity checking itself.
869 * ------------------------------------------------------------------
871 void
872 pick_and_place_parse_file_to_images(gerb_file_t *fd, gerbv_image_t **topImage,
873 gerbv_image_t **bottomImage)
875 GArray *parsedPickAndPlaceData = pick_and_place_parse_file (fd);
877 *bottomImage = pick_and_place_convert_pnp_data_to_image(parsedPickAndPlaceData, 0);
878 *topImage = pick_and_place_convert_pnp_data_to_image(parsedPickAndPlaceData, 1);
880 g_array_free (parsedPickAndPlaceData, TRUE);
881 } /* pick_and_place_parse_file_to_image */