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;
240 int i_length
= 0, i_width
= 0;
243 char *buf
= NULL
, buf0
[MAXL
+2];
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" );
256 /* Read out one row */
257 buf
= gerb_fgetstring(fd
, '\n');
262 /* Remove the \n too */
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
277 if(len
>= 0 && buf
[len
] == '\n') {
280 if(len
>= 0 && buf
[len
] == '\r') {
283 if (len
<= 11) { //lets check a minimum length of 11
287 if ((len
> 0) && (buf
[0] == '%')) {
291 /* Abort if we see a G54 */
292 if ((len
> 4) && (strncmp(buf
,"G54 ", 4) == 0)) {
293 g_array_free (pnpParseDataArray
, TRUE
);
298 /* abort if we see a G04 code */
299 if ((len
> 4) && (strncmp(buf
,"G04 ", 4) == 0)) {
300 g_array_free (pnpParseDataArray
, TRUE
);
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) { */
312 ret
= csv_row_parse(buf
, MAXL
, buf0
, MAXL
, row
, 11, ',', CSV_QUOTES
);
315 foundValidDataRow
= TRUE
;
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",
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
);
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 */
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)) {
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
;
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
;
398 pnpPartData
.length
= 0.015;
399 pnpPartData
.width
= 0.015;
400 pnpPartData
.shape
= PART_SHAPE_UNKNOWN
;
403 g_array_append_val (pnpParseDataArray
, pnpPartData
);
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
);
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.
427 * ------------------------------------------------------------------
430 pick_and_place_check_file_type(gerb_file_t
*fd
, gboolean
*returnFoundBinary
)
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
);
454 GERB_FATAL_ERROR("malloc buf failed while checking for pick-place file.\n");
458 if (fd
->datalen
== idx
) {
462 len
= ((fd
->datalen
- idx
) < MAXL
)? (fd
->datalen
- idx
) : MAXL
;
463 memset(buf
, 0, MAXL
);
464 memcpy(buf
, &fd
->data
[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')) {
478 if (g_strstr_len(buf
, len
, "G54")) {
481 if (g_strstr_len(buf
, len
, "M00")) {
484 if (g_strstr_len(buf
, len
, "M02")) {
487 if (g_strstr_len(buf
, len
, "G02")) {
490 if (g_strstr_len(buf
, len
, "ADD")) {
493 if (g_strstr_len(buf
, len
, ",")) {
496 /* Semicolon can be separator too */
497 if (g_strstr_len(buf
, len
, ";")) {
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 */
507 if ((letter
= g_strstr_len(buf
, len
, "C")) != NULL
) {
508 if (isdigit((int) letter
[1])) { /* grab char after C */
512 if ((letter
= g_strstr_len(buf
, len
, "U")) != NULL
) {
513 if (isdigit((int) letter
[1])) { /* grab char after U */
518 /* Look for board side indicator since this is required
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
;
540 /* Now form logical expression determining if this is a pick-place file */
541 *returnFoundBinary
= found_binary
;
552 if (found_comma
&& (found_R
|| found_C
|| found_U
) &&
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.
566 * ------------------------------------------------------------------
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
;
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
) {
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')))
589 if ((boardSide
== 1) && !((partData
.layer
[0]=='t') || (partData
.layer
[0]=='T')))
597 image
= gerbv_create_image(image
, "Pick and Place (X-Y) File");
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();
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
;
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')))
660 if ((boardSide
== 1) && !((partData
.layer
[0]=='t') || (partData
.layer
[0]=='T')))
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
;
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
;
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
;
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
;
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
;
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
);
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
;
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);
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
;
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
));
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
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
);
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 * ------------------------------------------------------------------
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 */