42 static void pnp_init_net(
48 gerb_transf_free(gerbv_transf_t* transf) {
53 gerb_transf_reset(gerbv_transf_t* transf) {
54 memset(transf, 0,
sizeof(gerbv_transf_t));
56 transf->r_mat[0][0] = transf->r_mat[1][1] = 1.0;
64 gerb_transf_new(
void) {
65 gerbv_transf_t* transf;
67 transf = g_new(gerbv_transf_t, 1);
68 gerb_transf_reset(transf);
81 double s = sin(angle), c = cos(angle);
83 memcpy(m, transf->r_mat,
sizeof(m));
84 transf->r_mat[0][0] = c * m[0][0] - s * m[1][0];
85 transf->r_mat[0][1] = c * m[0][1] - s * m[1][1];
86 transf->r_mat[1][0] = s * m[0][0] + c * m[1][0];
87 transf->r_mat[1][1] = s * m[0][1] + c * m[1][1];
101 transf->offset[0] += shift_x;
102 transf->offset[1] += shift_y;
107 gerb_transf_apply(
double x,
double y, gerbv_transf_t* transf,
double* out_x,
double* out_y) {
111 *out_x = (x * transf->r_mat[0][0] + y * transf->r_mat[0][1]) * transf->scale;
112 *out_y = (x * transf->r_mat[1][0] + y * transf->r_mat[1][1]) * transf->scale;
113 *out_x += transf->offset[0];
114 *out_y += transf->offset[1];
119 pick_and_place_reset_bounding_box(
gerbv_net_t* net) {
129 pick_and_place_get_float_unit(
const char* str,
const char* def_unit) {
131 char unit_str[41] = {
134 const char* unit = unit_str;
137 sscanf(str,
"%lf %40s", &x, unit_str);
139 if (unit_str[0] ==
'\0')
144 if (strstr(unit,
"mm")) {
146 }
else if (strstr(unit,
"in")) {
148 }
else if (strstr(unit,
"cmil")) {
150 }
else if (strstr(unit,
"dmil")) {
152 }
else if (strstr(unit,
"mil")) {
154 }
else if (strstr(unit,
"km")) {
156 }
else if (strstr(unit,
"dm")) {
158 }
else if (strstr(unit,
"cm")) {
160 }
else if (strstr(unit,
"um")) {
162 }
else if (strstr(unit,
"nm")) {
164 }
else if (strstr(unit,
"m")) {
178 char delimiter[4] =
"|,;:";
180 int idx, idx_max = 0;
182 memset(counter, 0,
sizeof(counter));
183 for (ptr = str; *ptr; ptr++) {
185 case '|': idx = 0;
break;
186 case ',': idx = 1;
break;
187 case ';': idx = 2;
break;
188 case ':': idx = 3;
break;
189 default:
continue;
break;
192 if (counter[idx] > counter[idx_max]) {
197 if (counter[idx_max] > n) {
198 return (
unsigned char)delimiter[idx_max];
214 PnpPartData pnpPartData;
215 memset(&pnpPartData, 0,
sizeof(PnpPartData));
216 int lineCounter = 0, parsedLines = 0;
219 char buf[MAXL + 2], buf0[MAXL + 2];
220 char def_unit[41] = {
224 gerbv_transf_t* tr_rot = gerb_transf_new();
225 GArray* pnpParseDataArray = g_array_new(FALSE, FALSE,
sizeof(PnpPartData));
226 gboolean foundValidDataRow = FALSE;
228 const char* def_unit_prefix =
"# X,Y in ";
234 setlocale(LC_NUMERIC,
"C");
236 while (fgets(buf, MAXL, fd->fd) != NULL) {
237 int len = strlen(buf) - 1;
238 int i_length = 0, i_width = 0;
241 if (lineCounter < 2) {
248 if (len >= 0 && buf[len] ==
'\n') {
251 if (len >= 0 && buf[len] ==
'\r') {
254 if (0 == strncmp(buf, def_unit_prefix, strlen(def_unit_prefix))) {
255 sscanf(&buf[strlen(def_unit_prefix)],
"%40s.", def_unit);
261 if ((len > 0) && (buf[0] ==
'%')) {
266 if ((len > 4) && (strncmp(buf,
"G54 ", 4) == 0)) {
267 g_array_free(pnpParseDataArray, TRUE);
272 if ((len > 4) && (strncmp(buf,
"G04 ", 4) == 0)) {
273 g_array_free(pnpParseDataArray, TRUE);
284 ret = csv_row_parse(buf, MAXL, buf0, MAXL, row, 11,
',', CSV_QUOTES);
287 foundValidDataRow = TRUE;
295 if (row[0] && row[8]) {
296 snprintf(pnpPartData.designator,
sizeof(pnpPartData.designator) - 1,
"%s", row[0]);
297 snprintf(pnpPartData.footprint,
sizeof(pnpPartData.footprint) - 1,
"%s", row[1]);
298 snprintf(pnpPartData.layer,
sizeof(pnpPartData.layer) - 1,
"%s", row[8]);
299 if (row[10] != NULL) {
300 if (!g_utf8_validate(row[10], -1, NULL)) {
301 gchar* str = g_convert(row[10], strlen(row[10]),
"UTF-8",
"ISO-8859-1", NULL, NULL, NULL);
305 snprintf(pnpPartData.comment,
sizeof(pnpPartData.comment) - 1,
"%s", str);
308 snprintf(pnpPartData.comment,
sizeof(pnpPartData.comment) - 1,
"%s", row[10]);
315 pnpPartData.mid_x = pick_and_place_get_float_unit(row[2], def_unit);
316 pnpPartData.mid_y = pick_and_place_get_float_unit(row[3], def_unit);
317 pnpPartData.ref_x = pick_and_place_get_float_unit(row[4], def_unit);
318 pnpPartData.ref_y = pick_and_place_get_float_unit(row[5], def_unit);
319 pnpPartData.pad_x = pick_and_place_get_float_unit(row[6], def_unit);
320 pnpPartData.pad_y = pick_and_place_get_float_unit(row[7], def_unit);
324 const int rc = sscanf(row[9],
"%lf", &pnpPartData.rotation);
329 g_array_free(pnpParseDataArray, TRUE);
337 else if (row[0] && row[1] && row[2] && row[3] && row[4] && row[5] && row[6]) {
338 snprintf(pnpPartData.designator,
sizeof(pnpPartData.designator) - 1,
"%s", row[0]);
339 snprintf(pnpPartData.footprint,
sizeof(pnpPartData.footprint) - 1,
"%s", row[1]);
340 snprintf(pnpPartData.layer,
sizeof(pnpPartData.layer) - 1,
"%s", row[6]);
341 pnpPartData.mid_x = pick_and_place_get_float_unit(row[3], def_unit);
342 pnpPartData.mid_y = pick_and_place_get_float_unit(row[4], def_unit);
343 pnpPartData.pad_x = pnpPartData.mid_x + 0.03;
344 pnpPartData.pad_y = pnpPartData.mid_y + 0.03;
349 if ((fabs(pnpPartData.mid_x) < 0.001) && (fabs(pnpPartData.mid_y) < 0.001)) {
355 const int rc = sscanf(row[5],
"%lf", &pnpPartData.rotation);
357 g_array_free(pnpParseDataArray, TRUE);
368 if (sscanf(pnpPartData.footprint,
"%02d%02d", &i_length, &i_width) == 2) {
370 pnpPartData.length = 0.01 * i_length;
371 pnpPartData.width = 0.01 * i_width;
372 pnpPartData.shape = PART_SHAPE_RECTANGLE;
374 gerb_transf_reset(tr_rot);
377 pnpPartData.pad_x - pnpPartData.mid_x, pnpPartData.pad_y - pnpPartData.mid_y, tr_rot, &tmp_x, &tmp_y
379 if ((fabs(tmp_y) > fabs(tmp_x / 100)) && (fabs(tmp_x) > fabs(tmp_y / 100))) {
380 pnpPartData.length = 2 * fabs(tmp_x);
381 pnpPartData.width = 2 * fabs(tmp_y);
382 pnpPartData.shape = PART_SHAPE_STD;
384 pnpPartData.length = 0.015;
385 pnpPartData.width = 0.015;
386 pnpPartData.shape = PART_SHAPE_UNKNOWN;
389 g_array_append_val(pnpParseDataArray, pnpPartData);
392 gerb_transf_free(tr_rot);
397 if ((((
float)parsedLines / (
float)lineCounter) < 0.3) || (!foundValidDataRow)) {
399 g_array_free(pnpParseDataArray, TRUE);
402 return pnpParseDataArray;
415 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 in %s()", __FUNCTION__);
436 while (fgets(buf, MAXL, fd->fd) != NULL) {
442 for (i = 0; i < len; i++) {
443 if (!isprint((
int)buf[i]) && (buf[i] !=
'\r') && (buf[i] !=
'\n') && (buf[i] !=
'\t')) {
448 if (g_strstr_len(buf, len,
"G54")) {
451 if (g_strstr_len(buf, len,
"M00")) {
454 if (g_strstr_len(buf, len,
"M02")) {
457 if (g_strstr_len(buf, len,
"G02")) {
460 if (g_strstr_len(buf, len,
"ADD")) {
463 if (g_strstr_len(buf, len,
",")) {
467 if (g_strstr_len(buf, len,
";")) {
472 if ((letter = g_strstr_len(buf, len,
"R")) != NULL) {
473 if (isdigit((
int)letter[1])) {
477 if ((letter = g_strstr_len(buf, len,
"C")) != NULL) {
478 if (isdigit((
int)letter[1])) {
482 if ((letter = g_strstr_len(buf, len,
"U")) != NULL) {
483 if (isdigit((
int)letter[1])) {
490 if (g_strstr_len(buf, len,
"top")) {
491 found_boardside = TRUE;
493 if (g_strstr_len(buf, len,
"Top")) {
494 found_boardside = TRUE;
496 if (g_strstr_len(buf, len,
"TOP")) {
497 found_boardside = TRUE;
500 if (g_strstr_len(buf, len,
"ayer")) {
501 found_boardside = TRUE;
503 if (g_strstr_len(buf, len,
"AYER")) {
504 found_boardside = TRUE;
511 *returnFoundBinary = found_binary;
522 if (found_comma && (found_R || found_C || found_U) && found_boardside)
537 pick_and_place_convert_pnp_data_to_image(GArray* parsedPickAndPlaceData, gint boardSide) {
540 gerbv_transf_t* tr_rot = gerb_transf_new();
542 gboolean foundElement = FALSE;
543 const double draw_width = 0.01;
547 for (guint i = 0; i < parsedPickAndPlaceData->len; i++) {
548 PnpPartData partData = g_array_index(parsedPickAndPlaceData, PnpPartData, i);
550 if ((boardSide == 0) && !((partData.layer[0] ==
'b') || (partData.layer[0] ==
'B')))
552 if ((boardSide == 1) && !((partData.layer[0] ==
't') || (partData.layer[0] ==
'T')))
562 GERB_FATAL_ERROR(
"malloc image failed in %s()", __FUNCTION__);
566 if (image->
format == NULL) {
567 GERB_FATAL_ERROR(
"malloc format failed in %s()", __FUNCTION__);
578 GERB_FATAL_ERROR(
"malloc pick_place_stats failed in %s()", __FUNCTION__);
584 pnp_reset_bbox(curr_net);
585 image->
info->min_x = HUGE_VAL;
586 image->
info->min_y = HUGE_VAL;
587 image->
info->max_x = -HUGE_VAL;
588 image->
info->max_y = -HUGE_VAL;
590 image->
aperture[0] = g_new0(gerbv_aperture_t, 1);
594 image->
aperture[0]->parameter[0] = draw_width;
595 image->
aperture[0]->nuf_parameters = 1;
597 for (guint i = 0; i < parsedPickAndPlaceData->len; i++) {
598 PnpPartData partData = g_array_index(parsedPickAndPlaceData, PnpPartData, i);
599 float radius, labelOffset;
601 curr_net = pnp_new_net(curr_net);
605 if ((partData.rotation > 89) && (partData.rotation < 91))
606 labelOffset = fabs(partData.length / 2);
607 else if ((partData.rotation > 179) && (partData.rotation < 181))
608 labelOffset = fabs(partData.width / 2);
609 else if ((partData.rotation > 269) && (partData.rotation < 271))
610 labelOffset = fabs(partData.length / 2);
611 else if ((partData.rotation > -91) && (partData.rotation < -89))
612 labelOffset = fabs(partData.length / 2);
613 else if ((partData.rotation > -181) && (partData.rotation < -179))
614 labelOffset = fabs(partData.width / 2);
615 else if ((partData.rotation > -271) && (partData.rotation < -269))
616 labelOffset = fabs(partData.length / 2);
618 labelOffset = fabs(partData.width / 2);
620 partData.rotation = DEG2RAD(partData.rotation);
623 if ((boardSide == 0) && !((partData.layer[0] ==
'b') || (partData.layer[0] ==
'B')))
625 if ((boardSide == 1) && !((partData.layer[0] ==
't') || (partData.layer[0] ==
'T')))
628 curr_net = pnp_new_net(curr_net);
634 curr_net->
start_y = curr_net->
stop_y = partData.mid_y + labelOffset + draw_width;
636 gerb_transf_reset(tr_rot);
640 if ((partData.shape == PART_SHAPE_RECTANGLE) || (partData.shape == PART_SHAPE_STD)) {
643 curr_net = pnp_new_net(curr_net);
646 gerb_transf_apply(partData.length / 2, partData.width / 2, tr_rot, &curr_net->
start_x, &curr_net->
start_y);
647 gerb_transf_apply(-partData.length / 2, partData.width / 2, tr_rot, &curr_net->
stop_x, &curr_net->
stop_y);
651 curr_net = pnp_new_net(curr_net);
654 gerb_transf_apply(-partData.length / 2, partData.width / 2, tr_rot, &curr_net->
start_x, &curr_net->
start_y);
655 gerb_transf_apply(-partData.length / 2, -partData.width / 2, tr_rot, &curr_net->
stop_x, &curr_net->
stop_y);
657 curr_net = pnp_new_net(curr_net);
661 -partData.length / 2, -partData.width / 2, tr_rot, &curr_net->
start_x, &curr_net->
start_y
663 gerb_transf_apply(partData.length / 2, -partData.width / 2, tr_rot, &curr_net->
stop_x, &curr_net->
stop_y);
665 curr_net = pnp_new_net(curr_net);
668 gerb_transf_apply(partData.length / 2, -partData.width / 2, tr_rot, &curr_net->
start_x, &curr_net->
start_y);
669 gerb_transf_apply(partData.length / 2, partData.width / 2, tr_rot, &curr_net->
stop_x, &curr_net->
stop_y);
671 curr_net = pnp_new_net(curr_net);
674 if (partData.shape == PART_SHAPE_RECTANGLE) {
676 partData.length / 4, -partData.width / 2, tr_rot, &curr_net->
start_x, &curr_net->
start_y
679 partData.length / 4, partData.width / 2, tr_rot, &curr_net->
stop_x, &curr_net->
stop_y
683 partData.length / 4, partData.width / 2, tr_rot, &curr_net->
start_x, &curr_net->
start_y
686 partData.length / 4, partData.width / 4, tr_rot, &curr_net->
stop_x, &curr_net->
stop_y
689 curr_net = pnp_new_net(curr_net);
695 partData.length / 2, partData.width / 4, tr_rot, &curr_net->
start_x, &curr_net->
start_y
698 partData.length / 4, partData.width / 4, tr_rot, &curr_net->
stop_x, &curr_net->
stop_y
703 radius = MAX(partData.length / 2, partData.width / 2);
705 gdouble tmp_x, tmp_y;
709 curr_net->
start_x = partData.mid_x;
710 curr_net->
start_y = partData.mid_y;
711 gerb_transf_apply(partData.pad_x - partData.mid_x, partData.pad_y - partData.mid_y, tr_rot, &tmp_x, &tmp_y);
716 curr_net = pnp_new_net(curr_net);
721 curr_net->
start_x = partData.mid_x;
722 curr_net->
start_y = partData.mid_y;
723 curr_net->
stop_x = partData.pad_x;
724 curr_net->
stop_y = partData.pad_y;
726 curr_net->
cirseg = g_new0(gerbv_cirseg_t, 1);
727 curr_net->
cirseg->angle1 = 0.0;
728 curr_net->
cirseg->angle2 = 360.0;
729 curr_net->
cirseg->cp_x = partData.mid_x;
730 curr_net->
cirseg->cp_y = partData.mid_y;
731 radius = hypot(partData.pad_x - partData.mid_x, partData.pad_y - partData.mid_y);
734 curr_net->
cirseg->width = 2 * radius;
735 curr_net->
cirseg->height = 2 * radius;
742 image->
info->min_x = MIN(image->
info->min_x, (partData.mid_x - radius - 0.02));
743 image->
info->min_y = MIN(image->
info->min_y, (partData.mid_y - radius - 0.02));
744 image->
info->max_x = MAX(image->
info->max_x, (partData.mid_x + radius + 0.02));
745 image->
info->max_y = MAX(image->
info->max_y, (partData.mid_y + radius + 0.02));
747 curr_net->
next = NULL;
749 gerb_transf_free(tr_rot);
767 if (parsedPickAndPlaceData != NULL) {
769 if (*bottomImage == NULL)
770 *bottomImage = pick_and_place_convert_pnp_data_to_image(parsedPickAndPlaceData, 0);
772 if (*topImage == NULL)
773 *topImage = pick_and_place_convert_pnp_data_to_image(parsedPickAndPlaceData, 1);
775 g_array_free(parsedPickAndPlaceData, TRUE);
810 if (strlen(label) > 0) {
811 net->
label = g_string_new(label);
Header info for the parsing support functions for the pick and place parser.
gerbv_drill_stats_t * gerbv_drill_stats_new(void)
Allocates a new drill_stats structure.
gerbv_image_t * gerbv_create_image(gerbv_image_t *image, const gchar *type)
Allocate a new gerbv_image structure.
Header info for the RS274X parsing functions.
The main header file for the libgerbv library.
@ GERBV_APERTURE_STATE_OFF
@ GERBV_APERTURE_STATE_ON
@ GERBV_INTERPOLATION_CW_CIRCULAR
@ GERBV_INTERPOLATION_LINEARx1
@ GERBV_LAYERTYPE_PICKANDPLACE_BOT
@ GERBV_LAYERTYPE_PICKANDPLACE_TOP
void gerb_transf_rotate(gerbv_transf_t *transf, double angle)
Rotation.
void gerb_transf_shift(gerbv_transf_t *transf, double shift_x, double shift_y)
Translation.
GArray * pick_and_place_parse_file(gerb_file_t *fd)
Parses the PNP data.
int pick_and_place_screen_for_delimiter(char *str, int n)
search a string for a delimiter.
Header info for the PNP (pick-and-place) parsing functions.
gerbv_layertype_t layertype
gerbv_drill_stats_t * drill_stats
gerbv_aperture_t * aperture[APERTURE_MAX]
gerbv_netstate_t * states
gerbv_image_info_t * info
gerbv_render_size_t boundingBox
gerbv_aperture_state_t aperture_state
gerbv_interpolation_t interpolation