* rework export svg/pdf/ps functionality to export images with 1:1 scale. Previously...
[geda-gerbv.git] / src / pick-and-place.c
blob205cad103d7e76a8001881fbf87dbc8d6b423096
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 ret;
240 char *row[12];
241 char buf[MAXL+2], buf0[MAXL+2];
242 double tmp_x, tmp_y;
243 gerbv_transf_t *tr_rot = gerb_transf_new();
244 GArray *pnpParseDataArray = g_array_new (FALSE, FALSE, sizeof(PnpPartData));
245 gboolean foundValidDataRow = FALSE;
248 * many locales redefine "." as "," and so on, so sscanf has problems when
249 * reading Pick and Place files using %f format
251 setlocale(LC_NUMERIC, "C" );
253 while ( fgets(buf, MAXL, fd->fd) != NULL ) {
254 int len = strlen(buf)-1;
255 int i_length = 0, i_width = 0;
257 lineCounter += 1; /*next line*/
258 if(lineCounter < 2) {
260 * TODO in principle column names could be read and interpreted
261 * but we skip the first line with names of columns for this time
263 continue;
265 if(len >= 0 && buf[len] == '\n') {
266 buf[len--] = 0;
268 if(len >= 0 && buf[len] == '\r') {
269 buf[len--] = 0;
271 if (len <= 11) { //lets check a minimum length of 11
272 continue;
275 if ((len > 0) && (buf[0] == '%')) {
276 continue;
279 /* Abort if we see a G54 */
280 if ((len > 4) && (strncmp(buf,"G54 ", 4) == 0)) {
281 g_array_free (pnpParseDataArray, TRUE);
282 return NULL;
285 /* abort if we see a G04 code */
286 if ((len > 4) && (strncmp(buf,"G04 ", 4) == 0)) {
287 g_array_free (pnpParseDataArray, TRUE);
288 return NULL;
291 /* this accepts file both with and without quotes */
292 /* if (!pnp_state) { /\* we are in first line *\/ */
293 /* if ((delimiter = pnp_screen_for_delimiter(buf, 8)) < 0) { */
294 /* continue; */
295 /* } */
296 /* } */
298 ret = csv_row_parse(buf, MAXL, buf0, MAXL, row, 11, ',', CSV_QUOTES);
300 if (ret > 0) {
301 foundValidDataRow = TRUE;
302 } else {
303 continue;
305 /* 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); */
306 /* g_warning ("FFF %s %s\n",row[8],row[6]); */
308 if (row[0] && row[8]) { // here could be some better check for the syntax
309 snprintf (pnpPartData.designator, sizeof(pnpPartData.designator)-1, "%s", row[0]);
310 snprintf (pnpPartData.footprint, sizeof(pnpPartData.footprint)-1, "%s", row[1]);
311 snprintf (pnpPartData.layer, sizeof(pnpPartData.layer)-1, "%s", row[8]);
312 if (row[10] != NULL) {
313 if ( ! g_utf8_validate(row[10], -1, NULL)) {
314 gchar * str = g_convert(row[10], strlen(row[10]), "UTF-8", "ISO-8859-1",
315 NULL, NULL, NULL);
316 // I have not decided yet whether it is better to use always
317 // "ISO-8859-1" or current locale.
318 // str = g_locale_to_utf8(row[10], -1, NULL, NULL, NULL);
319 snprintf (pnpPartData.comment, sizeof(pnpPartData.comment)-1, "%s", str);
320 g_free(str);
321 } else {
322 snprintf (pnpPartData.comment, sizeof(pnpPartData.comment)-1, "%s", row[10]);
326 gchar* g_convert(const gchar *str, gssize len, const gchar *to_codeset, const gchar *from_codeset, gsize *bytes_read, gsize *bytes_written, GError **error);
328 pnpPartData.mid_x = pick_and_place_get_float_unit(row[2]);
329 pnpPartData.mid_y = pick_and_place_get_float_unit(row[3]);
330 pnpPartData.ref_x = pick_and_place_get_float_unit(row[4]);
331 pnpPartData.ref_y = pick_and_place_get_float_unit(row[5]);
332 pnpPartData.pad_x = pick_and_place_get_float_unit(row[6]);
333 pnpPartData.pad_y = pick_and_place_get_float_unit(row[7]);
334 /* This line causes segfault if we accidently starts parsing
335 * a gerber file. It is crap crap crap */
336 if (row[9])
337 sscanf(row[9], "%lf", &pnpPartData.rotation); // no units, always deg
339 /* for now, default back to PCB program format
340 * TODO: implement better checking for format
342 else if (row[0] && row[1] && row[2] && row[3] && row[4] && row[5] && row[6]) {
343 snprintf (pnpPartData.designator, sizeof(pnpPartData.designator)-1, "%s", row[0]);
344 snprintf (pnpPartData.footprint, sizeof(pnpPartData.footprint)-1, "%s", row[1]);
345 snprintf (pnpPartData.layer, sizeof(pnpPartData.layer)-1, "%s", row[6]);
346 pnpPartData.mid_x = pick_and_place_get_float_unit(row[3]);
347 pnpPartData.mid_y = pick_and_place_get_float_unit(row[4]);
348 pnpPartData.pad_x = pnpPartData.mid_x + 0.03;
349 pnpPartData.pad_y = pnpPartData.mid_y + 0.03;
350 sscanf(row[5], "%lf", &pnpPartData.rotation); // no units, always deg
351 /* check for coordinate sanity, and abort if it fails
352 * Note: this is mainly to catch comment lines that get parsed
354 if ((fabs(pnpPartData.mid_x) < 0.001)&&(fabs(pnpPartData.mid_y) < 0.001)) {
355 continue;
357 } else {
358 continue;
363 * now, try and figure out the actual footprint shape to draw, or just
364 * guess something reasonable
366 if(sscanf(pnpPartData.footprint, "%02d%02d", &i_length, &i_width) == 2) {
367 // parse footprints like 0805 or 1206
368 pnpPartData.length = 0.01 * i_length;
369 pnpPartData.width = 0.01 * i_width;
370 pnpPartData.shape = PART_SHAPE_RECTANGLE;
371 } else {
372 gerb_transf_reset(tr_rot);
373 gerb_transf_rotate(tr_rot, -pnpPartData.rotation * M_PI/180);/* rotate it back to get dimensions */
374 gerb_transf_apply( pnpPartData.pad_x - pnpPartData.mid_x,
375 pnpPartData.pad_y - pnpPartData.mid_y, tr_rot, &tmp_x, &tmp_y);
376 if ((fabs(tmp_y) > fabs(tmp_x/100)) && (fabs(tmp_x) > fabs(tmp_y/100))){
377 pnpPartData.length = 2 * fabs(tmp_x);/* get dimensions*/
378 pnpPartData.width = 2 * fabs(tmp_y);
379 pnpPartData.shape = PART_SHAPE_STD;
380 } else {
381 pnpPartData.length = 0.015;
382 pnpPartData.width = 0.015;
383 pnpPartData.shape = PART_SHAPE_UNKNOWN;
386 g_array_append_val (pnpParseDataArray, pnpPartData);
387 parsedLines += 1;
389 gerb_transf_free(tr_rot);
390 /* fd->ptr=0; */
391 /* rewind(fd->fd); */
393 /* so a sanity check and see if this is a valid pnp file */
394 if ((((float) parsedLines / (float) lineCounter) < 0.3) ||
395 (!foundValidDataRow)) {
396 /* this doesn't look like a valid PNP file, so return error */
397 g_array_free (pnpParseDataArray, TRUE);
398 return NULL;
400 return pnpParseDataArray;
401 } /* pick_and_place_parse_file */
404 /* ------------------------------------------------------------------
405 * pick_and_place_check_file_type
406 * ------------------------------------------------------------------
407 * Description: Tries to parse the given file into a pick-and-place
408 * data set. If it fails to read any good rows, then returns
409 * FALSE, otherwise it returns TRUE.
410 * Notes:
411 * ------------------------------------------------------------------
413 gboolean
414 pick_and_place_check_file_type(gerb_file_t *fd, gboolean *returnFoundBinary)
416 char *buf;
417 int len = 0;
418 int i;
419 char *letter;
420 gboolean found_binary = FALSE;
421 gboolean found_G54 = FALSE;
422 gboolean found_M0 = FALSE;
423 gboolean found_M2 = FALSE;
424 gboolean found_G2 = FALSE;
425 gboolean found_ADD = FALSE;
426 gboolean found_comma = FALSE;
427 gboolean found_R = FALSE;
428 gboolean found_U = FALSE;
429 gboolean found_C = FALSE;
430 gboolean found_boardside = FALSE;
432 buf = malloc(MAXL);
433 if (buf == NULL)
434 GERB_FATAL_ERROR("malloc buf failed while checking for pick-place file.\n");
436 while (fgets(buf, MAXL, fd->fd) != NULL) {
437 len = strlen(buf);
439 /* First look through the file for indications of its type */
441 /* check for non-binary file */
442 for (i = 0; i < len; i++) {
443 if (!isprint((int) buf[i]) && (buf[i] != '\r') &&
444 (buf[i] != '\n') && (buf[i] != '\t')) {
445 found_binary = TRUE;
449 if (g_strstr_len(buf, len, "G54")) {
450 found_G54 = TRUE;
452 if (g_strstr_len(buf, len, "M00")) {
453 found_M0 = TRUE;
455 if (g_strstr_len(buf, len, "M02")) {
456 found_M2 = TRUE;
458 if (g_strstr_len(buf, len, "G02")) {
459 found_G2 = TRUE;
461 if (g_strstr_len(buf, len, "ADD")) {
462 found_ADD = TRUE;
464 if (g_strstr_len(buf, len, ",")) {
465 found_comma = TRUE;
467 /* Semicolon can be separator too */
468 if (g_strstr_len(buf, len, ";")) {
469 found_comma = TRUE;
472 /* Look for refdes -- This is dumb, but what else can we do? */
473 if ((letter = g_strstr_len(buf, len, "R")) != NULL) {
474 if (isdigit((int) letter[1])) { /* grab char after R */
475 found_R = TRUE;
478 if ((letter = g_strstr_len(buf, len, "C")) != NULL) {
479 if (isdigit((int) letter[1])) { /* grab char after C */
480 found_C = TRUE;
483 if ((letter = g_strstr_len(buf, len, "U")) != NULL) {
484 if (isdigit((int) letter[1])) { /* grab char after U */
485 found_U = TRUE;
489 /* Look for board side indicator since this is required
490 * by many vendors */
491 if (g_strstr_len(buf, len, "top")) {
492 found_boardside = TRUE;
494 if (g_strstr_len(buf, len, "Top")) {
495 found_boardside = TRUE;
497 if (g_strstr_len(buf, len, "TOP")) {
498 found_boardside = TRUE;
500 /* Also look for evidence of "Layer" in header.... */
501 if (g_strstr_len(buf, len, "ayer")) {
502 found_boardside = TRUE;
504 if (g_strstr_len(buf, len, "AYER")) {
505 found_boardside = TRUE;
509 rewind(fd->fd);
510 free(buf);
512 /* Now form logical expression determining if this is a pick-place file */
513 *returnFoundBinary = found_binary;
514 if (found_G54)
515 return FALSE;
516 if (found_M0)
517 return FALSE;
518 if (found_M2)
519 return FALSE;
520 if (found_G2)
521 return FALSE;
522 if (found_ADD)
523 return FALSE;
524 if (found_comma && (found_R || found_C || found_U) &&
525 found_boardside)
526 return TRUE;
528 return FALSE;
530 } /* pick_and_place_check_file_type */
533 /* ------------------------------------------------------------------
534 * pick_and_place_convert_pnp_data_to_image
535 * ------------------------------------------------------------------
536 * Description: Render a parsedPickAndPlaceData array into a gerb_image.
537 * Notes:
538 * ------------------------------------------------------------------
540 gerbv_image_t *
541 pick_and_place_convert_pnp_data_to_image(GArray *parsedPickAndPlaceData, gint boardSide)
543 gerbv_image_t *image = NULL;
544 gerbv_net_t *curr_net = NULL;
545 int i;
546 gerbv_transf_t *tr_rot = gerb_transf_new();
547 gerbv_drill_stats_t *stats; /* Eventually replace with pick_place_stats */
548 gboolean foundElement = FALSE;
550 /* step through and make sure we have an element on the layer before
551 we actually create a new image for it and fill it */
552 for (i = 0; i < parsedPickAndPlaceData->len; i++) {
553 PnpPartData partData = g_array_index(parsedPickAndPlaceData, PnpPartData, i);
555 if ((boardSide == 0) && !((partData.layer[0]=='b') || (partData.layer[0]=='B')))
556 continue;
557 if ((boardSide == 1) && !((partData.layer[0]=='t') || (partData.layer[0]=='T')))
558 continue;
560 foundElement = TRUE;
562 if (!foundElement)
563 return NULL;
565 image = gerbv_create_image(image, "Pick and Place (X-Y) File");
566 if (image == NULL) {
567 GERB_FATAL_ERROR("malloc image failed\n");
570 image->format = (gerbv_format_t *)g_malloc(sizeof(gerbv_format_t));
571 if (image->format == NULL) {
572 GERB_FATAL_ERROR("malloc format failed\n");
574 memset((void *)image->format, 0, sizeof(gerbv_format_t));
576 image->layertype = GERBV_LAYERTYPE_PICKANDPLACE;
577 stats = gerbv_drill_stats_new();
578 if (stats == NULL)
579 GERB_FATAL_ERROR("malloc pick_place_stats failed\n");
580 image->drill_stats = stats;
583 curr_net = image->netlist;
584 curr_net->layer = image->layers;
585 curr_net->state = image->states;
586 pick_and_place_reset_bounding_box (curr_net);
587 image->info->min_x = HUGE_VAL;
588 image->info->min_y = HUGE_VAL;
589 image->info->max_x = -HUGE_VAL;
590 image->info->max_y = -HUGE_VAL;
592 image->aperture[0] = (gerbv_aperture_t *)g_malloc(sizeof(gerbv_aperture_t));
593 memset((void *) image->aperture[0], 0, sizeof(gerbv_aperture_t));
594 image->aperture[0]->type = GERBV_APTYPE_CIRCLE;
595 image->aperture[0]->amacro = NULL;
596 image->aperture[0]->parameter[0] = 0.01;
597 image->aperture[0]->nuf_parameters = 1;
599 for (i = 0; i < parsedPickAndPlaceData->len; i++) {
600 PnpPartData partData = g_array_index(parsedPickAndPlaceData, PnpPartData, i);
601 float radius,labelOffset;
603 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
604 curr_net = curr_net->next;
606 assert(curr_net);
607 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
608 curr_net->layer = image->layers;
609 curr_net->state = image->states;
610 if ((partData.rotation > 89) && (partData.rotation < 91))
611 labelOffset = fabs(partData.length/2);
612 else if ((partData.rotation > 179) && (partData.rotation < 181))
613 labelOffset = fabs(partData.width/2);
614 else if ((partData.rotation > 269) && (partData.rotation < 271))
615 labelOffset = fabs(partData.length/2);
616 else if ((partData.rotation > -91) && (partData.rotation < -89))
617 labelOffset = fabs(partData.length/2);
618 else if ((partData.rotation > -181) && (partData.rotation < -179))
619 labelOffset = fabs(partData.width/2);
620 else if ((partData.rotation > -271) && (partData.rotation < -269))
621 labelOffset = fabs(partData.length/2);
622 else labelOffset = fabs(partData.width/2);
624 partData.rotation *= M_PI/180; /* convert deg to rad */
625 /* check if the entry is on the specified layer */
626 if ((boardSide == 0) && !((partData.layer[0]=='b') || (partData.layer[0]=='B')))
627 continue;
628 if ((boardSide == 1) && !((partData.layer[0]=='t') || (partData.layer[0]=='T')))
629 continue;
631 /* this first net is just a label holder, so calculate the lower
632 left location to line up above the element */
634 curr_net->start_x = curr_net->stop_x = partData.mid_x;
635 curr_net->start_y = curr_net->stop_y = partData.mid_y + labelOffset + 0.01;
636 curr_net->aperture = 0;
637 curr_net->aperture_state = GERBV_APERTURE_STATE_OFF;
638 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
639 curr_net->layer = image->layers;
640 curr_net->state = image->states;
641 pick_and_place_reset_bounding_box (curr_net);
643 /* assign a label to this first draw primitive, in case we want
644 * to render some text next to the mark
646 if (strlen (partData.designator) > 0) {
647 curr_net->label = g_string_new (partData.designator);
650 gerb_transf_reset(tr_rot);
651 gerb_transf_shift(tr_rot, partData.mid_x, partData.mid_y);
652 gerb_transf_rotate(tr_rot, -partData.rotation);
654 if ((partData.shape == PART_SHAPE_RECTANGLE) ||
655 (partData.shape == PART_SHAPE_STD)) {
656 // TODO: draw rectangle length x width taking into account rotation or pad x,y
660 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
661 curr_net = curr_net->next;
662 assert(curr_net);
663 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
664 gerb_transf_apply(partData.length/2, partData.width/2, tr_rot,
665 &curr_net->start_x, &curr_net->start_y);
666 gerb_transf_apply(-partData.length/2, partData.width/2, tr_rot,
667 &curr_net->stop_x, &curr_net->stop_y);
669 curr_net->aperture = 0;
670 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
671 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
672 curr_net->layer = image->layers;
673 curr_net->state = image->states;
674 pick_and_place_reset_bounding_box (curr_net);
676 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
677 curr_net = curr_net->next;
678 assert(curr_net);
679 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
681 gerb_transf_apply(-partData.length/2, partData.width/2, tr_rot,
682 &curr_net->start_x, &curr_net->start_y);
683 gerb_transf_apply(-partData.length/2, -partData.width/2, tr_rot,
684 &curr_net->stop_x, &curr_net->stop_y);
686 curr_net->aperture = 0;
687 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
688 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
689 curr_net->layer = image->layers;
690 curr_net->state = image->states;
691 pick_and_place_reset_bounding_box (curr_net);
693 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
694 curr_net = curr_net->next;
695 assert(curr_net);
696 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
698 gerb_transf_apply(-partData.length/2, -partData.width/2, tr_rot,
699 &curr_net->start_x, &curr_net->start_y);
700 gerb_transf_apply(partData.length/2, -partData.width/2, tr_rot,
701 &curr_net->stop_x, &curr_net->stop_y);
703 curr_net->aperture = 0;
704 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
705 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
706 curr_net->layer = image->layers;
707 curr_net->state = image->states;
708 pick_and_place_reset_bounding_box (curr_net);
710 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
711 curr_net = curr_net->next;
712 assert(curr_net);
713 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
715 gerb_transf_apply(partData.length/2, -partData.width/2, tr_rot,
716 &curr_net->start_x, &curr_net->start_y);
717 gerb_transf_apply(partData.length/2, partData.width/2, tr_rot,
718 &curr_net->stop_x, &curr_net->stop_y);
720 curr_net->aperture = 0;
721 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
722 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
723 curr_net->layer = image->layers;
724 curr_net->state = image->states;
725 pick_and_place_reset_bounding_box (curr_net);
727 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
728 curr_net = curr_net->next;
729 assert(curr_net);
730 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
732 if (partData.shape == PART_SHAPE_RECTANGLE) {
733 gerb_transf_apply(partData.length/4, -partData.width/2, tr_rot,
734 &curr_net->start_x, &curr_net->start_y);
735 gerb_transf_apply(partData.length/4, partData.width/2, tr_rot,
736 &curr_net->stop_x, &curr_net->stop_y);
737 } else {
738 gerb_transf_apply(partData.length/4, partData.width/2, tr_rot,
739 &curr_net->start_x, &curr_net->start_y);
740 gerb_transf_apply(partData.length/4, partData.width/4, tr_rot,
741 &curr_net->stop_x, &curr_net->stop_y);
743 curr_net->aperture = 0;
744 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
745 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
746 curr_net->layer = image->layers;
747 curr_net->state = image->states;
748 pick_and_place_reset_bounding_box (curr_net);
750 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
751 curr_net = curr_net->next;
752 assert(curr_net);
753 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
754 gerb_transf_apply(partData.length/2, partData.width/4, tr_rot,
755 &curr_net->start_x, &curr_net->start_y);
756 gerb_transf_apply(partData.length/4, partData.width/4, tr_rot,
757 &curr_net->stop_x, &curr_net->stop_y);
759 curr_net->aperture = 0;
760 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
761 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
762 curr_net->layer = image->layers;
763 curr_net->state = image->states;
764 pick_and_place_reset_bounding_box (curr_net);
766 /* calculate a rough radius for the min/max screen calcs later */
767 radius = max (partData.length/2, partData.width/2);
768 } else {
769 gdouble tmp_x,tmp_y;
771 curr_net->start_x = partData.mid_x;
772 curr_net->start_y = partData.mid_y;
773 gerb_transf_apply( partData.pad_x - partData.mid_x,
774 partData.pad_y - partData.mid_y, tr_rot, &tmp_x, &tmp_y);
776 curr_net->stop_x = tmp_x;
777 curr_net->stop_y = tmp_y;
779 curr_net->aperture = 0;
780 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
781 curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
782 curr_net->layer = image->layers;
783 curr_net->state = image->states;
785 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
786 curr_net = curr_net->next;
787 assert(curr_net);
788 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
790 curr_net->start_x = partData.mid_x;
791 curr_net->start_y = partData.mid_y;
792 curr_net->stop_x = partData.pad_x;
793 curr_net->stop_y = partData.pad_y;
795 curr_net->aperture = 0;
796 curr_net->aperture_state = GERBV_APERTURE_STATE_ON;
797 curr_net->interpolation = GERBV_INTERPOLATION_CW_CIRCULAR;
798 curr_net->layer = image->layers;
799 curr_net->state = image->states;
800 pick_and_place_reset_bounding_box (curr_net);
802 curr_net->cirseg = g_new0 (gerbv_cirseg_t,1);
803 curr_net->cirseg->angle1 = 0.0;
804 curr_net->cirseg->angle2 = 360.0;
805 curr_net->cirseg->cp_x = partData.mid_x;
806 curr_net->cirseg->cp_y = partData.mid_y;
807 radius = sqrt((partData.pad_x-partData.mid_x)*(partData.pad_x-partData.mid_x) +
808 (partData.pad_y-partData.mid_y)*(partData.pad_y-partData.mid_y));
809 if (radius < 0.001)
810 radius = 0.1;
811 curr_net->cirseg->width = 2*radius; /* fabs(pad_x-mid_x) */
812 curr_net->cirseg->height = 2*radius;
816 * update min and max numbers so the screen zoom-to-fit
817 *function will work
819 image->info->min_x = min(image->info->min_x, (partData.mid_x - radius - 0.02));
820 image->info->min_y = min(image->info->min_y, (partData.mid_y - radius - 0.02));
821 image->info->max_x = max(image->info->max_x, (partData.mid_x + radius + 0.02));
822 image->info->max_y = max(image->info->max_y, (partData.mid_y + radius + 0.02));
824 curr_net->next = NULL;
826 gerb_transf_free(tr_rot);
827 return image;
828 } /* pick_and_place_parse_file_to_image */
831 /* ------------------------------------------------------------------
832 * pick_and_place_parse_file_to_image
833 * ------------------------------------------------------------------
834 * Description: Renders a pick and place file to a gerb_image.
835 * Notes: The file format should already be verified before calling
836 * this function, since it does very little sanity checking itself.
837 * ------------------------------------------------------------------
839 void
840 pick_and_place_parse_file_to_images(gerb_file_t *fd, gerbv_image_t **topImage,
841 gerbv_image_t **bottomImage)
843 GArray *parsedPickAndPlaceData = pick_and_place_parse_file (fd);
845 *bottomImage = pick_and_place_convert_pnp_data_to_image(parsedPickAndPlaceData, 0);
846 *topImage = pick_and_place_convert_pnp_data_to_image(parsedPickAndPlaceData, 1);
848 g_array_free (parsedPickAndPlaceData, TRUE);
849 } /* pick_and_place_parse_file_to_image */