gerbv  2.6A
gerb_image.c
Go to the documentation of this file.
1 /*
2  * gEDA - GNU Electronic Design Automation
3  * This files is a part of gerbv.
4  *
5  * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
6  *
7  * $Id$
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
22  */
23 
29 #include "gerbv.h"
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34 
35 #include "common.h"
36 #include "gerb_image.h"
37 #include "gerber.h"
38 #include "amacro.h"
39 
40 typedef struct {
41  int oldAperture;
42  int newAperture;
43 } gerb_translation_entry_t;
44 
46 gerbv_create_image(gerbv_image_t *image, const gchar *type)
47 {
48  gerbv_destroy_image(image);
49 
50  /* Malloc space for image */
51  if ((image = (gerbv_image_t *)g_malloc(sizeof(gerbv_image_t))) == NULL) {
52  return NULL;
53  }
54  memset((void *)image, 0, sizeof(gerbv_image_t));
55 
56  /* Malloc space for image->netlist */
57  if ((image->netlist = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t))) == NULL) {
58  g_free(image);
59  return NULL;
60  }
61  memset((void *)image->netlist, 0, sizeof(gerbv_net_t));
62 
63  /* Malloc space for image->info */
64  if ((image->info = (gerbv_image_info_t *)g_malloc(sizeof(gerbv_image_info_t))) == NULL) {
65  g_free(image->netlist);
66  g_free(image);
67  return NULL;
68  }
69  memset((void *)image->info, 0, sizeof(gerbv_image_info_t));
70 
71  /* Set aside position for stats struct */
72  image->gerbv_stats = NULL;
73  image->drill_stats = NULL;
74 
75  image->info->min_x = HUGE_VAL;
76  image->info->min_y = HUGE_VAL;
77  image->info->max_x = -HUGE_VAL;
78  image->info->max_y = -HUGE_VAL;
79 
80  /* create our first layer and fill with non-zero default values */
81  image->layers = g_new0 (gerbv_layer_t, 1);
82  image->layers->stepAndRepeat.X = 1;
83  image->layers->stepAndRepeat.Y = 1;
85 
86  /* create our first netstate and fill with non-zero default values */
87  image->states = g_new0 (gerbv_netstate_t, 1);
88  image->states->scaleA = 1;
89  image->states->scaleB = 1;
90 
91  /* fill in some values for our first net */
92  image->netlist->layer = image->layers;
93  image->netlist->state = image->states;
94 
95  if (type == NULL)
96  image->info->type = g_strdup (_("unknown"));
97  else
98  image->info->type = g_strdup (type);
99 
100  /* the individual file parsers will have to set this. */
101  image->info->attr_list = NULL;
102  image->info->n_attr = 0;
103 
104  return image;
105 }
106 
107 
108 void
110 {
111  int i;
112  gerbv_net_t *net, *tmp;
113  gerbv_layer_t *layer;
114  gerbv_netstate_t *state;
115  gerbv_simplified_amacro_t *sam,*sam2;
116 
117  if(image==NULL)
118  return;
119 
120  /*
121  * Free apertures
122  */
123  for (i = 0; i < APERTURE_MAX; i++)
124  if (image->aperture[i] != NULL) {
125  for (sam = image->aperture[i]->simplified; sam != NULL; ){
126  sam2 = sam->next;
127  g_free (sam);
128  sam = sam2;
129  }
130 
131  g_free(image->aperture[i]);
132  image->aperture[i] = NULL;
133  }
134 
135  /*
136  * Free aperture macro
137  */
138 
139  if (image->amacro) {
140  free_amacro(image->amacro);
141  }
142 
143  /*
144  * Free format
145  */
146  if (image->format)
147  g_free(image->format);
148 
149  /*
150  * Free info
151  */
152  if (image->info) {
153  g_free(image->info->name);
154  g_free(image->info->type);
155  gerbv_attribute_destroy_HID_attribute (image->info->attr_list, image->info->n_attr);
156  g_free(image->info);
157  }
158 
159  /*
160  * Free netlist
161  */
162  for (net = image->netlist; net != NULL; ) {
163  tmp = net;
164  net = net->next;
165  if (tmp->cirseg != NULL) {
166  g_free(tmp->cirseg);
167  tmp->cirseg = NULL;
168  }
169  if (tmp->label) {
170  g_string_free (tmp->label, TRUE);
171  }
172  g_free(tmp);
173  tmp = NULL;
174  }
175  for (layer = image->layers; layer != NULL; ) {
176  gerbv_layer_t *tempLayer = layer;
177 
178  layer = layer->next;
179  g_free (tempLayer);
180  }
181  for (state = image->states; state != NULL; ) {
182  gerbv_netstate_t *tempState = state;
183 
184  state = state->next;
185  g_free (tempState);
186  }
189 
190  /*
191  * Free and reset the final image
192  */
193  g_free(image);
194  image = NULL;
195 
196  return;
197 }
198 
199 
200 /*
201  * Check that the parsed gerber image is complete.
202  * Returned errorcodes are:
203  * 0: No problems
204  * 1: Missing netlist
205  * 2: Missing format
206  * 4: Missing apertures
207  * 8: Missing info
208  * It could be any of above or'ed together
209  */
210 gerb_verify_error_t
211 gerbv_image_verify(gerbv_image_t const* image)
212 {
213  gerb_verify_error_t error = GERB_IMAGE_OK;
214  int i, n_nets;;
215  gerbv_net_t *net;
216 
217  if (image->netlist == NULL) error |= GERB_IMAGE_MISSING_NETLIST;
218  if (image->format == NULL) error |= GERB_IMAGE_MISSING_FORMAT;
219  if (image->info == NULL) error |= GERB_IMAGE_MISSING_INFO;
220 
221  /* Count how many nets we have */
222  n_nets = 0;
223  if (image->netlist != NULL) {
224  for (net = image->netlist->next ; net != NULL; net = net->next) {
225  n_nets++;
226  }
227  }
228 
229  /* If we have nets but no apertures are defined, then complain */
230  if( n_nets > 0) {
231  for (i = 0; i < APERTURE_MAX && image->aperture[i] == NULL; i++);
232  if (i == APERTURE_MAX) error |= GERB_IMAGE_MISSING_APERTURES;
233  }
234 
235  return error;
236 } /* gerb_image_verify */
237 
238 
239 static void
240 gerbv_image_interpolation(gerbv_interpolation_t interpolation)
241 {
242  switch (interpolation) {
244  printf(_("linearX1"));
245  break;
247  printf(_("linearX10"));
248  break;
250  printf(_("linearX01"));
251  break;
253  printf(_("linearX001"));
254  break;
256  printf(_("CW circular"));
257  break;
259  printf(_("CCW circular"));
260  break;
262  printf(_("polygon area start"));
263  break;
265  printf(_("polygon area end"));
266  break;
267  default:
268  printf(_("unknown"));
269  }
270 } /* gerb_image_interpolation */
271 
272 static void
273 gerbv_image_aperture_state(gerbv_aperture_state_t state)
274 {
275  switch (state) {
277  printf(_("..state off"));
278  break;
280  printf(_("..state on"));
281  break;
283  printf(_("..state flash"));
284  break;
285  default:
286  printf(_("..state unknown"));
287  }
288 }
289 
290 /* Dumps a written version of image to stdout */
291 void
292 gerbv_image_dump(gerbv_image_t const* image)
293 {
294  int i, j;
295  gerbv_aperture_t * const* aperture;
296  gerbv_net_t const * net;
297 
298  /* Apertures */
299  printf(_("Apertures:\n"));
300  aperture = image->aperture;
301  for (i = 0; i < APERTURE_MAX; i++) {
302  if (aperture[i]) {
303  printf(_(" Aperture no:%d is an "), i);
304  switch(aperture[i]->type) {
305  case GERBV_APTYPE_CIRCLE:
306  printf(_("circle"));
307  break;
309  printf(_("rectangle"));
310  break;
311  case GERBV_APTYPE_OVAL:
312  printf(_("oval"));
313  break;
315  printf(_("polygon"));
316  break;
317  case GERBV_APTYPE_MACRO:
318  printf(_("macro"));
319  break;
320  default:
321  printf(_("unknown"));
322  }
323  for (j = 0; j < aperture[i]->nuf_parameters; j++) {
324  printf(" %f", aperture[i]->parameter[j]);
325  }
326  printf("\n");
327  }
328  }
329 
330  /* Netlist */
331  net = image->netlist;
332  while (net){
333  printf(_("(%f,%f)->(%f,%f) with %d ("), net->start_x, net->start_y,
334  net->stop_x, net->stop_y, net->aperture);
335  gerbv_image_interpolation(net->interpolation);
336  gerbv_image_aperture_state(net->aperture_state);
337  printf(")\n");
338  net = net->next;
339  }
340 } /* gerbv_image_dump */
341 
342 
344 gerbv_image_return_new_layer (gerbv_layer_t *previousLayer)
345 {
346  gerbv_layer_t *newLayer = g_new0 (gerbv_layer_t, 1);
347 
348  *newLayer = *previousLayer;
349  previousLayer->next = newLayer;
350  /* clear this boolean so we only draw the knockout once */
351  newLayer->knockout.firstInstance = FALSE;
352  newLayer->next = NULL;
353 
354  return newLayer;
355 } /* gerbv_image_return_new_layer */
356 
357 
359 gerbv_image_return_new_netstate (gerbv_netstate_t *previousState)
360 {
361  gerbv_netstate_t *newState = g_new0 (gerbv_netstate_t, 1);
362 
363  *newState = *previousState;
364  previousState->next = newState;
365  newState->scaleA = 1.0;
366  newState->scaleB = 1.0;
367  newState->next = NULL;
368 
369  return newState;
370 } /* gerbv_image_return_new_netstate */
371 
373 gerbv_image_duplicate_layer (gerbv_layer_t *oldLayer) {
374  gerbv_layer_t *newLayer = g_new (gerbv_layer_t,1);
375 
376  *newLayer = *oldLayer;
377  newLayer->name = g_strdup (oldLayer->name);
378  return newLayer;
379 }
380 
382 gerbv_image_duplicate_state (gerbv_netstate_t *oldState) {
383  gerbv_netstate_t *newState = g_new (gerbv_netstate_t,1);
384 
385  *newState = *oldState;
386  return newState;
387 }
388 
389 gerbv_aperture_t *
390 gerbv_image_duplicate_aperture (gerbv_aperture_t *oldAperture){
391  gerbv_aperture_t *newAperture = g_new0 (gerbv_aperture_t,1);
392  gerbv_simplified_amacro_t *simplifiedMacro, *tempSimplified;
393 
394  *newAperture = *oldAperture;
395 
396  /* delete the amacro section, since we really don't need it anymore
397  now that we have the simplified section */
398  newAperture->amacro = NULL;
399  newAperture->simplified = NULL;
400 
401  /* copy any simplified macros over */
402  tempSimplified = NULL;
403  for (simplifiedMacro = oldAperture->simplified; simplifiedMacro != NULL; simplifiedMacro = simplifiedMacro->next) {
404  gerbv_simplified_amacro_t *newSimplified = g_new0 (gerbv_simplified_amacro_t,1);
405  *newSimplified = *simplifiedMacro;
406  if (tempSimplified)
407  tempSimplified->next = newSimplified;
408  else
409  newAperture->simplified = newSimplified;
410  tempSimplified = newSimplified;
411  }
412  return newAperture;
413 }
414 
415 void
416 gerbv_image_copy_all_nets (gerbv_image_t *sourceImage, gerbv_image_t *newImage, gerbv_layer_t *lastLayer,
417  gerbv_netstate_t *lastState, gerbv_net_t *lastNet, gerbv_user_transformation_t *transform,
418  GArray *translationTable){
419  gerbv_netstate_t *oldState,*newSavedState;
420  gerbv_layer_t *oldLayer,*newSavedLayer;
421  gerbv_net_t *currentNet,*newNet,*newSavedNet;
422  int i;
423 
424  oldLayer = sourceImage->layers;
425  oldState = sourceImage->states;
426 
427  newSavedLayer = lastLayer;
428  newSavedState = lastState;
429  newSavedNet = lastNet;
430 
431  for (currentNet = sourceImage->netlist; currentNet; currentNet = currentNet->next){
432  /* check for any new layers and duplicate them if needed */
433  if (currentNet->layer != oldLayer) {
434  newSavedLayer->next = gerbv_image_duplicate_layer (currentNet->layer);
435  newSavedLayer = newSavedLayer->next;
436  }
437  /* check for any new states and duplicate them if needed */
438  if (currentNet->state != oldState) {
439  newSavedState->next = gerbv_image_duplicate_state (currentNet->state);
440  newSavedState = newSavedState->next;
441  }
442  /* create and copy the actual net over */
443  newNet = g_new (gerbv_net_t,1);
444  *newNet = *currentNet;
445 
446  if (currentNet->cirseg) {
447  newNet->cirseg = g_new (gerbv_cirseg_t,1);
448  *(newNet->cirseg) = *(currentNet->cirseg);
449  }
450 
451  if (currentNet->label)
452  newNet->label = g_string_new(currentNet->label->str);
453 
454  newNet->state = newSavedState;
455  newNet->layer = newSavedLayer;
456  /* check if we need to translate the aperture number */
457  if (translationTable) {
458  for (i=0; i<translationTable->len; i++){
459  gerb_translation_entry_t translationEntry=g_array_index (translationTable, gerb_translation_entry_t, i);
460 
461  if (translationEntry.oldAperture == newNet->aperture) {
462  newNet->aperture = translationEntry.newAperture;
463  break;
464  }
465  }
466  }
467  /* check if we are transforming the net (translating, scaling, etc) */
468  if (transform) {
469  newNet->start_x += transform->translateX;
470  newNet->start_y += transform->translateY;
471  newNet->stop_x += transform->translateX;
472  newNet->stop_y += transform->translateY;
473  if (newNet->cirseg) {
474  newNet->cirseg->cp_x += transform->translateX;
475  newNet->cirseg->cp_y += transform->translateY;
476  }
477  }
478  if (newSavedNet)
479  newSavedNet->next = newNet;
480  else
481  newImage->netlist = newNet;
482  newSavedNet = newNet;
483  }
484 
485 }
486 
487 gint
488 gerbv_image_find_existing_aperture_match (gerbv_aperture_t *checkAperture, gerbv_image_t *imageToSearch) {
489  int i,j;
490  gboolean isMatch;
491 
492  for (i = 0; i < APERTURE_MAX; i++) {
493  if (imageToSearch->aperture[i] != NULL) {
494  if ((imageToSearch->aperture[i]->type == checkAperture->type) &&
495  (imageToSearch->aperture[i]->simplified == NULL) &&
496  (imageToSearch->aperture[i]->unit == checkAperture->unit)) {
497  /* check all parameters match too */
498  isMatch=TRUE;
499  for (j=0; j<APERTURE_PARAMETERS_MAX; j++){
500  if (imageToSearch->aperture[i]->parameter[j] != checkAperture->parameter[j])
501  isMatch = FALSE;
502  }
503  if (isMatch)
504  return i;
505  }
506  }
507  }
508  return 0;
509 }
510 
511 int
512 gerbv_image_find_unused_aperture_number (int startIndex, gerbv_image_t *image){
513  int i;
514 
515  for (i = startIndex; i < APERTURE_MAX; i++) {
516  if (image->aperture[i] == NULL) {
517  return i;
518  }
519  }
520  return -1;
521 }
522 
525  gerbv_image_t *newImage = gerbv_create_image(NULL, sourceImage->info->type);
526  int i;
527  int lastUsedApertureNumber = APERTURE_MIN - 1;
528  GArray *apertureNumberTable = g_array_new(FALSE,FALSE,sizeof(gerb_translation_entry_t));
529 
530  newImage->layertype = sourceImage->layertype;
531  /* copy information layer over */
532  *(newImage->info) = *(sourceImage->info);
533  newImage->info->name = g_strdup (sourceImage->info->name);
534  newImage->info->type = g_strdup (sourceImage->info->type);
535  newImage->info->plotterFilm = g_strdup (sourceImage->info->plotterFilm);
536  newImage->info->attr_list = gerbv_attribute_dup (sourceImage->info->attr_list,
537  sourceImage->info->n_attr);
538 
539  /* copy apertures over, compressing all the numbers down for a cleaner output, and
540  moving and apertures less than 10 up to the correct range */
541  for (i = 0; i < APERTURE_MAX; i++) {
542  if (sourceImage->aperture[i] != NULL) {
543  gerbv_aperture_t *newAperture = gerbv_image_duplicate_aperture (sourceImage->aperture[i]);
544 
545  lastUsedApertureNumber = gerbv_image_find_unused_aperture_number (lastUsedApertureNumber + 1, newImage);
546  /* store the aperture numbers (new and old) in the translation table */
547  gerb_translation_entry_t translationEntry={i,lastUsedApertureNumber};
548  g_array_append_val (apertureNumberTable,translationEntry);
549 
550  newImage->aperture[lastUsedApertureNumber] = newAperture;
551  }
552  }
553 
554  /* step through all nets and create new layers and states on the fly, since
555  we really don't have any other way to figure out where states and layers are used */
556  gerbv_image_copy_all_nets (sourceImage, newImage, newImage->layers, newImage->states, NULL, transform, apertureNumberTable);
557  g_array_free (apertureNumberTable, TRUE);
558  return newImage;
559 }
560 
561 void
562 gerbv_image_copy_image (gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform, gerbv_image_t *destinationImage) {
563  int lastUsedApertureNumber = APERTURE_MIN - 1;
564  int i;
565  GArray *apertureNumberTable = g_array_new(FALSE,FALSE,sizeof(gerb_translation_entry_t));
566 
567  /* copy apertures over */
568  for (i = 0; i < APERTURE_MAX; i++) {
569  if (sourceImage->aperture[i] != NULL) {
570  gint existingAperture = gerbv_image_find_existing_aperture_match (sourceImage->aperture[i], destinationImage);
571 
572  /* if we already have an existing aperture in the destination image that matches what
573  we want, just use it instead */
574  if (existingAperture > 0) {
575  gerb_translation_entry_t translationEntry={i,existingAperture};
576  g_array_append_val (apertureNumberTable,translationEntry);
577  }
578  /* else, create a new aperture and put it in the destination image */
579  else {
580  gerbv_aperture_t *newAperture = gerbv_image_duplicate_aperture (sourceImage->aperture[i]);
581 
582  lastUsedApertureNumber = gerbv_image_find_unused_aperture_number (lastUsedApertureNumber + 1, destinationImage);
583  /* store the aperture numbers (new and old) in the translation table */
584  gerb_translation_entry_t translationEntry={i,lastUsedApertureNumber};
585  g_array_append_val (apertureNumberTable,translationEntry);
586 
587  destinationImage->aperture[lastUsedApertureNumber] = newAperture;
588  }
589  }
590  }
591  /* find the last layer, state, and net in the linked chains */
592  gerbv_netstate_t *lastState;
593  gerbv_layer_t *lastLayer;
594  gerbv_net_t *lastNet;
595 
596  for (lastState = destinationImage->states; lastState->next; lastState=lastState->next){}
597  for (lastLayer = destinationImage->layers; lastLayer->next; lastLayer=lastLayer->next){}
598  for (lastNet = destinationImage->netlist; lastNet->next; lastNet=lastNet->next){}
599 
600  /* and then copy them all to the destination image, using the aperture translation table we just built */
601  gerbv_image_copy_all_nets (sourceImage, destinationImage, lastLayer, lastState, lastNet, transform, apertureNumberTable);
602  g_array_free (apertureNumberTable, TRUE);
603 }
604 
605 void
607  gerbv_net_t *tempNet;
608 
609  g_assert (currentNet);
610  /* we have a match, so just zero out all the important data fields */
611  currentNet->aperture = 0;
613 
614  /* if this is a polygon start, we need to erase all the rest of the
615  nets in this polygon too */
617  for (tempNet = currentNet->next; tempNet; tempNet = tempNet->next){
618  tempNet->aperture = 0;
620 
623  break;
624  }
625  /* make sure we don't leave a polygon interpolation in, since
626  it will still draw if it is */
628  }
629  }
630  /* make sure we don't leave a polygon interpolation in, since
631  it will still draw if it is */
633 }
634 
635 void
636 gerbv_image_delete_selected_nets (gerbv_image_t *sourceImage, GArray *selectedNodeArray) {
637  int i;
638  gerbv_net_t *currentNet;
639 
640  for (currentNet = sourceImage->netlist; currentNet; currentNet = currentNet->next){
641  for (i=0; i<selectedNodeArray->len; i++){
642  gerbv_selection_item_t sItem = g_array_index (selectedNodeArray,
643  gerbv_selection_item_t, i);
644  if (sItem.net == currentNet) {
645  gerbv_image_delete_net (currentNet);
646 
647  }
648  }
649  }
650 }
651 
652 void
654  gdouble coordinateY, gdouble width, gdouble height) {
655  gerbv_net_t *currentNet;
656 
657  /* run through and find last net pointer */
658  for (currentNet = image->netlist; currentNet->next; currentNet = currentNet->next){}
659 
660  /* create the polygon start node */
661  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
663 
664  /* go to start point (we need this to create correct RS274X export code) */
665  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
668  currentNet->start_x = coordinateX;
669  currentNet->start_y = coordinateY;
670  currentNet->stop_x = coordinateX;
671  currentNet->stop_y = coordinateY;
672 
673  /* draw the 4 corners */
674  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
677  currentNet->start_x = coordinateX;
678  currentNet->start_y = coordinateY;
679  currentNet->stop_x = coordinateX + width;
680  currentNet->stop_y = coordinateY;
681  gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
682  0,0,0,0);
683  gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
684 
685  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
688  currentNet->stop_x = coordinateX + width;
689  currentNet->stop_y = coordinateY + height;
690  gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
691  0,0,0,0);
692  gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
693 
694  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
697  currentNet->stop_x = coordinateX;
698  currentNet->stop_y = coordinateY + height;
699  gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
700  0,0,0,0);
701  gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
702 
703  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
706  currentNet->stop_x = coordinateX;
707  currentNet->stop_y = coordinateY;
708  gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
709  0,0,0,0);
710  gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
711 
712  /* create the polygon end node */
713  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
715 
716  return;
717 }
718 
719 gerbv_net_t *
720 gerb_image_return_aperture_index (gerbv_image_t *image, gdouble lineWidth, int *apertureIndex){
721  gerbv_net_t *currentNet;
722  gerbv_aperture_t *aperture=NULL;
723  int i;
724 
725  /* run through and find last net pointer */
726  for (currentNet = image->netlist; currentNet->next; currentNet = currentNet->next){}
727 
728  /* try to find an existing aperture that matches the requested width and type */
729  for (i = 0; i < APERTURE_MAX; i++) {
730  if (image->aperture[i] != NULL) {
731  if ((image->aperture[i]->type == GERBV_APTYPE_CIRCLE) &&
732  (fabs (image->aperture[i]->parameter[0] - lineWidth) < 0.001)){
733  aperture = image->aperture[i];
734  *apertureIndex = i;
735  break;
736  }
737  }
738  }
739 
740  if (!aperture) {
741  /* we didn't find a useable old aperture, so create a new one */
742  if (!gerber_create_new_aperture (image, apertureIndex,
743  GERBV_APTYPE_CIRCLE, lineWidth, 0)) {
744  /* if we didn't succeed, then return */
745  return FALSE;
746  }
747  }
748  return currentNet;
749 }
750 
751 void
752 gerbv_image_create_arc_object (gerbv_image_t *image, gdouble centerX, gdouble centerY,
753  gdouble radius, gdouble startAngle, gdouble endAngle, gdouble lineWidth,
754  gerbv_aperture_type_t apertureType) {
755  int apertureIndex;
756  gerbv_net_t *currentNet;
757  gerbv_cirseg_t cirSeg = {centerX, centerY, radius, radius, startAngle, endAngle};
758 
759  currentNet = gerb_image_return_aperture_index(image, lineWidth, &apertureIndex);
760 
761  if (!currentNet)
762  return;
763 
764  /* draw the arc */
765  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
768  currentNet->aperture = apertureIndex;
769  currentNet->start_x = centerX + (cos(startAngle*M_PI/180) * radius);
770  currentNet->start_y = centerY + (sin(startAngle*M_PI/180) * radius);
771  currentNet->stop_x = centerX + (cos(endAngle*M_PI/180) * radius);
772  currentNet->stop_y = centerY + (sin(endAngle*M_PI/180) * radius);;
773  currentNet->cirseg = g_new0 (gerbv_cirseg_t,1);
774  *(currentNet->cirseg) = cirSeg;
775 
776  gdouble angleDiff = currentNet->cirseg->angle2 - currentNet->cirseg->angle1;
777  gint i, steps = abs(angleDiff);
778  for (i=0; i<=steps; i++){
779  gdouble tempX = currentNet->cirseg->cp_x + currentNet->cirseg->width / 2.0 *
780  cos ((currentNet->cirseg->angle1 +
781  (angleDiff * i) / steps)*M_PI/180);
782  gdouble tempY = currentNet->cirseg->cp_y + currentNet->cirseg->width / 2.0 *
783  sin ((currentNet->cirseg->angle1 +
784  (angleDiff * i) / steps)*M_PI/180);
785  gerber_update_min_and_max (&currentNet->boundingBox,
786  tempX, tempY,
787  lineWidth/2,lineWidth/2,
788  lineWidth/2,lineWidth/2);
789  }
790  gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
791  return;
792 }
793 
794 void
795 gerbv_image_create_line_object (gerbv_image_t *image, gdouble startX, gdouble startY,
796  gdouble endX, gdouble endY, gdouble lineWidth, gerbv_aperture_type_t apertureType) {
797  int apertureIndex;
798  gerbv_net_t *currentNet;
799 
800  currentNet = gerb_image_return_aperture_index(image, lineWidth, &apertureIndex);
801 
802  if (!currentNet)
803  return;
804 
805  /* draw the line */
806  currentNet = gerber_create_new_net (currentNet, NULL, NULL);
808 
809  /* if the start and end coordinates are the same, use a "flash" aperture state */
810  if ((fabs(startX - endX) < 0.001) && (fabs(startY - endY) < 0.001))
812  else
814  currentNet->aperture = apertureIndex;
815  currentNet->start_x = startX;
816  currentNet->start_y = startY;
817  currentNet->stop_x = endX;
818  currentNet->stop_y = endY;
819 
820  gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
821  lineWidth/2,lineWidth/2,lineWidth/2,lineWidth/2);
822  gerber_update_min_and_max (&currentNet->boundingBox,currentNet->start_x,currentNet->start_y,
823  lineWidth/2,lineWidth/2,lineWidth/2,lineWidth/2);
824  gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
825  return;
826 }
827 
828 void
829 gerbv_image_create_window_pane_objects (gerbv_image_t *image, gdouble lowerLeftX,
830  gdouble lowerLeftY, gdouble width, gdouble height, gdouble areaReduction,
831  gint paneRows, gint paneColumns, gdouble paneSeparation){
832  int i,j;
833  gdouble startX,startY,boxWidth,boxHeight;
834 
835  startX = lowerLeftX + (areaReduction * width) / 2.0;
836  startY = lowerLeftY + (areaReduction * height) / 2.0;
837  boxWidth = (width * (1.0 - areaReduction) - (paneSeparation * (paneColumns - 1))) / paneColumns;
838  boxHeight = (height * (1.0 - areaReduction) - (paneSeparation * (paneRows - 1))) / paneRows;
839 
840  for (i=0; i<paneColumns; i++){
841  for (j=0; j<paneRows; j++) {
842  gerbv_image_create_rectangle_object (image, startX + (i * (boxWidth + paneSeparation)),
843  startY + (j * (boxHeight + paneSeparation)),boxWidth, boxHeight);
844  }
845  }
846 
847  return;
848 }
849 
850 gboolean
851 gerbv_image_reduce_area_of_selected_objects (GArray *selectionArray,
852  gdouble areaReduction, gint paneRows, gint paneColumns, gdouble paneSeparation){
853  int i;
854  gdouble minX,minY,maxX,maxY;
855 
856  for (i=0; i<selectionArray->len; i++) {
857  gerbv_selection_item_t sItem = g_array_index (selectionArray,gerbv_selection_item_t, i);
858  gerbv_image_t *image = sItem.image;
859  gerbv_net_t *currentNet = sItem.net;
860 
861  /* determine the object type first */
862  minX = HUGE_VAL;
863  maxX = -HUGE_VAL;
864  minY = HUGE_VAL;
865  maxY = -HUGE_VAL;
866 
867  if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
868  /* if it's a polygon, just determine the overall area of it and delete it */
870 
871  for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
872  if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END)
873  break;
875  if (currentNet->stop_x < minX)
876  minX = currentNet->stop_x;
877  if (currentNet->stop_y < minY)
878  minY = currentNet->stop_y;
879  if (currentNet->stop_x > maxX)
880  maxX = currentNet->stop_x;
881  if (currentNet->stop_y > maxY)
882  maxY = currentNet->stop_y;
883  }
885  }
886  else if ((currentNet->interpolation == GERBV_INTERPOLATION_x10) ||
887  (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx01) ||
889  (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx1)) {
890  gdouble dx=0,dy=0;
891  /* figure out the overall size of this element */
892  switch (image->aperture[currentNet->aperture]->type) {
893  case GERBV_APTYPE_CIRCLE :
894  case GERBV_APTYPE_OVAL :
895  case GERBV_APTYPE_POLYGON :
896  dx = dy = image->aperture[currentNet->aperture]->parameter[0];
897  break;
899  dx = (image->aperture[currentNet->aperture]->parameter[0]/ 2);
900  dy = (image->aperture[currentNet->aperture]->parameter[1]/ 2);
901  break;
902  default :
903  break;
904  }
905  if (currentNet->start_x-dx < minX)
906  minX = currentNet->start_x-dx;
907  if (currentNet->start_y-dy < minY)
908  minY = currentNet->start_y-dy;
909  if (currentNet->start_x+dx > maxX)
910  maxX = currentNet->start_x+dx;
911  if (currentNet->start_y+dy > maxY)
912  maxY = currentNet->start_y+dy;
913 
914  if (currentNet->stop_x-dx < minX)
915  minX = currentNet->stop_x-dx;
916  if (currentNet->stop_y-dy < minY)
917  minY = currentNet->stop_y-dy;
918  if (currentNet->stop_x+dx > maxX)
919  maxX = currentNet->stop_x+dx;
920  if (currentNet->stop_y+dy > maxY)
921  maxY = currentNet->stop_y+dy;
922 
923  /* finally, delete node */
925  }
926  /* we don't current support arcs */
927  else
928  return FALSE;
929 
930  /* create new structures */
931  gerbv_image_create_window_pane_objects (image, minX, minY, maxX - minX, maxY - minY,
932  areaReduction, paneRows, paneColumns, paneSeparation);
933  }
934  return TRUE;
935 }
936 
937 gboolean
938 gerbv_image_move_selected_objects (GArray *selectionArray, gdouble translationX,
939  gdouble translationY) {
940  int i;
941 
942  for (i=0; i<selectionArray->len; i++) {
943  gerbv_selection_item_t sItem = g_array_index (selectionArray,gerbv_selection_item_t, i);
944  gerbv_net_t *currentNet = sItem.net;
945 
946  if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
947  /* if it's a polygon, step through every vertex and translate the point */
948  for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
949  if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END)
950  break;
951  currentNet->start_x += translationX;
952  currentNet->start_y += translationY;
953  currentNet->stop_x += translationX;
954  currentNet->stop_y += translationY;
955  }
956  }
957  else {
958  /* otherwise, just move the single element */
959  currentNet->start_x += translationX;
960  currentNet->start_y += translationY;
961  currentNet->stop_x += translationX;
962  currentNet->stop_y += translationY;
963  }
964  }
965  return TRUE;
966 }
967 
968 gerbv_net_t *
970  gerbv_net_t *currentNet=oldNet;
971 
972  if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
973  /* if it's a polygon, step to the next non-polygon net */
974  for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
975  if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END) {
976  return currentNet->next;
977  }
978  }
979  return NULL;
980  }
981  else {
982  return currentNet->next;
983  }
984 }
985 
986 void
988  gerbv_net_t *currentNet;
989 
990  /* run through and find last net pointer */
991  for (currentNet = parsed_image->netlist; currentNet->next; currentNet = currentNet->next){
992  if (parsed_image->aperture[currentNet->aperture] == NULL) {
993  parsed_image->aperture[currentNet->aperture] = g_new0 (gerbv_aperture_t, 1);
994  parsed_image->aperture[currentNet->aperture]->type = GERBV_APTYPE_CIRCLE;
995  parsed_image->aperture[currentNet->aperture]->parameter[0] = 0;
996  parsed_image->aperture[currentNet->aperture]->parameter[1] = 0;
997  }
998  }
999 }