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
29 #endif /* HAVE_CONFIG_H */
38 #include <gtk/gtk.h> /* What's this for? */
46 #endif /* HAVE_UNISTD_H */
53 #endif /* HAVE_GETOPT_H */
59 #ifdef RENDER_USING_GDK
66 #include "pick-and-place.h"
68 /* CHECKME - here gi18n is disabled */
69 #define _(String) (String)
72 #define max(a,b) ((a) > (b) ? (a) : (b))
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
)
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;
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
);
107 } /*gerb_transf_new*/
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
)
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*/
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*/
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
166 pick_and_place_get_float_unit(char *str
)
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")) {
177 } else { /* default to mils */
182 } /* pick_and_place_get_float_unit*/
185 /** search a string for a delimiter.
186 Must occur at least n times. */
188 pick_and_place_screen_for_delimiter(char *str
, int n
)
191 char delimiter
[4] = "|,;:";
193 int idx
, idx_max
= 0;
195 memset(counter
, 0, sizeof(counter
));
196 for(ptr
= str
; *ptr
; ptr
++) {
215 if(counter
[idx
] > counter
[idx_max
]) {
220 if (counter
[idx_max
] > n
) {
221 return (unsigned char) delimiter
[idx_max
];
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
235 pick_and_place_parse_file(gerb_file_t
*fd
)
237 PnpPartData pnpPartData
;
238 int lineCounter
= 0, parsedLines
= 0;
241 char buf
[MAXL
+2], buf0
[MAXL
+2];
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
265 if(len
>= 0 && buf
[len
] == '\n') {
268 if(len
>= 0 && buf
[len
] == '\r') {
271 if (len
<= 11) { //lets check a minimum length of 11
275 if ((len
> 0) && (buf
[0] == '%')) {
279 /* Abort if we see a G54 */
280 if ((len
> 4) && (strncmp(buf
,"G54 ", 4) == 0)) {
281 g_array_free (pnpParseDataArray
, TRUE
);
285 /* abort if we see a G04 code */
286 if ((len
> 4) && (strncmp(buf
,"G04 ", 4) == 0)) {
287 g_array_free (pnpParseDataArray
, TRUE
);
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) { */
298 ret
= csv_row_parse(buf
, MAXL
, buf0
, MAXL
, row
, 11, ',', CSV_QUOTES
);
301 foundValidDataRow
= TRUE
;
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",
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
);
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 */
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)) {
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
;
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
;
381 pnpPartData
.length
= 0.015;
382 pnpPartData
.width
= 0.015;
383 pnpPartData
.shape
= PART_SHAPE_UNKNOWN
;
386 g_array_append_val (pnpParseDataArray
, pnpPartData
);
389 gerb_transf_free(tr_rot
);
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
);
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.
411 * ------------------------------------------------------------------
414 pick_and_place_check_file_type(gerb_file_t
*fd
, gboolean
*returnFoundBinary
)
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
;
434 GERB_FATAL_ERROR("malloc buf failed while checking for pick-place file.\n");
436 while (fgets(buf
, MAXL
, fd
->fd
) != NULL
) {
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')) {
449 if (g_strstr_len(buf
, len
, "G54")) {
452 if (g_strstr_len(buf
, len
, "M00")) {
455 if (g_strstr_len(buf
, len
, "M02")) {
458 if (g_strstr_len(buf
, len
, "G02")) {
461 if (g_strstr_len(buf
, len
, "ADD")) {
464 if (g_strstr_len(buf
, len
, ",")) {
467 /* Semicolon can be separator too */
468 if (g_strstr_len(buf
, len
, ";")) {
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 */
478 if ((letter
= g_strstr_len(buf
, len
, "C")) != NULL
) {
479 if (isdigit((int) letter
[1])) { /* grab char after C */
483 if ((letter
= g_strstr_len(buf
, len
, "U")) != NULL
) {
484 if (isdigit((int) letter
[1])) { /* grab char after U */
489 /* Look for board side indicator since this is required
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
;
512 /* Now form logical expression determining if this is a pick-place file */
513 *returnFoundBinary
= found_binary
;
524 if (found_comma
&& (found_R
|| found_C
|| found_U
) &&
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.
538 * ------------------------------------------------------------------
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
;
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')))
557 if ((boardSide
== 1) && !((partData
.layer
[0]=='t') || (partData
.layer
[0]=='T')))
565 image
= gerbv_create_image(image
, "Pick and Place (X-Y) File");
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();
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
;
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')))
628 if ((boardSide
== 1) && !((partData
.layer
[0]=='t') || (partData
.layer
[0]=='T')))
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
;
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
;
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
;
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
;
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
;
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
);
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
;
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);
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
;
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
));
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
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
);
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 * ------------------------------------------------------------------
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 */